From 77c61c89a2844c4a4129cbc7d3e40f737dffee1b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 02:24:33 +0000 Subject: [PATCH 01/17] build(deps): bump ejs from 3.1.9 to 3.1.10 in /apps/OpenSign Bumps [ejs](https://github.com/mde/ejs) from 3.1.9 to 3.1.10. - [Release notes](https://github.com/mde/ejs/releases) - [Commits](https://github.com/mde/ejs/compare/v3.1.9...v3.1.10) --- updated-dependencies: - dependency-name: ejs dependency-type: indirect ... Signed-off-by: dependabot[bot] --- apps/OpenSign/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/OpenSign/package-lock.json b/apps/OpenSign/package-lock.json index a4b48dc59..ec320e048 100644 --- a/apps/OpenSign/package-lock.json +++ b/apps/OpenSign/package-lock.json @@ -9883,9 +9883,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dependencies": { "jake": "^10.8.5" }, From 4b9f22a5bcb901b23839261b3f8edf08fa129f86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 02:25:30 +0000 Subject: [PATCH 02/17] build(deps): bump tar from 6.2.0 to 6.2.1 in /apps/OpenSign Bumps [tar](https://github.com/isaacs/node-tar) from 6.2.0 to 6.2.1. - [Release notes](https://github.com/isaacs/node-tar/releases) - [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md) - [Commits](https://github.com/isaacs/node-tar/compare/v6.2.0...v6.2.1) --- updated-dependencies: - dependency-name: tar dependency-type: indirect ... Signed-off-by: dependabot[bot] --- apps/OpenSign/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/OpenSign/package-lock.json b/apps/OpenSign/package-lock.json index a4b48dc59..c76a98565 100644 --- a/apps/OpenSign/package-lock.json +++ b/apps/OpenSign/package-lock.json @@ -22168,9 +22168,9 @@ } }, "node_modules/tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "optional": true, "dependencies": { "chownr": "^2.0.0", From 13e2d92ce64388184f8c7125d453136804c9376c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 02:26:18 +0000 Subject: [PATCH 03/17] build(deps): bump webpack-dev-middleware in /apps/OpenSign Bumps [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) from 5.3.3 to 5.3.4. - [Release notes](https://github.com/webpack/webpack-dev-middleware/releases) - [Changelog](https://github.com/webpack/webpack-dev-middleware/blob/v5.3.4/CHANGELOG.md) - [Commits](https://github.com/webpack/webpack-dev-middleware/compare/v5.3.3...v5.3.4) --- updated-dependencies: - dependency-name: webpack-dev-middleware dependency-type: indirect ... Signed-off-by: dependabot[bot] --- apps/OpenSign/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/OpenSign/package-lock.json b/apps/OpenSign/package-lock.json index a4b48dc59..1a5d4f564 100644 --- a/apps/OpenSign/package-lock.json +++ b/apps/OpenSign/package-lock.json @@ -23188,9 +23188,9 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.3", From b1dd4df3c018ce267c43197b3264f2c6a74bd22d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 17:03:30 +0000 Subject: [PATCH 04/17] build(deps): bump react-pdf from 7.7.1 to 7.7.3 in /apps/OpenSign Bumps [react-pdf](https://github.com/wojtekmaj/react-pdf/tree/HEAD/packages/react-pdf) from 7.7.1 to 7.7.3. - [Release notes](https://github.com/wojtekmaj/react-pdf/releases) - [Commits](https://github.com/wojtekmaj/react-pdf/commits/v7.7.3/packages/react-pdf) --- updated-dependencies: - dependency-name: react-pdf dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- apps/OpenSign/package-lock.json | 8 ++++---- apps/OpenSign/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/OpenSign/package-lock.json b/apps/OpenSign/package-lock.json index a4b48dc59..b74c428e4 100644 --- a/apps/OpenSign/package-lock.json +++ b/apps/OpenSign/package-lock.json @@ -33,7 +33,7 @@ "react-helmet": "^6.1.0", "react-konva": "^18.2.10", "react-modal": "^3.16.1", - "react-pdf": "^7.7.1", + "react-pdf": "^7.7.3", "react-quill": "^2.0.0", "react-redux": "^9.1.0", "react-rnd": "^10.4.10", @@ -19821,9 +19821,9 @@ } }, "node_modules/react-pdf": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-7.7.1.tgz", - "integrity": "sha512-cbbf/PuRtGcPPw+HLhMI1f6NSka8OJgg+j/yPWTe95Owf0fK6gmVY7OXpTxMeh92O3T3K3EzfE0ML0eXPGwR5g==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-7.7.3.tgz", + "integrity": "sha512-a2VfDl8hiGjugpqezBTUzJHYLNB7IS7a2t7GD52xMI9xHg8LdVaTMsnM9ZlNmKadnStT/tvX5IfV0yLn+JvYmw==", "dependencies": { "clsx": "^2.0.0", "dequal": "^2.0.3", diff --git a/apps/OpenSign/package.json b/apps/OpenSign/package.json index cf4c66752..2b9861354 100644 --- a/apps/OpenSign/package.json +++ b/apps/OpenSign/package.json @@ -28,7 +28,7 @@ "react-helmet": "^6.1.0", "react-konva": "^18.2.10", "react-modal": "^3.16.1", - "react-pdf": "^7.7.1", + "react-pdf": "^7.7.3", "react-quill": "^2.0.0", "react-redux": "^9.1.0", "react-rnd": "^10.4.10", From c5f39e2a2417aed8d188a937def532d09fc584cb Mon Sep 17 00:00:00 2001 From: RaktimaNXG Date: Fri, 10 May 2024 16:59:58 +0530 Subject: [PATCH 05/17] fix: tour & model for email verification is shown simaltaneously, issue of navigate tour message on another page to show warning complete signature --- .../src/components/pdf/RenderAllPdfPage.js | 70 +++++- apps/OpenSign/src/pages/PdfRequestFiles.js | 140 +++++------ apps/OpenSign/src/pages/PlaceHolderSign.js | 5 +- apps/OpenSign/src/pages/SignyourselfPdf.js | 225 +++++++++--------- 4 files changed, 235 insertions(+), 205 deletions(-) diff --git a/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js b/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js index cb1fa0700..f8642ab9a 100644 --- a/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js +++ b/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState } from "react"; import RSC from "react-scrollbars-custom"; import { Document, Page } from "react-pdf"; import { themeColor } from "../../constant/const"; @@ -9,13 +9,48 @@ function RenderAllPdfPage({ setAllPages, setPageNumber, setSignBtnPosition, - pageNumber + pageNumber, + signerPos, + signerObjectId }) { + const [signPageNumber, setSignPageNumber] = useState([]); //set all number of pages after load pdf function onDocumentLoad({ numPages }) { setAllPages(numPages); + if (signerPos) { + const checkUser = signerPos.filter( + (data) => data.signerObjId === signerObjectId + ); + let pageNumberArr = []; + if (checkUser?.length > 0) { + checkUser[0]?.placeHolder?.map((data) => { + pageNumberArr.push(data?.pageNumber); + }); + + setSignPageNumber(pageNumberArr); + } + } } + //'function `addSignatureBookmark`f function is utilized to display the page where the user's signature is located. + const addSignatureBookmark = (index) => { + const ispageNumber = signPageNumber.includes(index + 1); + return ( + ispageNumber && ( +
+ +
+ ) + ); + }; return (
{ setPageNumber(index + 1); @@ -75,15 +111,25 @@ function RenderAllPdfPage({ } }} > - + {signerPos && addSignatureBookmark(index)} + +
+ +
))} diff --git a/apps/OpenSign/src/pages/PdfRequestFiles.js b/apps/OpenSign/src/pages/PdfRequestFiles.js index 624abf6e2..bdd274ecd 100644 --- a/apps/OpenSign/src/pages/PdfRequestFiles.js +++ b/apps/OpenSign/src/pages/PdfRequestFiles.js @@ -472,36 +472,8 @@ function PdfRequestFiles() { }); }; - // const checkSendInOrder = () => { - // if (sendInOrder) { - // const index = pdfDetails?.[0].Signers.findIndex( - // (x) => x.Email === jsonSender.email - // ); - // const newIndex = index - 1; - // if (newIndex !== -1) { - // const user = pdfDetails?.[0].Signers[newIndex]; - // const isPrevUserSigned = - // pdfDetails?.[0].AuditTrail && - // pdfDetails?.[0].AuditTrail.some( - // (x) => - // x.UserPtr.objectId === user.objectId && x.Activity === "Signed" - // ); - // if (isPrevUserSigned) { - // return true; - // } else { - // return false; - // } - // } else { - // return true; - // } - // } else { - // return true; - // } - // }; //function for embed signature or image url in pdf async function embedWidgetsData() { - // const validateSigning = checkSendInOrder(); - // if (validateSigning) { try { const checkUser = signerPos.filter( (data) => data.signerObjId === signerObjectId @@ -512,83 +484,97 @@ function PdfRequestFiles() { showAlert = false, widgetKey, radioExist, - requiredCheckbox; + requiredCheckbox, + pageNumber; // `pageNumber` is used to check on which page user did not fill widget's data then change current pageNumber and show tour message on that page for (let i = 0; i < checkUser[0].placeHolder.length; i++) { for (let j = 0; j < checkUser[0].placeHolder[i].pos.length; j++) { + //get current page + const updatePage = checkUser[0].placeHolder[i]?.pageNumber; + //checking checbox type widget checkboxExist = checkUser[0].placeHolder[i].pos[j].type === "checkbox"; + //checking radio button type widget radioExist = checkUser[0].placeHolder[i].pos[j].type === radioButtonWidget; + //condition to check checkbox widget exist or not if (checkboxExist) { + //get all required type checkbox requiredCheckbox = checkUser[0].placeHolder[i].pos.filter( (position) => !position.options?.isReadOnly && position.type === "checkbox" ); - + //if required type checkbox data exit then check user checked all checkbox or some checkbox remain to check + //also validate to minimum and maximum required checkbox if (requiredCheckbox && requiredCheckbox.length > 0) { for (let i = 0; i < requiredCheckbox.length; i++) { + //get minimum required count if exit const minCount = requiredCheckbox[i].options?.validation?.minRequiredCount; const parseMin = minCount && parseInt(minCount); + //get maximum required count if exit const maxCount = requiredCheckbox[i].options?.validation?.maxRequiredCount; const parseMax = maxCount && parseInt(maxCount); + //in `response` variable is used to get how many checkbox checked by user const response = requiredCheckbox[i].options?.response?.length; + //in `defaultValue` variable is used to get how many checkbox checked by default const defaultValue = requiredCheckbox[i].options?.defaultValue?.length; - if (parseMin === 0 && parseMax === 0) { - if (!showAlert) { - showAlert = false; - setminRequiredCount(null); - } - } else if (parseMin === 0 && parseMax > 0) { - if (!showAlert) { - showAlert = false; - setminRequiredCount(null); - } - } else if (!response) { - if (!defaultValue) { - if (!showAlert) { - showAlert = true; - widgetKey = requiredCheckbox[i].key; - setminRequiredCount(parseMin); - } - } - } else if (parseMin > 0 && parseMin > response) { + //condition to check parseMin and parseMax greater than 0 then consider it as a required check box + if ( + parseMin > 0 && + parseMax > 0 && + !response && + !defaultValue && + !showAlert + ) { + showAlert = true; + widgetKey = requiredCheckbox[i].key; + pageNumber = updatePage; + setminRequiredCount(parseMin); + } + //else condition to validate minimum required checkbox + else if (parseMin > 0 && parseMin > response) { if (!showAlert) { showAlert = true; widgetKey = requiredCheckbox[i].key; + pageNumber = updatePage; + setminRequiredCount(parseMin); } } } } - } else if (radioExist) { + } + //condition to check radio widget exist or not + else if (radioExist) { + //get all required type radio button requiredRadio = checkUser[0].placeHolder[i].pos.filter( (position) => !position.options?.isReadOnly && position.type === radioButtonWidget ); + //if required type radio data exit then check user checked all radio button or some radio remain to check if (requiredRadio && requiredRadio?.length > 0) { let checkSigned; for (let i = 0; i < requiredRadio?.length; i++) { checkSigned = requiredRadio[i]?.options.response; - if (!checkSigned) { - let checkDefaultSigned = - requiredRadio[i]?.options.defaultValue; - if (!checkDefaultSigned) { - if (!showAlert) { - showAlert = true; - widgetKey = requiredRadio[i].key; - setminRequiredCount(null); - } - } + let checkDefaultSigned = + requiredRadio[i]?.options.defaultValue; + if (!checkSigned && !checkDefaultSigned && !showAlert) { + showAlert = true; + widgetKey = requiredRadio[i].key; + pageNumber = updatePage; + setminRequiredCount(null); } } } - } else { + } + //else condition to check all type widget data fill or not except checkbox and radio button + else { + //get all required type widgets except checkbox and radio const requiredWidgets = checkUser[0].placeHolder[i].pos.filter( (position) => position.options?.status === "required" && @@ -601,33 +587,36 @@ function PdfRequestFiles() { checkSigned = requiredWidgets[i]?.options?.response; if (!checkSigned) { const checkSignUrl = requiredWidgets[i]?.pos?.SignUrl; - let checkDefaultSigned = requiredWidgets[i]?.options?.defaultValue; - if (!checkSignUrl) { - if (!checkDefaultSigned) { - if (!showAlert) { - showAlert = true; - widgetKey = requiredWidgets[i].key; - setminRequiredCount(null); - } - } + if (!checkSignUrl && !checkDefaultSigned && !showAlert) { + showAlert = true; + widgetKey = requiredWidgets[i].key; + pageNumber = updatePage; + setminRequiredCount(null); } } } } } } + //when showAlert is true then break the loop and show alert to fill required data in widgets + if (showAlert) { + break; + } } if (checkboxExist && requiredCheckbox && showAlert) { setUnSignedWidgetId(widgetKey); + setPageNumber(pageNumber); setWidgetsTour(true); } else if (radioExist && showAlert) { setUnSignedWidgetId(widgetKey); + setPageNumber(pageNumber); setWidgetsTour(true); } else if (showAlert) { setUnSignedWidgetId(widgetKey); + setPageNumber(pageNumber); setWidgetsTour(true); } else { setIsUiLoading(true); @@ -882,15 +871,6 @@ function PdfRequestFiles() { alertMessage: "something went wrong, please try again later." }); } - - // } - // else { - // setIsAlert({ - // isShow: true, - // alertMessage: - // "Please wait for your turn to sign this document, as it has been set up by the creator to be signed in a specific order; you'll be notified when it's your turn." - // }); - // } } //function for update TourStatus @@ -1349,6 +1329,8 @@ function PdfRequestFiles() { {/* this component used to render all pdf pages in left side */} 0) { + const alreadyPlaceholder = documentData[0]?.SignedUrl; + if (alreadyPlaceholder) { + setCheckTourStatus(true); + } else if (tourstatus && tourstatus.length > 0) { setTourStatus(tourstatus); const checkTourRecipients = tourstatus.filter( (data) => data.placeholder diff --git a/apps/OpenSign/src/pages/SignyourselfPdf.js b/apps/OpenSign/src/pages/SignyourselfPdf.js index 027abb889..db813272f 100644 --- a/apps/OpenSign/src/pages/SignyourselfPdf.js +++ b/apps/OpenSign/src/pages/SignyourselfPdf.js @@ -233,29 +233,6 @@ function SignYourSelf() { setSignBtnPosition([]); } } - - if (!isCompleted) { - //check current user email verified or not - const currentUser = JSON.parse(JSON.stringify(Parse.User.current())); - let isEmailVerified; - isEmailVerified = currentUser?.emailVerified; - if (isEmailVerified) { - setIsEmailVerified(isEmailVerified); - } else { - try { - const userQuery = new Parse.Query(Parse.User); - const user = await userQuery.get(currentUser.objectId, { - sessionToken: localStorage.getItem("accesstoken") - }); - if (user) { - isEmailVerified = user?.get("emailVerified"); - setIsEmailVerified(isEmailVerified); - } - } catch (e) { - setHandleError("Error: Something went wrong!"); - } - } - } } else if ( documentData === "Error: Something went wrong!" || (documentData.result && documentData.result.error) @@ -603,104 +580,126 @@ function SignYourSelf() { }; //function for send placeholder's co-ordinate(x,y) position embed signature url or stamp url async function embedWidgetsData() { - let showAlert = false, - isSignatureExist = false; - try { - for (let i = 0; i < xyPostion?.length; i++) { - const requiredWidgets = xyPostion[i].pos.filter( - (position) => position.type !== "checkbox" - ); - if (requiredWidgets && requiredWidgets?.length > 0) { - let checkSigned; - for (let i = 0; i < requiredWidgets?.length; i++) { - checkSigned = requiredWidgets[i]?.options?.response; - if (!checkSigned) { - const checkSignUrl = requiredWidgets[i]?.pos?.SignUrl; - let checkDefaultSigned = - requiredWidgets[i]?.options?.defaultValue; - if (!checkSignUrl) { - if (!checkDefaultSigned) { - if (!showAlert) { - showAlert = true; + //check current user email is verified or not + const currentUser = JSON.parse(JSON.stringify(Parse.User.current())); + let isEmailVerified; + isEmailVerified = currentUser?.emailVerified; + if (isEmailVerified) { + setIsEmailVerified(isEmailVerified); + } else { + try { + const userQuery = new Parse.Query(Parse.User); + const user = await userQuery.get(currentUser.objectId, { + sessionToken: localStorage.getItem("accesstoken") + }); + if (user) { + isEmailVerified = user?.get("emailVerified"); + setIsEmailVerified(isEmailVerified); + } + } catch (e) { + setHandleError("Error: Something went wrong!"); + } + } + if (isEmailVerified) { + let showAlert = false, + isSignatureExist = false; + try { + for (let i = 0; i < xyPostion?.length; i++) { + const requiredWidgets = xyPostion[i].pos.filter( + (position) => position.type !== "checkbox" + ); + if (requiredWidgets && requiredWidgets?.length > 0) { + let checkSigned; + for (let i = 0; i < requiredWidgets?.length; i++) { + checkSigned = requiredWidgets[i]?.options?.response; + if (!checkSigned) { + const checkSignUrl = requiredWidgets[i]?.pos?.SignUrl; + let checkDefaultSigned = + requiredWidgets[i]?.options?.defaultValue; + if (!checkSignUrl) { + if (!checkDefaultSigned) { + if (!showAlert) { + showAlert = true; + } } } } } } - } - //condition to check exist signature widget or not - if (!isSignatureExist) { - isSignatureExist = xyPostion[i].pos.some( - (data) => data?.type === "signature" - ); - } - } - if (xyPostion.length === 0 || !isSignatureExist) { - setIsAlert({ - header: "Fields required", - isShow: true, - alertMessage: - "Please ensure there's at least one signature widget added" - }); - return; - } else if (showAlert) { - setIsAlert({ - isShow: true, - alertMessage: - "Please ensure all field is accurately filled and meets all requirements." - }); - return; - } else { - setIsCeleb(true); - setTimeout(() => { - setIsCeleb(false); - }, 3000); - setIsUiLoading(true); - const existingPdfBytes = pdfArrayBuffer; - // Load a PDFDocument from the existing PDF bytes - try { - const pdfDoc = await PDFDocument.load(existingPdfBytes); - const isSignYourSelfFlow = true; - const extUserPtr = pdfDetails[0].ExtUserPtr; - const HeaderDocId = extUserPtr?.HeaderDocId; - //embed document's object id to all pages in pdf document - if (!HeaderDocId) { - await embedDocId(pdfDoc, documentId, allPages); - } - //embed multi signature in pdf - const pdfBytes = await multiSignEmbed( - xyPostion, - pdfDoc, - pdfOriginalWidth, - isSignYourSelfFlow, - containerWH - ); - // console.log("pdf", pdfBytes); - //function for call to embed signature in pdf and get digital signature pdf - await signPdfFun(pdfBytes, documentId); - } catch (err) { - setIsUiLoading(false); - if (err && err.message.includes("is encrypted.")) { - setIsAlert({ - isShow: true, - alertMessage: `Currently encrypted pdf files are not supported.` - }); - } else { - console.log("err in signing", err); - setIsAlert({ - isShow: true, - alertMessage: `Something went wrong.` - }); + //condition to check exist signature widget or not + if (!isSignatureExist) { + isSignatureExist = xyPostion[i].pos.some( + (data) => data?.type === "signature" + ); } } + if (xyPostion.length === 0 || !isSignatureExist) { + setIsAlert({ + header: "Fields required", + isShow: true, + alertMessage: + "Please ensure there's at least one signature widget added" + }); + return; + } else if (showAlert) { + setIsAlert({ + isShow: true, + alertMessage: + "Please ensure all field is accurately filled and meets all requirements." + }); + return; + } else { + setIsCeleb(true); + setTimeout(() => { + setIsCeleb(false); + }, 3000); + setIsUiLoading(true); + const existingPdfBytes = pdfArrayBuffer; + // Load a PDFDocument from the existing PDF bytes + try { + const pdfDoc = await PDFDocument.load(existingPdfBytes); + const isSignYourSelfFlow = true; + const extUserPtr = pdfDetails[0].ExtUserPtr; + const HeaderDocId = extUserPtr?.HeaderDocId; + //embed document's object id to all pages in pdf document + if (!HeaderDocId) { + await embedDocId(pdfDoc, documentId, allPages); + } + //embed multi signature in pdf + const pdfBytes = await multiSignEmbed( + xyPostion, + pdfDoc, + pdfOriginalWidth, + isSignYourSelfFlow, + containerWH + ); + // console.log("pdf", pdfBytes); + //function for call to embed signature in pdf and get digital signature pdf + await signPdfFun(pdfBytes, documentId); + } catch (err) { + setIsUiLoading(false); + if (err && err.message.includes("is encrypted.")) { + setIsAlert({ + isShow: true, + alertMessage: `Currently encrypted pdf files are not supported.` + }); + } else { + console.log("err in signing", err); + setIsAlert({ + isShow: true, + alertMessage: `Something went wrong.` + }); + } + } + } + } catch (err) { + console.log("err in embedselfsign ", err); + setIsUiLoading(false); + setIsAlert({ + isShow: true, + alertMessage: "something went wrong, please try again later." + }); } - } catch (err) { - console.log("err in embedselfsign ", err); - setIsUiLoading(false); - setIsAlert({ - isShow: true, - alertMessage: "something went wrong, please try again later." - }); } } //function for get digital signature From 836e952ba07e92ccf48c60efa1c413a221ca3ca1 Mon Sep 17 00:00:00 2001 From: RaktimaNXG Date: Fri, 10 May 2024 18:14:19 +0530 Subject: [PATCH 06/17] fix: add comment --- apps/OpenSign/src/components/pdf/RenderAllPdfPage.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js b/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js index f8642ab9a..d2bf93880 100644 --- a/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js +++ b/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js @@ -17,6 +17,7 @@ function RenderAllPdfPage({ //set all number of pages after load pdf function onDocumentLoad({ numPages }) { setAllPages(numPages); + //check is signerPos exist then save page number exist in signerPos array if (signerPos) { const checkUser = signerPos.filter( (data) => data.signerObjId === signerObjectId @@ -32,7 +33,7 @@ function RenderAllPdfPage({ } } - //'function `addSignatureBookmark`f function is utilized to display the page where the user's signature is located. + //'function `addSignatureBookmark` is used to display the page where the user's signature is located. const addSignatureBookmark = (index) => { const ispageNumber = signPageNumber.includes(index + 1); return ( From ec0e2916045c1e049a068a7f35ed2a8ca3ea2627 Mon Sep 17 00:00:00 2001 From: Raktima <110812506+raktima-opensignlabs@users.noreply.github.com> Date: Fri, 10 May 2024 18:16:11 +0530 Subject: [PATCH 07/17] Update RenderAllPdfPage.js --- apps/OpenSign/src/components/pdf/RenderAllPdfPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js b/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js index d2bf93880..9c5d42b9c 100644 --- a/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js +++ b/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js @@ -17,7 +17,7 @@ function RenderAllPdfPage({ //set all number of pages after load pdf function onDocumentLoad({ numPages }) { setAllPages(numPages); - //check is signerPos exist then save page number exist in signerPos array + //check if signerPos array exist then save page number exist in signerPos array to show bookmark icon if (signerPos) { const checkUser = signerPos.filter( (data) => data.signerObjId === signerObjectId From 055ef3f2098383f7b6e16ef3203b49a9f3a72172 Mon Sep 17 00:00:00 2001 From: RaktimaNXG Date: Fri, 10 May 2024 19:28:53 +0530 Subject: [PATCH 08/17] fix: min required checkbox validation issue --- apps/OpenSign/src/pages/PdfRequestFiles.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/OpenSign/src/pages/PdfRequestFiles.js b/apps/OpenSign/src/pages/PdfRequestFiles.js index bdd274ecd..388b564dc 100644 --- a/apps/OpenSign/src/pages/PdfRequestFiles.js +++ b/apps/OpenSign/src/pages/PdfRequestFiles.js @@ -536,7 +536,7 @@ function PdfRequestFiles() { setminRequiredCount(parseMin); } //else condition to validate minimum required checkbox - else if (parseMin > 0 && parseMin > response) { + else if (parseMin > 0 && (parseMin > response || !response)) { if (!showAlert) { showAlert = true; widgetKey = requiredCheckbox[i].key; @@ -605,7 +605,6 @@ function PdfRequestFiles() { break; } } - if (checkboxExist && requiredCheckbox && showAlert) { setUnSignedWidgetId(widgetKey); setPageNumber(pageNumber); From 3bf35166fcdf1c181d5eddcd6262f4278f445e1b Mon Sep 17 00:00:00 2001 From: RaktimaNXG Date: Fri, 10 May 2024 20:27:04 +0530 Subject: [PATCH 09/17] fix: bookmark color according to user's widget color --- .../src/components/pdf/RenderAllPdfPage.js | 7 +++- apps/OpenSign/src/pages/PdfRequestFiles.js | 34 +++++++++++-------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js b/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js index 9c5d42b9c..2fae32a0d 100644 --- a/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js +++ b/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js @@ -14,6 +14,7 @@ function RenderAllPdfPage({ signerObjectId }) { const [signPageNumber, setSignPageNumber] = useState([]); + const [bookmarkColor, setBookmarkColor] = useState(""); //set all number of pages after load pdf function onDocumentLoad({ numPages }) { setAllPages(numPages); @@ -22,6 +23,7 @@ function RenderAllPdfPage({ const checkUser = signerPos.filter( (data) => data.signerObjId === signerObjectId ); + setBookmarkColor(checkUser[0]?.blockColor); let pageNumberArr = []; if (checkUser?.length > 0) { checkUser[0]?.placeHolder?.map((data) => { @@ -47,7 +49,10 @@ function RenderAllPdfPage({ transform: "translate(50% -50%)" }} > - +
) ); diff --git a/apps/OpenSign/src/pages/PdfRequestFiles.js b/apps/OpenSign/src/pages/PdfRequestFiles.js index 388b564dc..31be42769 100644 --- a/apps/OpenSign/src/pages/PdfRequestFiles.js +++ b/apps/OpenSign/src/pages/PdfRequestFiles.js @@ -560,14 +560,16 @@ function PdfRequestFiles() { if (requiredRadio && requiredRadio?.length > 0) { let checkSigned; for (let i = 0; i < requiredRadio?.length; i++) { - checkSigned = requiredRadio[i]?.options.response; - let checkDefaultSigned = - requiredRadio[i]?.options.defaultValue; - if (!checkSigned && !checkDefaultSigned && !showAlert) { - showAlert = true; - widgetKey = requiredRadio[i].key; - pageNumber = updatePage; - setminRequiredCount(null); + checkSigned = requiredRadio[i]?.options?.response; + if (!checkSigned) { + let checkDefaultSigned = + requiredRadio[i]?.options?.defaultValue; + if (!checkDefaultSigned && !showAlert) { + showAlert = true; + widgetKey = requiredRadio[i].key; + pageNumber = updatePage; + setminRequiredCount(null); + } } } } @@ -587,13 +589,15 @@ function PdfRequestFiles() { checkSigned = requiredWidgets[i]?.options?.response; if (!checkSigned) { const checkSignUrl = requiredWidgets[i]?.pos?.SignUrl; - let checkDefaultSigned = - requiredWidgets[i]?.options?.defaultValue; - if (!checkSignUrl && !checkDefaultSigned && !showAlert) { - showAlert = true; - widgetKey = requiredWidgets[i].key; - pageNumber = updatePage; - setminRequiredCount(null); + if (!checkSignUrl) { + let checkDefaultSigned = + requiredWidgets[i]?.options?.defaultValue; + if (!checkDefaultSigned && !showAlert) { + showAlert = true; + widgetKey = requiredWidgets[i].key; + pageNumber = updatePage; + setminRequiredCount(null); + } } } } From 11a2f6b8ec484ae017dceeef796eab1511d4e184 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs Date: Fri, 10 May 2024 21:07:06 +0530 Subject: [PATCH 10/17] feat: add resend mail api, add expiry date in create document api & return certificate url in get document api --- .../cloud/customRoute/v1/apiV1.js | 6 +- .../v1/routes/CreateDocumentWithTemplate.js | 4 + .../v1/routes/createDocumentwithCoordinate.js | 4 + .../customRoute/v1/routes/getDocument.js | 1 + .../customRoute/v1/routes/getDocumentList.js | 2 +- .../cloud/customRoute/v1/routes/resendMail.js | 156 ++++++++++++++++++ 6 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 apps/OpenSignServer/cloud/customRoute/v1/routes/resendMail.js diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js index 343db0d3c..e4f532853 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -17,7 +17,6 @@ import getTemplatetList from './routes/getTemplateList.js'; import updateTemplate from './routes/updateTemplate.js'; import createContact from './routes/createContact.js'; import multer from 'multer'; -// import fs from 'node:fs'; import updateDocument from './routes/updateDocument.js'; import deleteDocument from './routes/deleteDocument.js'; import createDocumentWithTemplate from './routes/CreateDocumentWithTemplate.js'; @@ -26,6 +25,7 @@ import deleteWebhook from './routes/deleteWebhook.js'; import getWebhook from './routes/getWebhook.js'; import createDocumentwithCoordinate from './routes/createDocumentwithCoordinate.js'; import createTemplatewithCoordinate from './routes/createTemplatewithCoordinate.js'; +import resendMail from './routes/resendMail.js'; dotenv.config(); const storage = multer.memoryStorage(); const upload = multer({ storage: storage }); @@ -102,3 +102,7 @@ app.post('/webhook', saveWebhook); // set and update webhook app.delete('/webhook', deleteWebhook); + +// resend mail +app.post('/resendmail', resendMail); + diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js index 630fe1090..70dfd94b6 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/CreateDocumentWithTemplate.js @@ -55,6 +55,7 @@ export default async function createDocumentWithTemplate(request, response) { const email_subject = request.body.email_subject; const email_body = request.body.email_body; const sendInOrder = request.body.sendInOrder || false; + const TimeToCompleteDays = request.body.TimeToCompleteDays || 15; try { const reqToken = request.headers['x-api-token']; @@ -178,6 +179,9 @@ export default async function createDocumentWithTemplate(request, response) { } object.set('URL', template.URL); object.set('SignedUrl', template.URL); + if (TimeToCompleteDays) { + object.set('TimeToCompleteDays', TimeToCompleteDays); + } object.set('CreatedBy', template.CreatedBy); object.set('ExtUserPtr', { __type: 'Pointer', diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js index 40b124cd8..993faa6d6 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocumentwithCoordinate.js @@ -66,6 +66,7 @@ export default async function createDocumentwithCoordinate(request, response) { const email_subject = request.body.email_subject; const email_body = request.body.email_body; const sendInOrder = request.body.sendInOrder || false; + const TimeToCompleteDays = request.body.TimeToCompleteDays || 15; // console.log('fileData ', fileData); const protocol = customAPIurl(); const baseUrl = new URL(process.env.SERVER_URL); @@ -142,6 +143,9 @@ export default async function createDocumentwithCoordinate(request, response) { object.set('SignedUrl', fileUrl); object.set('CreatedBy', userPtr); object.set('ExtUserPtr', extUserPtr); + if (TimeToCompleteDays) { + object.set('TimeToCompleteDays', TimeToCompleteDays); + } object.set('IsSendMail', send_email); let contact = []; if (signers && signers.length > 0) { diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js index cc1e1e03c..30e13d1cb 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js @@ -40,6 +40,7 @@ export default async function getDocument(request, response) { note: document.Note || '', folder: { objectId: document?.Folder?.objectId, name: document?.Folder?.Name } || '', file: document?.SignedUrl || document.URL, + certificateUrl: document?.CertificateUrl || '', owner: document?.ExtUserPtr?.Name, signers: document?.Placeholders?.map(y => ({ diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js index 5f5b49e71..1deae9605 100644 --- a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -77,7 +77,7 @@ export default async function getDocumentList(request, response) { title: x.Name, note: x.Note || '', folder: { objectId: x?.Folder?.objectId, name: x?.Folder?.Name } || '', - file: x?.SignedUrl || x.URL, + // file: x?.SignedUrl || x.URL, owner: x?.ExtUserPtr?.Name, signers: x?.Placeholders?.map(y => ({ diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/resendMail.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/resendMail.js new file mode 100644 index 000000000..cbca5db24 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/resendMail.js @@ -0,0 +1,156 @@ +import axios from 'axios'; +import { replaceMailVaribles } from '../../../../Utils.js'; + +export default async function resendMail(request, response) { + try { + const reqToken = request.headers['x-api-token']; + const docId = request.body.document_id; + const userMail = request.body.email; + const email_subject = request.body.email_subject; + const email_body = request.body.email_body; + const baseUrl = new URL(process.env.SERVER_URL); + + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + tokenQuery.include('userId'); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const parseUser = JSON.parse(JSON.stringify(token)); + const userPtr = { + __type: 'Pointer', + className: '_User', + objectId: parseUser.userId.objectId, + }; + + const docQuery = new Parse.Query('contracts_Document'); + docQuery.equalTo('objectId', docId); + docQuery.equalTo('CreatedBy', userPtr); + docQuery.include('Signers,ExtUserPtr'); + docQuery.notEqualTo('IsCompleted', true); + docQuery.notEqualTo('IsDeclined', true); + docQuery.notEqualTo('IsArchive', true); + docQuery.lessThanOrEqualTo('ExpiryDate', new Date()); + docQuery.exists('SignedUrl'); + + const resDoc = await docQuery.first({ useMasterKey: true }); + if (resDoc) { + const _resDoc = resDoc.toJSON(); + const contact = _resDoc.Signers.find(x => x.Email === userMail); + if (contact) { + try { + const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png'; + let url = `${process.env.SERVER_URL}/functions/sendmailv3/`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': process.env.APP_ID, + 'X-Parse-Master-Key': process.env.MASTER_KEY, + }; + + const objectId = contact.objectId; + const hostUrl = baseUrl.origin; + const title = _resDoc.Name; + const receiverMail = contact.Email; + //encode this url value `${response.id}/${receiverMail}/${objectId}` to base64 using `btoa` function + const encodeBase64 = btoa(`${_resDoc.objectId}/${receiverMail}/${objectId}`); + let signPdf = `${hostUrl}/login/${encodeBase64}`; + const openSignUrl = 'https://www.opensignlabs.com/contact-us'; + const orgName = _resDoc.ExtUserPtr.Company ? _resDoc.ExtUserPtr.Company : ''; + const newDate = new Date(_resDoc.ExpiryDate.iso); + newDate.setDate(newDate.getDate() + 15); + const sender = _resDoc.ExtUserPtr.Email; + const localExpireDate = newDate.toLocaleDateString('en-US', { + day: 'numeric', + month: 'long', + year: 'numeric', + }); + + const themeBGcolor = '#47a3ad'; + const email_html = + "

Digital Signature Request

" + + _resDoc.ExtUserPtr.Name + + ' has requested you to review and sign ' + + title + + ".

Sender " + + sender + + "
Organization " + + orgName + + "
Expires on " + + localExpireDate + + "

This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " + + sender + + ' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ here.

'; + let replaceVar; + const variables = { + document_title: title, + sender_name: _resDoc.ExtUserPtr.Name, + sender_mail: _resDoc.ExtUserPtr.Email, + sender_phone: _resDoc.ExtUserPtr.Phone, + receiver_name: contact.Name, + receiver_email: contact.Email, + receiver_phone: contact.Phone, + expiry_date: localExpireDate, + company_name: orgName, + signing_url: signPdf, + }; + if (email_subject && email_body) { + replaceVar = replaceMailVaribles(email_subject, email_body, variables); + } else if (email_subject) { + replaceVar = replaceMailVaribles(email_subject, '', variables); + replaceVar = { subject: replaceVar.subject, body: email_html }; + } else if (email_body) { + replaceVar = replaceMailVaribles( + `${_resDoc.ExtUserPtr.Name} has requested you to sign "${title}"`, + email_body, + variables + ); + } else { + replaceVar = { + subject: `${_resDoc.ExtUserPtr.Name} has requested you to sign "${title}"`, + body: email_html, + }; + } + const subject = replaceVar.subject; + const html = replaceVar.body; + + let params = { + recipient: contact.Email, + subject: subject, + from: sender, + html: html, + extUserId: _resDoc.ExtUserPtr.objectId, + }; + + const res = await axios.post(url, params, { headers: headers }); + if (res.data.result && res.data.result.status === 'success') { + return response.json({ result: 'mail sent successfully.' }); + } + } catch (error) { + console.log('error', error); + return response.status(400).json({ error: error.message }); + } + } else { + return response.status(404).json({ error: 'user not found.' }); + } + } else { + return response.status(404).json({ error: 'document not found.' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token.' }); + } + } catch (err) { + console.log('err in resendmail', err); + return response.status(400).json({ error: err.message || 'Something went wrong.' }); + } +} From a54c7e7fd7725cf9e3ce96f51bd36ecab35b4cf4 Mon Sep 17 00:00:00 2001 From: RaktimaNXG Date: Mon, 13 May 2024 10:57:53 +0530 Subject: [PATCH 11/17] fix: help button fridge in user profile ofdisable documentId --- apps/OpenSign/src/pages/UserProfile.js | 1 - apps/OpenSign/src/primitives/Tooltip.js | 12 ++---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/apps/OpenSign/src/pages/UserProfile.js b/apps/OpenSign/src/pages/UserProfile.js index 3d3f6f483..813d8ab52 100644 --- a/apps/OpenSign/src/pages/UserProfile.js +++ b/apps/OpenSign/src/pages/UserProfile.js @@ -404,7 +404,6 @@ function UserProfile() { url={ "https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid" } - isSubscribe={isSubscribe} />{" "} {!isSubscribe && isEnableSubscription && } {" "} diff --git a/apps/OpenSign/src/primitives/Tooltip.js b/apps/OpenSign/src/primitives/Tooltip.js index f49e4bce7..1264e86e1 100644 --- a/apps/OpenSign/src/primitives/Tooltip.js +++ b/apps/OpenSign/src/primitives/Tooltip.js @@ -1,17 +1,9 @@ import React from "react"; import { Tooltip as ReactTooltip } from "react-tooltip"; import { openInNewTab } from "../constant/Utils"; -import { isEnableSubscription } from "../constant/const"; -const Tooltip = ({ id, message, url, iconColor, isSubscribe }) => +const Tooltip = ({ id, message, url, iconColor }) => url ? ( -