diff --git a/apps/OpenSign/package-lock.json b/apps/OpenSign/package-lock.json index a4b48dc59..95ce733d0 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", @@ -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" }, @@ -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", @@ -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", @@ -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", 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", diff --git a/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js b/apps/OpenSign/src/components/pdf/RenderAllPdfPage.js index cb1fa0700..2fae32a0d 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,54 @@ function RenderAllPdfPage({ setAllPages, setPageNumber, setSignBtnPosition, - pageNumber + pageNumber, + signerPos, + signerObjectId }) { + const [signPageNumber, setSignPageNumber] = useState([]); + const [bookmarkColor, setBookmarkColor] = useState(""); //set all number of pages after load pdf function onDocumentLoad({ numPages }) { setAllPages(numPages); + //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 + ); + setBookmarkColor(checkUser[0]?.blockColor); + let pageNumberArr = []; + if (checkUser?.length > 0) { + checkUser[0]?.placeHolder?.map((data) => { + pageNumberArr.push(data?.pageNumber); + }); + + setSignPageNumber(pageNumberArr); + } + } } + //'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 ( + ispageNumber && ( +
+ +
+ ) + ); + }; return (
{ setPageNumber(index + 1); @@ -75,15 +117,25 @@ function RenderAllPdfPage({ } }} > - + {signerPos && addSignatureBookmark(index)} + +
+ +
))} diff --git a/apps/OpenSign/src/components/shared/fields/SelectFolder.js b/apps/OpenSign/src/components/shared/fields/SelectFolder.js index dcf24e95f..84bd44aa3 100644 --- a/apps/OpenSign/src/components/shared/fields/SelectFolder.js +++ b/apps/OpenSign/src/components/shared/fields/SelectFolder.js @@ -169,32 +169,40 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => { {required && *}
-
-
- -
-
-
-

- {selectFolder && selectFolder.Name - ? selectFolder.Name - : "OpenSign™ Drive"} -

-
SetIsOpen(true)}> - -
+
+
SetIsOpen(true)} + className=" cursor-pointer rounded px-[20px] py-[20px] bg-white border border-gray-200 shadow flex max-w-sm gap-8 items-center" + > +
+ +
+
+
+

+ {selectFolder && selectFolder.Name + ? selectFolder.Name + : "OpenSign™ Drive"} +

+
SetIsOpen(true)} + > + +
+
+

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

-

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

{ required />
- - + {props.title !== "New Template" && ( + + )} {props.title === "Request Signatures" && (

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.' }); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateFolder.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateFolder.js new file mode 100644 index 000000000..eb16ae923 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateFolder.js @@ -0,0 +1,67 @@ +export default async function updateFolder(request, response) { + const apiToken = request.headers['x-api-token']; + const folderId = request.params.folder_id; + const name = request.body.foldername; + const parentFolderId = request.body.parentFolderId; + if (!apiToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + try { + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', apiToken); + 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 folderCls = new Parse.Query('contracts_Document'); + folderCls.equalTo('CreatedBy', userPtr); + folderCls.equalTo('objectId', folderId); + folderCls.equalTo('Type', 'Folder'); + folderCls.notEqualTo('IsArchive', true); + + const res = await folderCls.first({ useMasterKey: true }); + if (res) { + const updateFolder = new Parse.Object('contracts_Document'); + updateFolder.id = res.id; + updateFolder.set('Name', name); + if (parentFolderId) { + updateFolder.set('Folder', { + __type: 'Pointer', + className: 'contracts_Document', + objectId: parentFolderId, + }); + } + const updateRes = await updateFolder.save(null, { useMasterKey: true }); + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_update_folder', + properties: { response_code: 200 }, + }); + } + return response.json({ objectId: updateRes.id, updatedAt: updateRes.updatedAt }); + } else { + if (request.posthog) { + request.posthog?.capture({ + distinctId: parseUser.userId.email, + event: 'api_update_folder', + properties: { response_code: 404 }, + }); + } + return response.status(404).json({ error: 'folder not found.' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.status(400).json({ error: 'Something went wrong, please try again later!' }); + } +}