diff --git a/.all-contributorsrc b/.all-contributorsrc index aebf49231..c6fe8646b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -196,6 +196,15 @@ "contributions": [ "code" ] + }, + { + "login": "VikramNagwal", + "name": "Vikram", + "avatar_url": "https://avatars.githubusercontent.com/u/123088024?v=4", + "profile": "https://github.com/VikramNagwal", + "contributions": [ + "code" + ] } ] } diff --git a/.env.local_dev b/.env.local_dev index a04faba14..2303bf980 100644 --- a/.env.local_dev +++ b/.env.local_dev @@ -45,14 +45,14 @@ DO_REGION=us-west USE_LOCAL=TRUE # Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) ********************************************************************************************************************* -MAILGUN_API_KEY=XXXXX +MAILGUN_API_KEY= MAILGUN_DOMAIN=mail.yourdomain.com MAILGUN_SENDER=postmaster@mail.yourdomain.com SMTP_ENABLE= -SMTP_HOST= -SMTP_PORT= -SMTP_USER_EMAIL= -SMTP_PASS= +SMTP_HOST=smtp.yourhost.com +SMTP_PORT=443 +SMTP_USER_EMAIL=mailer@yourdomain.com +SMTP_PASS=password # Base64 encoded PFX or p12 document signing certificate file ********************************************************************************************************************* diff --git a/README.md b/README.md index 510848dd2..9c5d5b378 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,9 @@ We would like to thank all our contributors and users for their support and feed Govinda Kocharekar
Govinda Kocharekar

💻 Bilal Ahmad Bhat
Bilal Ahmad Bhat

💻 + + Vikram
Vikram

💻 + diff --git a/apps/OpenSign/public/version.txt b/apps/OpenSign/public/version.txt index 3e82ea442..e69de29bb 100644 --- a/apps/OpenSign/public/version.txt +++ b/apps/OpenSign/public/version.txt @@ -1 +0,0 @@ -v1.0.5-beta diff --git a/apps/OpenSign/src/components/AppendFormInForm.js b/apps/OpenSign/src/components/AppendFormInForm.js index 22017e423..47679d033 100644 --- a/apps/OpenSign/src/components/AppendFormInForm.js +++ b/apps/OpenSign/src/components/AppendFormInForm.js @@ -46,6 +46,7 @@ const AppendFormInForm = (props) => { // Define a function to handle form submission const handleSubmit = async (e) => { e.preventDefault(); + e.stopPropagation(); setIsLoader(true); Parse.serverURL = parseBaseUrl; Parse.initialize(parseAppId); @@ -105,13 +106,18 @@ const AppendFormInForm = (props) => { const res = await contactQuery.save(); const parseData = JSON.parse(JSON.stringify(res)); - props.details({ - value: parseData[props.valueKey], - label: parseData[props.displayKey] - }); + if (props.details) { + props.details({ + value: parseData[props.valueKey], + label: parseData[props.displayKey] + }); + } if (props.closePopup) { props.closePopup(); } + if (props.handleUserData) { + props.handleUserData(parseData); + } setIsLoader(false); // Reset the form fields @@ -158,13 +164,18 @@ const AppendFormInForm = (props) => { const res = await contactQuery.save(); const parseData = JSON.parse(JSON.stringify(res)); - props.details({ - value: parseData[props.valueKey], - label: parseData[props.displayKey] - }); + if (props.details) { + props.details({ + value: parseData[props.valueKey], + label: parseData[props.displayKey] + }); + } if (props.closePopup) { props.closePopup(); } + if (props.handleUserData) { + props.handleUserData(parseData); + } setIsLoader(false); // Reset the form fields setAddYourself(false); diff --git a/apps/OpenSign/src/components/TreeWidget.js b/apps/OpenSign/src/components/TreeWidget.js index ecbce7af4..569112d71 100644 --- a/apps/OpenSign/src/components/TreeWidget.js +++ b/apps/OpenSign/src/components/TreeWidget.js @@ -5,7 +5,7 @@ import Parse from "parse"; import axios from "axios"; import "../styles/spinner.css"; import TreeFormComponent from "./TreeFormComponent"; -import TreeEditForm from "./TreeEditForm"; +// import TreeEditForm from "./TreeEditForm"; import "../styles/modal.css"; import Modal from "react-modal"; @@ -22,7 +22,7 @@ const TreeWidget = (props) => { const [schemaState, setSchemaState] = useState({}); const [TabURL, setTabURL] = useState(""); const [editable, setEditable] = useState(false); - const [editId, setEditId] = useState(""); + // const [editId, setEditId] = useState(""); const [defaultState, setDefaultState] = useState(false); const [isShowModal, setIsShowModal] = useState(false); const selectFolderHandle = async () => { diff --git a/apps/OpenSign/src/components/fields/CreateFolder.js b/apps/OpenSign/src/components/fields/CreateFolder.js new file mode 100644 index 000000000..1f921e904 --- /dev/null +++ b/apps/OpenSign/src/components/fields/CreateFolder.js @@ -0,0 +1,147 @@ +import React, { useEffect, useState } from "react"; +import Parse from "parse"; +import Alert from "../../primitives/Alert"; + +const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => { + const folderPtr = { + __type: "Pointer", + className: folderCls, + objectId: parentFolderId + }; + const [name, setName] = useState(""); + const [folderList, setFolderList] = useState([]); + const [isAlert, setIsAlert] = useState(false); + const [selectedParent, setSelectedParent] = useState(); + const [alert, setAlert] = useState({ type: "info", message: "" }); + useEffect(() => { + fetchFolder(); + // eslint-disable-next-line + }, []); + + const fetchFolder = async () => { + try { + const FolderQuery = new Parse.Query(folderCls); + if (parentFolderId) { + FolderQuery.equalTo("Folder", folderPtr); + FolderQuery.equalTo("Type", "Folder"); + } else { + FolderQuery.doesNotExist("Folder"); + FolderQuery.equalTo("Type", "Folder"); + } + + const res = await FolderQuery.find(); + if (res) { + const result = JSON.parse(JSON.stringify(res)); + if (result) { + setFolderList(result); + } + } + } catch (error) { + console.log("Err ", error); + } + }; + const handleCreateFolder = async (event) => { + event.preventDefault(); + if (name) { + const currentUser = Parse.User.current(); + const exsitQuery = new Parse.Query(folderCls); + exsitQuery.equalTo("Name", name); + exsitQuery.equalTo("Type", "Folder"); + if (parentFolderId) { + exsitQuery.equalTo("Folder", folderPtr); + } + const templExist = await exsitQuery.first(); + if (templExist) { + setAlert({ type: "dange", message: "Folder already exist!" }); + setIsAlert(true); + setTimeout(() => { + setIsAlert(false); + }, 1000); + } else { + const template = new Parse.Object(folderCls); + template.set("Name", name); + template.set("Type", "Folder"); + + if (selectedParent) { + template.set("Folder", { + __type: "Pointer", + className: folderCls, + objectId: selectedParent + }); + } else if (parentFolderId) { + template.set("Folder", folderPtr); + } + template.set("CreatedBy", Parse.User.createWithoutData(currentUser.id)); + const res = await template.save(); + if (res) { + if (onSuccess) { + setAlert({ + type: "success", + message: "Folder created successfully!" + }); + setIsAlert(true); + setTimeout(() => { + setIsAlert(false); + }, 1000); + onSuccess(res); + } + } + } + } else { + setAlert({ type: "info", message: "Please fill folder name" }); + setIsAlert(true); + setTimeout(() => { + setIsAlert(false); + }, 1000); + } + }; + const handleOptions = (e) => { + setSelectedParent(e.target.value); + }; + return ( +
+ {isAlert && {alert.message}} +
+

Create Folder

+
+ + setName(e.target.value)} + required + /> +
+
+ + +
+
+ +
+
+
+ ); +}; + +export default CreateFolder; diff --git a/apps/OpenSign/src/components/fields/DropboxChoose.js b/apps/OpenSign/src/components/fields/DropboxChoose.js index 9ed1bb3f8..a97e2e20f 100644 --- a/apps/OpenSign/src/components/fields/DropboxChoose.js +++ b/apps/OpenSign/src/components/fields/DropboxChoose.js @@ -41,7 +41,8 @@ export default function DropboxChooser({ children, onSuccess, onCancel }) { [onSuccess, onCancel] ); - const handleChoose = useCallback(() => { + const handleChoose = useCallback((e) => { + e.preventDefault() if (window.Dropbox) { window.Dropbox.choose(options); } diff --git a/apps/OpenSign/src/components/fields/FileUpload.js b/apps/OpenSign/src/components/fields/FileUpload.js index 09a11e8d2..e6c632a02 100644 --- a/apps/OpenSign/src/components/fields/FileUpload.js +++ b/apps/OpenSign/src/components/fields/FileUpload.js @@ -258,7 +258,7 @@ const FileUpload = (props) => {
- file selected : {props.formData.split("/")[3]} + file selected : {props.formData?.split("/")[3]?.split("_")[1]}
{ @@ -271,10 +271,12 @@ const FileUpload = (props) => {
- + {process.env.REACT_APP_DROPBOX_API_KEY && ( + + )}
) : (
@@ -294,10 +296,12 @@ const FileUpload = (props) => { accept="application/pdf,application/vnd.ms-excel" onChange={onChange} /> - + {process.env.REACT_APP_DROPBOX_API_KEY && ( + + )}
)} diff --git a/apps/OpenSign/src/components/fields/SelectFolder.js b/apps/OpenSign/src/components/fields/SelectFolder.js new file mode 100644 index 000000000..13c2ff157 --- /dev/null +++ b/apps/OpenSign/src/components/fields/SelectFolder.js @@ -0,0 +1,355 @@ +import React, { useEffect, useState } from "react"; +import Parse from "parse"; +import CreateFolder from "./CreateFolder"; +import ModalUi from "../../primitives/ModalUi"; + +const SelectFolder = ({ required, onSuccess, folderCls }) => { + const [isOpen, SetIsOpen] = useState(false); + const [clickFolder, setClickFolder] = useState(""); + const [selectFolder, setSelectedFolder] = useState({}); + const [folderList, setFolderList] = useState([]); + const [tabList, setTabList] = useState([]); + const [isLoader, setIsLoader] = useState(false); + const [folderPath, setFolderPath] = useState(""); + const [isAdd, setIsAdd] = useState(false); + useEffect(() => { + if (isOpen) { + setIsAdd(false); + setClickFolder({}); + setFolderList([]); + setTabList([]); + fetchFolder(); + } + // eslint-disable-next-line + }, [isOpen]); + const fetchFolder = async (folderPtr) => { + setIsLoader(true); + try { + const FolderQuery = new Parse.Query(folderCls); + if (folderPtr) { + FolderQuery.equalTo("Folder", folderPtr); + FolderQuery.equalTo("Type", "Folder"); + } else { + FolderQuery.doesNotExist("Folder"); + FolderQuery.equalTo("Type", "Folder"); + } + + const res = await FolderQuery.find(); + if (res) { + const result = JSON.parse(JSON.stringify(res)); + if (result) { + setFolderList(result); + setIsLoader(false); + } + setIsLoader(false); + } + } catch (error) { + setIsLoader(false); + } + }; + const handleSelect = (item) => { + setFolderList([]); + setClickFolder({ ObjectId: item.objectId, Name: item.Name }); + if (tabList.length > 0) { + const tab = tabList.some((x) => x.objectId === item.objectId); + if (!tab) { + setTabList((tabs) => [...tabs, item]); + const folderPtr = { + __type: "Pointer", + className: folderCls, + objectId: item.objectId + }; + fetchFolder(folderPtr); + } + } else { + setTabList((tabs) => [...tabs, item]); + const folderPtr = { + __type: "Pointer", + className: folderCls, + objectId: item.objectId + }; + + fetchFolder(folderPtr); + } + }; + + const handleSubmit = () => { + let url = "Root"; + tabList.forEach((t) => { + url = url + " / " + t.Name; + }); + setFolderPath(url); + setSelectedFolder(clickFolder); + if (onSuccess) { + onSuccess(clickFolder); + } + SetIsOpen(false); + }; + const handleCancel = () => { + SetIsOpen(false); + setClickFolder({}); + setFolderList([]); + setTabList([]); + }; + + const removeTabListItem = async (e, i) => { + e.preventDefault(); + // setEditable(false); + if (!isAdd) { + setIsLoader(true); + let folderPtr; + if (i) { + setFolderList([]); + let list = tabList.filter((itm, j) => { + if (j <= i) { + return itm; + } + }); + let _len = list.length - 1; + folderPtr = { + __type: "Pointer", + className: folderCls, + objectId: list[_len].objectId + }; + setTabList(list); + } else { + setClickFolder({}); + setSelectedFolder({}); + setFolderList([]); + setTabList([]); + } + fetchFolder(folderPtr); + } + }; + const handleCreate = () => { + setIsAdd(!isAdd); + }; + const handleAddFolder = () => { + setFolderList([]); + if (clickFolder && clickFolder.ObjectId) { + fetchFolder({ + __type: "Pointer", + className: folderCls, + objectId: clickFolder.ObjectId + }); + } else { + fetchFolder(); + } + }; + return ( +
+
+ +
+
+
+ +
+
+
+

+ {selectFolder && selectFolder.Name ? selectFolder.Name : "Root"} +

+
SetIsOpen(true)}> + +
+
+

+ {selectFolder && selectFolder.Name ? `(${folderPath})` : ""} +

+
+
+ +
+
+ removeTabListItem(e)} + > + Root /{" "} + + {tabList && + tabList.map((tab, i) => ( + + removeTabListItem(e, i)} + > + {tab.Name} + + {" / "} + + ))} +
+
+
+ {!isAdd && + folderList.length > 0 && + folderList.map((folder) => ( +
handleSelect(folder)} + > +
+ + {folder.Name} +
+
+ ))} + {isAdd && ( + + )} + {isLoader && ( +
+ +
+ )} +
+
+
+
+
+ {isAdd ? ( + + ) : ( + + )} +
+
+ +
+
+
+ {/* {isOpen && ( +
+
+
+ Select Folder +
+
+ +
+
+
+
+
+ removeTabListItem(e)} + > + Root /{" "} + + {tabList && + tabList.map((tab, i) => ( + + removeTabListItem(e, i)} + > + {tab.Name} + + {" / "} + + ))} +
+
+
+ {!isAdd && + folderList.length > 0 && + folderList.map((folder) => ( +
handleSelect(folder)} + > +
+ + {folder.Name} +
+
+ ))} + {isAdd && ( + + )} + {isLoader && ( +
+ +
+ )} +
+
+
+
+
+ {isAdd ? ( + + ) : ( + + )} +
+
+ +
+
+
+ )} */} +
+ ); +}; + +export default SelectFolder; diff --git a/apps/OpenSign/src/components/fields/SignersInput.js b/apps/OpenSign/src/components/fields/SignersInput.js new file mode 100644 index 000000000..0e9697965 --- /dev/null +++ b/apps/OpenSign/src/components/fields/SignersInput.js @@ -0,0 +1,190 @@ +import React, { useState, useEffect } from "react"; +import Select from "react-select"; +import AppendFormInForm from "../AppendFormInForm"; +import Modal from "react-modal"; +import Parse from "parse"; +function arrayMove(array, from, to) { + array = array.slice(); + array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]); + return array; +} + +/** + * react-sortable-hoc is depcreated not usable from react 18.x.x + * need to replace it with @dnd-kit + * code changes required + */ + +const SignersInput = (props) => { + Modal.setAppElement("body"); + const [state, setState] = useState(undefined); + // const [editFormData, setEditFormData] = useState([]); + const [selected, setSelected] = React.useState([]); + const [isModal, setIsModel] = useState(false); + const onChange = (selectedOptions) => setSelected(selectedOptions); + const [modalIsOpen, setModalIsOpen] = useState(false); + + const onSortEnd = ({ oldIndex, newIndex }) => { + const newValue = arrayMove(selected, oldIndex, newIndex); + setSelected(newValue); + }; + + const GetSelectListData = async () => { + try { + const currentUser = Parse.User.current(); + const contactbook = new Parse.Query("contracts_Contactbook"); + contactbook.equalTo( + "CreatedBy", + Parse.User.createWithoutData(currentUser.id) + ); + contactbook.notEqualTo("IsDeleted", true); + const contactRes = await contactbook.find(); + if (contactRes) { + const res = JSON.parse(JSON.stringify(contactRes)); + let list = []; + + // let _selected = []; + res.forEach((x) => { + let obj = { + label: x.Name, + value: x.objectId, + isChecked: true + }; + + list.push(obj); + }); + setState(list); + } + } catch (error) { + console.log("err", error); + } + }; + + useEffect(() => { + GetSelectListData(); + }, []); + + useEffect(() => { + if (selected && selected.length) { + let newData = []; + selected.forEach((x) => { + newData.push(x.value); + }); + if (props.onChange) { + props.onChange(newData); + } + } + + // eslint-disable-next-line + }, [selected]); + + const handleModalCloseClick = () => { + setIsModel(false); + setModalIsOpen(false); + }; + + const openModal = () => { + setModalIsOpen(true); + }; + + // `handleNewDetails` is used to set just save from quick form to selected option in dropdown + const handleNewDetails = (data) => { + setState([...state, data]); + if (selected.length > 0) { + setSelected([...selected, data]); + } else { + setSelected([data]); + } + }; + + return ( +
+ +
+
+ handleFileInput(e)} + accept="application/pdf,application/vnd.ms-excel" + required + /> + {process.env.REACT_APP_DROPBOX_API_KEY && ( + + )} +
+ )} +
+
+ + handleStrInput(e)} + required + /> +
+
+ + handleStrInput(e)} + required + /> +
+
+ + handleStrInput(e)} + /> +
+ {/* */} + +
+ +
handleReset()} + > + Reset +
+
+ +
+ ); +}; + +export default TemplateForm; diff --git a/apps/OpenSign/src/routes/Form.js b/apps/OpenSign/src/routes/Form.js index fd5c67449..2c6c67709 100644 --- a/apps/OpenSign/src/routes/Form.js +++ b/apps/OpenSign/src/routes/Form.js @@ -25,6 +25,7 @@ import TreeWidget from "../components/TreeWidget"; import parse from "html-react-parser"; import Title from "../components/Title"; import { formJson } from "../json/FormJson"; +import TemplateForm from "../primitives/TemplateForm"; const widget = { TimeWidget: TimeWidget }; @@ -41,15 +42,19 @@ const fields = () => { function FormBuilderFn(props) { const { id } = useParams(); const navigate = useNavigate(); - return ( - - ); + if (id === "template") { + return ; + } else { + return ( + + ); + } } class FormBuilder extends Component { state = { diff --git a/apps/OpenSign/src/routes/Report.js b/apps/OpenSign/src/routes/Report.js index 88e80417f..af3273095 100644 --- a/apps/OpenSign/src/routes/Report.js +++ b/apps/OpenSign/src/routes/Report.js @@ -15,6 +15,7 @@ const Report = () => { const [heading, setHeading] = useState([]); const [isNextRecord, setIsNextRecord] = useState(false); const [isMoreDocs, setIsMoreDocs] = useState(true); + const [form, setForm]= useState("") const abortController = new AbortController(); const docPerPage = 10; @@ -50,6 +51,7 @@ const Report = () => { setActions(json.actions); setHeading(json.heading); setReportName(json.reportName); + setForm(json.form) Parse.serverURL = localStorage.getItem("BaseUrl12"); Parse.initialize(localStorage.getItem("AppID12")); const currentUser = Parse.User.current().id; @@ -154,6 +156,7 @@ const Report = () => { setIsNextRecord={setIsNextRecord} isMoreDocs={isMoreDocs} docPerPage={docPerPage} + form={form} /> ) : (
diff --git a/apps/OpenSignServer/cloud/main.js b/apps/OpenSignServer/cloud/main.js index e42ee38e5..7532bc00d 100644 --- a/apps/OpenSignServer/cloud/main.js +++ b/apps/OpenSignServer/cloud/main.js @@ -17,6 +17,8 @@ import getUserDetails from './parsefunction/getUserDetails.js'; import getDocument from './parsefunction/getDocument.js'; import getDrive from './parsefunction/getDrive.js'; import getReport from './parsefunction/getReport.js'; +import TemplateAfterSave from './parsefunction/TemplateAfterSave.js'; +import GetTemplate from './parsefunction/GetTemplate.js'; Parse.Cloud.define('AddUserToRole', addUserToGroups); Parse.Cloud.define('UserGroups', getUserGroups); @@ -26,9 +28,6 @@ Parse.Cloud.define('googlesign', GoogleSign); Parse.Cloud.define('zohodetails', ZohoDetails); Parse.Cloud.define('usersignup', usersignup); Parse.Cloud.define('facebooksign', FacebookSign); -Parse.Cloud.afterSave('contracts_Document', DocumentAftersave); -Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave); -Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave); Parse.Cloud.define('SendOTPMailV1', sendMailOTPv1); Parse.Cloud.define('sendmail', SendMailv1); Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail); @@ -36,4 +35,9 @@ Parse.Cloud.define('getUserId', getUserId); Parse.Cloud.define('getUserDetails', getUserDetails); Parse.Cloud.define('getDocument', getDocument); Parse.Cloud.define('getDrive', getDrive) -Parse.Cloud.define('getReport', getReport) \ No newline at end of file +Parse.Cloud.define('getReport', getReport) +Parse.Cloud.define("getTemplate", GetTemplate) +Parse.Cloud.afterSave('contracts_Document', DocumentAftersave); +Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave); +Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave); +Parse.Cloud.afterSave("contracts_Template", TemplateAfterSave) \ No newline at end of file diff --git a/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js b/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js new file mode 100644 index 000000000..768827eee --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/GetTemplate.js @@ -0,0 +1,53 @@ +import axios from 'axios'; + +export default async function GetTemplate(request) { + const serverUrl = process.env.SERVER_URL; + const templateId = request.params.templateId; + + try { + const userRes = await axios.get(serverUrl + '/users/me', { + headers: { + 'X-Parse-Application-Id': process.env.APP_ID, + 'X-Parse-Session-Token': request.headers['sessiontoken'], + }, + }); + const userId = userRes.data && userRes.data.objectId; + // console.log("templateId ", templateId) + // console.log("userId ",userId) + if (templateId && userId) { + try { + const template = new Parse.Query('contracts_Template'); + template.equalTo('objectId', templateId); + template.include('ExtUserPtr'); + template.include('Signers'); + template.include('CreateBy'); + const res = await template.first({ useMasterKey: true }); + // console.log("res ", res) + if (res) { + // console.log("res ",res) + const acl = res.getACL(); + console.log("acl", acl.getReadAccess(userId)) + if (acl && acl.getReadAccess(userId)) { + return res; + } else { + return { error: "You don't have access of this document!" }; + } + } else { + return { error: "You don't have access of this document!" }; + } + } catch (err) { + console.log('err', err); + return err; + } + } else { + return { error: 'Please pass required parameters!' }; + } + } catch (err) { + console.log('err', err); + if (err.code == 209) { + return { error: 'Invalid session token' }; + } else { + return { error: "You don't have access of this document!" }; + } + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js new file mode 100644 index 000000000..7d22ccb86 --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js @@ -0,0 +1,83 @@ +export default async function TemplateAfterSave(request) { + try { + if (!request.original) { + console.log('new entry is insert in contracts_Template'); + // update acl of New Document If There are signers present in array + const signers = request.object.get('Signers'); + + if (signers && signers.length > 0) { + await updateAclDoc(request.object.id); + } else { + await updateSelfDoc(request.object.id); + } + } else { + if (request.user) { + const signers = request.object.get('Signers'); + if (signers && signers.length > 0) { + await updateAclDoc(request.object.id); + } else { + await updateSelfDoc(request.object.id); + } + } + } + } catch (err) { + console.log('err in aftersave of contracts_Template'); + console.log(err); + } + + async function updateAclDoc(objId) { + // console.log("In side updateAclDoc func") + // console.log(objId) + const Query = new Parse.Query('contracts_Template'); + Query.include('Signers'); + const updateACL = await Query.get(objId, { useMasterKey: true }); + const res = JSON.parse(JSON.stringify(updateACL)); + // console.log("res"); + // console.log(JSON.stringify(res)); + const UsersPtr = res.Signers.map(item => item.UserId); + + if (res.Signers[0].ExtUserPtr) { + const ExtUserSigners = res.Signers.map(item => { + return { + __type: 'Pointer', + className: 'contracts_Users', + objectId: item.ExtUserPtr.objectId, + }; + }); + updateACL.set('Signers', ExtUserSigners); + } + + // console.log("UsersPtr") + // console.log(JSON.stringify(UsersPtr)) + const newACL = new Parse.ACL(); + newACL.setPublicReadAccess(false); + newACL.setPublicWriteAccess(false); + newACL.setReadAccess(request.user, true); + newACL.setWriteAccess(request.user, true); + + UsersPtr.forEach(x => { + newACL.setReadAccess(x.objectId, true); + newACL.setWriteAccess(x.objectId, true); + }); + + updateACL.setACL(newACL); + updateACL.save(null, { useMasterKey: true }); + } + + async function updateSelfDoc(objId) { + // console.log("Inside updateSelfDoc func") + + const Query = new Parse.Query('contracts_Template'); + const updateACL = await Query.get(objId, { useMasterKey: true }); + // const res = JSON.parse(JSON.stringify(updateACL)); + // console.log("res"); + // console.log(JSON.stringify(res)); + const newACL = new Parse.ACL(); + newACL.setPublicReadAccess(false); + newACL.setPublicWriteAccess(false); + newACL.setReadAccess(request.user, true); + newACL.setWriteAccess(request.user, true); + updateACL.setACL(newACL); + updateACL.save(null, { useMasterKey: true }); + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/getDocument.js b/apps/OpenSignServer/cloud/parsefunction/getDocument.js index 9e4d71ff3..8666cafdf 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getDocument.js +++ b/apps/OpenSignServer/cloud/parsefunction/getDocument.js @@ -40,7 +40,7 @@ export default async function getDocument(request) { return { error: 'Please pass required parameters!' }; } } catch (err) { - console.log('err'); + console.log('err', err); if (err.code == 209) { return { error: 'Invalid session token' }; } else { diff --git a/apps/OpenSignServer/cloud/parsefunction/getReport.js b/apps/OpenSignServer/cloud/parsefunction/getReport.js index 759765aaa..ee72f0d20 100644 --- a/apps/OpenSignServer/cloud/parsefunction/getReport.js +++ b/apps/OpenSignServer/cloud/parsefunction/getReport.js @@ -19,7 +19,7 @@ export default async function getReport(request) { const userId = userRes.data && userRes.data.objectId; if (userId) { const json = reportId && reportJson(reportId, userId); - const clsName = reportId === '5KhaPr482K' ? 'contracts_Contactbook' : 'contracts_Document'; + const clsName = json?.reportClass ? json.reportClass : 'contracts_Document'; if (json) { const { params, keys } = json; const orderBy = '-updatedAt'; diff --git a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js index 8ad9c47df..238846b83 100644 --- a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js +++ b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js @@ -32,6 +32,18 @@ export default function reportJson(id, userId) { $gt: { __type: 'Date', iso: new Date().toISOString() }, }, Placeholders: { $ne: null }, + Signers: { + $inQuery: { + where: { + UserId: { + __type: 'Pointer', + className: '_User', + objectId: currentUserId, + }, + }, + className: 'contracts_Contactbook', + }, + }, }, keys: [ 'Name', @@ -154,7 +166,7 @@ export default function reportJson(id, userId) { $gt: { __type: 'Date', iso: new Date().toISOString() }, }, }, - keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], + keys: ['Name', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], }; // Recent signature requests report show on dashboard case '5Go51Q7T8r': @@ -168,17 +180,20 @@ export default function reportJson(id, userId) { $gt: { __type: 'Date', iso: new Date().toISOString() }, }, Placeholders: { $ne: null }, + Signers: { + $inQuery: { + where: { + UserId: { + __type: 'Pointer', + className: '_User', + objectId: currentUserId, + }, + }, + className: 'contracts_Contactbook', + }, + }, }, - keys: [ - 'Name', - 'Note', - 'Folder.Name', - 'URL', - 'ExtUserPtr.Name', - 'Signers.Name', - 'Signers.UserId', - 'AuditTrail', - ], + keys: ['Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name', 'Signers.UserId', 'AuditTrail'], }; // Drafts report show on dashboard case 'kC5mfynCi4': @@ -202,6 +217,7 @@ export default function reportJson(id, userId) { case '5KhaPr482K': return { reportName: 'Contactbook', + reportClass: 'contracts_Contactbook', params: { CreatedBy: { __type: 'Pointer', @@ -212,6 +228,21 @@ export default function reportJson(id, userId) { }, keys: ['Name', 'Email', 'Phone'], }; + // Templates report + case '6TeaPr321t': + return { + reportName: 'Templates', + reportClass: 'contracts_Template', + params: { + Type: { $ne: 'Folder' }, + CreatedBy: { + __type: 'Pointer', + className: '_User', + objectId: currentUserId, + }, + }, + keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], + }; default: return null; } diff --git a/apps/OpenSignServer/databases/migrations/20231129103946-update_menu.cjs b/apps/OpenSignServer/databases/migrations/20231129103946-update_menu.cjs index 9581be3a8..2bb108b99 100644 --- a/apps/OpenSignServer/databases/migrations/20231129103946-update_menu.cjs +++ b/apps/OpenSignServer/databases/migrations/20231129103946-update_menu.cjs @@ -38,7 +38,7 @@ exports.up = async Parse => { pageType: 'form', description: '', objectId: '8mZzFxbG1z', - }, + } ], }, { diff --git a/apps/OpenSignServer/databases/migrations/20231208132950-update_template_menu.cjs b/apps/OpenSignServer/databases/migrations/20231208132950-update_template_menu.cjs new file mode 100644 index 000000000..9c33a5102 --- /dev/null +++ b/apps/OpenSignServer/databases/migrations/20231208132950-update_template_menu.cjs @@ -0,0 +1,572 @@ +/** + * + * @param {Parse} Parse + */ +exports.up = async Parse => { + const className = 'w_menu'; + const userMenu = new Parse.Query(className); + const updateUserMenu = await userMenu.get('H9vRfEYKhT'); + updateUserMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fas fa-file-signature', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + { + icon: 'fas fa-file-signature', + title: 'New template', + target: '_self', + pageType: 'form', + description: '', + objectId: 'template', + }, + ], + }, + { + icon: 'fas fa-file-signature', + title: 'Templates', + target: '_self', + pageType: 'report', + description: '', + objectId: '6TeaPr321t', + }, + { + icon: 'fas fa-folder', + title: 'OpenSignDriveâ„¢', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + ], + }, + ]); + + const AdminMenu = new Parse.Query(className); + const updateAdminMenu = await AdminMenu.get('VPh91h0ZHk'); + updateAdminMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fas fa-file-signature', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + ], + }, + { + icon: 'fas fa-folder', + title: 'OpenSignDriveâ„¢', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + { + icon: 'far fa-user', + title: 'Add User', + target: '_self', + pageType: 'form', + description: '', + objectId: 'lM0xRnM3iE', + }, + ], + }, + ]); + // TODO: Set the schema here + // Example: + // schema.addString('name').addNumber('cash'); + const batch = [updateUserMenu, updateAdminMenu]; + return Parse.Object.saveAll(batch, { useMasterKey: true }); +}; + +/** + * + * @param {Parse} Parse + */ +exports.down = async Parse => { + // TODO: set className here + const className = 'w_menu'; + const userMenu = new Parse.Query(className); + const revertUserMenu = await userMenu.get('H9vRfEYKhT'); + revertUserMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fas fa-file-signature', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + ], + }, + { + icon: 'fas fa-folder', + title: 'OpenSignDriveâ„¢', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + ], + }, + ]); + + const adminMenu = new Parse.Query(className); + const revertAdminMenu = await adminMenu.get('VPh91h0ZHk'); + revertAdminMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fas fa-file-signature', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + ], + }, + { + icon: 'fas fa-folder', + title: 'OpenSignDriveâ„¢', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + { + icon: 'far fa-user', + title: 'Add User', + target: '_self', + pageType: 'form', + description: '', + objectId: 'lM0xRnM3iE', + }, + ], + }, + ]); + // TODO: Set the schema here + // Example: + // schema.addString('name').addNumber('cash'); + const batch = [revertUserMenu, revertAdminMenu]; + return Parse.Object.saveAll(batch, { useMasterKey: true }); +}; diff --git a/apps/OpenSignServer/databases/migrations/20231220171155-create_template_cls.cjs b/apps/OpenSignServer/databases/migrations/20231220171155-create_template_cls.cjs new file mode 100644 index 000000000..295a9840e --- /dev/null +++ b/apps/OpenSignServer/databases/migrations/20231220171155-create_template_cls.cjs @@ -0,0 +1,40 @@ +/** + * + * @param {Parse} Parse + */ +exports.up = async Parse => { + const className = 'contracts_Template'; + const schema = new Parse.Schema(className); + + schema.addString('Name'); + schema.addString('URL'); + schema.addString('Note'); + schema.addString('Description'); + schema.addArray('Signers'); + schema.addBoolean('IsArchive'); + schema.addArray('Placeholders'); + schema.addPointer('Folder', 'contracts_Template'); + schema.addString('Type'); + schema.addPointer('CreatedBy', '_User'); + schema.addPointer('ExtUserPtr', 'contracts_Users'); + schema.addBoolean('EnablePhoneOTP') + schema.addBoolean('EnableEmailOTP') + schema.addBoolean('SendinOrder') + schema.addBoolean('SentToOthers') + schema.addBoolean('AutomaticReminders') + + + + return schema.save(); +}; + +/** + * + * @param {Parse} Parse + */ +exports.down = async Parse => { + const className = 'contracts_Template'; + const schema = new Parse.Schema(className); + + return schema.purge().then(() => schema.delete()); +}; \ No newline at end of file diff --git a/apps/OpenSignServer/index.js b/apps/OpenSignServer/index.js index 819940954..ae3e75bce 100644 --- a/apps/OpenSignServer/index.js +++ b/apps/OpenSignServer/index.js @@ -69,7 +69,9 @@ if (process.env.SMTP_ENABLE) { export const config = { databaseURI: process.env.DATABASE_URI || process.env.MONGODB_URI || 'mongodb://localhost:27017/dev', - cloud: process.env.CLOUD || __dirname + '/cloud/main.js', + cloud: function () { + import('./cloud/main.js'); + }, appId: process.env.APP_ID || 'myAppId', masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret! masterKeyIps: ['0.0.0.0/0', '::1'], // '::1' @@ -170,12 +172,6 @@ app.get('/', function (req, res) { res.status(200).send('open-sign-server is running !!!'); }); -// There will be a test page available on the /test path of your server url -// Remove this before launching your app -app.get('/test', function (req, res) { - res.sendFile(path.join(__dirname, '/public/test.html')); -}); - if (!process.env.TESTING) { const port = process.env.PORT || 8080; const httpServer = http.createServer(app); diff --git a/microfrontends/SignDocuments/package-lock.json b/microfrontends/SignDocuments/package-lock.json index 4598b6dad..aeedb863c 100644 --- a/microfrontends/SignDocuments/package-lock.json +++ b/microfrontends/SignDocuments/package-lock.json @@ -29,11 +29,13 @@ "react-dnd-touch-backend": "^16.0.1", "react-dom": "^18.2.0", "react-draggable": "^4.4.6", + "react-helmet": "^6.1.0", "react-pdf": "^7.4.0", "react-rnd": "^10.4.1", "react-router-dom": "^6.16.0", "react-scripts": "5.0.1", "react-scrollbars-custom": "^4.1.1", + "react-select": "^5.8.0", "react-signature-canvas": "^1.0.6", "reactour": "^1.19.1", "select-dom": "^9.0.0", @@ -2310,6 +2312,65 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, "node_modules/@emotion/is-prop-valid": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", @@ -2322,8 +2383,52 @@ "node_modules/@emotion/memoize": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", - "peer": true + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.1.tgz", + "integrity": "sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.2", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.2.tgz", + "integrity": "sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/serialize/node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" }, "node_modules/@emotion/stylis": { "version": "0.8.5", @@ -2337,6 +2442,24 @@ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", "peer": true }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -10608,6 +10731,11 @@ "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -14810,6 +14938,11 @@ "node": ">= 4.0.0" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -17748,6 +17881,25 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, + "node_modules/react-helmet": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", + "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", + "dependencies": { + "object-assign": "^4.1.1", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.1.1", + "react-side-effect": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.3.0" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -18003,6 +18155,34 @@ "react": ">=16.0.0" } }, + "node_modules/react-select": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz", + "integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-side-effect": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz", + "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==", + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-signature-canvas": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/react-signature-canvas/-/react-signature-canvas-1.0.6.tgz", @@ -19527,6 +19707,11 @@ "postcss": "^8.2.15" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/sucrase": { "version": "3.34.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", @@ -20443,6 +20628,19 @@ } } }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-sidecar": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", diff --git a/microfrontends/SignDocuments/package.json b/microfrontends/SignDocuments/package.json index 5bc6f7685..c0e70c06d 100644 --- a/microfrontends/SignDocuments/package.json +++ b/microfrontends/SignDocuments/package.json @@ -25,11 +25,13 @@ "react-dnd-touch-backend": "^16.0.1", "react-dom": "^18.2.0", "react-draggable": "^4.4.6", + "react-helmet": "^6.1.0", "react-pdf": "^7.4.0", "react-rnd": "^10.4.1", "react-router-dom": "^6.16.0", "react-scripts": "5.0.1", "react-scrollbars-custom": "^4.1.1", + "react-select": "^5.8.0", "react-signature-canvas": "^1.0.6", "reactour": "^1.19.1", "select-dom": "^9.0.0", diff --git a/microfrontends/SignDocuments/src/Component/ManageSign.js b/microfrontends/SignDocuments/src/Component/ManageSign.js index e6b110f4e..c0e1208cd 100644 --- a/microfrontends/SignDocuments/src/Component/ManageSign.js +++ b/microfrontends/SignDocuments/src/Component/ManageSign.js @@ -157,7 +157,7 @@ const ManageSign = () => { file = base64StringtoFile(image, `${replaceSpace}.png`); } } - console.log("isUrl ", isUrl); + // console.log("isUrl ", isUrl); let imgUrl; if (!isUrl) { imgUrl = await uploadFile(file); diff --git a/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js b/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js index c3b3c492a..228ac55fa 100644 --- a/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js +++ b/microfrontends/SignDocuments/src/Component/PdfRequestFiles.js @@ -21,8 +21,9 @@ import { embedDocId, pdfNewWidthFun, signPdfFun, - calculateImgAspectRatio, - onImageSelect + onImageSelect, + onSaveSign, + onSaveImage } from "../utils/Utils"; import Loader from "./component/loader"; import HandleError from "./component/HandleError"; @@ -482,181 +483,99 @@ function PdfRequestFiles() { } }; //function for upload stamp image - const onSaveImage = () => { + const saveImage = () => { + //get current signers placeholder position data const currentSigner = signerPos.filter( (data) => data.signerObjId === signerObjectId ); - const i = currentSigner[0].placeHolder.findIndex((object) => { + //get current pagenumber placeholder index + const getIndex = currentSigner[0].placeHolder.findIndex((object) => { return object.pageNumber === pageNumber; }); - const updateFilter = currentSigner[0].placeHolder[i].pos.filter( - (data) => - data.key === signKey && data.Width && data.Height && data.SignUrl + //get current signer placeholder position data + const placeholderPosition = currentSigner[0].placeHolder; + //function of save image and get updated position with image url + const getUpdatePosition = onSaveImage( + placeholderPosition, + getIndex, + signKey, + imgWH, + image ); - let getIMGWH = calculateImgAspectRatio(imgWH); - - if (updateFilter.length > 0) { - const getXYdata = currentSigner[0].placeHolder[i].pos; - const getPosData = getXYdata; - const addSign = getPosData.map((url, ind) => { - if (url.key === signKey) { - return { - ...url, - Width: getIMGWH.newWidth, - Height: getIMGWH.newHeight, - SignUrl: image.src, - ImageType: image.imgType - }; - } - return url; - }); - - const newUpdateUrl = currentSigner[0].placeHolder.map((obj, ind) => { - if (ind === i) { - return { ...obj, pos: addSign }; - } - return obj; - }); - const getPlaceData = currentSigner[0].placeHolder; - getPlaceData.splice(0, getPlaceData.length, ...newUpdateUrl); - - const indexofSigner = signerPos.findIndex((object) => { - return object.signerObjId === signerObjectId; - }); - setSignerPos((prevState) => { - const newState = [...prevState]; // Create a copy of the state - newState.splice(indexofSigner, 1, ...currentSigner); // Modify the copy - return newState; // Update the state with the modified copy - }); - } else { - const getXYdata = currentSigner[0].placeHolder[i].pos; - - const getPosData = getXYdata; - - const addSign = getPosData.map((url, ind) => { - if (url.key === signKey) { - return { - ...url, - Width: getIMGWH.newWidth, - Height: getIMGWH.newHeight, - SignUrl: image.src, - ImageType: image.imgType - }; - } - return url; - }); - - const newUpdateUrl = currentSigner[0].placeHolder.map((obj, ind) => { - if (ind === i) { - return { ...obj, pos: addSign }; - } - return obj; - }); - const getPlaceData = currentSigner[0].placeHolder; - getPlaceData.splice(0, getPlaceData.length, ...newUpdateUrl); - - const indexofSigner = signerPos.findIndex((object) => { - return object.signerObjId === signerObjectId; - }); - setSignerPos((prevState) => { - const newState = [...prevState]; // Create a copy of the state - newState.splice(indexofSigner, 1, ...currentSigner); // Modify the copy - return newState; // Update the state with the modified copy - }); - } + //replace updated placeholder position with old data + placeholderPosition.splice( + 0, + placeholderPosition.length, + ...getUpdatePosition + ); + //get current signers placeholder position data index number in array + const indexofSigner = signerPos.findIndex((object) => { + return object.signerObjId === signerObjectId; + }); + //update current signers data with new placeholder position array data + setSignerPos((prevState) => { + const newState = [...prevState]; // Create a copy of the state + newState.splice(indexofSigner, 1, ...currentSigner); // Modify the copy + return newState; // Update the state with the modified copy + }); }; //function for save button to save signature or image url - const onSaveSign = (isDefaultSign) => { + const saveSign = (isDefaultSign) => { const signatureImg = isDefaultSign ? defaultSignImg : signature; - const isSign = true; - let getIMGWH; + let imgWH = { width: "", height: "" }; setIsSignPad(false); setIsImageSelect(false); setImage(); + + //get current signers placeholder position data + const currentSigner = signerPos.filter( + (data) => data.signerObjId === signerObjectId + ); + //get current pagenumber placeholder index + const getIndex = currentSigner[0].placeHolder.findIndex((object) => { + return object.pageNumber === pageNumber; + }); + + //set default signature image width and height if (isDefaultSign) { const img = new Image(); img.src = defaultSignImg; if (img.complete) { - let imgWH = { + imgWH = { width: img.width, height: img.height }; - getIMGWH = calculateImgAspectRatio(imgWH); } } - const currentSigner = signerPos.filter( - (data) => data.signerObjId === signerObjectId + //get current signer placeholder position data + const placeholderPosition = currentSigner[0].placeHolder; + //function of save signature image and get updated position with signature image url + const getUpdatePosition = onSaveSign( + placeholderPosition, + getIndex, + signKey, + signatureImg, + imgWH, + isDefaultSign ); - const i = currentSigner[0].placeHolder.findIndex((object) => { - return object.pageNumber === pageNumber; + const updateSignerData = currentSigner.map((obj, ind) => { + if (obj.signerObjId === signerObjectId) { + return { ...obj, placeHolder: getUpdatePosition }; + } + return obj; }); - let updateFilter; - - updateFilter = currentSigner[0].placeHolder[i].pos.filter( - (data) => data.key === signKey && data.SignUrl + const index = signerPos.findIndex( + (data) => data.signerObjId === signerObjectId ); - - const getXYdata = currentSigner[0].placeHolder[i].pos; - const getPosData = getXYdata; - const posWidth = isDefaultSign - ? getIMGWH.newWidth - : isSign && getPosData[0].ImageType - ? 150 - : getPosData[0].Width - ? getPosData[0].Width - : 150; - const posHidth = isDefaultSign - ? getIMGWH.newHeight - : isSign && getPosData[0].ImageType - ? 60 - : getPosData[0].Height - ? getPosData[0].Height - : 60; - if (updateFilter.length > 0) { - updateFilter[0].SignUrl = signatureImg; - updateFilter[0].Width = posWidth; - updateFilter[0].Height = posHidth; - } else { - const addSign = getPosData.map((url, ind) => { - if (url.key === signKey) { - return { - ...url, - SignUrl: signatureImg, - Width: posWidth, - Height: posHidth, - ImageType: "sign" - }; - } - return url; - }); - - const newUpdateUrl = currentSigner[0].placeHolder.map((obj, ind) => { - if (obj.pageNumber === pageNumber) { - return { ...obj, pos: addSign }; - } - return obj; - }); - - const newUpdatePos = currentSigner.map((obj, ind) => { - if (obj.signerObjId === signerObjectId) { - return { ...obj, placeHolder: newUpdateUrl }; - } - return obj; - }); - - const index = signerPos.findIndex( - (data) => data.signerObjId === signerObjectId - ); - setSignerPos((prevState) => { - const newState = [...prevState]; // Create a copy of the state - newState.splice(index, 1, ...newUpdatePos); // Modify the copy - return newState; // Update the state with the modified copy - }); - } + setSignerPos((prevState) => { + const newState = [...prevState]; + newState.splice(index, 1, ...updateSignerData); + return newState; + }); }; const checkSignerBackColor = (obj) => { @@ -782,6 +701,7 @@ function PdfRequestFiles() { allPages={allPages} setAllPages={setAllPages} setPageNumber={setPageNumber} + pageNumber={pageNumber} /> {/* pdf render view */} @@ -831,8 +751,8 @@ function PdfRequestFiles() { onImageChange={onImageChange} setSignature={setSignature} image={image} - onSaveImage={onSaveImage} - onSaveSign={onSaveSign} + onSaveImage={saveImage} + onSaveSign={saveSign} defaultSign={defaultSignImg} /> {/* pdf header which contain funish back button */} @@ -888,7 +808,7 @@ function PdfRequestFiles() { }} className="signedStyle" > - Signed By + Signed by
{signedSigners.map((obj, ind) => { @@ -897,8 +817,8 @@ function PdfRequestFiles() { style={{ display: "flex", flexDirection: "row", - padding: "10px", - + alignItems: "center", + padding: "10px 0", background: checkSignerBackColor(obj) }} key={ind} @@ -913,17 +833,18 @@ function PdfRequestFiles() { borderRadius: 30 / 2, justifyContent: "center", alignItems: "center", - marginRight: "20px" + margin: "0 10px 0 5px" }} > - {" "} {getFirstLetter(obj.Name)}
@@ -954,7 +875,7 @@ function PdfRequestFiles() { marginTop: signedSigners.length > 0 && "20px" }} > - Yet To Sign + Yet to sign
{unsignedSigners.map((obj, ind) => { @@ -963,7 +884,8 @@ function PdfRequestFiles() { style={{ display: "flex", flexDirection: "row", - padding: "10px", + alignItems: "center", + padding:"10px 0", background: checkSignerBackColor(obj) }} key={ind} @@ -972,23 +894,24 @@ function PdfRequestFiles() { className="signerStyle" style={{ background: "#abd1d0", - width: 20, - height: 20, + width: 30, + height: 30, display: "flex", borderRadius: 30 / 2, justifyContent: "center", alignItems: "center", - marginRight: "20px" + margin: "0 10px 0 5px" }} > - {" "} {getFirstLetter(obj.Name)}
diff --git a/microfrontends/SignDocuments/src/Component/SignYourselfPdf.js b/microfrontends/SignDocuments/src/Component/SignYourselfPdf.js index e1fad20b6..c2a363590 100644 --- a/microfrontends/SignDocuments/src/Component/SignYourselfPdf.js +++ b/microfrontends/SignDocuments/src/Component/SignYourselfPdf.js @@ -23,7 +23,9 @@ import { multiSignEmbed, pdfNewWidthFun, addDefaultSignatureImg, - onImageSelect + onImageSelect, + placeholderHeight, + placeholderWidth } from "../utils/Utils"; import { useParams } from "react-router-dom"; import Tour from "reactour"; @@ -36,6 +38,7 @@ import RenderPdf from "./component/renderPdf"; import { contractUsers, contactBook, urlValidator } from "../utils/Utils"; import { modalAlign } from "../utils/Utils"; import AlertComponent from "./component/alertComponent"; +import PlaceholderCopy from "./component/PlaceholderCopy"; //For signYourself inProgress section signer can add sign and complete doc sign. function SignYourSelf() { @@ -79,6 +82,7 @@ function SignYourSelf() { const [noData, setNoData] = useState(false); const [contractName, setContractName] = useState(""); const [containerWH, setContainerWH] = useState({}); + const [isPageCopy, setIsPageCopy] = useState(false); const [showAlreadySignDoc, setShowAlreadySignDoc] = useState({ status: false }); @@ -102,7 +106,6 @@ function SignYourSelf() { const [{ isDragSign }, dragSignature] = useDrag({ type: "BOX", - item: { type: "BOX", id: 1, @@ -115,7 +118,6 @@ function SignYourSelf() { const [{ isDragStamp }, dragStamp] = useDrag({ type: "BOX", - item: { type: "BOX", id: 2, @@ -140,7 +142,6 @@ function SignYourSelf() { const [{ isDragStampSS }, dragStampSS] = useDrag({ type: "BOX", - item: { type: "BOX", id: 4, @@ -329,7 +330,6 @@ function SignYourSelf() { isDrag: false, key: key, isStamp: monitor, - yBottom: window.innerHeight / 2 - 60 }; @@ -516,22 +516,31 @@ function SignYourSelf() { const scale = isMobile ? pdfOriginalWidth / newWidth : 1; if (xyPostion.length === 1 && xyPostion[0].pos.length === 1) { + const xPos = () => { + const resizePos = xyPosData.xPosition; + if (isMobile) { + return resizePos * scale; + } else { + return resizePos; + } + }; const height = xyPosData.Height ? xyPosData.Height : 60; + const resizePos = xyPosData.yBottom; const bottomY = xyPosData.isDrag - ? xyPosData.yBottom * scale - height * scale + ? resizePos * scale - height * scale : xyPosData.firstYPos - ? xyPosData.yBottom * scale - height * scale + xyPosData.firstYPos - : xyPosData.yBottom * scale - height * scale; + ? resizePos * scale - height * scale + xyPosData.firstYPos + : resizePos * scale - height * scale; singleSign = { pdfFile: pdfBase64Url, docId: documentId, sign: { Base64: base64Url, - Left: isMobile ? xyPosData.xPosition * scale : xyPosData.xPosition, + Left: xPos(), Bottom: bottomY, - Width: xyPosData.Width ? xyPosData.Width * scale : 150 * scale, - Height: height * scale, + Width: placeholderWidth(xyPosData, scale), + Height: placeholderHeight(xyPosData, scale), Page: pageNo } }; @@ -650,7 +659,7 @@ function SignYourSelf() { //function for save button to save signature or image url const saveSign = (isDefaultSign) => { const signatureImg = isDefaultSign ? defaultSignImg : signature; - const signFlag = true; + let imgWH = { width: "", height: "" }; setIsSignPad(false); setIsImageSelect(false); @@ -672,8 +681,7 @@ function SignYourSelf() { signKey, signatureImg, imgWH, - isDefaultSign, - signFlag + isDefaultSign ); setXyPostion(getUpdatePosition); @@ -826,6 +834,7 @@ function SignYourSelf() { setAllPages={setAllPages} setPageNumber={setPageNumber} setSignBtnPosition={setSignBtnPosition} + pageNumber={pageNumber} /> {/* pdf render view */} @@ -881,6 +890,15 @@ function SignYourSelf() { )} + {/* this is modal of signature pad */} )} diff --git a/microfrontends/SignDocuments/src/Component/TemplatePlaceholder.js b/microfrontends/SignDocuments/src/Component/TemplatePlaceholder.js new file mode 100644 index 000000000..13cc69416 --- /dev/null +++ b/microfrontends/SignDocuments/src/Component/TemplatePlaceholder.js @@ -0,0 +1,1279 @@ +import React, { useEffect, useState, useRef } from "react"; +import RenderAllPdfPage from "./component/renderAllPdfPage"; +import { useParams, useNavigate } from "react-router-dom"; +import axios from "axios"; +import "../css/./signature.css"; +import sign from "../assests/sign3.png"; +import stamp from "../assests/stamp2.png"; +import { themeColor } from "../utils/ThemeColor/backColor"; +import { DndProvider } from "react-dnd"; +import { HTML5Backend } from "react-dnd-html5-backend"; +import { useDrag, useDrop } from "react-dnd"; +import FieldsComponent from "./component/fieldsComponent"; +import Tour from "reactour"; +import Loader from "./component/loader"; +import HandleError from "./component/HandleError"; +import Nodata from "./component/Nodata"; +import SignerListPlace from "./component/signerListPlace"; +import Header from "./component/header"; +import { + pdfNewWidthFun, + contractUsers, + getHostUrl, + randomId, + addZIndex, + createDocument +} from "../utils/Utils"; +import RenderPdf from "./component/renderPdf"; +import "../css/AddUser.css"; +import Title from "./component/Title"; +import LinkUserModal from "./component/LinkUserModal"; +import EditTemplate from "./component/EditTemplate"; +import ModalUi from "../premitives/ModalUi"; +import AddRoleModal from "./component/AddRoleModal"; +import PlaceholderCopy from "./component/PlaceholderCopy"; +import ModalComponent from "./component/modalComponent"; + +const TemplatePlaceholder = () => { + const navigate = useNavigate(); + const { templateId } = useParams(); + const [pdfDetails, setPdfDetails] = useState([]); + const [isMailSend, setIsMailSend] = useState(false); + const [allPages, setAllPages] = useState(null); + const numPages = 1; + const [pageNumber, setPageNumber] = useState(1); + const [signBtnPosition, setSignBtnPosition] = useState([]); + const [xySignature, setXYSignature] = useState({}); + const [dragKey, setDragKey] = useState(); + const [signersdata, setSignersData] = useState([]); + const [signerObjId, setSignerObjId] = useState(); + const [signerPos, setSignerPos] = useState([]); + const [isSelectListId, setIsSelectId] = useState(); + const [isSendAlert, setIsSendAlert] = useState(false); + const [isCreateDocModal, setIsCreateDocModal] = useState(false); + const [isLoading, setIsLoading] = useState({ + isLoad: true, + message: "This might take some time" + }); + const [handleError, setHandleError] = useState(); + const [currentEmail, setCurrentEmail] = useState(); + const [pdfNewWidth, setPdfNewWidth] = useState(); + const [templateTour, setTemplateTour] = useState(true); + const [checkTourStatus, setCheckTourStatus] = useState(false); + const [tourStatus, setTourStatus] = useState([]); + const [signerUserId, setSignerUserId] = useState(); + const [noData, setNoData] = useState(false); + const [pdfOriginalWidth, setPdfOriginalWidth] = useState(); + const [contractName, setContractName] = useState(""); + const [containerWH, setContainerWH] = useState(); + const signRef = useRef(null); + const dragRef = useRef(null); + const divRef = useRef(null); + const [isShowEmail, setIsShowEmail] = useState(false); + const [selectedEmail, setSelectedEmail] = useState(false); + const [isResize, setIsResize] = useState(false); + const [isSigners, setIsSigners] = useState(false); + const [zIndex, setZIndex] = useState(1); + const [pdfLoadFail, setPdfLoadFail] = useState({ + status: false, + type: "load" + }); + const color = [ + "#93a3db", + "#e6c3db", + "#c0e3bc", + "#bce3db", + "#b8ccdb", + "#ceb8db", + "#ffccff", + "#99ffcc", + "#cc99ff", + "#ffcc99", + "#66ccff", + "#ffffcc" + ]; + const isMobile = window.innerWidth < 767; + const [{ isOver }, drop] = useDrop({ + accept: "BOX", + drop: (item, monitor) => addPositionOfSignature(item, monitor), + collect: (monitor) => ({ + isOver: !!monitor.isOver() + }) + }); + const [{ isDragSign }, dragSignature] = useDrag({ + type: "BOX", + item: { + type: "BOX", + id: 1, + text: "drag me" + }, + collect: (monitor) => ({ + isDragSign: !!monitor.isDragging() + }) + }); + const [{ isDragStamp }, dragStamp] = useDrag({ + type: "BOX", + + item: { + type: "BOX", + id: 2, + text: "drag me" + }, + collect: (monitor) => ({ + isDragStamp: !!monitor.isDragging() + }) + }); + + const [{ isDragSignatureSS }, dragSignatureSS] = useDrag({ + type: "BOX", + item: { + type: "BOX", + id: 3, + text: "drag me" + }, + collect: (monitor) => ({ + isDragSignatureSS: !!monitor.isDragging() + }) + }); + + const [{ isDragStampSS }, dragStampSS] = useDrag({ + type: "BOX", + item: { + type: "BOX", + id: 4, + text: "drag me" + }, + collect: (monitor) => ({ + isDragStampSS: !!monitor.isDragging() + }) + }); + + const [uniqueId, setUniqueId] = useState(""); + const [isModalRole, setIsModalRole] = useState(false); + const [roleName, setRoleName] = useState(""); + const [isAddUser, setIsAddUser] = useState({}); + const [isCreateDoc, setIsCreateDoc] = useState(false); + const [isEditTemplate, setIsEditTemplate] = useState(false); + const [isPageCopy, setIsPageCopy] = useState(false); + const [signKey, setSignKey] = useState(); + const [IsReceipent, setIsReceipent] = useState(true); + const senderUser = + localStorage.getItem( + `Parse/${localStorage.getItem("parseAppId")}/currentUser` + ) && + localStorage.getItem( + `Parse/${localStorage.getItem("parseAppId")}/currentUser` + ); + const jsonSender = JSON.parse(senderUser); + + useEffect(() => { + fetchTemplate(); + // eslint-disable-next-line + }, []); + + useEffect(() => { + if (divRef.current) { + const pdfWidth = pdfNewWidthFun(divRef); + setPdfNewWidth(pdfWidth); + setContainerWH({ + width: divRef.current.offsetWidth, + height: divRef.current.offsetHeight + }); + } + }, [divRef.current]); + + // `fetchTemplate` function in used to get Template from server and setPlaceholder ,setSigner if present + const fetchTemplate = async () => { + try { + const params = { templateId: templateId }; + const templateDeatils = await axios.post( + `${localStorage.getItem("baseUrl")}functions/getTemplate`, + params, + { + headers: { + "Content-Type": "application/json", + "X-Parse-Application-Id": localStorage.getItem("parseAppId"), + sessiontoken: localStorage.getItem("accesstoken") + } + } + ); + // console.log("templateDeatils.data ", templateDeatils.data); + const documentData = + templateDeatils.data && templateDeatils.data.result + ? [templateDeatils.data.result] + : []; + + if (documentData && documentData.length > 0) { + setPdfDetails(documentData); + setIsSigners(true); + if (documentData[0].Signers && documentData[0].Signers.length > 0) { + setSignerObjId(documentData[0].Signers[0].objectId); + setContractName(documentData[0].Signers[0].className); + setIsSelectId(0); + if ( + documentData[0].Placeholders && + documentData[0].Placeholders.length > 0 + ) { + setSignerPos(documentData[0].Placeholders); + let signers = [...documentData[0].Signers]; + let updatedSigners = documentData[0].Placeholders.map((x) => { + let matchingSigner = signers.find( + (y) => x.signerObjId && x.signerObjId === y.objectId + ); + + if (matchingSigner) { + return { + ...matchingSigner, + Role: x.Role ? x.Role : matchingSigner.Role, + Id: x.Id, + blockColor: x.blockColor + }; + } else { + return { + Role: x.Role, + Id: x.Id, + blockColor: x.blockColor + }; + } + }); + setSignersData(updatedSigners); + setUniqueId(updatedSigners[0].Id); + } else { + const updatedSigners = documentData[0].Signers.map((x, index) => ({ + ...x, + Id: randomId(), + Role: "User " + (index + 1) + })); + setSignersData(updatedSigners); + setUniqueId(updatedSigners[0].Id); + } + } else { + setRoleName("User 1"); + if ( + documentData[0].Placeholders && + documentData[0].Placeholders.length > 0 + ) { + let updatedSigners = documentData[0].Placeholders.map((x) => { + return { + Role: x.Role, + Id: x.Id, + blockColor: x.blockColor + }; + }); + setSignerPos(documentData[0].Placeholders); + setUniqueId(updatedSigners[0].Id); + setSignersData(updatedSigners); + setIsSelectId(0); + } + } + } else if ( + documentData === "Error: Something went wrong!" || + (documentData.result && documentData.result.error) + ) { + const loadObj = { + isLoad: false + }; + setHandleError("Error: Something went wrong!"); + setIsLoading(loadObj); + } else { + setNoData(true); + + const loadObj = { + isLoad: false + }; + setIsLoading(loadObj); + } + } catch (err) { + console.log("err ", err); + if (err?.response?.data?.code === 101) { + setHandleError("Error: Template not found!"); + } else { + setHandleError("Error: Something went wrong!"); + } + } + const res = await contractUsers(jsonSender.email); + if (res[0] && res.length) { + setSignerUserId(res[0].objectId); + setCurrentEmail(res[0].Email); + const tourstatus = res[0].TourStatus && res[0].TourStatus; + if (tourstatus && tourstatus.length > 0) { + setTourStatus(tourstatus); + const checkTourRecipients = tourstatus.filter( + (data) => data.templatetour + ); + if (checkTourRecipients && checkTourRecipients.length > 0) { + setCheckTourStatus(checkTourRecipients[0].templatetour); + } + } + const loadObj = { + isLoad: false + }; + setIsLoading(loadObj); + } else if (res === "Error: Something went wrong!") { + const loadObj = { + isLoad: false + }; + setHandleError("Error: Something went wrong!"); + setIsLoading(loadObj); + } else if (res.length === 0) { + setNoData(true); + + const loadObj = { + isLoad: false + }; + setIsLoading(loadObj); + } + }; + + //function for setting position after drop signature button over pdf + const addPositionOfSignature = (item, monitor) => { + getSignerPos(item, monitor); + }; + + // `getSignerPos` is used to get placeholder position when user place it and save it in array + const getSignerPos = (item, monitor) => { + const signer = signersdata.find((x) => x.Id === uniqueId); + if (signer) { + const posZIndex = zIndex + 1; + setZIndex(posZIndex); + const newWidth = containerWH.width; + const scale = pdfOriginalWidth / newWidth; + const key = randomId(); + // let filterSignerPos = signerPos.filter( + // (data) => data.signerObjId === signerObjId + // ); + let filterSignerPos = signerPos.filter((data) => data.Id === uniqueId); + let dropData = []; + let xyPosArr = []; + let xyPos = {}; + if (item === "onclick") { + const dropObj = { + xPosition: window.innerWidth / 2 - 100, + yPosition: window.innerHeight / 2 - 60, + isStamp: monitor, + key: key, + isDrag: false, + scale: scale, + isMobile: isMobile, + yBottom: window.innerHeight / 2 - 60, + zIndex: posZIndex + }; + dropData.push(dropObj); + xyPos = { + pageNumber: pageNumber, + pos: dropData + }; + + xyPosArr.push(xyPos); + } else if (item.type === "BOX") { + const offset = monitor.getClientOffset(); + //adding and updating drop position in array when user drop signature button in div + const containerRect = document + .getElementById("container") + .getBoundingClientRect(); + const x = offset.x - containerRect.left; + const y = offset.y - containerRect.top; + const ybottom = containerRect.bottom - offset.y; + + const dropObj = { + xPosition: signBtnPosition[0] ? x - signBtnPosition[0].xPos : x, + yPosition: signBtnPosition[0] ? y - signBtnPosition[0].yPos : y, + isStamp: isDragStamp || isDragStampSS ? true : false, + key: key, + isDrag: false, + firstXPos: signBtnPosition[0] && signBtnPosition[0].xPos, + firstYPos: signBtnPosition[0] && signBtnPosition[0].yPos, + yBottom: ybottom, + scale: scale, + isMobile: isMobile, + zIndex: posZIndex + }; + + dropData.push(dropObj); + xyPos = { + pageNumber: pageNumber, + pos: dropData + }; + + xyPosArr.push(xyPos); + } + const { blockColor, Role } = signersdata.find((x) => x.Id === uniqueId); + //adding placholder in existing signer pos array (placaholder) + if (filterSignerPos.length > 0) { + // const colorIndex = signerPos + // .map((e) => e.signerObjId) + // .indexOf(signerObjId); + + const colorIndex = signerPos.map((e) => e.Id).indexOf(uniqueId); + const getPlaceHolder = filterSignerPos[0].placeHolder; + const updatePlace = getPlaceHolder.filter( + (data) => data.pageNumber !== pageNumber + ); + const getPageNumer = getPlaceHolder.filter( + (data) => data.pageNumber === pageNumber + ); + + //add entry of position for same signer on multiple page + if (getPageNumer.length > 0) { + const getPos = getPageNumer[0].pos; + const newSignPos = getPos.concat(dropData); + let xyPos = { + pageNumber: pageNumber, + pos: newSignPos + }; + updatePlace.push(xyPos); + let placeHolderPos; + if (contractName) { + placeHolderPos = { + blockColor: blockColor ? blockColor : color[isSelectListId], + signerObjId: signerObjId, + placeHolder: updatePlace, + signerPtr: { + __type: "Pointer", + className: `${contractName}`, + objectId: signerObjId + }, + Role: Role ? Role : roleName, + Id: uniqueId + }; + } else { + placeHolderPos = { + blockColor: blockColor ? blockColor : color[isSelectListId], + signerObjId: "", + placeHolder: updatePlace, + signerPtr: {}, + Role: Role ? Role : roleName, + Id: uniqueId + }; + } + // signerPos.splice(colorIndex, 1, placeHolderPos); + const newArry = [placeHolderPos]; + const newArray = [ + ...signerPos.slice(0, colorIndex), + ...newArry, + ...signerPos.slice(colorIndex + 1) + ]; + setSignerPos(newArray); + } else { + const newSignPoss = getPlaceHolder.concat(xyPosArr[0]); + let placeHolderPos; + if (contractName) { + placeHolderPos = { + blockColor: color[isSelectListId], + signerObjId: signerObjId, + placeHolder: newSignPoss, + signerPtr: { + __type: "Pointer", + className: `${contractName}`, + objectId: signerObjId + }, + Role: Role ? Role : roleName, + Id: uniqueId + }; + } else { + placeHolderPos = { + blockColor: color[isSelectListId], + signerObjId: "", + placeHolder: newSignPoss, + signerPtr: {}, + Role: Role ? Role : roleName, + Id: uniqueId + }; + } + + const newArry = [placeHolderPos]; + const newArray = [ + ...signerPos.slice(0, colorIndex), + ...newArry, + ...signerPos.slice(colorIndex + 1) + ]; + + setSignerPos(newArray); + } + } else { + //adding new placeholder for selected signer in pos array (placeholder) + let placeHolderPos; + if (contractName) { + placeHolderPos = { + signerPtr: { + __type: "Pointer", + className: `${contractName}`, + objectId: signerObjId + }, + signerObjId: signerObjId, + blockColor: blockColor ? blockColor : color[isSelectListId], + placeHolder: xyPosArr, + Role: Role ? Role : roleName, + Id: uniqueId + }; + } else { + placeHolderPos = { + signerPtr: {}, + signerObjId: "", + blockColor: blockColor ? blockColor : color[isSelectListId], + placeHolder: xyPosArr, + Role: Role ? Role : roleName, + Id: uniqueId + }; + } + + setSignerPos((prev) => [...prev, placeHolderPos]); + } + setIsMailSend(false); + } else { + setIsReceipent(false); + } + }; + //function for get pdf page details + const pageDetails = async (pdf) => { + const load = { + status: true + }; + setPdfLoadFail(load); + pdf.getPage(1).then((pdfPage) => { + const pageWidth = pdfPage.view[2]; + setPdfOriginalWidth(pageWidth); + }); + }; + //function for save x and y position and show signature tab on that position + const handleTabDrag = (key) => { + setDragKey(key); + }; + + //function for set and update x and y postion after drag and drop signature tab + const handleStop = (event, dragElement, signerId, key) => { + if (!isResize) { + const dataNewPlace = addZIndex(signerPos, key, setZIndex); + let updateSignPos = [...signerPos]; + updateSignPos.splice(0, updateSignPos.length, ...dataNewPlace); + // signerPos.splice(0, signerPos.length, ...dataNewPlace); + const containerRect = document + .getElementById("container") + .getBoundingClientRect(); + const signId = signerId; //? signerId : signerObjId; + const keyValue = key ? key : dragKey; + const ybottom = containerRect.height - dragElement.y; + + if (keyValue >= 0) { + const filterSignerPos = updateSignPos.filter( + (data) => data.Id === signId + ); + + if (filterSignerPos.length > 0) { + const getPlaceHolder = filterSignerPos[0].placeHolder; + + const getPageNumer = getPlaceHolder.filter( + (data) => data.pageNumber === pageNumber + ); + + if (getPageNumer.length > 0) { + const getXYdata = getPageNumer[0].pos; + + const getPosData = getXYdata; + const addSignPos = getPosData.map((url, ind) => { + if (url.key === keyValue) { + return { + ...url, + xPosition: dragElement.x, + yPosition: dragElement.y, + isDrag: true, + yBottom: ybottom + }; + } + return url; + }); + + const newUpdateSignPos = getPlaceHolder.map((obj, ind) => { + if (obj.pageNumber === pageNumber) { + return { ...obj, pos: addSignPos }; + } + return obj; + }); + const newUpdateSigner = updateSignPos.map((obj, ind) => { + if (obj.Id === signId) { + return { ...obj, placeHolder: newUpdateSignPos }; + } + return obj; + }); + + setSignerPos(newUpdateSigner); + } + } + } + } + setIsMailSend(false); + }; + + //function for delete signature block + const handleDeleteSign = (key, Id) => { + const updateData = []; + // const filterSignerPos = signerPos.filter( + // (data) => data.signerObjId === signerId + // ); + + const filterSignerPos = signerPos.filter((data) => data.Id === Id); + + if (filterSignerPos.length > 0) { + const getPlaceHolder = filterSignerPos[0].placeHolder; + + const getPageNumer = getPlaceHolder.filter( + (data) => data.pageNumber === pageNumber + ); + + if (getPageNumer.length > 0) { + const getXYdata = getPageNumer[0].pos.filter( + (data, ind) => data.key !== key + ); + + if (getXYdata.length > 0) { + updateData.push(getXYdata); + const newUpdatePos = getPlaceHolder.map((obj, ind) => { + if (obj.pageNumber === pageNumber) { + return { ...obj, pos: updateData[0] }; + } + return obj; + }); + + const newUpdateSigner = signerPos.map((obj, ind) => { + if (obj.Id === Id) { + return { ...obj, placeHolder: newUpdatePos }; + } + return obj; + }); + + setSignerPos(newUpdateSigner); + } else { + const updateFilter = signerPos.filter((data) => data.Id !== Id); + const getRemainPage = filterSignerPos[0].placeHolder.filter( + (data) => data.pageNumber !== pageNumber + ); + + if (getRemainPage && getRemainPage.length > 0) { + const newUpdatePos = filterSignerPos.map((obj, ind) => { + if (obj.Id === Id) { + return { ...obj, placeHolder: getRemainPage }; + } + return obj; + }); + let signerupdate = []; + signerupdate = signerPos.filter((data) => data.Id !== Id); + signerupdate.push(newUpdatePos[0]); + + setSignerPos(signerupdate); + } else { + setSignerPos(updateFilter); + } + } + } + } + }; + + //function for change page + function changePage(offset) { + setSignBtnPosition([]); + setPageNumber((prevPageNumber) => prevPageNumber + offset); + } + + //function for capture position on hover signature button + const handleDivClick = (e) => { + const divRect = e.currentTarget.getBoundingClientRect(); + const mouseX = e.clientX - divRect.left; + const mouseY = e.clientY - divRect.top; + + const xyPosition = { + xPos: mouseX, + yPos: mouseY + }; + + setXYSignature(xyPosition); + }; + + //function for capture position of x and y on hover signature button last position + const handleMouseLeave = (e) => { + setSignBtnPosition([xySignature]); + }; + + const alertSendEmail = async () => { + if (signerPos.length !== signersdata.length) { + setIsSendAlert(true); + } else { + handleSaveTemplate(); + } + }; + const handleSaveTemplate = async () => { + if (signersdata?.length) { + const loadObj = { + isLoad: true, + message: "This might take some time" + }; + setIsLoading(loadObj); + setIsSendAlert(false); + let signers = []; + if (signersdata?.length > 0) { + signersdata.forEach((x) => { + if (x.objectId) { + const obj = { + __type: "Pointer", + className: "contracts_Contactbook", + objectId: x.objectId + }; + signers.push(obj); + } + }); + } + try { + const data = { + Placeholders: signerPos, + SignedUrl: pdfDetails[0].URL, + Signers: signers + }; + + await axios + .put( + `${localStorage.getItem("baseUrl")}classes/${localStorage.getItem( + "_appName" + )}_Template/${templateId}`, + data, + { + headers: { + "Content-Type": "application/json", + "X-Parse-Application-Id": localStorage.getItem("parseAppId"), + "X-Parse-Session-Token": localStorage.getItem("accesstoken") + } + } + ) + .then((result) => { + setIsCreateDocModal(true); + setIsMailSend(true); + const loadObj = { + isLoad: false + }; + setIsLoading(loadObj); + }) + .catch((err) => { + console.log("axois err ", err); + }); + } catch (e) { + console.log("error", e); + } + } else { + setIsReceipent(false); + } + }; + //here you can add your messages in content and selector is key of particular steps + + const tourConfig = [ + { + selector: '[data-tut="reactourAddbtn"]', + content: `Clicking "Add role" button will allow you to add various signer roles. You can attach users to each role in subsequent steps.`, + position: "top", + observe: '[data-tut="reactourAddbtn--observe"]', + style: { fontSize: "13px" } + }, + { + selector: '[data-tut="reactourFirst"]', + content: `Select a recipient from this list to add a place-holder where he is supposed to sign.The placeholder will appear in the same colour as the recipient name once you drop it on the document.`, + position: "top", + style: { fontSize: "13px" }, + action: () => handleCloseRoleModal() + }, + { + selector: '[data-tut="reactourSecond"]', + content: `Drag the signature or stamp placeholder onto the PDF to choose your desired signing location.`, + position: "top", + style: { fontSize: "13px" } + }, + { + selector: '[data-tut="reactourThird"]', + content: `Drag the placeholder for a recipient anywhere on the document.Remember, it will appear in the same colour as the name of the recipient for easy reference.`, + position: "top", + style: { fontSize: "13px" } + }, + { + selector: '[data-tut="reactourFour"]', + content: `Clicking "Save" button will save the template and will ask you for creating new document.`, + position: "top", + style: { fontSize: "13px" } + } + ]; + + //function for update TourStatus + const closeTour = async () => { + setTemplateTour(false); + const extUserClass = localStorage.getItem("extended_class"); + let updatedTourStatus = []; + if (tourStatus.length > 0) { + updatedTourStatus = [...tourStatus]; + const templatetourIndex = tourStatus.findIndex( + (obj) => obj["templatetour"] === false || obj["templatetour"] === true + ); + if (templatetourIndex !== -1) { + updatedTourStatus[templatetourIndex] = { templatetour: true }; + } else { + updatedTourStatus.push({ templatetour: true }); + } + } else { + updatedTourStatus = [{ templatetour: true }]; + } + await axios + .put( + `${localStorage.getItem( + "baseUrl" + )}classes/${extUserClass}/${signerUserId}`, + { + TourStatus: updatedTourStatus + }, + { + headers: { + "Content-Type": "application/json", + "X-Parse-Application-Id": localStorage.getItem("parseAppId"), + sessionToken: localStorage.getItem("accesstoken") + } + } + ) + .then((Listdata) => { + // const json = Listdata.data; + // const res = json.results; + }) + .catch((err) => { + console.log("axois err ", err); + }); + }; + + // `handleCreateDocModal` is used to create Document from template when user click on yes from modal + const handleCreateDocModal = async () => { + setIsCreateDocModal(false); + setIsCreateDoc(true); + const hostUrl = getHostUrl(); + // handle create document + const res = await createDocument(pdfDetails, signerPos, signersdata); + if (res.status === "success") { + navigate(`${hostUrl}placeHolderSign/${res.id}`); + setIsCreateDoc(false); + } else { + setHandleError("Error: Something went wrong!"); + setIsCreateDoc(false); + } + }; + + // `handleAddSigner` is used to open Add Role Modal + const handleAddSigner = () => { + setIsModalRole(true); + setRoleName(""); + }; + + // `handleAddRole` function is called when use click on add button in addRole modal + // save Role in entry in signerList and user + const handleAddRole = (e) => { + e.preventDefault(); + const count = signersdata.length > 0 ? signersdata.length + 1 : 1; + const Id = randomId(); + const index = signersdata.length; + const obj = { + Role: roleName || "User " + count, + Id: Id, + blockColor: color[index] + }; + setSignersData((prevArr) => [...prevArr, obj]); + setIsModalRole(false); + setRoleName(""); + setUniqueId(Id); + setIsSelectId(index); + setIsMailSend(false); + }; + // `handleDeleteUser` function is used to delete record and placeholder when user click on delete which is place next user name in recipients list + const handleDeleteUser = (Id) => { + const updateSigner = signersdata + .filter((x) => x.Id !== Id) + .map((x, i) => ({ ...x, blockColor: color[i] })); + setSignersData(updateSigner); + const updatePlaceholderUser = signerPos + .filter((x) => x.Id !== Id) + .map((x, i) => ({ ...x, blockColor: color[i] })); + const index = signersdata.findIndex((x)=> x.Id === Id) + if(index === signersdata.length - 1){ + setUniqueId(updateSigner[updateSigner.length - 1]?.Id ||""); + setIsSelectId(0); + }else{ + setUniqueId(updateSigner[index]?.Id ||""); + setIsSelectId(index); + } + + setSignerPos(updatePlaceholderUser); + setIsMailSend(false); + }; + + // `handleLinkUser` is used to open Add/Choose Signer Modal when user can link existing or new User with placeholder + // and update entry in signersList + const handleLinkUser = (id) => { + setIsAddUser({ [id]: true }); + }; + const handleAddUser = (data) => { + const signerPtr = { + __type: "Pointer", + className: "contracts_Contactbook", + objectId: data.objectId + }; + const updatePlaceHolder = signerPos.map((x) => { + if (x.Id === uniqueId) { + return { ...x, signerPtr: signerPtr, signerObjId: data.objectId }; + } + return { ...x }; + }); + setSignerPos(updatePlaceHolder); + + const updateSigner = signersdata.map((x) => { + if (x.Id === uniqueId) { + return { ...x, ...data }; + } + return { ...x }; + }); + setSignersData(updateSigner); + setIsMailSend(false); + }; + + // `closePopup` is used to close Add/Choose signer modal + const closePopup = () => { + setIsAddUser({}); + }; + + // `handleRoleChange` function is call when user update Role name from recipients list + const handleRoleChange = (event, roleId) => { + // Update the role when the content changes + const updatedRoles = signersdata.map((role) => + role.Id === roleId ? { ...role, Role: event.target.value } : role + ); + setSignersData(updatedRoles); + const updatedPlaceholder = signerPos.map((role) => + role.Id === roleId ? { ...role, Role: event.target.value } : role + ); + setSignerPos(updatedPlaceholder); + setIsMailSend(false); + }; + + // `handleOnBlur` function is call when user click outside input box + const handleOnBlur = (updateRole, roleId) => { + // Update the role when the content changes + if (!updateRole) { + const updatedRoles = signersdata.map((role) => + role.Id === roleId ? { ...role, Role: roleName } : role + ); + setSignersData(updatedRoles); + const updatedPlaceholder = signerPos?.map((role) => + role.Id === roleId ? { ...role, Role: roleName } : role + ); + setSignerPos(updatedPlaceholder); + } + }; + + const handleEditTemplateModal = () => { + setIsEditTemplate(!isEditTemplate); + }; + + const handleEditTemplateForm = (data) => { + setIsEditTemplate(false); + const updateTemplate = pdfDetails.map((x) => { + return { ...x, ...data }; + }); + setPdfDetails(updateTemplate); + setIsMailSend(false); + }; + + const handleCloseRoleModal = () => { + setIsModalRole(false); + }; + + return ( +
+ + <DndProvider backend={HTML5Backend}> + {isLoading.isLoad ? ( + <Loader isLoading={isLoading} /> + ) : handleError ? ( + <HandleError handleError={handleError} /> + ) : noData ? ( + <Nodata /> + ) : ( + <div className="signatureContainer" ref={divRef}> + {/* this component used for UI interaction and show their functionality */} + {!checkTourStatus && ( + //this tour component used in your html component where you want to put + //onRequestClose function to close tour + //steps is defined what will be your messages and style also + //isOpen is takes boolean value to open + <Tour + onRequestClose={closeTour} + steps={tourConfig} + isOpen={templateTour} + rounded={5} + closeWithMask={false} + /> + )} + {/* this component used to render all pdf pages in left side */} + <RenderAllPdfPage + signPdfUrl={pdfDetails[0].URL} + allPages={allPages} + setAllPages={setAllPages} + setPageNumber={setPageNumber} + setSignBtnPosition={setSignBtnPosition} + pageNumber={pageNumber} + /> + + {/* pdf render view */} + <div + style={{ + marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px", + marginRight: !isMobile && pdfOriginalWidth > 500 && "20px" + }} + > + {/* this modal is used show alert set placeholder for all signers before send mail */} + <ModalUi + headerColor={"#dc3545"} + isOpen={isSendAlert} + title={"Fields required"} + handleClose={() => setIsSendAlert(false)} + > + <div style={{ height: "100%", padding: 20 }}> + <p>Please add field for all recipients.</p> + </div> + </ModalUi> + <ModalUi + headerColor={"#dc3545"} + isOpen={!IsReceipent} + title={"Receipent required"} + handleClose={() => setIsReceipent(true)} + > + <div style={{ height: "100%", padding: 20 }}> + <p>Please add receipent.</p> + </div> + </ModalUi> + {/* this modal is used show send mail message and after send mail success message */} + <ModalUi + isOpen={isCreateDocModal} + title={"Create Document"} + handleClose={() => setIsCreateDocModal(false)} + > + <div style={{ height: "100%", padding: 20 }}> + <p>Do you want to create a document using the template you just created ?</p> + <div + style={{ + height: "1px", + backgroundColor: "#9f9f9f", + width: "100%", + marginTop: "15px", + marginBottom: "15px" + }} + ></div> + {currentEmail.length > 0 && ( + <> + <button + onClick={() => { + handleCreateDocModal(); + }} + style={{ + background: themeColor(), + color: "white" + }} + type="button" + className="finishBtn" + > + Yes + </button> + <button + onClick={() => { + setIsCreateDocModal(false); + }} + style={{ + color: "black" + }} + type="button" + className="finishBtn" + > + No + </button> + </> + )} + </div> + </ModalUi> + {isCreateDoc && <Loader isLoading={isLoading} />} + <ModalComponent + isShow={isShowEmail} + type={"signersAlert"} + setIsShowEmail={setIsShowEmail} + /> + <PlaceholderCopy + isPageCopy={isPageCopy} + setIsPageCopy={setIsPageCopy} + xyPostion={signerPos} + setXyPostion={setSignerPos} + allPages={allPages} + pageNumber={pageNumber} + signKey={signKey} + // signerObjId={signerObjId} + Id={uniqueId} + /> + {/* pdf header which contain funish back button */} + <Header + completeBtnTitle={"Save"} + isPlaceholder={true} + pageNumber={pageNumber} + allPages={allPages} + changePage={changePage} + pdfDetails={pdfDetails} + signerPos={signerPos} + signersdata={signersdata} + isMailSend={isMailSend} + alertSendEmail={alertSendEmail} + isShowHeader={true} + currentSigner={true} + setIsEditTemplate={handleEditTemplateModal} + dataTut4="reactourFour" + /> + <div data-tut="reactourThird"> + {containerWH && ( + <RenderPdf + pageNumber={pageNumber} + pdfOriginalWidth={pdfOriginalWidth} + pdfNewWidth={pdfNewWidth} + pdfDetails={pdfDetails} + signerPos={signerPos} + successEmail={false} + numPages={numPages} + pageDetails={pageDetails} + placeholder={true} + drop={drop} + handleDeleteSign={handleDeleteSign} + handleTabDrag={handleTabDrag} + handleStop={handleStop} + setPdfLoadFail={setPdfLoadFail} + pdfLoadFail={pdfLoadFail} + setSignerPos={setSignerPos} + containerWH={containerWH} + setIsResize={setIsResize} + setZIndex={setZIndex} + handleLinkUser={handleLinkUser} + setUniqueId={setUniqueId} + signersdata={signersdata} + setIsPageCopy={setIsPageCopy} + setSignKey={setSignKey} + setSignerObjId={setSignerObjId} + /> + )} + </div> + </div> + {/* signature button */} + {isMobile ? ( + <div> + <FieldsComponent + dataTut="reactourFirst" + dataTut2="reactourSecond" + pdfUrl={isMailSend} + sign={sign} + stamp={stamp} + dragSignature={dragSignature} + signRef={signRef} + handleDivClick={handleDivClick} + handleMouseLeave={handleMouseLeave} + isDragSign={isDragSign} + themeColor={themeColor} + dragStamp={dragStamp} + dragRef={dragRef} + isDragStamp={isDragStamp} + isSignYourself={true} + isDragSignatureSS={isDragSignatureSS} + dragSignatureSS={dragSignatureSS} + dragStampSS={dragStampSS} + addPositionOfSignature={addPositionOfSignature} + signerPos={signerPos} + signersdata={signersdata} + isSelectListId={isSelectListId} + setSignerObjId={setSignerObjId} + setIsSelectId={setIsSelectId} + setContractName={setContractName} + isSigners={isSigners} + setIsShowEmail={setIsShowEmail} + isMailSend={isMailSend} + setSelectedEmail={setSelectedEmail} + selectedEmail={selectedEmail} + handleAddSigner={handleAddSigner} + setUniqueId={setUniqueId} + setRoleName={setRoleName} + handleDeleteUser={handleDeleteUser} + handleRoleChange={handleRoleChange} + handleOnBlur={handleOnBlur} + /> + </div> + ) : ( + <div> + <div className="signerComponent"> + <SignerListPlace + signerPos={signerPos} + signersdata={signersdata} + isSelectListId={isSelectListId} + setSignerObjId={setSignerObjId} + setRoleName={setRoleName} + setIsSelectId={setIsSelectId} + setContractName={setContractName} + handleAddSigner={handleAddSigner} + setUniqueId={setUniqueId} + handleDeleteUser={handleDeleteUser} + handleRoleChange={handleRoleChange} + handleOnBlur={handleOnBlur} + /> + <div data-tut="reactourSecond"> + <FieldsComponent + pdfUrl={isMailSend} + sign={sign} + stamp={stamp} + dragSignature={dragSignature} + signRef={signRef} + handleDivClick={handleDivClick} + handleMouseLeave={handleMouseLeave} + isDragSign={isDragSign} + themeColor={themeColor} + dragStamp={dragStamp} + dragRef={dragRef} + isDragStamp={isDragStamp} + isSignYourself={false} + addPositionOfSignature={addPositionOfSignature} + /> + </div> + </div> + </div> + )} + </div> + )} + </DndProvider> + <div data-tut="reactourAddbtn--observe"> + <AddRoleModal + isModalRole={isModalRole} + roleName={roleName} + signersdata={signersdata} + setRoleName={setRoleName} + handleAddRole={handleAddRole} + handleCloseRoleModal={handleCloseRoleModal} + /> + </div> + <div> + <LinkUserModal + handleAddUser={handleAddUser} + isAddUser={isAddUser} + uniqueId={uniqueId} + closePopup={closePopup} + /> + </div> + <ModalUi + title={"Edit Template"} + isOpen={isEditTemplate} + handleClose={handleEditTemplateModal} + > + <EditTemplate + template={pdfDetails?.[0]} + onSuccess={handleEditTemplateForm} + /> + </ModalUi> + </div> + ); +}; + +export default TemplatePlaceholder; diff --git a/microfrontends/SignDocuments/src/Component/component/AddRoleModal.js b/microfrontends/SignDocuments/src/Component/component/AddRoleModal.js new file mode 100644 index 000000000..ede404e54 --- /dev/null +++ b/microfrontends/SignDocuments/src/Component/component/AddRoleModal.js @@ -0,0 +1,72 @@ +import React from "react"; +import ModalUi from "../../premitives/ModalUi"; + +const AddRoleModal = (props) => { + return ( + <ModalUi + title={"Add Role"} + isOpen={props.isModalRole} + handleClose={props.handleCloseRoleModal} + > + <div + className="addusercontainer" + > + <form + style={{ display: "flex", flexDirection: "column" }} + onSubmit={props.handleAddRole} + > + <input + value={props.roleName} + onChange={(e) => props.setRoleName(e.target.value)} + placeholder={ + props.signersdata.length > 0 + ? "User " + (props.signersdata.length + 1) + : "User 1" + } + className="addUserInput" + /> + <p + style={{ + color: "grey", + fontSize: 11, + margin: "10px 0 10px 5px" + }} + > + e.g: Hr, Director, Manager, New joinee, Accountant, etc... + </p> + <div> + <div + style={{ + height: "1px", + backgroundColor: "#9f9f9f", + width: "100%", + marginBottom: "15px" + }} + ></div> + <button + type="submit" + style={{ + background: "#00a2b7" + }} + className="finishBtn" + > + Add + </button> + <button + onClick={props.handleCloseRoleModal} + style={{ + color: "black" + }} + type="button" + className="finishBtn" + > + Close + </button> + </div> + </form> + </div> + </ModalUi> + ); +}; + +export default AddRoleModal; diff --git a/microfrontends/SignDocuments/src/Component/component/EditTemplate.js b/microfrontends/SignDocuments/src/Component/component/EditTemplate.js new file mode 100644 index 000000000..883051507 --- /dev/null +++ b/microfrontends/SignDocuments/src/Component/component/EditTemplate.js @@ -0,0 +1,101 @@ +import React, { useState } from "react"; +import "../../css/AddUser.css"; +// import SelectFolder from "../../premitives/SelectFolder"; + +const EditTemplate = ({ template, onSuccess }) => { + // const [folder, setFolder] = useState({ ObjectId: "", Name: "" }); + const [formData, setFormData] = useState({ + Name: template?.Name || "", + Note: template?.Note || "", + Description: template?.Description || "" + }); + + const handleStrInput = (e) => { + setFormData({ ...formData, [e.target.name]: e.target.value }); + }; + // const handleFolder = (data) => { + // console.log("handleFolder ", data) + // setFolder(data); + // }; + + // Define a function to handle form submission + const handleSubmit = async (e) => { + e.preventDefault(); + e.stopPropagation(); + const data = {...formData } + onSuccess(data); + }; + + return ( + <div className="addusercontainer"> + <div className="form-wrapper"> + <form onSubmit={handleSubmit}> + <div> + <label htmlFor="name" style={{ fontSize: 13 }}> + File + </label> + <div + style={{ + padding: "0.5rem 0.75rem", + border: "1px solid #d1d5db", + borderRadius: "0.375rem", + fontSize: "0.75rem", + fontWeight: "700" + }} + > + file selected : {template.URL?.split("/")[3]?.split("_")[1]} + </div> + </div> + <div className="form-section"> + <label htmlFor="name" style={{ fontSize: 13 }}> + Name + <span style={{ color: "red", fontSize: 13 }}> *</span> + </label> + <input + type="text" + name="Name" + value={formData.Name} + onChange={(e) => handleStrInput(e)} + required + className="addUserInput" + /> + </div> + <div className="form-section"> + <label htmlFor="Note" style={{ fontSize: 13 }}> + Note + </label> + <input + type="text" + name="Note" + id="Note" + value={formData.Note} + onChange={(e) => handleStrInput(e)} + className="addUserInput" + /> + </div> + <div className="form-section"> + <label htmlFor="Description" style={{ fontSize: 13 }}> + Description + </label> + <input + type="text" + name="Description" + id="Description" + value={formData.Description} + onChange={(e) => handleStrInput(e)} + className="addUserInput" + /> + </div> + {/* <SelectFolder onSuccess={handleFolder} folderCls={"contracts_Template"} /> */} + <div className="buttoncontainer"> + <button type="submit" className="submitbutton"> + Submit + </button> + </div> + </form> + </div> + </div> + ); +}; + +export default EditTemplate; diff --git a/microfrontends/SignDocuments/src/Component/component/LinkUserModal.js b/microfrontends/SignDocuments/src/Component/component/LinkUserModal.js new file mode 100644 index 000000000..5b14264bb --- /dev/null +++ b/microfrontends/SignDocuments/src/Component/component/LinkUserModal.js @@ -0,0 +1,35 @@ +import React from "react"; +import SelectSigners from "../../premitives/SelectSigners"; +import AddUser from "../../premitives/AddUser"; +import ModalUi from "../../premitives/ModalUi"; + +const LinkUserModal = (props) => { + return ( + <ModalUi title={"Add/Choose Signer"} isOpen={props.isAddUser[props.uniqueId]} handleClose={props.closePopup}> + <SelectSigners + details={props.handleAddUser} + closePopup={props.closePopup} + /> + <div style={{ display: "flex", alignItems: "center", gap: 5, margin:"0px 25px" }}> + <span + style={{ + height: 1, + width: "100%", + backgroundColor: "grey" + }} + ></span> + <span>or</span> + <span + style={{ + height: 1, + width: "100%", + backgroundColor: "grey" + }} + ></span> + </div> + <AddUser details={props.handleAddUser} closePopup={props.closePopup} /> + </ModalUi> + ); +}; + +export default LinkUserModal; diff --git a/microfrontends/SignDocuments/src/Component/component/PlaceholderCopy.js b/microfrontends/SignDocuments/src/Component/component/PlaceholderCopy.js new file mode 100644 index 000000000..c2a099463 --- /dev/null +++ b/microfrontends/SignDocuments/src/Component/component/PlaceholderCopy.js @@ -0,0 +1,259 @@ +import React, { useState } from "react"; +import Modal from "react-bootstrap/Modal"; +import ModalHeader from "react-bootstrap/esm/ModalHeader"; +import { themeColor } from "../../utils/ThemeColor/backColor"; + +function PlaceholderCopy(props) { + const copyType = ["All pages", "All pages but last", "All pages but first"]; + const [selectCopyType, setSelectCopyType] = useState(""); + + //get RandomKey Id + const randomKey = () => { + const randomId = Math.floor(1000 + Math.random() * 9000); + return randomId; + }; + + //function for get copy placeholder position + const getCopyPlaceholderPosition = ( + type, + rest, + newPageNumber, + existPlaceholderPosition + ) => { + let obj; + + const filterPosition = + existPlaceholderPosition && + existPlaceholderPosition.filter( + (data) => data.xPosition !== rest.xPosition + ); + //copy all page placeholder at requested position except first page + if (newPageNumber === 1 && type === "first") { + if (filterPosition && filterPosition.length > 0) { + return (obj = { + pageNumber: newPageNumber, + pos: [...filterPosition] + }); + } + } + //copy all page placeholder at requested position except last page + else if (newPageNumber === props.allPages && type === "last") { + if (existPlaceholderPosition) { + return (obj = { + pageNumber: newPageNumber, + pos: [...filterPosition] + }); + } + } + //copy all page placeholder at requested position with existing placeholder position + else if (existPlaceholderPosition) { + return (obj = { + pageNumber: newPageNumber, + pos: [...filterPosition, rest] + }); + } + //copy all page placeholder at requested position + else { + return (obj = { + pageNumber: newPageNumber, + pos: [rest] + }); + } + }; + + //function for copy placeholder as per select copy type + const copyPlaceholder = (type) => { + let newPlaceholderPosition = []; + let newPageNumber = 1; + const signerPosition = props.xyPostion; + const signerId = props.signerObjId ? props.signerObjId : props.Id; + //handle placeholder array and copy for multiple signers placeholder at requested location + if (signerId) { + //get current signers data + let filterSignerPosition; + if (props?.signerObjId) { + filterSignerPosition = signerPosition.filter( + (data) => data.signerObjId === signerId + ); + } else { + filterSignerPosition = signerPosition.filter( + (item) => item.Id === signerId + ); + } + //get current pagenumber's all placeholder position data + const placeholderPosition = filterSignerPosition[0].placeHolder.filter( + (data) => data.pageNumber === props.pageNumber + ); + //get current placeholder position data which user want to copy + const currentPlaceholder = placeholderPosition[0].pos.filter( + (position) => position.key === props.signKey + ); + const { key, ...rest } = currentPlaceholder[0]; + for (let i = 0; i < props.allPages; i++) { + const newId = randomKey(); + rest.key = newId; + //get exist placeholder position for particular page + const existPlaceholder = filterSignerPosition[0].placeHolder.filter( + (data) => data.pageNumber === newPageNumber + ); + const existPlaceholderPosition = + existPlaceholder[0] && existPlaceholder[0].pos; + + //function for get copy to requested location of placeholder position + const getPlaceholderObj = getCopyPlaceholderPosition( + type, + rest, + newPageNumber, + existPlaceholderPosition + ); + if (getPlaceholderObj) { + newPlaceholderPosition.push(getPlaceholderObj); + } + newPageNumber++; + } + let updatedSignerPlaceholder; + if (props?.signerObjId) { + updatedSignerPlaceholder = signerPosition.map((signersData, ind) => { + if (signersData.signerObjId === props.signerObjId) { + return { + ...signersData, + placeHolder: newPlaceholderPosition + }; + } + return signersData; + }); + } else { + updatedSignerPlaceholder = signerPosition.map((signersData, ind) => { + if (signersData.Id === props.Id) { + return { + ...signersData, + placeHolder: newPlaceholderPosition + }; + } + return signersData; + }); + } + // const updatedSignerPlaceholder = signerPosition.map( + // (signersData, ind) => { + // if (signersData.signerObjId === props.signerObjId) { + // return { + // ...signersData, + // placeHolder: newPlaceholderPosition + // }; + // } + // return signersData; + // } + // ); + + const signersData = signerPosition; + signersData.splice(0, signerPosition.length, ...updatedSignerPlaceholder); + props.setXyPostion(signersData); + } + //handle signyourself array and copy for single signers placeholder at requested location + else { + const xyPostion = props.xyPostion; + + const placeholderPosition = xyPostion.filter( + (data) => data.pageNumber === props.pageNumber + ); + //get current placeholder position data which user want to copy + const currentPlaceholder = placeholderPosition[0].pos.filter( + (pos) => pos.key === props.signKey + ); + const { key, ...rest } = currentPlaceholder[0]; + for (let i = 0; i < props.allPages; i++) { + //get exist placeholder position for particular page + const existPlaceholder = xyPostion.filter( + (data) => data.pageNumber === newPageNumber + ); + const existPlaceholderPosition = + existPlaceholder[0] && existPlaceholder[0].pos; + + const newId = randomKey(); + rest.key = newId; + //function for get copy to requested location of placeholder position + const getPlaceholderObj = getCopyPlaceholderPosition( + type, + rest, + newPageNumber, + existPlaceholderPosition + ); + if (getPlaceholderObj) { + newPlaceholderPosition.push(getPlaceholderObj); + } + + newPageNumber++; + } + props.setXyPostion(newPlaceholderPosition); + } + }; + + //function for getting selected type placeholder copy + const handleApplyCopy = () => { + if (selectCopyType === "All pages") { + copyPlaceholder("all"); + } else if (selectCopyType === "All pages but last") { + copyPlaceholder("last"); + } else if (selectCopyType === "All pages but first") { + copyPlaceholder("first"); + } + }; + + return ( + <Modal show={props.isPageCopy}> + <ModalHeader style={{ background: themeColor() }}> + <span style={{ color: "white" }}>Copy to all pages</span> + </ModalHeader> + + <Modal.Body> + {copyType.map((data, key) => { + return ( + <div key={key} style={{ display: "flex", flexDirection: "column" }}> + <label key={key} style={{ fontSize: "16px", fontWeight: "500" }}> + <input + style={{ accentColor: "red", marginRight: "10px" }} + type="radio" + value={data} + onChange={() => setSelectCopyType(data)} + checked={selectCopyType === data} + /> + + {data} + </label> + </div> + ); + })} + </Modal.Body> + + <Modal.Footer> + <button + style={{ + color: "black" + }} + type="button" + className="finishBtn" + onClick={() => props.setIsPageCopy(false)} + > + Cancel + </button> + + <button + onClick={() => { + handleApplyCopy(); + props.setIsPageCopy(false); + }} + style={{ + background: themeColor() + }} + type="button" + disabled={!selectCopyType} + className="finishBtn" + > + Apply + </button> + </Modal.Footer> + </Modal> + ); +} + +export default PlaceholderCopy; diff --git a/microfrontends/SignDocuments/src/Component/component/Title.js b/microfrontends/SignDocuments/src/Component/component/Title.js new file mode 100644 index 000000000..892edee3a --- /dev/null +++ b/microfrontends/SignDocuments/src/Component/component/Title.js @@ -0,0 +1,19 @@ +import React from "react"; +import { Helmet } from "react-helmet"; + +function Title({ title }) { + return ( + <Helmet> + <title>{`${title} - OpenSignâ„¢`} + + + + ); +} + +export default Title; diff --git a/microfrontends/SignDocuments/src/Component/component/borderResize.js b/microfrontends/SignDocuments/src/Component/component/borderResize.js index 1596d09bb..505c68d30 100644 --- a/microfrontends/SignDocuments/src/Component/component/borderResize.js +++ b/microfrontends/SignDocuments/src/Component/component/borderResize.js @@ -1,12 +1,12 @@ import React from "react"; -function BorderResize() { +function BorderResize({ right, top }) { return (
{data} - - print img removeChip(ind)} - src={close} - width={10} - height={10} - style={{ fontWeight: "600", marginLeft: "7px" }} - className="emailChipClose" - /> + > + +
); })} diff --git a/microfrontends/SignDocuments/src/Component/component/fieldsComponent.js b/microfrontends/SignDocuments/src/Component/component/fieldsComponent.js index 71280710f..b3cb187bc 100644 --- a/microfrontends/SignDocuments/src/Component/component/fieldsComponent.js +++ b/microfrontends/SignDocuments/src/Component/component/fieldsComponent.js @@ -1,6 +1,6 @@ -import React from "react"; -import * as Select from "@radix-ui/react-select"; -import classnames from "classnames"; +import React, { useState } from "react"; +import ModalUi from "../../premitives/ModalUi"; +import RecipientList from "../../premitives/RecipientList"; function FieldsComponent({ pdfUrl, @@ -20,7 +20,6 @@ function FieldsComponent({ isDragSignatureSS, isSignYourself, addPositionOfSignature, - signersdata, isSelectListId, setSignerObjId, @@ -29,29 +28,19 @@ function FieldsComponent({ isSigners, dataTut, dataTut2, - setIsShowEmail, isMailSend, - selectedEmail, - setSelectedEmail, + handleAddSigner, + setUniqueId, + setRoleName, + handleDeleteUser, + signerPos, + handleRoleChange, + handleOnBlur }) { + const [isSignersModal, setIsSignersModal] = useState(false); const signStyle = pdfUrl ? "disableSign" : "signatureBtn"; - const isMobile = window.innerWidth <767; - - const SelectItem = React.forwardRef( - ({ children, className, ...props }, forwardedRef) => { - return ( - - {children} - - - ); - } - ); + const isMobile = window.innerWidth < 767; const color = [ "#93a3db", @@ -65,9 +54,12 @@ function FieldsComponent({ "#cc99ff", "#ffcc99", "#66ccff", - "#ffffcc", + "#ffffcc" ]; + const handleModal = () => { + setIsSignersModal(!isSignersModal); + }; return ( <> {isMobile && isSignYourself ? ( @@ -88,102 +80,41 @@ function FieldsComponent({ padding: "10px 20px", display: "flex", alignItems: "center", - justifyContent: "center", + justifyContent: "center" + }} + onClick={() => { + if (signersdata?.length) { + handleModal(); + } }} > - - Signer : + + Recipient + + + {signersdata[isSelectListId]?.Role && ( +
+ {signersdata[isSelectListId]?.Name + ? ` : ${signersdata[isSelectListId]?.Name}` + : ` : ${signersdata[isSelectListId]?.Role}`} +
+ )}
- - { - const [selectedKey, selectedData] = obj.split("|"); - const parseData = JSON.parse(selectedData); - - setSignerObjId(parseData.objectId); - setIsSelectId(selectedKey); - setContractName(parseData.className); - setSelectedEmail(true); - }} - > - - - {!selectedEmail && - - - } - - - - - - - - - {signersdata.Signers.map((obj, ind) => { - return ( - - {" "} - {obj.Email} - - ); - })} - {/* Orange - Apple - */} - - - - - - - - +
+ )} + {handleAddSigner && ( +
handleAddSigner()} + > + + Add role
)}
{ - if (isSigners) { - if (selectedEmail) { - addPositionOfSignature("onclick", false); - } else { - setIsShowEmail(true); - } - } else { - addPositionOfSignature("onclick", false); - } - }} + onClick={() => addPositionOfSignature("onclick", false)} ref={(element) => { dragSignatureSS(element); if (element) { @@ -221,24 +142,15 @@ function FieldsComponent({ backgroundSize: "70% 70%", backgroundRepeat: "no-repeat", backgroundPosition: "center center", - paddingBottom: "2.2rem", + paddingBottom: "2.2rem" }} > - {/* sign img */} Signature @@ -261,7 +173,7 @@ function FieldsComponent({ backgroundSize: "32px 33px", backgroundRepeat: "no-repeat", backgroundPosition: "center center", - paddingBottom: "2.2rem", + paddingBottom: "2.2rem" }} > Stamp @@ -283,8 +195,7 @@ function FieldsComponent({
Fields @@ -299,7 +210,7 @@ function FieldsComponent({ fontWeight: "400", fontSize: "15px", padding: "3px 20px 0px 20px", - color: "#bfbfbf", + color: "#bfbfbf" }} > Signature @@ -310,7 +221,7 @@ function FieldsComponent({ style={{ width: "30px", height: "28px", - background: "#d3edeb", + background: "#d3edeb" }} src={sign} /> @@ -321,7 +232,7 @@ function FieldsComponent({ fontWeight: "400", fontSize: "15px", padding: "3px 0px 0px 35px", - color: "#bfbfbf", + color: "#bfbfbf" }} > Stamp @@ -332,7 +243,7 @@ function FieldsComponent({ style={{ width: "25px", height: "28px", - background: "#d3edeb", + background: "#d3edeb" }} src={stamp} /> @@ -355,7 +266,7 @@ function FieldsComponent({ style={{ opacity: isDragSign ? 0.5 : 1, boxShadow: - "0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18)", + "0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18)" }} > Signature @@ -373,7 +284,7 @@ function FieldsComponent({ style={{ width: "30px", height: "28px", - background: themeColor(), + background: themeColor() }} src={sign} /> @@ -393,7 +304,7 @@ function FieldsComponent({ style={{ opacity: isDragStamp ? 0.5 : 1, boxShadow: - "0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18)", + "0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18)" }} > Stamp @@ -412,7 +323,7 @@ function FieldsComponent({ style={{ width: "25px", height: "28px", - background: themeColor(), + background: themeColor() }} src={stamp} /> @@ -422,6 +333,25 @@ function FieldsComponent({
)} + + + ); } diff --git a/microfrontends/SignDocuments/src/Component/component/header.js b/microfrontends/SignDocuments/src/Component/component/header.js index fe6b0cab0..b92dfff72 100644 --- a/microfrontends/SignDocuments/src/Component/component/header.js +++ b/microfrontends/SignDocuments/src/Component/component/header.js @@ -34,7 +34,9 @@ function Header({ dataTut4, alreadySign, isSignYourself, - setIsEmail + setIsEmail, + completeBtnTitle, + setIsEditTemplate }) { const isMobile = window.innerWidth < 767; const navigate = useNavigate(); @@ -345,7 +347,7 @@ function Header({ }} > @@ -415,7 +417,7 @@ function Header({ }} data-tut={dataTut4} > - Send + {completeBtnTitle ? completeBtnTitle : "Send"}
) : (
{!isMailSend && - signersdata.Signers && - signersdata.Signers.length !== signerPos.length && ( + signersdata.length > 0 && + signersdata.length !== signerPos.length && (
{signerPos.length === 0 ? ( - Add all {signersdata.Signers.length - signerPos.length}{" "} + Add {signersdata.length - signerPos.length}{" "} recipients signature ) : ( - Add {signersdata.Signers.length - signerPos.length} more + Add {signersdata.length - signerPos.length} more recipients signature )} @@ -551,6 +553,11 @@ function Header({ )}
+ {setIsEditTemplate && ( + + )}
@@ -723,7 +730,7 @@ function Header({ onClick={() => setIsEmail(true)} >
+ ); +} + +export default PlaceholderBorder; diff --git a/microfrontends/SignDocuments/src/Component/component/renderAllPdfPage.js b/microfrontends/SignDocuments/src/Component/component/renderAllPdfPage.js index ffac41108..85d424200 100644 --- a/microfrontends/SignDocuments/src/Component/component/renderAllPdfPage.js +++ b/microfrontends/SignDocuments/src/Component/component/renderAllPdfPage.js @@ -10,6 +10,7 @@ function RenderAllPdfPage({ setAllPages, setPageNumber, setSignBtnPosition, + pageNumber }) { pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`; @@ -20,75 +21,80 @@ function RenderAllPdfPage({ return (
-
-
-
- Pages -
+
+
+
+ Pages +
- -
- - + - {Array.from(new Array(allPages), (el, index) => ( -
+ {Array.from(new Array(allPages), (el, index) => ( +
{ - setPageNumber(index + 1); - if (setSignBtnPosition) { - setSignBtnPosition([]); - } - }} - > - -
- ))} - - + display: "flex", + justifyContent: "center", + alignItems: "center", + contain: "content" + }} + onClick={() => { + setPageNumber(index + 1); + if (setSignBtnPosition) { + setSignBtnPosition([]); + } + }} + > + +
+ ))} +
+
+
+
-
- - -
); } diff --git a/microfrontends/SignDocuments/src/Component/component/renderPdf.js b/microfrontends/SignDocuments/src/Component/component/renderPdf.js index 7469e6630..808e12c9b 100644 --- a/microfrontends/SignDocuments/src/Component/component/renderPdf.js +++ b/microfrontends/SignDocuments/src/Component/component/renderPdf.js @@ -10,6 +10,7 @@ import { handleSignYourselfImageResize } from "../../utils/Utils"; import EmailToast from "./emailToast"; +import PlaceholderBorder from "./placeholderBorder"; pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`; @@ -48,7 +49,12 @@ function RenderPdf({ index, containerWH, setIsResize, - setZIndex + setZIndex, + handleLinkUser, + setUniqueId, + signersdata, + setIsPageCopy, + setSignerObjId }) { const isMobile = window.innerWidth < 767; const newWidth = containerWH.width; @@ -57,121 +63,146 @@ function RenderPdf({ const isGuestSigner = localStorage.getItem("isGuestSigner"); // handle signature block width and height according to screen - const posWidth = (pos) => { + const posWidth = (pos, signYourself) => { + const defaultWidth = 150; + const posWidth = pos.Width ? pos.Width : defaultWidth; let width; - if (isMobile) { - if (!pos.isMobile) { - if (pos.IsResize) { - width = pos.Width ? pos.Width : 150; - return width; + if (signYourself) { + width = posWidth; + return width; + } else { + if (isMobile) { + if (!pos.isMobile) { + if (pos.IsResize) { + width = posWidth ? posWidth : defaultWidth; + return width; + } else { + width = (posWidth || defaultWidth) / scale; + return width; + } } else { - width = (pos.Width || 150) / scale; + width = posWidth; return width; } } else { - width = pos.Width ? pos.Width : 150; - return width; - } - } else { - if (pos.isMobile) { - if (pos.IsResize) { - width = pos.Width ? pos.Width : 150; - return width; + if (pos.isMobile) { + if (pos.IsResize) { + width = posWidth ? posWidth : defaultWidth; + return width; + } else { + width = (posWidth || defaultWidth) * pos.scale; + return width; + } } else { - width = (pos.Width || 150) * pos.scale; + width = posWidth ? posWidth : defaultWidth; return width; } - } else { - width = pos.Width ? pos.Width : 150; - return width; } } }; - const posHeight = (pos) => { + const posHeight = (pos, signYourself) => { let height; - if (isMobile) { - if (!pos.isMobile) { - if (pos.IsResize) { - height = pos.Height ? pos.Height : 60; - return height; + const posHeight = pos.Height; + const defaultHeight = 60; + if (signYourself) { + height = posHeight ? posHeight : defaultHeight; + return height; + } else { + if (isMobile) { + if (!pos.isMobile) { + if (pos.IsResize) { + height = posHeight ? posHeight : defaultHeight; + return height; + } else { + height = (posHeight || defaultHeight) / scale; + return height; + } } else { - height = (pos.Height || 60) / scale; + height = posHeight ? posHeight : defaultHeight; return height; } } else { - height = pos.Height ? pos.Height : 60; - return height; - } - } else { - if (pos.isMobile) { - if (pos.IsResize) { - height = pos.Height ? pos.Height : 60; - return height; + if (pos.isMobile) { + if (pos.IsResize) { + height = posHeight ? posHeight : defaultHeight; + return height; + } else { + height = (posHeight || defaultHeight) * pos.scale; + return height; + } } else { - height = (pos.Height || 60) * pos.scale; + height = posHeight ? posHeight : defaultHeight; return height; } - } else { - height = pos.Height ? pos.Height : 60; - return height; } } }; - //function for render placeholder block over pdf document - const checkSignedSignes = (data) => { - const checkSign = signedSigners.filter( - (sign) => sign.objectId === data.signerObjId - ); - if (data.signerObjId === signerObjectId) { - setCurrentSigner(true); - } - const xPos = (pos) => { + const xPos = (pos, signYourself) => { + const resizePos = pos.xPosition; + if (signYourself) { + return resizePos; + } else { //checking both condition mobile and desktop view if (isMobile) { //if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale if (!pos.isMobile) { - return pos.xPosition / scale; + return resizePos / scale; } //pos.isMobile true -- placeholder save from mobile view(small device) handle position in mobile view(small screen) view divided by scale else { - return pos.xPosition * (pos.scale / scale); + return resizePos * (pos.scale / scale); } } else { //else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale if (pos.isMobile) { - return pos.scale && pos.xPosition * pos.scale; + return pos.scale && resizePos * pos.scale; } //else placeholder save from desktop(bigscreen) and show in desktop(bigscreen) else { - return pos.xPosition; + return resizePos; } } - }; - const yPos = (pos) => { + } + }; + const yPos = (pos, signYourself) => { + const resizePos = pos.yPosition; + if (signYourself) { + return resizePos; + } else { //checking both condition mobile and desktop view if (isMobile) { //if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale if (!pos.isMobile) { - return pos.yPosition / scale; + return resizePos / scale; } //pos.isMobile true -- placeholder save from mobile view(small device) handle position in mobile view(small screen) view divided by scale else { - return pos.yPosition * (pos.scale / scale); + return resizePos * (pos.scale / scale); } } else { //else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale if (pos.isMobile) { - return pos.scale && pos.yPosition * pos.scale; + return pos.scale && resizePos * pos.scale; } //else placeholder save from desktop(bigscreen) and show in desktop(bigscreen) else { - return pos.yPosition; + return resizePos; } } - }; + } + }; + //function for render placeholder block over pdf document + const checkSignedSignes = (data) => { + const checkSign = signedSigners.filter( + (sign) => sign.objectId === data.signerObjId + ); + if (data.signerObjId === signerObjectId) { + setCurrentSigner(true); + } + return ( checkSign.length === 0 && data.placeHolder.map((placeData, key) => { @@ -201,20 +232,30 @@ function RenderPdf({ data.signerObjId === signerObjectId ? "pointer" : "not-allowed", - borderColor: themeColor(), background: data.blockColor, + borderColor: themeColor(), + borderStyle: "dashed", + borderWidth: "0.1px", zIndex: "1" }} - className="placeholderBlock" + className="signYourselfBlock" size={{ width: posWidth(pos), height: posHeight(pos) }} + onClick={() => { + if (data.signerObjId === signerObjectId) { + setIsSignPad(true); + setSignKey(pos.key); + setIsStamp(pos.isStamp); + } + }} onResize={(e, direction, ref, delta, position) => { + e.stopPropagation(); handleImageResize( ref, pos.key, - data.signerObjId, + data.Id, position, signerPos, pageNumber, @@ -231,13 +272,6 @@ function RenderPdf({ x: xPos(pos), y: yPos(pos) }} - onClick={() => { - if (data.signerObjId === signerObjectId) { - setIsSignPad(true); - setSignKey(pos.key); - setIsStamp(pos.isStamp); - } - }} >
{data.signerObjId === signerObjectId && ( @@ -289,16 +323,83 @@ function RenderPdf({ ); }; - //handled x-position in mobile view saved from big screen or small screen - const xPos = (pos) => { - //if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale - if (!pos.isMobile) { - return pos.xPosition / scale; + const PlaceholderDesign = ({ pos, data }) => { + return ( +
+ { + e.stopPropagation(); + setIsPageCopy(true); + setSignKey(pos.key); + }} + style={{ + color: "#188ae2" + }} + > + { + e.stopPropagation(); + if (data) { + handleDeleteSign(pos.key, data.signerObjId); + } else { + handleDeleteSign(pos.key); + setIsStamp(false); + } + }} + style={{ + color: "#188ae2" + }} + > + + {pos.SignUrl ? ( +
+ signimg +
+ ) : ( +
+ {pos.isStamp ? "stamp" : "signature"} +
+ )} +
+ ); + }; + const handleUserName = (signerId, Role) => { + if (signerId) { + const checkSign = signersdata.filter( + (sign) => sign.objectId === signerId + ); + if (checkSign.length > 0) { + return ( + <> +
+ {checkSign[0].Name} +
+
{`(${Role})`}
+ + ); + } else { + return
{Role}
; + } } else { - return pos.xPosition * (pos.scale / scale); + return
{Role}
; } }; - return ( <> {isMobile && scale ? ( @@ -341,9 +442,14 @@ function RenderPdf({ style={{ cursor: "all-scroll", borderColor: themeColor(), - zIndex: "1" + borderStyle: "dashed", + borderWidth: "0.1px", + zIndex: "1", + background: data.blockColor + ? data.blockColor + : "#daebe0" }} - className="placeholderBlock" + className="signYourselfBlock" onResize={( e, direction, @@ -354,13 +460,9 @@ function RenderPdf({ handleSignYourselfImageResize( ref, pos.key, - direction, - position, xyPostion, index, - setXyPostion, - pdfOriginalWidth, - containerWH + setXyPostion ); }} size={{ @@ -370,13 +472,9 @@ function RenderPdf({ lockAspectRatio={ pos.Width ? pos.Width / pos.Height : 2.5 } - //if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divide by scale - //else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale default={{ x: xPos(pos), - y: !pos.isMobile - ? pos.yPosition / scale - : pos.yPosition * (pos.scale / scale) + y: yPos(pos) }} onClick={() => { setIsSignPad(true); @@ -409,7 +507,15 @@ function RenderPdf({ marginTop: "0px" }} > - {pos.isStamp ? "stamp" : "signature"} + {pos.isStamp ? ( +
stamp
+ ) : ( +
signature
+ )} + {handleUserName( + data.signerObjId, + data.Role + )}
)} @@ -427,7 +533,7 @@ function RenderPdf({ ); }) - : placeholder + : placeholder // placeholder mobile ? signerPos.map((data, ind) => { return ( @@ -438,6 +544,7 @@ function RenderPdf({ placeData.pos.map((pos) => { return ( handleTabDrag(pos.key)} size={{ - width: pos.Width ? pos.Width : 150, - height: pos.Height ? pos.Height : 60 + width: posWidth(pos), + height: posHeight(pos) }} + // size={{ + // width: pos.Width ? pos.Width : 150, + // height: pos.Height ? pos.Height : 60 + // }} lockAspectRatio={ pos.Width ? pos.Width / pos.Height : 2.5 } - onDragStop={(event, dragElement) => - handleStop( - event, - dragElement, - data.signerObjId, - pos.key - ) + onDragStop={ + (event, dragElement) => + handleStop( + event, + dragElement, + data.Id, + pos.key + ) + // data.signerObjId, } + // default={{ + // x: pos.xPosition, + // y: pos.yPosition + // }} default={{ - x: pos.xPosition, - y: pos.yPosition + x: xPos(pos), + y: yPos(pos) }} onResizeStart={() => { setIsResize(true); @@ -495,17 +611,23 @@ function RenderPdf({ handleImageResize( ref, pos.key, - data.signerObjId, + data.Id, position, signerPos, pageNumber, setSignerPos, pdfOriginalWidth, containerWH, - false + true ); }} > + +
{ const dataNewPlace = addZIndex( @@ -523,45 +645,83 @@ function RenderPdf({ return newState; }); }} - style={{ - cursor: "all-scroll", - borderColor: themeColor(), - background: data.blockColor, - zIndex: pos.zIndex, - height: pos.Height - ? pos.Height - : 60, - width: pos.Width ? pos.Width : 150 - }} > - - -
{ + { + e.stopPropagation(); + handleLinkUser(data.Id); + setUniqueId(data.Id); + }} + onClick={(e) => { + e.stopPropagation(); + handleLinkUser(data.Id); + setUniqueId(data.Id); + }} + style={{ + color: "#188ae2" + }} + > + { + e.stopPropagation(); + setIsPageCopy(true); + setSignKey(pos.key); + setSignerObjId(data.signerObjId); + setUniqueId(data.Id); + }} + onClick={(e) => { + e.stopPropagation(); + setIsPageCopy(true); + setSignKey(pos.key); + setSignerObjId(data.signerObjId); + setUniqueId(data.Id); + }} + style={{ + color: "#188ae2" + }} + > + { e.stopPropagation(); handleDeleteSign( pos.key, - data.signerObjId + data.Id ); + // data.signerObjId + }} + onClick={(e) => { + e.stopPropagation(); + handleDeleteSign( + pos.key, + data.Id + ); + // data.signerObjId }} style={{ - background: themeColor() + color: "#188ae2" }} - className="placeholdCloseBtn" - > - x -
+ > +
- {pos.isStamp - ? "stamp" - : "signature"} + {pos.isStamp ? ( +
stamp
+ ) : ( +
signature
+ )} + {handleUserName( + data.signerObjId, + data.Role + )}
@@ -595,22 +755,23 @@ function RenderPdf({ lockAspectRatio={ pos.Width ? pos.Width / pos.Height : 2.5 } - className="placeholderBlock" bounds="parent" ref={nodeRef} key={pos.key} + className="signYourselfBlock" style={{ + border: "1px solid red", cursor: "all-scroll", - borderColor: themeColor(), - zIndex: "1" + zIndex: "1", + background: "#daebe0" }} size={{ - width: pos.Width ? pos.Width : 151, - height: pos.Height ? pos.Height : 61 + width: posWidth(pos, true), + height: posHeight(pos, true) }} default={{ - x: pos.xPosition, - y: pos.yPosition + x: xPos(pos, true), + y: yPos(pos, true) }} onDrag={() => handleTabDrag(pos.key)} onDragStop={handleStop} @@ -624,20 +785,30 @@ function RenderPdf({ handleSignYourselfImageResize( ref, pos.key, - direction, - position, xyPostion, index, - setXyPostion, - pdfOriginalWidth, - containerWH + setXyPostion + ); }} > - {" "} + +
{ - if (!isDragging) { + if (!isDragging && isMobile) { setTimeout(() => { e.stopPropagation(); setIsSignPad(true); @@ -646,41 +817,54 @@ function RenderPdf({ }, 500); } }} - style={{ - height: "100%" - }} > - -
{ + { e.stopPropagation(); - handleDeleteSign(pos.key); - setIsStamp(false); + setIsPageCopy(true); + setSignKey(pos.key); }} style={{ - background: themeColor() + color: "#188ae2" }} - className="placeholdCloseBtn" - > - x -
+ > + { + e.stopPropagation(); + if (data) { + handleDeleteSign( + pos.key, + data.signerObjId + ); + } else { + handleDeleteSign(pos.key); + setIsStamp(false); + } + }} + style={{ + color: "#188ae2" + }} + > + {pos.SignUrl ? ( - signimg +
+ signimg +
) : (
@@ -792,13 +976,9 @@ function RenderPdf({ handleSignYourselfImageResize( ref, pos.key, - direction, - position, xyPostion, index, - setXyPostion, - pdfOriginalWidth, - containerWH + setXyPostion ); }} key={pos.key} @@ -806,9 +986,14 @@ function RenderPdf({ style={{ cursor: "all-scroll", borderColor: themeColor(), - zIndex: "1" + borderStyle: "dashed", + borderWidth: "0.1px", + zIndex: "1", + background: data.blockColor + ? data.blockColor + : "#daebe0" }} - className="placeholderBlock" + className="signYourselfBlock" size={{ width: posWidth(pos), height: posHeight(pos) @@ -816,15 +1001,9 @@ function RenderPdf({ lockAspectRatio={ pos.Width ? pos.Width / pos.Height : 2.5 } - //if pos.isMobile false -- placeholder saved from mobile view then handle position in desktop view to multiply by scale - default={{ - x: pos.isMobile - ? pos.scale && pos.xPosition * pos.scale - : pos.xPosition, - y: pos.isMobile - ? pos.scale && pos.yPosition * pos.scale - : pos.yPosition + x: xPos(pos), + y: yPos(pos) }} onClick={() => { setIsSignPad(true); @@ -851,14 +1030,22 @@ function RenderPdf({ ) : (
- {pos.isStamp ? "stamp" : "signature"} + {pos.isStamp ? ( +
stamp
+ ) : ( +
signature
+ )} + {handleUserName( + data.signerObjId, + data.Role + )}
)}
@@ -919,31 +1106,36 @@ function RenderPdf({ style={{ cursor: "all-scroll", background: data.blockColor, - borderColor: themeColor(), zIndex: pos.zIndex }} - className="placeholderBlock" + className="signYourselfBlock" onDrag={() => handleTabDrag(pos.key)} size={{ - width: pos.Width ? pos.Width : 150, - height: pos.Height ? pos.Height : 60 + width: posWidth(pos), + height: posHeight(pos) }} lockAspectRatio={ pos.Width ? pos.Width / pos.Height : 2.5 } - onDragStop={(event, dragElement) => - handleStop( - event, - dragElement, - data.signerObjId, - pos.key - ) + onDragStop={ + (event, dragElement) => + handleStop( + event, + dragElement, + data.Id, + pos.key + ) + // data.signerObjId, } + // default={{ + // x: pos.xPosition, + // y: pos.yPosition + // }} default={{ - x: pos.xPosition, - y: pos.yPosition + x: xPos(pos), + y: yPos(pos) }} onResizeStart={() => { setIsResize(true); @@ -958,10 +1150,11 @@ function RenderPdf({ delta, position ) => { + e.stopPropagation(); handleImageResize( ref, pos.key, - data.signerObjId, + data.Id, //data.signerObjId, position, signerPos, pageNumber, @@ -972,34 +1165,71 @@ function RenderPdf({ ); }} > - -
{ - e.stopPropagation(); - handleDeleteSign( - pos.key, - data.signerObjId - ); - }} - style={{ - background: themeColor() - }} - className="placeholdCloseBtn" - > - x -
-
+ +
+ { + e.stopPropagation(); + handleLinkUser(data.Id); + setUniqueId(data.Id); + }} + style={{ + color: "#188ae2" + }} + > + { + e.stopPropagation(); + setIsPageCopy(true); + setSignKey(pos.key); + setUniqueId(data.Id); + setSignerObjId( + data.signerObjId + ); + }} + style={{ + color: "#188ae2" + }} + > + { + e.stopPropagation(); + handleDeleteSign( + pos.key, + data.Id + ); + // data.signerObjId + }} + style={{ + color: "#188ae2" + }} + > - marginTop: "0px" - }} - > - {pos.isStamp - ? "stamp" - : "signature"} +
+ {pos.isStamp ? ( +
stamp
+ ) : ( +
signature
+ )} + {handleUserName( + data.signerObjId, + data.Role + )} +
); @@ -1034,12 +1264,13 @@ function RenderPdf({ topLeft: false }} bounds="parent" + className="signYourselfBlock" style={{ - borderColor: themeColor(), + border: "1px solid red", cursor: "all-scroll", - zIndex: "1" + zIndex: "1", + background: "#daebe0" }} - className="placeholderBlock" onDrag={() => handleTabDrag(pos.key)} size={{ width: pos.Width ? pos.Width : 150, @@ -1050,6 +1281,13 @@ function RenderPdf({ x: pos.xPosition, y: pos.yPosition }} + onClick={() => { + if (!isDragging) { + setIsSignPad(true); + setSignKey(pos.key); + setIsStamp(pos.isStamp); + } + }} onResize={( e, direction, @@ -1057,66 +1295,23 @@ function RenderPdf({ delta, position ) => { + e.stopPropagation(); handleSignYourselfImageResize( ref, pos.key, - direction, - position, xyPostion, index, - setXyPostion, - pdfOriginalWidth, - containerWH + setXyPostion ); }} - onClick={() => { - if (!isDragging) { - setIsSignPad(true); - setSignKey(pos.key); - setIsStamp(pos.isStamp); - } - }} > - - - { - e.stopPropagation(); - handleDeleteSign(pos.key); - setIsStamp(false); - }} - style={{ - background: themeColor() - }} - className="placeholdCloseBtn" - > - x - - - {pos.SignUrl ? ( -
- signimg -
- ) : ( -
- {pos.isStamp ? "stamp" : "signature"} -
- )} + + + ) ); diff --git a/microfrontends/SignDocuments/src/Component/component/signerListPlace.js b/microfrontends/SignDocuments/src/Component/component/signerListPlace.js index 28a5231d7..9a4c56b08 100644 --- a/microfrontends/SignDocuments/src/Component/component/signerListPlace.js +++ b/microfrontends/SignDocuments/src/Component/component/signerListPlace.js @@ -1,161 +1,32 @@ -import React, { useState } from "react"; -import check from "../../assests/checkBox.png"; +import React from "react"; import { themeColor } from "../../utils/ThemeColor/backColor"; +import "../../css/signerListPlace.css"; +import RecipientList from "../../premitives/RecipientList"; -function SignerListPlace({ - signerPos, - signersdata, - isSelectListId, - setSignerObjId, - setIsSelectId, - setContractName -}) { - const color = [ - "#93a3db", - "#e6c3db", - "#c0e3bc", - "#bce3db", - "#b8ccdb", - "#ceb8db", - "#ffccff", - "#99ffcc", - "#cc99ff", - "#ffcc99", - "#66ccff", - "#ffffcc", - ]; - - const nameColor = [ - "#304fbf", - "#7d5270", - "#5f825b", - "#578077", - "#576e80", - "#6d527d", - "#cc00cc", - "#006666", - "#cc00ff", - "#ff9900", - "#336699", - "#cc9900", - ]; - const [isHover, setIsHover] = useState(); - - //function for onhover signer name change background color - const onHoverStyle = (ind) => { - const style = { - background: color[ind % color.length], - padding: "10px", - marginTop: "2px", - display: "flex", - flexDirection: "row", - borderBottom: "1px solid #e3e1e1", - }; - return style; - }; - //function for onhover signer name remove background color - const nonHoverStyle = (ind) => { - const style = { - // width:"250px", - padding: "10px", - marginTop: "2px", - display: "flex", - flexDirection: "row", - - justifyContent: "space-between", - }; - return style; - }; - - const getFirstLetter = (name) => { - const firstLetter = name.charAt(0); - return firstLetter; - }; - +function SignerListPlace(props) { return ( -
+
- Reicipents + Recipients
-
- {signersdata.Signers && - signersdata.Signers.map((obj, ind) => { - return ( -
setIsHover(ind)} - onMouseLeave={() => setIsHover(null)} - key={ind} - style={ - isHover === ind || isSelectListId === ind - ? onHoverStyle(ind) - : nonHoverStyle(ind) - } - onClick={() => { - setSignerObjId(obj.objectId); - setIsSelectId(ind); - setContractName(obj.className) - }} - > -
-
- - {" "} - {getFirstLetter(obj.Name)} - -
-
- {obj.Name} - {obj.Email} -
-
- {signerPos.map((data, key) => { - return ( - data.signerObjId === obj.objectId && ( -
- no img -
- ) - ); - })} - -
-
- ); - })} +
- + {props.handleAddSigner && ( +
props.handleAddSigner()} + > + + Add role +
+ )}
); } diff --git a/microfrontends/SignDocuments/src/Component/placeHolderSign.js b/microfrontends/SignDocuments/src/Component/placeHolderSign.js index 564938f7f..32e1f3607 100644 --- a/microfrontends/SignDocuments/src/Component/placeHolderSign.js +++ b/microfrontends/SignDocuments/src/Component/placeHolderSign.js @@ -22,11 +22,15 @@ import { contractDocument, contractUsers, getHostUrl, - addZIndex + addZIndex, + randomId } from "../utils/Utils"; import RenderPdf from "./component/renderPdf"; import ModalComponent from "./component/modalComponent"; import { useNavigate } from "react-router-dom"; +import PlaceholderCopy from "./component/PlaceholderCopy"; +import LinkUserModal from "./component/LinkUserModal"; +import Title from "./component/Title"; function PlaceHolderSign() { const navigate = useNavigate(); @@ -66,12 +70,17 @@ function PlaceHolderSign() { const [isShowEmail, setIsShowEmail] = useState(false); const [selectedEmail, setSelectedEmail] = useState(false); const [isResize, setIsResize] = useState(false); - const [isAlreadyPlace, setIsAlreadyPlace] = useState(false); const [zIndex, setZIndex] = useState(1); + const [signKey, setSignKey] = useState(); const [pdfLoadFail, setPdfLoadFail] = useState({ status: false, type: "load" }); + const [isPageCopy, setIsPageCopy] = useState(false); + const [uniqueId, setUniqueId] = useState(""); + const [roleName, setRoleName] = useState(""); + const [isAddUser, setIsAddUser] = useState({}); + const [signerExistModal, setSignerExistModal] = useState(false); const color = [ "#93a3db", "#e6c3db", @@ -96,7 +105,6 @@ function PlaceHolderSign() { }); const [{ isDragSign }, dragSignature] = useDrag({ type: "BOX", - item: { type: "BOX", id: 1, @@ -108,7 +116,6 @@ function PlaceHolderSign() { }); const [{ isDragStamp }, dragStamp] = useDrag({ type: "BOX", - item: { type: "BOX", id: 2, @@ -121,7 +128,6 @@ function PlaceHolderSign() { const [{ isDragSignatureSS }, dragSignatureSS] = useDrag({ type: "BOX", - item: { type: "BOX", id: 3, @@ -134,7 +140,6 @@ function PlaceHolderSign() { const [{ isDragStampSS }, dragStampSS] = useDrag({ type: "BOX", - item: { type: "BOX", id: 4, @@ -184,23 +189,82 @@ function PlaceHolderSign() { //getting document details const documentData = await contractDocument(documentId); if (documentData && documentData.length > 0) { - const alreadyPlaceholder = - documentData[0].Placeholders && documentData[0].Placeholders; - if (alreadyPlaceholder && alreadyPlaceholder.length > 0) { - setIsAlreadyPlace(true); - } + // const alreadyPlaceholder = + // documentData[0].Placeholders && documentData[0].Placeholders; + // if (alreadyPlaceholder && alreadyPlaceholder.length > 0) { + // setIsAlreadyPlace(true); + // } + // setSignersData(documentData[0]); + // setIsSelectId(0); + // setSignerObjId(documentData[0].Signers[0].objectId); + // setContractName(documentData[0].Signers[0].className); setPdfDetails(documentData); - const currEmail = documentData[0].ExtUserPtr.Email; - const filterCurrEmail = documentData[0].Signers.filter( - (data) => data.Email === currEmail - ); - setCurrentEmail(filterCurrEmail); - setSignersData(documentData[0]); + if (documentData[0].Signers && documentData[0].Signers.length > 0) { + const currEmail = documentData[0].ExtUserPtr.Email; + const filterCurrEmail = documentData[0].Signers.filter( + (data) => data.Email === currEmail + ); + setCurrentEmail(filterCurrEmail); + setSignerObjId(documentData[0].Signers[0].objectId); + setContractName(documentData[0].Signers[0].className); + setIsSelectId(0); + if ( + documentData[0].Placeholders && + documentData[0].Placeholders.length > 0 + ) { + setSignerPos(documentData[0].Placeholders); + let signers = [...documentData[0].Signers]; + let updatedSigners = documentData[0].Placeholders.map((x) => { + let matchingSigner = signers.find( + (y) => x.signerObjId && x.signerObjId === y.objectId + ); - setSignerObjId(documentData[0].Signers[0].objectId); - setContractName(documentData[0].Signers[0].className); - setIsSelectId(0); + if (matchingSigner) { + return { + ...matchingSigner, + Role: x.Role ? x.Role : matchingSigner.Role, + Id: x.Id, + blockColor: x.blockColor + }; + } else { + return { + Role: x.Role, + Id: x.Id, + blockColor: x.blockColor + }; + } + }); + setSignersData(updatedSigners); + setUniqueId(updatedSigners[0].Id); + } else { + const updatedSigners = documentData[0].Signers.map((x, index) => ({ + ...x, + Id: randomId(), + Role: "User " + (index + 1) + })); + setSignersData(updatedSigners); + setUniqueId(updatedSigners[0].Id); + } + } else { + setRoleName("User 1"); + if ( + documentData[0].Placeholders && + documentData[0].Placeholders.length > 0 + ) { + let updatedSigners = documentData[0].Placeholders.map((x) => { + return { + Role: x.Role, + Id: x.Id, + blockColor: x.blockColor + }; + }); + setSignerPos(documentData[0].Placeholders); + setSignersData(updatedSigners); + setIsSelectId(0); + setUniqueId(updatedSigners[0].Id); + } + } } else if ( documentData === "Error: Something went wrong!" || (documentData.result && documentData.result.error) @@ -270,9 +334,11 @@ function PlaceHolderSign() { const newWidth = containerWH.width; const scale = pdfOriginalWidth / newWidth; const key = Math.floor(1000 + Math.random() * 9000); - let filterSignerPos = signerPos.filter( - (data) => data.signerObjId === signerObjId - ); + // let filterSignerPos = signerPos.filter( + // (data) => data.signerObjId === signerObjId + // ); + let filterSignerPos = signerPos.filter((data) => data.Id === uniqueId); + let dropData = []; let xyPosArr = []; let xyPos = {}; @@ -330,9 +396,11 @@ function PlaceHolderSign() { //add signers objId first inseretion if (filterSignerPos.length > 0) { - const colorIndex = signerPos - .map((e) => e.signerObjId) - .indexOf(signerObjId); + // const colorIndex = signerPos + // .map((e) => e.signerObjId) + // .indexOf(signerObjId); + + const colorIndex = signerPos.map((e) => e.Id).indexOf(uniqueId); const getPlaceHolder = filterSignerPos[0].placeHolder; const updatePlace = getPlaceHolder.filter( @@ -351,16 +419,30 @@ function PlaceHolderSign() { pos: newSignPos }; updatePlace.push(xyPos); - let placeHolderPos = { - blockColor: color[isSelectListId], - signerObjId: signerObjId, - placeHolder: updatePlace, - signerPtr: { - __type: "Pointer", - className: `${contractName}`, - objectId: signerObjId - } - }; + let placeHolderPos; + if (contractName) { + placeHolderPos = { + blockColor: color[isSelectListId], + signerObjId: signerObjId, + placeHolder: updatePlace, + signerPtr: { + __type: "Pointer", + className: `${contractName}`, + objectId: signerObjId + }, + Role: roleName, + Id: uniqueId + }; + } else { + placeHolderPos = { + blockColor: color[isSelectListId], + signerObjId: "", + placeHolder: updatePlace, + signerPtr: {}, + Role: roleName, + Id: uniqueId + }; + } // signerPos.splice(colorIndex, 1, placeHolderPos); const newArry = [placeHolderPos]; const newArray = [ @@ -368,21 +450,33 @@ function PlaceHolderSign() { ...newArry, ...signerPos.slice(colorIndex + 1) ]; - setSignerPos(newArray); } else { const newSignPoss = getPlaceHolder.concat(xyPosArr[0]); - - let placeHolderPos = { - blockColor: color[isSelectListId], - signerObjId: signerObjId, - placeHolder: newSignPoss, - signerPtr: { - __type: "Pointer", - className: `${contractName}`, - objectId: signerObjId - } - }; + let placeHolderPos; + if (contractName) { + placeHolderPos = { + blockColor: color[isSelectListId], + signerObjId: signerObjId, + placeHolder: newSignPoss, + signerPtr: { + __type: "Pointer", + className: `${contractName}`, + objectId: signerObjId + }, + Role: roleName, + Id: uniqueId + }; + } else { + placeHolderPos = { + blockColor: color[isSelectListId], + signerObjId: "", + placeHolder: newSignPoss, + signerPtr: {}, + Role: roleName, + Id: uniqueId + }; + } // signerPos.splice(colorIndex, 1, placeHolderPos); const newArry = [placeHolderPos]; @@ -395,19 +489,34 @@ function PlaceHolderSign() { setSignerPos(newArray); } } else { - let placeHolderPos = { - signerPtr: { - __type: "Pointer", - className: `${contractName}`, - objectId: signerObjId - }, - signerObjId: signerObjId, - blockColor: color[isSelectListId], - placeHolder: xyPosArr - }; + let placeHolderPos; + if (contractName) { + placeHolderPos = { + signerPtr: { + __type: "Pointer", + className: `${contractName}`, + objectId: signerObjId + }, + signerObjId: signerObjId, + blockColor: color[isSelectListId], + placeHolder: xyPosArr, + Role: roleName, + Id: uniqueId + }; + } else { + placeHolderPos = { + signerPtr: {}, + signerObjId: "", + blockColor: color[isSelectListId], + placeHolder: xyPosArr, + Role: roleName, + Id: uniqueId + }; + } setSignerPos((prev) => [...prev, placeHolderPos]); } + setIsMailSend(false); }; //function for get pdf page details @@ -432,17 +541,19 @@ function PlaceHolderSign() { const handleStop = (event, dragElement, signerId, key) => { if (!isResize) { const dataNewPlace = addZIndex(signerPos, key, setZIndex); - signerPos.splice(0, signerPos.length, ...dataNewPlace); + let updateSignPos = [...signerPos]; + updateSignPos.splice(0, updateSignPos.length, ...dataNewPlace); + // signerPos.splice(0, signerPos.length, ...dataNewPlace); const containerRect = document .getElementById("container") .getBoundingClientRect(); - const signId = signerId ? signerId : signerObjId; + const signId = signerId ? signerId : uniqueId; //? signerId : signerObjId; const keyValue = key ? key : dragKey; const ybottom = containerRect.height - dragElement.y; if (keyValue >= 0) { - const filterSignerPos = signerPos.filter( - (data) => data.signerObjId === signId + const filterSignerPos = updateSignPos.filter( + (data) => data.Id === signId ); if (filterSignerPos.length > 0) { @@ -475,8 +586,8 @@ function PlaceHolderSign() { } return obj; }); - const newUpdateSigner = signerPos.map((obj, ind) => { - if (obj.signerObjId === signId) { + const newUpdateSigner = updateSignPos.map((obj, ind) => { + if (obj.Id === signId) { return { ...obj, placeHolder: newUpdateSignPos }; } return obj; @@ -490,11 +601,13 @@ function PlaceHolderSign() { }; //function for delete signature block - const handleDeleteSign = (key, signerId) => { + const handleDeleteSign = (key, Id) => { const updateData = []; - const filterSignerPos = signerPos.filter( - (data) => data.signerObjId === signerId - ); + // const filterSignerPos = signerPos.filter( + // (data) => data.signerObjId === signerId + // ); + + const filterSignerPos = signerPos.filter((data) => data.Id === Id); if (filterSignerPos.length > 0) { const getPlaceHolder = filterSignerPos[0].placeHolder; @@ -518,7 +631,7 @@ function PlaceHolderSign() { }); const newUpdateSigner = signerPos.map((obj, ind) => { - if (obj.signerObjId === signerId) { + if (obj.Id === Id) { return { ...obj, placeHolder: newUpdatePos }; } return obj; @@ -526,24 +639,20 @@ function PlaceHolderSign() { setSignerPos(newUpdateSigner); } else { - const updateFilter = signerPos.filter( - (data) => data.signerObjId !== signerId - ); + const updateFilter = signerPos.filter((data) => data.Id !== Id); const getRemainPage = filterSignerPos[0].placeHolder.filter( (data) => data.pageNumber !== pageNumber ); if (getRemainPage && getRemainPage.length > 0) { const newUpdatePos = filterSignerPos.map((obj, ind) => { - if (obj.signerObjId === signerId) { + if (obj.Id === Id) { return { ...obj, placeHolder: getRemainPage }; } return obj; }); let signerupdate = []; - signerupdate = signerPos.filter( - (data) => data.signerObjId !== signerId - ); + signerupdate = signerPos.filter((data) => data.Id !== Id); signerupdate.push(newUpdatePos[0]); setSignerPos(signerupdate); @@ -581,12 +690,17 @@ function PlaceHolderSign() { }; const alertSendEmail = async () => { - if (signerPos.length === signersdata.Signers.length) { - const alert = { - mssg: "confirm", - alert: true - }; - setIsSendAlert(alert); + if (signerPos.length === signersdata.length) { + const IsSignerNotExist = signerPos?.some((x) => !x.signerObjId); + if (IsSignerNotExist) { + setSignerExistModal(true); + } else { + const alert = { + mssg: "confirm", + alert: true + }; + setIsSendAlert(alert); + } } else { const alert = { mssg: "sure", @@ -605,15 +719,16 @@ function PlaceHolderSign() { setIsSendAlert({}); let sendMail; - const expireDate = signersdata.ExpiryDate.iso; + // console.log("pdfDetails", pdfDetails); + const expireDate = pdfDetails?.[0].ExpiryDate.iso; const newDate = new Date(expireDate); const localExpireDate = newDate.toLocaleDateString("en-US", { day: "numeric", month: "long", year: "numeric" }); - let sender = signersdata.ExtUserPtr.Email; - const signerMail = signersdata.Signers; + let sender = pdfDetails?.[0].ExtUserPtr.Email; + const signerMail = signersdata; for (let i = 0; i < signerMail.length; i++) { try { @@ -633,12 +748,12 @@ function PlaceHolderSign() { )}&${localStorage.getItem("_appName")}`; const hostUrl = window.location.origin + "/loadmf/signmicroapp"; - let signPdf = `${hostUrl}/login/${signersdata.objectId}/${signerMail[i].Email}/${objectId}/${serverParams}`; + let signPdf = `${hostUrl}/login/${pdfDetails?.[0].objectId}/${signerMail[i].Email}/${objectId}/${serverParams}`; const openSignUrl = "https://www.opensignlabs.com/"; const themeBGcolor = themeColor(); let params = { recipient: signerMail[i].Email, - subject: `${signersdata.ExtUserPtr.Name} has requested you to sign ${signersdata.Name}`, + subject: `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign ${pdfDetails?.[0].Name}`, from: sender, html: @@ -647,9 +762,9 @@ function PlaceHolderSign() { " height='50' style='padding: 20px,width:170px,height:40px' />

Digital Signature Request

" + - signersdata.ExtUserPtr.Name + + pdfDetails?.[0].ExtUserPtr.Name + " has requested you to review and sign " + - signersdata.Name + + pdfDetails?.[0].Name + "

Sender " + sender + "
Organization Name __
Expire on " + @@ -669,10 +784,19 @@ function PlaceHolderSign() { } if (sendMail.data.result.status === "success") { + const signers = signersdata?.map((x) => { + return { + __type: "Pointer", + className: "contracts_Contactbook", + objectId: x.objectId + }; + }); + // console.log("signers ", signers); try { const data = { Placeholders: signerPos, - SignedUrl: pdfDetails[0].URL + SignedUrl: pdfDetails[0].URL, + Signers: signers }; await axios @@ -783,289 +907,380 @@ function PlaceHolderSign() { `${hostUrl}recipientSignPdf/${documentId}/${currentEmail[0].objectId}` ); }; + + const handleLinkUser = (id) => { + setIsAddUser({ [id]: true }); + }; + const handleAddUser = (data) => { + if(data && data.objectId){ + const signerPtr = { + __type: "Pointer", + className: "contracts_Contactbook", + objectId: data.objectId + }; + const updatePlaceHolder = signerPos.map((x) => { + if (x.Id === uniqueId) { + return { ...x, signerPtr: signerPtr, signerObjId: data.objectId }; + } + return { ...x }; + }); + // console.log("updatePlaceHolder ", updatePlaceHolder); + setSignerPos(updatePlaceHolder); + + const updateSigner = signersdata.map((x) => { + if (x.Id === uniqueId) { + return { ...x, ...data }; + } + return { ...x }; + }); + // console.log("updateSigner ", updateSigner); + + setSignersData(updateSigner); + } + }; + + const closePopup = () => { + setIsAddUser({}); + }; return ( - - {isLoading.isLoad ? ( - - ) : handleError ? ( - - ) : noData ? ( - - ) : ( -
- {/* this component used for UI interaction and show their functionality */} - {!checkTourStatus && ( - //this tour component used in your html component where you want to put - //onRequestClose function to close tour - //steps is defined what will be your messages and style also - //isOpen is takes boolean value to open - + + <DndProvider backend={HTML5Backend}> + {isLoading.isLoad ? ( + <Loader isLoading={isLoading} /> + ) : handleError ? ( + <HandleError handleError={handleError} /> + ) : noData ? ( + <Nodata /> + ) : ( + <div className="signatureContainer" ref={divRef}> + {/* this component used for UI interaction and show their functionality */} + {!checkTourStatus && ( + //this tour component used in your html component where you want to put + //onRequestClose function to close tour + //steps is defined what will be your messages and style also + //isOpen is takes boolean value to open + <Tour + onRequestClose={closeTour} + steps={tourConfig} + isOpen={placeholderTour} + rounded={5} + closeWithMask={false} + /> + )} + {/* this component used to render all pdf pages in left side */} + <RenderAllPdfPage + signPdfUrl={pdfDetails[0].URL} + allPages={allPages} + setAllPages={setAllPages} + setPageNumber={setPageNumber} + setSignBtnPosition={setSignBtnPosition} + pageNumber={pageNumber} /> - )} - {/* this component used to render all pdf pages in left side */} - <RenderAllPdfPage - signPdfUrl={pdfDetails[0].URL} - allPages={allPages} - setAllPages={setAllPages} - setPageNumber={setPageNumber} - setSignBtnPosition={setSignBtnPosition} - /> - - {/* pdf render view */} - <div - style={{ - marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px", - marginRight: !isMobile && pdfOriginalWidth > 500 && "20px" - }} - > - {/* this modal is used show alert set placeholder for all signers before send mail */} - - <Modal show={isSendAlert.alert}> - <Modal.Header - className={ - isSendAlert.mssg === "sure" - ? "bg-danger" - : isSendAlert.mssg === "confirm" && "bg-success" - } - > - {isSendAlert.mssg === "sure" ? ( - <span style={{ color: "white" }}>Fields required</span> - ) : ( - isSendAlert.mssg === "confirm" && ( - <span style={{ color: "white" }}>Send Mail</span> - ) - )} - </Modal.Header> - - {/* signature modal */} - <Modal.Body> - {isSendAlert.mssg === "sure" ? ( - <p>Please Add field for all recipients.</p> - ) : ( - isSendAlert.mssg === "confirm" && ( - <p> - Are you sure you want to send out this document for - signatures? - </p> - ) - )} - </Modal.Body> - <Modal.Footer> - <button - onClick={() => setIsSendAlert({})} - style={{ - color: "black" - }} - type="button" - className="finishBtn" + {/* pdf render view */} + <div + style={{ + marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px", + marginRight: !isMobile && pdfOriginalWidth > 500 && "20px" + }} + > + {/* this modal is used show alert set placeholder for all signers before send mail */} + + <Modal show={isSendAlert.alert}> + <Modal.Header + className={ + isSendAlert.mssg === "sure" + ? "bg-danger" + : isSendAlert.mssg === "confirm" && "bg-success" + } > - Close - </button> - {isSendAlert.mssg === "confirm" && ( + {isSendAlert.mssg === "sure" ? ( + <span style={{ color: "white" }}>Fields required</span> + ) : ( + isSendAlert.mssg === "confirm" && ( + <span style={{ color: "white" }}>Send Mail</span> + ) + )} + </Modal.Header> + + {/* signature modal */} + <Modal.Body> + {isSendAlert.mssg === "sure" ? ( + <p>Please add field for all recipients.</p> + ) : ( + isSendAlert.mssg === "confirm" && ( + <p> + Are you sure you want to send out this document for + signatures? + </p> + ) + )} + </Modal.Body> + + <Modal.Footer> <button - onClick={() => sendEmailToSigners()} + onClick={() => setIsSendAlert({})} style={{ - background: "#24b53a" + color: "black" }} type="button" className="finishBtn" > - Yes + Close </button> - )} - </Modal.Footer> - </Modal> - {/* this modal is used show send mail message and after send mail success message */} - <Modal show={isSend}> - <Modal.Header - style={{ - background: themeColor() - }} - > - <span style={{ color: "white" }}>Mails Sent</span> - </Modal.Header> - - {/* signature modal */} - <Modal.Body> - <p>You have successfully sent mails to all recipients!</p> - {currentEmail.length > 0 && ( - <p>Do you want to sign documents right now ?</p> - )} - </Modal.Body> - - <Modal.Footer> - {currentEmail.length > 0 ? ( - <> + {isSendAlert.mssg === "confirm" && ( <button - onClick={() => { - setIsSend(false); - setSignerPos([]); - }} + onClick={() => sendEmailToSigners()} style={{ - color: "black" + background: "#24b53a" }} type="button" className="finishBtn" > - No + Yes </button> - + )} + </Modal.Footer> + </Modal> + {/* this modal is used show send mail message and after send mail success message */} + <Modal show={isSend}> + <Modal.Header + style={{ + background: themeColor() + }} + > + <span style={{ color: "white" }}>Mails Sent</span> + </Modal.Header> + + {/* signature modal */} + <Modal.Body> + <p>You have successfully sent mails to all recipients!</p> + {currentEmail?.length > 0 && ( + <p>Do you want to sign documents right now ?</p> + )} + </Modal.Body> + + <Modal.Footer> + {currentEmail?.length > 0 ? ( + <> + <button + onClick={() => { + setIsSend(false); + setSignerPos([]); + }} + style={{ + color: "black" + }} + type="button" + className="finishBtn" + > + No + </button> + + <button + onClick={() => { + handleRecipientSign(); + }} + style={{ + background: themeColor(), + color: "white" + }} + type="button" + className="finishBtn" + > + Yes + </button> + </> + ) : ( <button onClick={() => { - handleRecipientSign(); + setIsSend(false); + setSignerPos([]); }} style={{ - background: themeColor(), - color: "white" + color: "black" }} type="button" className="finishBtn" > - Yes + Close </button> - </> - ) : ( - <button - onClick={() => { - setIsSend(false); - setSignerPos([]); - }} - style={{ - color: "black" - }} - type="button" - className="finishBtn" - > - Close - </button> - )} - </Modal.Footer> - </Modal> - <ModalComponent isShow={isAlreadyPlace} type={"alreadyPlace"} /> - <ModalComponent - isShow={isShowEmail} - type={"signersAlert"} - setIsShowEmail={setIsShowEmail} - /> - {/* pdf header which contain funish back button */} - <Header - isPlaceholder={true} - pageNumber={pageNumber} - allPages={allPages} - changePage={changePage} - pdfDetails={pdfDetails} - signerPos={signerPos} - signersdata={signersdata} - isMailSend={isMailSend} - alertSendEmail={alertSendEmail} - isShowHeader={true} - currentSigner={true} - dataTut4="reactourFour" - /> - <div data-tut="reactourThird"> - {containerWH && ( - <RenderPdf - pageNumber={pageNumber} - pdfOriginalWidth={pdfOriginalWidth} - pdfNewWidth={pdfNewWidth} - pdfDetails={pdfDetails} - signerPos={signerPos} - successEmail={false} - numPages={numPages} - pageDetails={pageDetails} - placeholder={true} - drop={drop} - handleDeleteSign={handleDeleteSign} - handleTabDrag={handleTabDrag} - handleStop={handleStop} - setPdfLoadFail={setPdfLoadFail} - pdfLoadFail={pdfLoadFail} - setSignerPos={setSignerPos} - containerWH={containerWH} - setIsResize={setIsResize} - setZIndex={setZIndex} - /> - )} - </div> - </div> - - {/* signature button */} - {isMobile ? ( - <div> - <FieldsComponent - dataTut="reactourFirst" - dataTut2="reactourSecond" - pdfUrl={isMailSend} - sign={sign} - stamp={stamp} - dragSignature={dragSignature} - signRef={signRef} - handleDivClick={handleDivClick} - handleMouseLeave={handleMouseLeave} - isDragSign={isDragSign} - themeColor={themeColor} - dragStamp={dragStamp} - dragRef={dragRef} - isDragStamp={isDragStamp} - isSignYourself={true} - isDragSignatureSS={isDragSignatureSS} - dragSignatureSS={dragSignatureSS} - dragStampSS={dragStampSS} - addPositionOfSignature={addPositionOfSignature} + )} + </Modal.Footer> + </Modal> + {/* <ModalComponent isShow={isAlreadyPlace} type={"alreadyPlace"} /> */} + <ModalComponent + isShow={isShowEmail} + type={"signersAlert"} + setIsShowEmail={setIsShowEmail} + /> + <PlaceholderCopy + isPageCopy={isPageCopy} + setIsPageCopy={setIsPageCopy} + xyPostion={signerPos} + setXyPostion={setSignerPos} + allPages={allPages} + pageNumber={pageNumber} + signKey={signKey} + // signerObjId={signerObjId} + Id={uniqueId} + /> + {/* pdf header which contain funish back button */} + <Header + isPlaceholder={true} + pageNumber={pageNumber} + allPages={allPages} + changePage={changePage} + pdfDetails={pdfDetails} signerPos={signerPos} signersdata={signersdata} - isSelectListId={isSelectListId} - setSignerObjId={setSignerObjId} - setIsSelectId={setIsSelectId} - setContractName={setContractName} - isSigners={true} - setIsShowEmail={setIsShowEmail} isMailSend={isMailSend} - setSelectedEmail={setSelectedEmail} - selectedEmail={selectedEmail} + alertSendEmail={alertSendEmail} + isShowHeader={true} + currentSigner={true} + dataTut4="reactourFour" /> + <div data-tut="reactourThird"> + {containerWH && ( + <RenderPdf + pageNumber={pageNumber} + pdfOriginalWidth={pdfOriginalWidth} + pdfNewWidth={pdfNewWidth} + pdfDetails={pdfDetails} + signerPos={signerPos} + successEmail={false} + numPages={numPages} + pageDetails={pageDetails} + placeholder={true} + drop={drop} + handleDeleteSign={handleDeleteSign} + handleTabDrag={handleTabDrag} + handleStop={handleStop} + setPdfLoadFail={setPdfLoadFail} + pdfLoadFail={pdfLoadFail} + setSignerPos={setSignerPos} + containerWH={containerWH} + setIsResize={setIsResize} + setZIndex={setZIndex} + setIsPageCopy={setIsPageCopy} + signersdata={signersdata} + setSignKey={setSignKey} + setSignerObjId={setSignerObjId} + handleLinkUser={handleLinkUser} + setUniqueId={setUniqueId} + /> + )} + </div> </div> - ) : ( - <div> - <div className="signerComponent"> - <SignerListPlace + + {/* signature button */} + {isMobile ? ( + <div> + <FieldsComponent + dataTut="reactourFirst" + dataTut2="reactourSecond" + pdfUrl={isMailSend} + sign={sign} + stamp={stamp} + dragSignature={dragSignature} + signRef={signRef} + handleDivClick={handleDivClick} + handleMouseLeave={handleMouseLeave} + isDragSign={isDragSign} + themeColor={themeColor} + dragStamp={dragStamp} + dragRef={dragRef} + isDragStamp={isDragStamp} + isSignYourself={true} + isDragSignatureSS={isDragSignatureSS} + dragSignatureSS={dragSignatureSS} + dragStampSS={dragStampSS} + addPositionOfSignature={addPositionOfSignature} signerPos={signerPos} signersdata={signersdata} isSelectListId={isSelectListId} setSignerObjId={setSignerObjId} setIsSelectId={setIsSelectId} setContractName={setContractName} + isSigners={true} + setIsShowEmail={setIsShowEmail} + isMailSend={isMailSend} + setSelectedEmail={setSelectedEmail} + selectedEmail={selectedEmail} + setUniqueId={setUniqueId} + setRoleName={setRoleName} /> - <div data-tut="reactourSecond"> - <FieldsComponent - pdfUrl={isMailSend} - sign={sign} - stamp={stamp} - dragSignature={dragSignature} - signRef={signRef} - handleDivClick={handleDivClick} - handleMouseLeave={handleMouseLeave} - isDragSign={isDragSign} - themeColor={themeColor} - dragStamp={dragStamp} - dragRef={dragRef} - isDragStamp={isDragStamp} - isSignYourself={false} - addPositionOfSignature={addPositionOfSignature} + </div> + ) : ( + <div> + <div className="signerComponent"> + <SignerListPlace + signerPos={signerPos} + signersdata={signersdata} + isSelectListId={isSelectListId} + setSignerObjId={setSignerObjId} + setIsSelectId={setIsSelectId} + setContractName={setContractName} + setUniqueId={setUniqueId} + setRoleName={setRoleName} + // handleAddSigner={handleAddSigner} /> + <div data-tut="reactourSecond"> + <FieldsComponent + pdfUrl={isMailSend} + sign={sign} + stamp={stamp} + dragSignature={dragSignature} + signRef={signRef} + handleDivClick={handleDivClick} + handleMouseLeave={handleMouseLeave} + isDragSign={isDragSign} + themeColor={themeColor} + dragStamp={dragStamp} + dragRef={dragRef} + isDragStamp={isDragStamp} + isSignYourself={false} + addPositionOfSignature={addPositionOfSignature} + /> + </div> </div> </div> - </div> - )} - </div> - )} - </DndProvider> + )} + </div> + )} + </DndProvider> + <div> + <Modal show={signerExistModal}> + <Modal.Header className="bg-danger"> + <span style={{ color: "white" }}>Users required</span> + </Modal.Header> + + {/* signature modal */} + <Modal.Body> + <p>Please attach users to all fields</p> + </Modal.Body> + <Modal.Footer> + <button + onClick={() => setSignerExistModal(false)} + style={{ + color: "black" + }} + type="button" + className="finishBtn" + > + Close + </button> + </Modal.Footer> + </Modal> + <LinkUserModal + handleAddUser={handleAddUser} + isAddUser={isAddUser} + uniqueId={uniqueId} + closePopup={closePopup} + /> + </div> + </> ); } diff --git a/microfrontends/SignDocuments/src/Component/recipientSignPdf.js b/microfrontends/SignDocuments/src/Component/recipientSignPdf.js index 6421e8a8b..b039b0975 100644 --- a/microfrontends/SignDocuments/src/Component/recipientSignPdf.js +++ b/microfrontends/SignDocuments/src/Component/recipientSignPdf.js @@ -794,8 +794,9 @@ function EmbedPdfImage() { allPages={allPages} setAllPages={setAllPages} setPageNumber={setPageNumber} + pageNumber={pageNumber} /> - {/* <div style={{width:"160px",border:"1px solid red"}}>kebjke</div> */} + {/* pdf render view */} <div style={{ diff --git a/microfrontends/SignDocuments/src/Routes.js b/microfrontends/SignDocuments/src/Routes.js index 605212871..e9dd50915 100644 --- a/microfrontends/SignDocuments/src/Routes.js +++ b/microfrontends/SignDocuments/src/Routes.js @@ -9,6 +9,7 @@ import DraftDocument from "./Component/DraftDocument"; import PdfRequestFiles from "./Component/PdfRequestFiles"; import LegaDrive from "./Component/LegaDrive/LegaDrive"; import PageNotFound from "./Component/PageNotFound"; +import TemplatePlaceHolder from "./Component/TemplatePlaceholder"; // `AppRoutes` is used to define route path of app and // it expose to host app, check moduleFederation.config.js for more @@ -47,6 +48,7 @@ function AppRoutes() { {/* lega drive route */} <Route path="/legadrive" element={<LegaDrive />} /> {/* Page Not Found */} + <Route path="/template/:templateId" element={<TemplatePlaceHolder />} /> <Route path="*" element={<PageNotFound />} /> </Routes> </div> diff --git a/microfrontends/SignDocuments/src/assests/checkBox.png b/microfrontends/SignDocuments/src/assests/checkBox.png deleted file mode 100644 index 47142b021..000000000 Binary files a/microfrontends/SignDocuments/src/assests/checkBox.png and /dev/null differ diff --git a/microfrontends/SignDocuments/src/assests/close.png b/microfrontends/SignDocuments/src/assests/close.png deleted file mode 100644 index 85e96612a..000000000 Binary files a/microfrontends/SignDocuments/src/assests/close.png and /dev/null differ diff --git a/microfrontends/SignDocuments/src/assests/download2.png b/microfrontends/SignDocuments/src/assests/download2.png deleted file mode 100644 index 1431ff2a0..000000000 Binary files a/microfrontends/SignDocuments/src/assests/download2.png and /dev/null differ diff --git a/microfrontends/SignDocuments/src/assests/draftDoc.png b/microfrontends/SignDocuments/src/assests/draftDoc.png deleted file mode 100644 index 0f445c66d..000000000 Binary files a/microfrontends/SignDocuments/src/assests/draftDoc.png and /dev/null differ diff --git a/microfrontends/SignDocuments/src/assests/mailLogo.png b/microfrontends/SignDocuments/src/assests/mailLogo.png deleted file mode 100644 index 2edeeaae6..000000000 Binary files a/microfrontends/SignDocuments/src/assests/mailLogo.png and /dev/null differ diff --git a/microfrontends/SignDocuments/src/assests/print.png b/microfrontends/SignDocuments/src/assests/print.png deleted file mode 100644 index 0ea2a9265..000000000 Binary files a/microfrontends/SignDocuments/src/assests/print.png and /dev/null differ diff --git a/microfrontends/SignDocuments/src/assests/signLogo.png b/microfrontends/SignDocuments/src/assests/signLogo.png deleted file mode 100644 index 1de0f2617..000000000 Binary files a/microfrontends/SignDocuments/src/assests/signLogo.png and /dev/null differ diff --git a/microfrontends/SignDocuments/src/css/AddUser.css b/microfrontends/SignDocuments/src/css/AddUser.css new file mode 100644 index 000000000..0e52ba2a0 --- /dev/null +++ b/microfrontends/SignDocuments/src/css/AddUser.css @@ -0,0 +1,79 @@ +.addusercontainer { + height: 100%; + padding: 20px; +} + +.loaderdiv { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: flex; + justify-content: center; + align-items: center; + background-color: rgba(0, 0, 0, 0.3); + +} + +.form-wrapper { + width: 100%; + margin-left: auto; + margin-right: auto; + padding: 8px; +} + +.form-section { + margin-bottom: 0.75rem; +} + +.checkbox-label { + margin-left: 0.5rem; + color: #4b5563; +} + +.addUserInput { + padding: 0.5rem 0.75rem; + width: 100%; + border-width: 1px; + border-color: #d1d5db; + border-radius: 0.375rem; + outline: none; + font-size: 0.75rem; +} + + +.buttoncontainer { + margin-top: 1rem; + display: flex; + justify-content: flex-start; +} + +.submitbutton { + background: #1ab6ce; + border-radius: 2px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18); + border: none; + text-transform: uppercase; + font-size: 13px; + font-weight: 600; + padding: 0.375rem 0.75rem; + text-align: center; + color: #ffffff; + outline: none; +} +/* For classes: bg-[#188ae2] text-sm text-white px-4 py-2 rounded ml-2 shadow focus:outline-none */ +.resetbutton { + background-color: #188ae2; + border-radius: 2px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18); + border: none; + text-transform: uppercase; + font-size: 13px; + font-weight: 600; + padding: 0.375rem 0.75rem; + text-align: center; + color: #ffffff; + outline: none; + margin-left: 8px; +} \ No newline at end of file diff --git a/microfrontends/SignDocuments/src/css/ModalUi.css b/microfrontends/SignDocuments/src/css/ModalUi.css new file mode 100644 index 000000000..6364ef60f --- /dev/null +++ b/microfrontends/SignDocuments/src/css/ModalUi.css @@ -0,0 +1,72 @@ +.modaloverlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.75); + justify-content: center; + align-items: center; + z-index: 900; +} + +.modalcontainer { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: #fff; + border-radius: 5px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); + z-index: 901; + max-height: 80%; + min-width: 500px; + overflow-y: auto; + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* Internet Explorer and Edge */ +} + +/* Hide scrollbar for Webkit browsers */ +.modalcontainer::-webkit-scrollbar { + display: none; +} + +.modalheader { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 20px; + border-bottom: 1px solid #ccc; + color: #ffffff; +} + +/* Styling for the modal title */ +.modaltitle { + font-size: 1.2rem; + font-weight:normal; +} + +/* Styling for the close button */ +.closebtn { + background: none; + border: none; + font-size: 1.5rem; + cursor: pointer; +} + +@media (max-width:767px) { + + .modalcontainer { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: #fff; + border-radius: 8px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); + z-index: 1000; + max-height: 80%; + min-width: 90%; + overflow-y: auto; + } +} \ No newline at end of file diff --git a/microfrontends/SignDocuments/src/css/signature.css b/microfrontends/SignDocuments/src/css/signature.css index b4aed0610..3aeeac8ce 100644 --- a/microfrontends/SignDocuments/src/css/signature.css +++ b/microfrontends/SignDocuments/src/css/signature.css @@ -110,10 +110,6 @@ padding: 5px 10px; } -.emailChipClose:hover { - cursor: pointer; -} - .addEmailInput { padding: 10px; border-radius: 4px; @@ -174,19 +170,44 @@ padding: 0px 5.1px 1px 5px; } -.placeholderBlock { - padding: 0px; +.signCloseBtn { position: absolute; - border-style: dashed; - width: 150px; - height: 60px; - background: #daebe0; - text-align: center; - justify-content: center; - border-width: 0.2px; - + right: -8px; + top: -18px; + font-size: 14px; + cursor: pointer; + z-index: 2; + background: white; +} +.signCopy { + position: absolute; + right: 12px; + top: -18px; + font-size: 13px; + cursor: pointer; + z-index: 2; + background: white; } +.signUserIcon { + position: absolute; + right: 32px; + top: -18px; + font-size: 13px; + cursor: pointer; + z-index: 2; + background: white; +} +.ScrollbarsCustom-Track { + width: 4px !important; +} +.signYourselfBlock { + padding: 0px; + display: flex !important; + text-align: center !important; + justify-content: center !important; + align-items: center !important; +} .finishBtn { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18); padding: 3px 30px; @@ -531,7 +552,6 @@ gap: 5px; border: none; background-color: #887abf; - width: 200px; white-space: nowrap; overflow: hidden !important; diff --git a/microfrontends/SignDocuments/src/css/signerListPlace.css b/microfrontends/SignDocuments/src/css/signerListPlace.css new file mode 100644 index 000000000..1df701b70 --- /dev/null +++ b/microfrontends/SignDocuments/src/css/signerListPlace.css @@ -0,0 +1,16 @@ +.addSignerBtn{ + padding: 10px; + margin-top: 2px; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + border: 1px solid #47a3ad; + margin: 1px; + color: #47a3ad; + cursor: pointer +} +.addSignerBtn:hover{ + background: #47a3ad; + color: #ffffff; +} diff --git a/microfrontends/SignDocuments/src/premitives/AddUser.js b/microfrontends/SignDocuments/src/premitives/AddUser.js new file mode 100644 index 000000000..07b6b1217 --- /dev/null +++ b/microfrontends/SignDocuments/src/premitives/AddUser.js @@ -0,0 +1,293 @@ +import React, { useState, useEffect } from "react"; +import Parse from "parse"; +import axios from "axios"; +import "../css/AddUser.css"; +const AddUser = (props) => { + const [name, setName] = useState(""); + const [phone, setPhone] = useState(""); + const [email, setEmail] = useState(""); + const [addYourself, setAddYourself] = useState(false); + const [isLoader, setIsLoader] = useState(false); + const [isUserExist, setIsUserExist] = useState(false); + const parseBaseUrl = localStorage.getItem("baseUrl"); + const parseAppId = localStorage.getItem("parseAppId"); + Parse.serverURL = parseBaseUrl; + Parse.initialize(parseAppId); + + useEffect(() => { + checkUserExist(); + }, []); + // Load user details from localStorage when the component mounts + useEffect(() => { + const savedUserDetails = JSON.parse( + localStorage.getItem("UserInformation") + ); + if (savedUserDetails && addYourself) { + setName(savedUserDetails.name); + setPhone(savedUserDetails.phone); + setEmail(savedUserDetails.email); + } + }, [addYourself]); + + const checkUserExist = async () => { + const user = Parse.User.current(); + try { + const query = new Parse.Query("contracts_Contactbook"); + query.equalTo("CreatedBy", user); + query.notEqualTo("IsDeleted", true); + query.equalTo("Email", user.getEmail()); + const res = await query.first(); + // console.log(res); + if (!res) { + setIsUserExist(true); + } + } catch (err) { + console.log("err", err); + } + }; + // Define a function to handle form submission + const handleSubmit = async (e) => { + e.preventDefault(); + e.stopPropagation(); + setIsLoader(true); + Parse.serverURL = parseBaseUrl; + Parse.initialize(parseAppId); + try { + const contactQuery = new Parse.Object("contracts_Contactbook"); + contactQuery.set("Name", name); + contactQuery.set("Phone", phone); + contactQuery.set("Email", email); + contactQuery.set("UserRole", "contracts_Guest"); + + if (localStorage.getItem("TenetId")) { + contactQuery.set("TenantId", { + __type: "Pointer", + className: "partners_Tenant", + objectId: localStorage.getItem("TenetId") + }); + } + + try { + const _users = Parse.Object.extend("User"); + const _user = new _users(); + _user.set("name", name); + _user.set("username", email); + _user.set("email", email); + _user.set("phone", phone); + _user.set("password", phone); + + const user = await _user.save(); + if (user) { + const roleurl = `${parseBaseUrl}functions/AddUserToRole`; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": parseAppId, + sessionToken: localStorage.getItem("accesstoken") + }; + const body = { + appName: localStorage.getItem("_appName"), + roleName: "contracts_Guest", + userId: user.id + }; + await axios.post(roleurl, body, { headers: headers }); + const currentUser = Parse.User.current(); + contactQuery.set( + "CreatedBy", + Parse.User.createWithoutData(currentUser.id) + ); + + contactQuery.set("UserId", user); + const acl = new Parse.ACL(); + acl.setPublicReadAccess(true); + acl.setPublicWriteAccess(true); + acl.setReadAccess(currentUser.id, true); + acl.setWriteAccess(currentUser.id, true); + + contactQuery.setACL(acl); + + const res = await contactQuery.save(); + + const parseData = JSON.parse(JSON.stringify(res)); + props.details(parseData); + if (props.closePopup) { + props.closePopup(); + } + + setIsLoader(false); + // Reset the form fields + setAddYourself(false); + setName(""); + setPhone(""); + setEmail(""); + } + } catch (err) { + console.log("err ", err); + if (err.code === 202) { + const params = { email: email }; + const userRes = await Parse.Cloud.run("getUserId", params); + const roleurl = `${parseBaseUrl}functions/AddUserToRole`; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": parseAppId, + sessionToken: localStorage.getItem("accesstoken") + }; + const body = { + appName: localStorage.getItem("_appName"), + roleName: "contracts_Guest", + userId: userRes.id + }; + await axios.post(roleurl, body, { headers: headers }); + const currentUser = Parse.User.current(); + contactQuery.set( + "CreatedBy", + Parse.User.createWithoutData(currentUser.id) + ); + + contactQuery.set("UserId", { + __type: "Pointer", + className: "_User", + objectId: userRes.id + }); + const acl = new Parse.ACL(); + acl.setPublicReadAccess(true); + acl.setPublicWriteAccess(true); + acl.setReadAccess(currentUser.id, true); + acl.setWriteAccess(currentUser.id, true); + + contactQuery.setACL(acl); + const res = await contactQuery.save(); + + const parseData = JSON.parse(JSON.stringify(res)); + props.details({ + value: parseData[props.valueKey], + label: parseData[props.displayKey] + }); + if (props.closePopup) { + props.closePopup(); + } + setIsLoader(false); + // Reset the form fields + setAddYourself(false); + setName(""); + setPhone(""); + setEmail(""); + } + } + } catch (err) { + // console.log("err", err); + setIsLoader(false); + alert("something went wrong!"); + } + }; + + // Define a function to handle the "add yourself" checkbox + const handleAddYourselfChange = () => { + if (addYourself) { + setAddYourself(false); + setName(""); + setPhone(""); + setEmail(""); + } else { + setAddYourself(true); + } + }; + const handleReset = () => { + setAddYourself(false); + }; + + return ( + <div className="addusercontainer"> + {isLoader && ( + <div className="loaderdiv"> + <div + style={{ + fontSize: "45px", + color: "#3dd3e0" + }} + className="loader-37" + ></div> + </div> + )} + <div className="form-wrapper"> + <div style={{ fontSize: 14, fontWeight: "700" }}>Add User</div> + + {isUserExist && ( + <div className="form-section"> + <input + type="checkbox" + id="addYourself" + checked={addYourself} + onChange={handleAddYourselfChange} + className="form-checkbox" + /> + <label htmlFor="addYourself" className="checkbox-label "> + Add Yourself + </label> + </div> + )} + <form onSubmit={handleSubmit}> + <div className="form-section"> + <label htmlFor="name" style={{ fontSize: 13 }}> + Name + <span style={{ color: "red", fontSize: 13 }}> *</span> + </label> + <input + type="text" + id="name" + value={name} + onChange={(e) => setName(e.target.value)} + required + disabled={addYourself} + className="addUserInput" + /> + </div> + <div className="form-section"> + <label htmlFor="email" style={{ fontSize: 13 }}> + Email + <span style={{ color: "red", fontSize: 13 }}> *</span> + </label> + <input + type="email" + id="email" + value={email} + onChange={(e) => setEmail(e.target.value)} + required + disabled={addYourself} + className="addUserInput" + /> + </div> + <div className="form-section"> + <label htmlFor="phone" style={{ fontSize: 13 }}> + Phone + <span style={{ color: "red", fontSize: 13 }}> *</span> + </label> + <input + type="text" + id="phone" + value={phone} + onChange={(e) => setPhone(e.target.value)} + required + disabled={addYourself} + className="addUserInput" + /> + </div> + + <div className="buttoncontainer"> + <button type="submit" className="submitbutton"> + Submit + </button> + <button + type="button" + onClick={() => handleReset()} + className="resetbutton" + > + Reset + </button> + </div> + </form> + </div> + </div> + ); +}; + +export default AddUser; diff --git a/microfrontends/SignDocuments/src/premitives/Alert.js b/microfrontends/SignDocuments/src/premitives/Alert.js new file mode 100644 index 000000000..72e3d1458 --- /dev/null +++ b/microfrontends/SignDocuments/src/premitives/Alert.js @@ -0,0 +1,30 @@ +import React from "react"; + +const Alert = ({ children, type }) => { + const textcolor = type ? theme(type) : theme(); + function theme(color) { + switch (color) { + case "success": + return "border-[#c3e6cb] bg-[#d4edda] text-[#155724]"; + case "info": + return "border-[#adcdeb] bg-[#c1daf0] text-[#153756]"; + case "danger": + return "border-[#f0a8a8] bg-[#f4bebe] text-[#c42121]"; + default: + return "border-[#d6d6d6] bg-[#d9d9d9] text-[#575757]"; + } + } + return ( + <> + {children && ( + <div + className={`z-40 fixed top-20 left-1/2 transform -translate-x-1/2 border-[1px] text-sm ${textcolor} rounded py-[.75rem] px-[1.25rem] `} + > + {children} + </div> + )} + </> + ); +}; + +export default Alert; diff --git a/microfrontends/SignDocuments/src/premitives/CreateFolder.js b/microfrontends/SignDocuments/src/premitives/CreateFolder.js new file mode 100644 index 000000000..b9967570e --- /dev/null +++ b/microfrontends/SignDocuments/src/premitives/CreateFolder.js @@ -0,0 +1,147 @@ +import React, { useEffect, useState } from "react"; +import Parse from "parse"; +import Alert from "./Alert"; + +const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => { + const folderPtr = { + __type: "Pointer", + className: folderCls, + objectId: parentFolderId + }; + const [name, setName] = useState(""); + const [folderList, setFolderList] = useState([]); + const [isAlert, setIsAlert] = useState(false); + const [selectedParent, setSelectedParent] = useState(); + const [alert, setAlert] = useState({ type: "info", message: "" }); + useEffect(() => { + fetchFolder(); + // eslint-disable-next-line + }, []); + + const fetchFolder = async () => { + try { + const FolderQuery = new Parse.Query(folderCls); + if (parentFolderId) { + FolderQuery.equalTo("Folder", folderPtr); + FolderQuery.equalTo("Type", "Folder"); + } else { + FolderQuery.doesNotExist("Folder"); + FolderQuery.equalTo("Type", "Folder"); + } + + const res = await FolderQuery.find(); + if (res) { + const result = JSON.parse(JSON.stringify(res)); + if (result) { + setFolderList(result); + } + } + } catch (error) { + console.log("Err ", error); + } + }; + const handleCreateFolder = async (event) => { + event.preventDefault(); + if (name) { + const currentUser = Parse.User.current(); + const exsitQuery = new Parse.Query(folderCls); + exsitQuery.equalTo("Name", name); + exsitQuery.equalTo("Type", "Folder"); + if (parentFolderId) { + exsitQuery.equalTo("Folder", folderPtr); + } + const templExist = await exsitQuery.first(); + if (templExist) { + setAlert({ type: "dange", message: "Folder already exist!" }); + setIsAlert(true); + setTimeout(() => { + setIsAlert(false); + }, 1000); + } else { + const template = new Parse.Object(folderCls); + template.set("Name", name); + template.set("Type", "Folder"); + + if (selectedParent) { + template.set("Folder", { + __type: "Pointer", + className: folderCls, + objectId: selectedParent + }); + } else if (parentFolderId) { + template.set("Folder", folderPtr); + } + template.set("CreatedBy", Parse.User.createWithoutData(currentUser.id)); + const res = await template.save(); + if (res) { + if (onSuccess) { + setAlert({ + type: "success", + message: "Folder created successfully!" + }); + setIsAlert(true); + setTimeout(() => { + setIsAlert(false); + }, 1000); + onSuccess(res); + } + } + } + } else { + setAlert({ type: "info", message: "Please fill folder name" }); + setIsAlert(true); + setTimeout(() => { + setIsAlert(false); + }, 1000); + } + }; + const handleOptions = (e) => { + setSelectedParent(e.target.value); + }; + return ( + <div> + {isAlert && <Alert type={alert.type}>{alert.message}</Alert>} + <div id="createFolder"> + <h1 className="text-base font-semibold">Create Folder</h1> + <div className="text-xs mt-2"> + <label className="block"> + Name<span style={{ color: "red", fontSize: 13 }}> *</span> + </label> + <input + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + value={name} + onChange={(e) => setName(e.target.value)} + required + /> + </div> + <div className="text-xs mt-2"> + <label className="block">Parent Folder</label> + <select + value={selectedParent} + onChange={handleOptions} + className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" + > + <option>select</option> + {folderList.length > 0 && + folderList.map((x) => ( + <option key={x.objectId} value={x.objectId}> + {x.Name} + </option> + ))} + </select> + </div> + <div> + <button + onClick={handleCreateFolder} + className="flex items-center rounded p-2 bg-[#33bbff] text-white mt-3" + > + <i className="fa-solid fa-plus mr-1"></i> + <span>Create</span> + </button> + </div> + </div> + </div> + ); +}; + +export default CreateFolder; diff --git a/microfrontends/SignDocuments/src/premitives/ModalUi.js b/microfrontends/SignDocuments/src/premitives/ModalUi.js new file mode 100644 index 000000000..68fe937c9 --- /dev/null +++ b/microfrontends/SignDocuments/src/premitives/ModalUi.js @@ -0,0 +1,29 @@ +import React from "react"; +import "../css/ModalUi.css"; +const ModalUi = ({ children, title, isOpen, handleClose, headerColor }) => { + return ( + <> + {isOpen && ( + <div className="modaloverlay"> + <div className="modalcontainer"> + {title && <div + style={{ background: headerColor ? headerColor : "#32a3ac" }} + className="modalheader" + > + <div className="modaltitle">{title}</div> + <div + className="closebtn" + onClick={() => handleClose && handleClose()} + > + × + </div> + </div>} + <div>{children}</div> + </div> + </div> + )} + </> + ); +}; + +export default ModalUi; diff --git a/microfrontends/SignDocuments/src/premitives/RecipientList.js b/microfrontends/SignDocuments/src/premitives/RecipientList.js new file mode 100644 index 000000000..9f533a849 --- /dev/null +++ b/microfrontends/SignDocuments/src/premitives/RecipientList.js @@ -0,0 +1,205 @@ +import React, { useRef, useState } from "react"; +import "../css/signerListPlace.css"; +import { darkenColor, getFirstLetter } from "../utils/Utils"; + +const RecipientList = (props) => { + const color = [ + "#93a3db", + "#e6c3db", + "#c0e3bc", + "#bce3db", + "#b8ccdb", + "#ceb8db", + "#ffccff", + "#99ffcc", + "#cc99ff", + "#ffcc99", + "#66ccff", + "#ffffcc" + ]; + + const nameColor = [ + "#304fbf", + "#7d5270", + "#5f825b", + "#578077", + "#576e80", + "#6d527d", + "#cc00cc", + "#006666", + "#cc00ff", + "#ff9900", + "#336699", + "#cc9900" + ]; + const [isHover, setIsHover] = useState(); + const [isEdit, setIsEdit] = useState(false); + //function for onhover signer name change background color + const inputRef = useRef(null); + const onHoverStyle = (ind, blockColor) => { + const style = { + background: blockColor ? blockColor : color[ind % color.length], + padding: "10px", + marginTop: "2px", + display: "flex", + flexDirection: "row", + borderBottom: "1px solid #e3e1e1", + alignItems: "center" + }; + return style; + }; + //function for onhover signer name remove background color + const nonHoverStyle = (ind) => { + const style = { + padding: "10px", + marginTop: "2px", + display: "flex", + flexDirection: "row", + borderBottom: "1px solid #e3e1e1", + alignItems: "center" + }; + return style; + }; + const isWidgetExist = (Id) => { + return props.signerPos.some((x) => x.Id === Id); + }; + + return ( + <> + {props.signersdata.length > 0 && + props.signersdata.map((obj, ind) => { + return ( + <div + data-tut="reactourFirst" + onMouseEnter={() => setIsHover(ind)} + onMouseLeave={() => setIsHover(null)} + key={ind} + style={ + isHover === ind || props.isSelectListId === ind + ? onHoverStyle(ind, obj.blockColor) + : nonHoverStyle(ind) + } + onClick={() => { + props.setSignerObjId(obj?.objectId); + props.setIsSelectId(ind); + props.setContractName(obj?.className); + props.setUniqueId(obj.Id); + props.setRoleName(obj.Role); + }} + > + <div + style={{ + display: "flex", + flexDirection: "row", + alignItems: "center", + width: "100%" + }} + > + <div + className="signerStyle" + style={{ + background: obj.blockColor + ? darkenColor(obj.blockColor, 0.4) + : nameColor[ind % nameColor.length], + width: 30, + height: 30, + display: "flex", + borderRadius: 30 / 2, + justifyContent: "center", + alignItems: "center", + marginRight: "12px" + }} + > + <span + style={{ + fontSize: "12px", + textAlign: "center", + fontWeight: "bold", + color: "white", + textTransform: "uppercase" + }} + > + {isWidgetExist(obj.Id) ? ( + <i className="fa-solid fa-check"></i> + ) : ( + <> + {obj.Name + ? getFirstLetter(obj.Name) + : getFirstLetter(obj.Role)} + </> + )} + </span> + </div> + <div + style={{ + display: "flex", + flexDirection: obj.Name ? "column" : "row", + alignItems: "center" + }} + > + {obj.Name ? ( + <span className="userName" style={{ cursor: "default" }}> + {obj.Name} + </span> + ) : ( + <> + <span + className="userName" + onClick={() => { + setIsEdit({ [obj.Id]: true }); + props.setRoleName(obj.Role); + }} + > + {isEdit?.[obj.Id] && props.handleRoleChange ? ( + <input + ref={inputRef} + style={{ + backgroundColor: "transparent", + width: "inherit" + }} + value={obj.Role} + onChange={(e) => props.handleRoleChange(e, obj.Id)} + onBlur={() => { + setIsEdit({}); + props.handleOnBlur(obj.Role, obj.Id); + }} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + inputRef.current.blur(); + } + }} + /> + ) : ( + obj.Role + )} + </span> + </> + )} + {obj.Name && ( + <span className="useEmail" style={{ cursor: "default" }}> + {obj.Role} + </span> + )} + </div> + </div> + {props.handleDeleteUser && ( + <div + onClick={(e) => { + e.stopPropagation(); + props.handleDeleteUser(obj.Id); + }} + style={{ cursor: "pointer" }} + > + <i className="fa-regular fa-trash-can"></i> + </div> + )} + <hr /> + </div> + ); + })} + </> + ); +}; + +export default RecipientList; diff --git a/microfrontends/SignDocuments/src/premitives/SelectFolder.js b/microfrontends/SignDocuments/src/premitives/SelectFolder.js new file mode 100644 index 000000000..c917155a5 --- /dev/null +++ b/microfrontends/SignDocuments/src/premitives/SelectFolder.js @@ -0,0 +1,348 @@ +import React, { useEffect, useState } from "react"; +import Parse from "parse"; +import CreateFolder from "./CreateFolder"; +import ModalUi from './ModalUi' + +const SelectFolder = ({ required, onSuccess, folderCls }) => { + const [isOpen, SetIsOpen] = useState(false); + const [clickFolder, setClickFolder] = useState(""); + const [selectFolder, setSelectedFolder] = useState({}); + const [folderList, setFolderList] = useState([]); + const [tabList, setTabList] = useState([]); + const [isLoader, setIsLoader] = useState(false); + const [folderPath, setFolderPath] = useState(""); + const [isAdd, setIsAdd] = useState(false); + useEffect(() => { + if (isOpen) { + setIsAdd(false); + setClickFolder({}); + setFolderList([]); + setTabList([]); + fetchFolder(); + } + }, [isOpen]); + const fetchFolder = async (folderPtr) => { + setIsLoader(true); + try { + const FolderQuery = new Parse.Query(folderCls); + if (folderPtr) { + FolderQuery.equalTo("Folder", folderPtr); + FolderQuery.equalTo("Type", "Folder"); + } else { + FolderQuery.doesNotExist("Folder"); + FolderQuery.equalTo("Type", "Folder"); + } + + const res = await FolderQuery.find(); + if (res) { + const result = JSON.parse(JSON.stringify(res)); + if (result) { + setFolderList(result); + setIsLoader(false); + } + setIsLoader(false); + } + } catch (error) { + setIsLoader(false); + } + }; + const handleSelect = (item) => { + setFolderList([]); + setClickFolder({ ObjectId: item.objectId, Name: item.Name }); + if (tabList.length > 0) { + const tab = tabList.some((x) => x.objectId === item.objectId); + if (!tab) { + setTabList((tabs) => [...tabs, item]); + const folderPtr = { + __type: "Pointer", + className: folderCls, + objectId: item.objectId + }; + fetchFolder(folderPtr); + } + } else { + setTabList((tabs) => [...tabs, item]); + const folderPtr = { + __type: "Pointer", + className: folderCls, + objectId: item.objectId + }; + + fetchFolder(folderPtr); + } + }; + + const handleSubmit = () => { + let url = "Root"; + tabList.forEach((t) => { + url = url + " / " + t.Name; + }); + setFolderPath(url); + setSelectedFolder(clickFolder); + if (onSuccess) { + onSuccess(clickFolder); + } + SetIsOpen(false); + }; + const handleCancel = () => { + SetIsOpen(false); + setClickFolder({}); + setFolderList([]); + setTabList([]); + }; + + const removeTabListItem = async (e, i) => { + e.preventDefault(); + // setEditable(false); + if (!isAdd) { + setIsLoader(true); + let folderPtr; + if (i) { + setFolderList([]); + let list = tabList.filter((itm, j) => { + if (j <= i) { + return itm; + } + }); + let _len = list.length - 1; + folderPtr = { + __type: "Pointer", + className: folderCls, + objectId: list[_len].objectId + }; + setTabList(list); + } else { + setClickFolder({}); + setSelectedFolder({}); + setFolderList([]); + setTabList([]); + } + fetchFolder(folderPtr); + } + }; + const handleCreate = () => { + setIsAdd(!isAdd); + }; + const handleAddFolder = () => { + setFolderList([]); + if (clickFolder && clickFolder.ObjectId) { + fetchFolder({ + __type: "Pointer", + className: folderCls, + objectId: clickFolder.ObjectId + }); + } else { + fetchFolder(); + } + }; + return ( + <div className="text-xs mt-2"> + <div> + <label className="block"> + Select Folder + {required && <span style={{ color: "red", fontSize: 13 }}> *</span>} + </label> + </div> + <div className="rounded px-[20px] py-[20px] bg-white border border-gray-200 shadow flex max-w-sm gap-8 items-center"> + <div> + <i + className="far fa-folder-open text-[40px] text-[#33bbff]" + style={{ fontSize: "40px" }} + aria-hidden="true" + ></i> + </div> + <div className="font-semibold "> + <div className="flex items-center gap-2"> + <p> + {selectFolder && selectFolder.Name ? selectFolder.Name : "Root"} + </p> + <div className="text-black text-sm" onClick={() => SetIsOpen(true)}> + <i + className="fa fa-pencil" + title="Select Folder" + aria-hidden="true" + ></i> + </div> + </div> + <p className="text-[10px] text-gray-400"> + {selectFolder && selectFolder.Name ? `(${folderPath})` : ""} + </p> + </div> + </div> + <ModalUi id="asd" title={"Select Folder"} isOpen={isOpen} handleClose={handleCancel}> <div className="w-full min-w-[300px] md:min-w-[500px] px-3"> + <div className="py-2 text-[#ac4848] text-[14px] font-[500]"> + <span + className="cursor-pointer" + title="Root" + onClick={(e) => removeTabListItem(e)} + > + Root /{" "} + </span> + {tabList && + tabList.map((tab, i) => ( + <React.Fragment key={`${tab.objectId}-${i}`}> + <span + className="cursor-pointer" + title={tab.Name} + onClick={(e) => removeTabListItem(e, i)} + > + {tab.Name} + </span> + {" / "} + </React.Fragment> + ))} + <hr /> + </div> + <div className="mt-2 mb-3"> + {!isAdd && + folderList.length > 0 && + folderList.map((folder) => ( + <div + key={folder.Name} + className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer" + onClick={() => handleSelect(folder)} + > + <div className="flex items-center gap-2"> + <i + className="fa fa-folder text-[#33bbff] text-[1.4rem]" + aria-hidden="true" + ></i> + <span className="font-semibold">{folder.Name}</span> + </div> + </div> + ))} + {isAdd && ( + <CreateFolder + parentFolderId={clickFolder && clickFolder.ObjectId} + folderCls={folderCls} + onSuccess={handleAddFolder} + /> + )} + {isLoader && ( + <div className="flex justify-center"> + <i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i> + </div> + )} + </div> + </div> + <hr /> + <div className="flex justify-between items-center py-[.75rem] px-[1.25rem]"> + <div + className="text-[30px] cursor-pointer text-[#33bbff]" + title="Save Here" + onClick={handleCreate} + > + {isAdd ? ( + <i className="fa-solid fa-arrow-left" aria-hidden="true"></i> + ) : ( + <i className="fa-solid fa-square-plus" aria-hidden="true"></i> + )} + </div> + <div + className="text-[30px] cursor-pointer" + title="Save Here" + onClick={handleSubmit} + > + <i className="fas fa-save" aria-hidden="true"></i> + </div> + </div></ModalUi> + {/* {isOpen && ( + <div + className={`fixed z-40 top-20 left-1/2 transform -translate-x-1/2 border-[1px] text-sm bg-white rounded `} + > + <div className="flex justify-between items-center py-[.75rem] px-[1.25rem] bg-[#f5f5f5]"> + <div className="font-semibold text-lg text-black"> + Select Folder + </div> + <div + onClick={handleCancel} + className="px-2 py-1 border-[1px] border-[#8a8a8a] bg-white rounded cursor-pointer" + > + <i className="fa-solid fa-xmark"></i> + </div> + </div> + <hr /> + <div className="w-full min-w-[300px] md:min-w-[500px] px-3"> + <div className="py-2 text-[#ac4848] text-[14px] font-[500]"> + <span + className="cursor-pointer" + title="Root" + onClick={(e) => removeTabListItem(e)} + > + Root /{" "} + </span> + {tabList && + tabList.map((tab, i) => ( + <React.Fragment key={`${tab.objectId}-${i}`}> + <span + className="cursor-pointer" + title={tab.Name} + onClick={(e) => removeTabListItem(e, i)} + > + {tab.Name} + </span> + {" / "} + </React.Fragment> + ))} + <hr /> + </div> + <div className="mt-2 mb-3"> + {!isAdd && + folderList.length > 0 && + folderList.map((folder) => ( + <div + key={folder.Name} + className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer" + onClick={() => handleSelect(folder)} + > + <div className="flex items-center gap-2"> + <i + className="fa fa-folder text-[#33bbff] text-[1.4rem]" + aria-hidden="true" + ></i> + <span className="font-semibold">{folder.Name}</span> + </div> + </div> + ))} + {isAdd && ( + <CreateFolder + parentFolderId={clickFolder && clickFolder.ObjectId} + folderCls={folderCls} + onSuccess={handleAddFolder} + /> + )} + {isLoader && ( + <div className="flex justify-center"> + <i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i> + </div> + )} + </div> + </div> + <hr /> + <div className="flex justify-between items-center py-[.75rem] px-[1.25rem]"> + <div + className="text-[30px] cursor-pointer text-[#33bbff]" + title="Save Here" + onClick={handleCreate} + > + {isAdd ? ( + <i className="fa-solid fa-arrow-left" aria-hidden="true"></i> + ) : ( + <i className="fa-solid fa-square-plus" aria-hidden="true"></i> + )} + </div> + <div + className="text-[30px] cursor-pointer" + title="Save Here" + onClick={handleSubmit} + > + <i className="fas fa-save" aria-hidden="true"></i> + </div> + </div> + </div> + )} */} + </div> + ); +}; + +export default SelectFolder; diff --git a/microfrontends/SignDocuments/src/premitives/SelectSigners.js b/microfrontends/SignDocuments/src/premitives/SelectSigners.js new file mode 100644 index 000000000..88b188842 --- /dev/null +++ b/microfrontends/SignDocuments/src/premitives/SelectSigners.js @@ -0,0 +1,101 @@ +import React, { useState } from "react"; +import Parse from "parse"; +import "../css/AddUser.css"; +import AsyncSelect from "react-select/async"; + +const customStyles = { + control: (provided) => ({ + ...provided, + fontSize: "13px" // Font size for the control + }), + option: (provided) => ({ + ...provided, + fontSize: "13px" // Font size for the options + }) +}; +const SelectSigners = (props) => { + const [userList, setUserList] = useState([]); + const [selected, setSelected] = useState(); + const [userData, setUserData] = useState({}); + const [isError, setIsError]= useState(false) + const parseBaseUrl = localStorage.getItem("baseUrl"); + const parseAppId = localStorage.getItem("parseAppId"); + Parse.serverURL = parseBaseUrl; + Parse.initialize(parseAppId); + + // `handleOptions` is used to set just save from quick form to selected option in dropdown + const handleOptions = (item) => { + setSelected(item); + const userData = userList.filter((x) => x.objectId === item.value); + if (userData.length > 0) { + setUserData(userData[0]); + } + }; + const handleAdd = () => { + if(userData && userData.objectId){ + props.details(userData); + if (props.closePopup) { + props.closePopup(); + } + }else{ + setIsError(true) + setTimeout(()=> setIsError(false), 1000) + } + }; + + const loadOptions = async (inputValue) => { + try { + const currentUser = Parse.User.current(); + const contactbook = new Parse.Query("contracts_Contactbook"); + contactbook.equalTo( + "CreatedBy", + Parse.User.createWithoutData(currentUser.id) + ); + if (inputValue.length > 1) { + contactbook.matches("Name", new RegExp(inputValue, "i")); + } + contactbook.notEqualTo("IsDeleted", true); + const contactRes = await contactbook.find(); + if (contactRes) { + const res = JSON.parse(JSON.stringify(contactRes)); + // console.log("userList ", res); + setUserList(res); + return await res.map((item) => ({ + label: item.Email, + value: item.objectId + })); + } + } catch (error) { + console.log("err", error); + } + }; + + return ( + <div className="addusercontainer"> + <div className="form-wrapper"> + <div className="form-section" style={{marginBottom: 0}}> + <label style={{ fontSize: 14 , fontWeight: "700"}}>Choose User</label> + <AsyncSelect + cacheOptions + defaultOptions + value={selected} + loadingMessage={() => "Loading..."} + noOptionsMessage={() => "User not Found"} + loadOptions={loadOptions} + onChange={handleOptions} + styles={customStyles} + /> + </div> + {isError ? <p style={{color:'red', fontSize: "12px", margin:"5px"}}>Please select signer</p>: <p style={{color:'transparent', fontSize: "12px", margin:"5px"}}>.</p>} + + <div > + <button className="submitbutton" onClick={() => handleAdd()}> + Add Signer + </button> + </div> + </div> + </div> + ); +}; + +export default SelectSigners; diff --git a/microfrontends/SignDocuments/src/utils/Utils.js b/microfrontends/SignDocuments/src/utils/Utils.js index 292a9c2f4..803d278d3 100644 --- a/microfrontends/SignDocuments/src/utils/Utils.js +++ b/microfrontends/SignDocuments/src/utils/Utils.js @@ -4,6 +4,9 @@ import { rgb } from "pdf-lib"; const isMobile = window.innerWidth < 767; +export const resizeBorderExtraWidth = () => { + return 20; +}; export async function getBase64FromUrl(url) { const data = await fetch(url); const blob = await data.blob(); @@ -77,91 +80,43 @@ export function getHostUrl() { } } -export const calculateImgAspectRatio = (imgWH) => { +export const calculateImgAspectRatio = (imgWH, pos) => { let newWidth, newHeight; + const placeholderHeight = pos && pos.Width ? pos.Height : 60; const aspectRatio = imgWH.width / imgWH.height; - if (aspectRatio === "2.533333333333333") { - newWidth = 150; - newHeight = 60; - } else if (aspectRatio === 1) { - newWidth = aspectRatio * 100; - newHeight = aspectRatio * 100; - } else if (aspectRatio < 1) { - newWidth = aspectRatio * 70; - newHeight = 70; - } else if (aspectRatio < 2) { - newWidth = aspectRatio * 100; - newHeight = 100; - } else if (aspectRatio > 2 && aspectRatio < 4) { - newWidth = aspectRatio * 70; - newHeight = 70; - } else if (aspectRatio > 4) { - newWidth = aspectRatio * 40; - newHeight = 40; - } else if (aspectRatio > 5) { - newWidth = aspectRatio * 10; - newHeight = 10; - } + newWidth = aspectRatio * placeholderHeight; + newHeight = placeholderHeight; + return { newHeight, newWidth }; }; //function for upload stamp or image export function onSaveImage(xyPostion, index, signKey, imgWH, image) { - const updateFilter = xyPostion[index].pos.filter( - (data, ind) => - data.key === signKey && data.Width && data.Height && data.SignUrl - ); - let getIMGWH = calculateImgAspectRatio(imgWH); - const getXYdata = xyPostion[index].pos; - if (updateFilter.length > 0) { - const addSign = getXYdata.map((url, ind) => { - if (url.key === signKey) { - return { - ...url, - Width: getIMGWH.newWidth, - Height: getIMGWH.newHeight, - SignUrl: image.src, - ImageType: image.imgType - }; - } - return url; - }); - - const newUpdateUrl = xyPostion.map((obj, ind) => { - if (ind === index) { - return { ...obj, pos: addSign }; - } - return obj; - }); - return newUpdateUrl; - } else { - const getXYdata = xyPostion[index].pos; - - let getPosData = xyPostion[index].pos.filter( - (data) => data.key === signKey - ); + let getIMGWH; + //get current page position + const getXYData = xyPostion[index].pos; + const updateXYData = getXYData.map((url) => { + if (url.key === signKey) { + getIMGWH = calculateImgAspectRatio(imgWH, url); - const addSign = getXYdata.map((url, ind) => { - if (url.key === signKey) { - return { - ...url, - Width: getIMGWH.newWidth, - Height: getIMGWH.newHeight, - SignUrl: image.src, - ImageType: image.imgType - }; - } - return url; - }); + return { + ...url, + Width: getIMGWH.newWidth, + Height: getIMGWH.newHeight, + SignUrl: image.src, + ImageType: image.imgType + }; + } + return url; + }); - const newUpdateUrl = xyPostion.map((obj, ind) => { - if (ind === index) { - return { ...obj, pos: addSign }; - } - return obj; - }); - return newUpdateUrl; - } + const updateXYposition = xyPostion.map((obj, ind) => { + if (ind === index) { + return { ...obj, pos: updateXYData }; + } + return obj; + }); + return updateXYposition; } //function for save button to save signature or image url @@ -171,52 +126,47 @@ export function onSaveSign( signKey, signatureImg, imgWH, - isDefaultSign, - isSign + isDefaultSign ) { - let getXYdata = xyPostion[index].pos; - let getPosData = xyPostion[index].pos.filter((data) => data.key === signKey); - let getIMGWH; - if (isDefaultSign) { - getIMGWH = calculateImgAspectRatio(imgWH); - } + let getXYdata = xyPostion[index].pos; + const updateXYData = getXYdata.map((position) => { + if (position.key === signKey) { + if (isDefaultSign) { + getIMGWH = calculateImgAspectRatio(imgWH, position); + } + const getSignImgWH = calculateImgAspectRatio( + { width: 150, height: 60 }, + position + ); + const posWidth = isDefaultSign + ? getIMGWH.newWidth + : position.Width + ? getSignImgWH.newWidth + : 150; + const posHeight = isDefaultSign + ? getIMGWH.newHeight + : position.Height + ? getSignImgWH.newHeight + : 60; - const posWidth = isDefaultSign - ? getIMGWH.newWidth - : isSign && getPosData[0].ImageType - ? 150 - : getPosData[0].Width - ? getPosData[0].Width - : 150; - const posHidth = isDefaultSign - ? getIMGWH.newHeight - : isSign && getPosData[0].ImageType - ? 60 - : getPosData[0].Height - ? getPosData[0].Height - : 60; - - const addSign = getXYdata.map((url, ind) => { - if (url.key === signKey) { return { - ...url, + ...position, Width: posWidth, - Height: posHidth, - SignUrl: signatureImg, - ImageType: "sign" + Height: posHeight, + SignUrl: signatureImg }; } - return url; + return position; }); - const newUpdateUrl = xyPostion.map((obj, ind) => { + const updateXYposition = xyPostion.map((obj, ind) => { if (ind === index) { - return { ...obj, pos: addSign }; + return { ...obj, pos: updateXYData }; } return obj; }); - return newUpdateUrl; + return updateXYposition; } export const addZIndex = (signerPos, key, setZIndex) => { @@ -260,14 +210,16 @@ export const addDefaultSignatureImg = (xyPostion, defaultSignImg) => { height: img.height }; } - const getIMGWH = calculateImgAspectRatio(imgWH); + let xyDefaultPos = []; for (let i = 0; i < xyPostion.length; i++) { + let getIMGWH; const getXYdata = xyPostion[i].pos; const getPageNo = xyPostion[i].pageNumber; const getPosData = getXYdata; const addSign = getPosData.map((url, ind) => { + getIMGWH = calculateImgAspectRatio(imgWH, url); if (url) { return { ...url, @@ -459,78 +411,87 @@ export function modalAlign() { modal.style.top = window.innerHeight / 3 + "px"; } } -export const containerWidth = (pos, scale, signyourself) => { + +export const placeholderWidth = (pos, scale, signyourself) => { let width; + const defaultWidth = 150; + const posWidth = pos.Width ? pos.Width : defaultWidth; + if (signyourself) { if (isMobile) { - return pos.Width * scale; + return posWidth * scale; } else { - return pos.Width; + return posWidth; } } else { if (isMobile) { if (pos.isMobile) { - width = pos.Width ? pos.Width * scale : 150 * scale; + width = posWidth ? posWidth * scale : defaultWidth * scale; return width; } else { if (pos.IsResize) { - width = pos.Width ? pos.Width * scale : 150 * scale; + width = posWidth ? posWidth * scale : defaultWidth * scale; return width; } else { - width = pos.Width ? pos.Width : 150; + width = posWidth ? posWidth : defaultWidth; return width; } } } else { if (pos.isMobile) { if (pos.IsResize) { - width = pos.Width ? pos.Width : 150; + width = posWidth ? posWidth : defaultWidth; return width; } else { - width = pos.Width ? pos.Width * pos.scale : 150 * pos.scale; + width = posWidth ? posWidth * pos.scale : defaultWidth * pos.scale; return width; } } else { - width = pos.Width ? pos.Width : 150; + width = posWidth ? posWidth : defaultWidth; return width; } } } }; -export const containerHeight = (pos, scale, signyourself) => { +export const placeholderHeight = (pos, scale, signyourself) => { let height; + const posHeight = pos.Height; + const defaultHeight = 60; if (signyourself) { if (isMobile) { - return pos.Height * scale; + return posHeight * scale; } else { - return pos.Height; + return posHeight; } } else { if (isMobile) { if (pos.isMobile) { - height = pos.Height ? pos.Height * scale : 60 * scale; + height = posHeight ? posHeight * scale : defaultHeight * scale; return height; } else { if (pos.IsResize) { - height = pos.Height ? pos.Height * scale : 60 * scale; + height = posHeight ? posHeight * scale : defaultHeight * scale; return height; } else { - height = pos.Height ? pos.Height : 60; + height = posHeight ? posHeight : defaultHeight; + return height; } } } else { if (pos.isMobile) { if (pos.IsResize) { - height = pos.Height ? pos.Height : 60; + height = posHeight ? posHeight : defaultHeight; return height; } else { - height = pos.Height ? pos.Height * pos.scale : 60 * pos.scale; + height = posHeight + ? posHeight * pos.scale + : defaultHeight * pos.scale; return height; } } else { - height = pos.Height ? pos.Height : 60; + height = posHeight ? posHeight : defaultHeight; return height; } } @@ -578,78 +539,80 @@ export const multiSignEmbed = async ( } else { img = await pdfDoc.embedPng(imgData); } - const imgHeight = imgUrlList[id].Height ? imgUrlList[id].Height : 60; - const scaleWidth = containerWidth(imgUrlList[id], scale, signyourself); - const scaleHeight = containerHeight(imgUrlList[id], scale, signyourself); + + const scaleWidth = placeholderWidth(imgUrlList[id], scale, signyourself); + const scaleHeight = placeholderHeight( + imgUrlList[id], + scale, + signyourself + ); const xPos = (pos) => { + const resizePos = pos.xPosition; if (signyourself) { if (isMobile) { - return imgUrlList[id].xPosition * scale; + return resizePos * scale; } else { - return imgUrlList[id].xPosition; + return resizePos; } } else { //checking both condition mobile and desktop view if (isMobile) { //if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale if (pos.isMobile) { - const x = pos.xPosition * (pos.scale / scale); + const x = resizePos * (pos.scale / scale); return x * scale; } else { - const x = pos.xPosition / scale; + const x = resizePos / scale; return x * scale; } } else { //else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale if (pos.isMobile) { - const x = pos.xPosition * pos.scale; + const x = resizePos * pos.scale; return x; } else { - return pos.xPosition; + return resizePos; } } } }; const yPos = (pos) => { + const resizePos = imgUrlList[id].yPosition; if (signyourself) { if (isMobile) { - return ( - page.getHeight() - - imgUrlList[id].yPosition * scale - - imgHeight * scale - ); + return page.getHeight() - resizePos * scale - scaleHeight; } else { - return page.getHeight() - imgUrlList[id].yPosition - imgHeight; + return page.getHeight() - resizePos - scaleHeight; } } else { //checking both condition mobile and desktop view - const y = pos.yPosition / scale; + const y = resizePos / scale; if (isMobile) { //if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale if (pos.isMobile) { - const y = pos.yPosition * (pos.scale / scale); - return page.getHeight() - y * scale - imgHeight * scale; + const y = resizePos * (pos.scale / scale); + return page.getHeight() - y * scale - scaleHeight; } else { if (pos.IsResize) { - return page.getHeight() - y * scale - imgHeight * scale; + return page.getHeight() - y * scale - scaleHeight; } else { - return page.getHeight() - y * scale - imgHeight; + return page.getHeight() - y * scale - scaleHeight; } } } else { //else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale if (pos.isMobile) { if (pos.IsResize) { - const y = pos.yPosition * pos.scale; - return page.getHeight() - y - imgHeight; + const y = resizePos * pos.scale; + return page.getHeight() - y - scaleHeight; } else { - const y = pos.yPosition * pos.scale; - return page.getHeight() - y - imgHeight * pos.scale; + const y = resizePos * pos.scale; + return page.getHeight() - y - scaleHeight; } } else { - return page.getHeight() - pos.yPosition - imgHeight; + return page.getHeight() - resizePos - scaleHeight; } } } @@ -706,9 +669,11 @@ export const handleImageResize = ( containerWH, showResize ) => { - const filterSignerPos = signerPos.filter( - (data) => data.signerObjId === signerId - ); + // const filterSignerPos = signerPos.filter( + // (data) => data.signerObjId === signerId + // ); + + const filterSignerPos = signerPos.filter((data) => data.Id === signerId); if (filterSignerPos.length > 0) { const getPlaceHolder = filterSignerPos[0].placeHolder; @@ -716,71 +681,83 @@ export const handleImageResize = ( (data) => data.pageNumber === pageNumber ); if (getPageNumer.length > 0) { - const getXYdata = getPageNumer[0].pos.filter( - (data, ind) => data.key === key && data.Width && data.Height - ); - if (getXYdata.length > 0) { - const getXYdata = getPageNumer[0].pos; - const getPosData = getXYdata; - const addSignPos = getPosData.map((url, ind) => { - if (url.key === key) { - return { - ...url, - Width: ref.offsetWidth, - Height: ref.offsetHeight, - IsResize: showResize ? true : false - }; - } - return url; - }); - - const newUpdateSignPos = getPlaceHolder.map((obj, ind) => { - if (obj.pageNumber === pageNumber) { - return { ...obj, pos: addSignPos }; - } - return obj; - }); - - const newUpdateSigner = signerPos.map((obj, ind) => { - if (obj.signerObjId === signerId) { - return { ...obj, placeHolder: newUpdateSignPos }; - } - return obj; - }); - - setSignerPos(newUpdateSigner); - } else { - const getXYdata = getPageNumer[0].pos; - const getPosData = getXYdata; - const addSignPos = getPosData.map((url, ind) => { - if (url.key === key) { - return { - ...url, - Width: ref.offsetWidth, - Height: ref.offsetHeight, - IsResize: showResize ? true : false - }; - } - return url; - }); + // const getXYdata = getPageNumer[0].pos.filter( + // (data, ind) => data.key === key && data.Width && data.Height + // ); + // if (getXYdata.length > 0) { + // const getXYdata = getPageNumer[0].pos; + // const getPosData = getXYdata; + // const addSignPos = getPosData.map((url, ind) => { + // if (url.key === key) { + // return { + // ...url, + // Width: ref.offsetWidth, + // Height: ref.offsetHeight, + // IsResize: showResize ? true : false + // }; + // } + // return url; + // }); + + // const newUpdateSignPos = getPlaceHolder.map((obj, ind) => { + // if (obj.pageNumber === pageNumber) { + // return { ...obj, pos: addSignPos }; + // } + // return obj; + // }); + + // // const newUpdateSigner = signerPos.map((obj, ind) => { + // // if (obj.signerObjId === signerId) { + // // return { ...obj, placeHolder: newUpdateSignPos }; + // // } + // // return obj; + // // }); + + // const newUpdateSigner = signerPos.map((obj, ind) => { + // if (obj.Id === signerId) { + // return { ...obj, placeHolder: newUpdateSignPos }; + // } + // return obj; + // }); + // setSignerPos(newUpdateSigner); + // } else { + const getXYdata = getPageNumer[0].pos; + const getPosData = getXYdata; + const addSignPos = getPosData.map((url, ind) => { + if (url.key === key) { + return { + ...url, + Width: ref.offsetWidth, + Height: ref.offsetHeight, + IsResize: showResize ? true : false + }; + } + return url; + }); - const newUpdateSignPos = getPlaceHolder.map((obj, ind) => { - if (obj.pageNumber === pageNumber) { - return { ...obj, pos: addSignPos }; - } - return obj; - }); + const newUpdateSignPos = getPlaceHolder.map((obj, ind) => { + if (obj.pageNumber === pageNumber) { + return { ...obj, pos: addSignPos }; + } + return obj; + }); - const newUpdateSigner = signerPos.map((obj, ind) => { - if (obj.signerObjId === signerId) { - return { ...obj, placeHolder: newUpdateSignPos }; - } - return obj; - }); + // const newUpdateSigner = signerPos.map((obj, ind) => { + // if (obj.signerObjId === signerId) { + // return { ...obj, placeHolder: newUpdateSignPos }; + // } + // return obj; + // }); + const newUpdateSigner = signerPos.map((obj, ind) => { + if (obj.Id === signerId) { + return { ...obj, placeHolder: newUpdateSignPos }; + } + return obj; + }); - setSignerPos(newUpdateSigner); - } + setSignerPos(newUpdateSigner); } + // } } }; @@ -871,34 +848,36 @@ export const signPdfFun = async ( const height = xyPosData.Height ? xyPosData.Height : 60; const xPos = (pos) => { + const resizePos = pos.xPosition; //checking both condition mobile and desktop view if (isMobile) { //if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale if (pos.isMobile) { - const x = pos.xPosition * (pos.scale / scale); + const x = resizePos * (pos.scale / scale); return x * scale; } else { - const x = pos.xPosition / scale; + const x = resizePos / scale; return x * scale; } } else { //else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale if (pos.isMobile) { - const x = pos.xPosition * pos.scale; + const x = resizePos * pos.scale; return x; } else { - return pos.xPosition; + return resizePos; } } }; const yBottom = (pos) => { + const resizePos = pos.yBottom; let yPosition; //checking both condition mobile and desktop view if (isMobile) { //if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale if (pos.isMobile) { - const y = pos.yBottom * (pos.scale / scale); + const y = resizePos * (pos.scale / scale); yPosition = pos.isDrag ? y * scale - height * scale : pos.firstYPos @@ -906,7 +885,7 @@ export const signPdfFun = async ( : y * scale - height * scale; return yPosition; } else { - const y = pos.yBottom / scale; + const y = resizePos / scale; if (pos.IsResize) { yPosition = pos.isDrag ? y * scale - height * scale @@ -926,7 +905,7 @@ export const signPdfFun = async ( } else { //else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale if (pos.isMobile) { - const y = pos.yBottom * pos.scale; + const y = resizePos * pos.scale; if (pos.IsResize) { yPosition = pos.isDrag ? y - height @@ -944,16 +923,15 @@ export const signPdfFun = async ( } } else { yPosition = pos.isDrag - ? pos.yBottom - height + ? resizePos - height : pos.firstYPos - ? pos.yBottom - height + pos.firstYPos - : pos.yBottom - height; + ? resizePos - height + pos.firstYPos + : resizePos - height; return yPosition; } } }; - const bottomY = yBottom(xyPosData); singleSign = { pdfFile: pdfBase64Url, docId: documentId, @@ -961,9 +939,9 @@ export const signPdfFun = async ( sign: { Base64: base64Url, Left: xPos(xyPosData), - Bottom: bottomY, - Width: containerWidth(xyPosData, scale), - Height: containerHeight(xyPosData, scale), + Bottom: yBottom(xyPosData), + Width: placeholderWidth(xyPosData, scale), + Height: placeholderHeight(xyPosData, scale), Page: pageNo } }; @@ -1001,3 +979,96 @@ export const signPdfFun = async ( return response; }; + +export const randomId = () => Math.floor(1000 + Math.random() * 9000); + +export const createDocument = async (template, placeholders, signerData) => { + if (template && template.length > 0) { + const Doc = template[0]; + + let placeholdersArr = []; + if (placeholders?.length > 0) { + placeholdersArr = placeholders; + } + let signers = []; + if (signerData?.length > 0) { + signerData.forEach((x) => { + if (x.objectId) { + const obj = { + __type: "Pointer", + className: "contracts_Contactbook", + objectId: x.objectId + }; + signers.push(obj); + } + }); + } + const data = { + Name: Doc.Name, + URL: Doc.URL, + SignedUrl: Doc.SignedUrl, + Description: Doc.Description, + Note: Doc.Note, + Placeholders: placeholdersArr, + ExtUserPtr: { + __type: "Pointer", + className: "contracts_Users", + objectId: Doc.ExtUserPtr.objectId + }, + CreatedBy: { + __type: "Pointer", + className: "_User", + objectId: Doc.CreatedBy.objectId + }, + Signers: signers + }; + + try { + const res = await axios.post( + `${localStorage.getItem("baseUrl")}classes/${localStorage.getItem( + "_appName" + )}_Document`, + data, + { + headers: { + "Content-Type": "application/json", + "X-Parse-Application-Id": localStorage.getItem("parseAppId"), + "X-Parse-Session-Token": localStorage.getItem("accesstoken") + } + } + ); + if (res) { + return { status: "success", id: res.data.objectId }; + } + } catch (err) { + console.log("axois err ", err); + return { status: "error", id: "Something Went Wrong!" }; + } + } +}; + +export const getFirstLetter = (name) => { + const firstLetter = name?.charAt(0); + return firstLetter; +}; + + +export const darkenColor = (color, factor) => { + // Remove '#' from the color code and parse it to get RGB values + const hex = color.replace("#", ""); + const r = parseInt(hex.substring(0, 2), 16); + const g = parseInt(hex.substring(2, 4), 16); + const b = parseInt(hex.substring(4, 6), 16); + + // Darken the color by reducing each RGB component + const darkerR = Math.floor(r * (1 - factor)); + const darkerG = Math.floor(g * (1 - factor)); + const darkerB = Math.floor(b * (1 - factor)); + + // Convert the darkened RGB components back to hex + return `#${((darkerR << 16) | (darkerG << 8) | darkerB) + .toString(16) + .padStart(6, "0")}`; +}; + +