mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-05 01:07:39 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
336114f6ec | ||
|
|
eb8e7b089b | ||
|
|
bce0e4971e | ||
|
|
4fb8aa9a16 |
Generated
+16871
File diff suppressed because it is too large
Load Diff
+25
-26
@@ -1,58 +1,57 @@
|
|||||||
{
|
{
|
||||||
"name": "open_sign",
|
"name": "open_sign",
|
||||||
"version": "2.32.0",
|
"version": "2.35.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formkit/auto-animate": "^0.9.0",
|
"@formkit/auto-animate": "^0.9.0",
|
||||||
"@imgly/background-removal": "^1.7.0",
|
"@imgly/background-removal": "^1.7.0",
|
||||||
"@lottiefiles/dotlottie-react": "^0.17.8",
|
"@lottiefiles/dotlottie-react": "^0.17.12",
|
||||||
"@pdf-lib/fontkit": "^1.1.1",
|
"@pdf-lib/fontkit": "^1.1.1",
|
||||||
"@radix-ui/themes": "^3.2.1",
|
"@radix-ui/themes": "^3.2.1",
|
||||||
"@reduxjs/toolkit": "^2.11.0",
|
"@reactour/tour": "^3.8.0",
|
||||||
|
"@reduxjs/toolkit": "^2.11.2",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
|
"body-scroll-lock": "^4.0.0-beta.0",
|
||||||
"date-fns-tz": "^3.2.0",
|
"date-fns-tz": "^3.2.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"i18next": "^25.7.1",
|
"i18next": "^25.7.3",
|
||||||
"i18next-browser-languagedetector": "^8.2.0",
|
"i18next-browser-languagedetector": "^8.2.0",
|
||||||
"i18next-http-backend": "^3.0.2",
|
"i18next-http-backend": "^3.0.2",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"parse": "^7.1.2",
|
"parse": "^8.0.0",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"pkijs": "^3.3.3",
|
"pkijs": "^3.3.3",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
"prismjs": "^1.30.0",
|
"prismjs": "^1.30.0",
|
||||||
"quill-html-edit-button": "^3.0.0",
|
"quill-html-edit-button": "^3.0.0",
|
||||||
"radix-ui": "^1.4.3",
|
"radix-ui": "^1.4.3",
|
||||||
"react": "^18.3.1",
|
"react": "^19.2.3",
|
||||||
"react-bootstrap": "^2.10.10",
|
"react-bootstrap": "^2.10.10",
|
||||||
"react-confetti": "^6.4.0",
|
"react-confetti": "^6.4.0",
|
||||||
"react-datepicker": "^8.10.0",
|
"react-datepicker": "^9.1.0",
|
||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
"react-dnd-html5-backend": "^16.0.1",
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
"react-dnd-multi-backend": "^9.0.0",
|
"react-dnd-multi-backend": "^9.0.0",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^19.2.3",
|
||||||
"react-gtm-module": "^2.0.11",
|
"react-gtm-module": "^2.0.11",
|
||||||
"react-helmet": "^6.1.0",
|
"react-i18next": "^16.5.0",
|
||||||
"react-i18next": "^16.3.5",
|
"react-konva": "^19.2.1",
|
||||||
"react-konva": "^18.2.12",
|
"react-pdf": "^10.2.0",
|
||||||
"react-pdf": "^9.2.1",
|
"react-quill-new": "^3.7.0",
|
||||||
"react-quill-new": "^3.6.0",
|
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
"react-rnd": "^10.5.2",
|
"react-rnd": "^10.5.2",
|
||||||
"react-router": "^7.10.0",
|
"react-router": "^7.11.0",
|
||||||
"react-scrollbars-custom": "^4.1.1",
|
"react-scrollbars-custom": "^4.1.1",
|
||||||
"react-select": "^5.10.2",
|
"react-select": "^5.10.2",
|
||||||
"react-signature-canvas": "^1.1.0-alpha.2",
|
"react-signature-canvas": "^1.1.0-alpha.2",
|
||||||
"react-timezone-select": "^3.2.8",
|
"react-timezone-select": "^3.2.8",
|
||||||
"react-to-print": "^3.2.0",
|
"react-to-print": "^3.2.0",
|
||||||
"react-tooltip": "^5.30.0",
|
"react-tooltip": "^5.30.0",
|
||||||
"reactour": "^1.19.4",
|
|
||||||
"redux": "^5.0.1",
|
"redux": "^5.0.1",
|
||||||
"regex-parser": "^2.3.1",
|
"regex-parser": "^2.3.1",
|
||||||
"serve": "^14.2.5",
|
"serve": "^14.2.5",
|
||||||
"styled-components": "^5.3.11",
|
|
||||||
"web-vitals": "^5.1.0",
|
"web-vitals": "^5.1.0",
|
||||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
||||||
},
|
},
|
||||||
@@ -99,32 +98,32 @@
|
|||||||
"@babel/preset-react": "^7.28.5",
|
"@babel/preset-react": "^7.28.5",
|
||||||
"@babel/runtime-corejs2": "^7.28.3",
|
"@babel/runtime-corejs2": "^7.28.3",
|
||||||
"@testing-library/jest-dom": "^6.8.0",
|
"@testing-library/jest-dom": "^6.8.0",
|
||||||
"@testing-library/react": "^16.3.0",
|
"@testing-library/react": "^16.3.1",
|
||||||
"@testing-library/user-event": "^14.6.1",
|
"@testing-library/user-event": "^14.6.1",
|
||||||
"@types/react": "^19.2.7",
|
"@types/react": "^19.2.7",
|
||||||
"@vitejs/plugin-react": "^5.1.1",
|
"@vitejs/plugin-react": "^5.1.2",
|
||||||
"@vitest/ui": "^4.0.15",
|
"@vitest/ui": "^4.0.16",
|
||||||
"autoprefixer": "^10.4.22",
|
"autoprefixer": "^10.4.23",
|
||||||
"babel-loader": "^10.0.0",
|
"babel-loader": "^10.0.0",
|
||||||
"commitizen": "^4.3.1",
|
"commitizen": "^4.3.1",
|
||||||
"concurrently": "^9.2.1",
|
"concurrently": "^9.2.1",
|
||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.2",
|
||||||
"daisyui": "^4.12.24",
|
"daisyui": "^4.12.24",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.2",
|
||||||
"eslint-plugin-prettier": "^5.5.4",
|
"eslint-plugin-prettier": "^5.5.4",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
"jsdom": "^27.2.0",
|
"jsdom": "^27.4.0",
|
||||||
"lint-staged": "^16.2.7",
|
"lint-staged": "^16.2.7",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"prettier": "^3.7.4",
|
"prettier": "^3.7.4",
|
||||||
"pretty-quick": "^4.2.2",
|
"pretty-quick": "^4.2.2",
|
||||||
"rollup-plugin-node-polyfills": "^0.2.1",
|
"rollup-plugin-node-polyfills": "^0.2.1",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.19",
|
||||||
"tmp": "^0.2.5",
|
"tmp": "^0.2.5",
|
||||||
"vite": "^7.2.6",
|
"vite": "^7.3.0",
|
||||||
"vite-plugin-svgr": "^4.5.0",
|
"vite-plugin-svgr": "^4.5.0",
|
||||||
"vite-tsconfig-paths": "^5.1.4",
|
"vite-tsconfig-paths": "^6.0.3",
|
||||||
"vitest": "^4.0.15"
|
"vitest": "^4.0.16"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"tmp": "$tmp"
|
"tmp": "$tmp"
|
||||||
|
|||||||
@@ -270,7 +270,7 @@
|
|||||||
"signature": "Unterschrift",
|
"signature": "Unterschrift",
|
||||||
"upload-image": "Bild hochladen",
|
"upload-image": "Bild hochladen",
|
||||||
"clear": "Löschen",
|
"clear": "Löschen",
|
||||||
"upload-signature/Image": "Bitte Unterschrift/Bild hochladen",
|
"upload-signature/Image": "Bitte Unterschrift/Bild hochladen/Stempel",
|
||||||
"initials": "Initialen",
|
"initials": "Initialen",
|
||||||
"API": "API",
|
"API": "API",
|
||||||
"api-token": "API-Token",
|
"api-token": "API-Token",
|
||||||
@@ -393,7 +393,8 @@
|
|||||||
"radio button": "Radiobutton",
|
"radio button": "Radiobutton",
|
||||||
"image": "Bild",
|
"image": "Bild",
|
||||||
"email": "E-Mail",
|
"email": "E-Mail",
|
||||||
"number": "Zahl"
|
"number": "Zahl",
|
||||||
|
"draw": "Zeichnen"
|
||||||
},
|
},
|
||||||
"fields": "Felder",
|
"fields": "Felder",
|
||||||
"recipients": "Empfänger",
|
"recipients": "Empfänger",
|
||||||
@@ -516,7 +517,7 @@
|
|||||||
"placeholder-alert-4": "Sie haben erfolgreich E-Mails an alle Empfänger gesendet!",
|
"placeholder-alert-4": "Sie haben erfolgreich E-Mails an alle Empfänger gesendet!",
|
||||||
"placeholder-mail-alert": "Sie haben erfolgreich eine E-Mail an {{name}} gesendet. Die nachfolgenden Unterzeichner erhalten eine E-Mail, sobald {{name}} das Dokument unterzeichnet.",
|
"placeholder-mail-alert": "Sie haben erfolgreich eine E-Mail an {{name}} gesendet. Die nachfolgenden Unterzeichner erhalten eine E-Mail, sobald {{name}} das Dokument unterzeichnet.",
|
||||||
"placeholder-mail-alert-you": "Nachfolgende Unterzeichner erhalten E-Mails, sobald Sie das Dokument unterschreiben.",
|
"placeholder-mail-alert-you": "Nachfolgende Unterzeichner erhalten E-Mails, sobald Sie das Dokument unterschreiben.",
|
||||||
"placeholder-alert-5": "Möchten Sie die Dokumente jetzt unterschreiben?",
|
"placeholder-alert-5": "Sie können jetzt unterschreiben oder es an Ihre E-Mail senden, um es später abzuschließen.",
|
||||||
"placeholder-alert-6": "Bitte richten Sie den E-Mail-Adapter ein, um E-Mails zu senden!",
|
"placeholder-alert-6": "Bitte richten Sie den E-Mail-Adapter ein, um E-Mails zu senden!",
|
||||||
"placeholder-alert-7": "Bitte wählen Sie einen Unterzeichner aus, um Platzhalter hinzuzufügen!",
|
"placeholder-alert-7": "Bitte wählen Sie einen Unterzeichner aus, um Platzhalter hinzuzufügen!",
|
||||||
"email-subject": "E-Mail-Betreff",
|
"email-subject": "E-Mail-Betreff",
|
||||||
@@ -588,7 +589,7 @@
|
|||||||
"provide-your-details": "Bitte geben Sie Ihre Daten an",
|
"provide-your-details": "Bitte geben Sie Ihre Daten an",
|
||||||
"provide-email": "Bitte E-Mail angeben.",
|
"provide-email": "Bitte E-Mail angeben.",
|
||||||
"additional-info": "Zusätzliche Informationen",
|
"additional-info": "Zusätzliche Informationen",
|
||||||
"signature-saved-alert": "Unterschrift erfolgreich gespeichert.",
|
"signature-saved-alert": "erfolgreich gespeichert.",
|
||||||
"saved-successfully": "Erfolgreich gespeichert.",
|
"saved-successfully": "Erfolgreich gespeichert.",
|
||||||
"fill-field": "Bitte dieses Feld ausfüllen",
|
"fill-field": "Bitte dieses Feld ausfüllen",
|
||||||
"error-template": "Fehler: Vorlage nicht gefunden!",
|
"error-template": "Fehler: Vorlage nicht gefunden!",
|
||||||
@@ -1243,6 +1244,7 @@
|
|||||||
},
|
},
|
||||||
"read-only-date-error": "Das schreibgeschützte Datums-Widget muss ein Standarddatum haben.",
|
"read-only-date-error": "Das schreibgeschützte Datums-Widget muss ein Standarddatum haben.",
|
||||||
"set-date": "Datum festlegen",
|
"set-date": "Datum festlegen",
|
||||||
|
"default-date": "Standarddatum",
|
||||||
"set-today": "Unterzeichnungsdatum",
|
"set-today": "Unterzeichnungsdatum",
|
||||||
"enter-name": "Name eingeben",
|
"enter-name": "Name eingeben",
|
||||||
"enter-email": "E-Mail eingeben",
|
"enter-email": "E-Mail eingeben",
|
||||||
@@ -1308,5 +1310,35 @@
|
|||||||
"your-credits-usage": "Ihr Kreditverbrauch",
|
"your-credits-usage": "Ihr Kreditverbrauch",
|
||||||
"remaining": "verbleibend",
|
"remaining": "verbleibend",
|
||||||
"used": "verwendet",
|
"used": "verwendet",
|
||||||
"your-credits-usage-help": "Dies ist die Anzahl der Credits, die mit Ihrem API-Schlüssel verbraucht wurden."
|
"your-credits-usage-help": "Dies ist die Anzahl der Credits, die mit Ihrem API-Schlüssel verbraucht wurden.",
|
||||||
|
"api-credits-updated": "API-Credits wurden erfolgreich zugewiesen.",
|
||||||
|
"min-date": "Mindestdatum",
|
||||||
|
"max-date": "Höchstdatum",
|
||||||
|
"invalid-min-date": "Ungültiges Mindestdatum.",
|
||||||
|
"min-less-max": "Das Mindestdatum muss kleiner oder gleich dem Höchstdatum sein.",
|
||||||
|
"invalid-max-date": "Ungültiges Höchstdatum.",
|
||||||
|
"max-less-min": "Das Höchstdatum muss größer oder gleich dem Mindestdatum sein.",
|
||||||
|
"date-range": "Datumsbereich",
|
||||||
|
"date-range-help": "Legen Sie ein Mindest- und/oder Höchstdatum fest, um die Auswahl einzuschränken. Das gewählte Datum muss innerhalb dieses Bereichs liegen.",
|
||||||
|
"option-disabled-by-owner": "Der Dokumentersteller hat diese Option deaktiviert",
|
||||||
|
"pen-colors": "Stiftfarben",
|
||||||
|
"pen-colors-help": "Wählen Sie aus, welche Stiftfarben für Signatur- und Initialen-Widgets verfügbar sind. Aktivieren Sie ein Kontrollkästchen, um eine Farbe anzuzeigen, und deaktivieren Sie es, um sie auszublenden.",
|
||||||
|
"security-key": "Sicherheitsschlüssel",
|
||||||
|
"remove-limit": "Limit entfernen",
|
||||||
|
"removed-api-credits": "Das API-Credit-Limit wurde entfernt.",
|
||||||
|
"enable-authentication": "Authentifizierung aktivieren",
|
||||||
|
"working": "In Bearbeitung",
|
||||||
|
"test-security-key": "Sicherheitsschlüssel testen",
|
||||||
|
"generate": "Generieren",
|
||||||
|
"regenerate": "Neu generieren",
|
||||||
|
"signing-date": "Signierdatum",
|
||||||
|
"date-widget": "Datums-Widget",
|
||||||
|
"mail-failed": "Beim Senden der E-Mail ist etwas schiefgelaufen. Bitte versuchen Sie es erneut.",
|
||||||
|
"mail-status-head": "Nächster Schritt: Ihr Dokument unterschreiben?",
|
||||||
|
"send-to-email": "Per E-Mail senden",
|
||||||
|
"date-pref-help-sub-title": "Mit den Datums-Widget-Einstellungen können Sie die Standardkonfiguration für das Datums-Widget festlegen. Diese Standards werden automatisch angewendet, wenn Sie ein neues Datums-Widget zu einem Dokument oder einer Vorlage hinzufügen. Sie können jedes Datums-Widget jederzeit individuell anpassen, indem Sie auf das Zahnradsymbol klicken.",
|
||||||
|
"date-pref-help-format": "Wählen Sie das standardmäßige Datumsformat für Datums-Widgets.",
|
||||||
|
"date-pref-help-default-date": "Legen Sie einen Standard-Datumswert für Datums-Widgets fest.",
|
||||||
|
"date-pref-help-signing-date": "Wenn aktiviert, verwendet das Datums-Widget automatisch das Datum, an dem der Unterzeichner das Dokument signiert.",
|
||||||
|
"date-pref-help-read-only": "Wenn aktiviert, ist das Datums-Widget für den Unterzeichner schreibgeschützt."
|
||||||
}
|
}
|
||||||
@@ -270,7 +270,7 @@
|
|||||||
"signature": "Signature",
|
"signature": "Signature",
|
||||||
"upload-image": " Upload image",
|
"upload-image": " Upload image",
|
||||||
"clear": "Clear",
|
"clear": "Clear",
|
||||||
"upload-signature/Image": "Please upload signature/Image",
|
"upload-signature/Image": "Please upload signature/Image/stamp",
|
||||||
"initials": "Initials",
|
"initials": "Initials",
|
||||||
"API": "API",
|
"API": "API",
|
||||||
"api-token": "API token",
|
"api-token": "API token",
|
||||||
@@ -393,7 +393,8 @@
|
|||||||
"radio button": "radio button",
|
"radio button": "radio button",
|
||||||
"image": "image",
|
"image": "image",
|
||||||
"email": "email",
|
"email": "email",
|
||||||
"number": "number"
|
"number": "number",
|
||||||
|
"draw": "draw"
|
||||||
},
|
},
|
||||||
"fields": "Fields",
|
"fields": "Fields",
|
||||||
"recipients": "Recipients",
|
"recipients": "Recipients",
|
||||||
@@ -517,7 +518,7 @@
|
|||||||
"placeholder-alert-4": "You have successfully sent mails to all recipients!",
|
"placeholder-alert-4": "You have successfully sent mails to all recipients!",
|
||||||
"placeholder-mail-alert": "You have successfully sent email to {{name}}. Subsequent signers will get email(s) once {{name}} signs the document",
|
"placeholder-mail-alert": "You have successfully sent email to {{name}}. Subsequent signers will get email(s) once {{name}} signs the document",
|
||||||
"placeholder-mail-alert-you": "Subsequent signers will get email(s) once you sign the document.",
|
"placeholder-mail-alert-you": "Subsequent signers will get email(s) once you sign the document.",
|
||||||
"placeholder-alert-5": "Do you want to sign the document right now?",
|
"placeholder-alert-5": "You can sign now or send it to your email to complete later.",
|
||||||
"placeholder-alert-6": "Please setup mail adapter to send mail!",
|
"placeholder-alert-6": "Please setup mail adapter to send mail!",
|
||||||
"placeholder-alert-7": "Please select signer for add placeholder!",
|
"placeholder-alert-7": "Please select signer for add placeholder!",
|
||||||
"email-subject": "email subject",
|
"email-subject": "email subject",
|
||||||
@@ -589,7 +590,7 @@
|
|||||||
"provide-your-details": "Provide your details",
|
"provide-your-details": "Provide your details",
|
||||||
"provide-email": "Please provide email.",
|
"provide-email": "Please provide email.",
|
||||||
"additional-info": "Additional info",
|
"additional-info": "Additional info",
|
||||||
"signature-saved-alert": "Signature saved successfully.",
|
"signature-saved-alert": "Saved successfully.",
|
||||||
"saved-successfully": "Saved successfully.",
|
"saved-successfully": "Saved successfully.",
|
||||||
"fill-field": "Please fill out this field",
|
"fill-field": "Please fill out this field",
|
||||||
"error-template": "Error: Template not found!",
|
"error-template": "Error: Template not found!",
|
||||||
@@ -1244,6 +1245,7 @@
|
|||||||
},
|
},
|
||||||
"read-only-date-error": "Read-only date widget must have a default date.",
|
"read-only-date-error": "Read-only date widget must have a default date.",
|
||||||
"set-date": "Set Date",
|
"set-date": "Set Date",
|
||||||
|
"default-date": "Default Date",
|
||||||
"set-today": "Signing Date",
|
"set-today": "Signing Date",
|
||||||
"enter-name": "Enter name",
|
"enter-name": "Enter name",
|
||||||
"enter-email": "Enter email",
|
"enter-email": "Enter email",
|
||||||
@@ -1309,5 +1311,35 @@
|
|||||||
"your-credits-usage": "Your credits usage",
|
"your-credits-usage": "Your credits usage",
|
||||||
"remaining": "remaining",
|
"remaining": "remaining",
|
||||||
"used": "used",
|
"used": "used",
|
||||||
"your-credits-usage-help": "This is the number of credits consumed with your API key."
|
"your-credits-usage-help": "This is the number of credits consumed with your API key.",
|
||||||
|
"api-credits-updated": "API credits have been allocated successfully.",
|
||||||
|
"min-date": "Min Date",
|
||||||
|
"max-date": "Max Date",
|
||||||
|
"invalid-min-date": "Invalid min date.",
|
||||||
|
"min-less-max": "Min date must be less than or equal to max date.",
|
||||||
|
"invalid-max-date": "Invalid max date.",
|
||||||
|
"max-less-min": "Max date must be greater than or equal to min date.",
|
||||||
|
"date-range": "Date range",
|
||||||
|
"date-range-help": "Set Min and/or Max to restrict selection. Chosen date must fall within the range.",
|
||||||
|
"option-disabled-by-owner": "Document creator has disabled this option",
|
||||||
|
"pen-colors": "Pen colors",
|
||||||
|
"pen-colors-help": "Choose which pen colors are available for Signature and Initials widgets. Check to show a color, uncheck to hide it.",
|
||||||
|
"security-key": "Security key",
|
||||||
|
"remove-limit": "Remove limit",
|
||||||
|
"removed-api-credits": "The API credit limit has been removed.",
|
||||||
|
"enable-authentication": "Enable authentication",
|
||||||
|
"working": "Working",
|
||||||
|
"test-security-key": "Test security key",
|
||||||
|
"generate": "Generate",
|
||||||
|
"regenerate": "Regenerate",
|
||||||
|
"signing-date": "Signing Date",
|
||||||
|
"date-widget": "Date Widget",
|
||||||
|
"mail-failed": "Something went wrong while sending the email. Please try again.",
|
||||||
|
"mail-status-head": "Next step: Sign your document ?",
|
||||||
|
"send-to-email": "Send to Email",
|
||||||
|
"date-pref-help-sub-title": "Date Widget Preferences let you define the default settings for the Date widget. These defaults are automatically applied whenever you add a new Date widget to a document or template. You can still customize any individual Date widget at any time by clicking the gear icon.",
|
||||||
|
"date-pref-help-format": "Choose the default date format used for Date widgets.",
|
||||||
|
"date-pref-help-default-date": "Set a default date value for Date widgets.",
|
||||||
|
"date-pref-help-signing-date": "When enabled, the Date widget automatically uses the date the signer signs the document.",
|
||||||
|
"date-pref-help-read-only": "When enabled, the Date widget is read-only for the signer."
|
||||||
}
|
}
|
||||||
@@ -270,7 +270,7 @@
|
|||||||
"signature": "Firma",
|
"signature": "Firma",
|
||||||
"upload-image": " Subir imagen",
|
"upload-image": " Subir imagen",
|
||||||
"clear": "Limpiar",
|
"clear": "Limpiar",
|
||||||
"upload-signature/Image": "Por favor, sube la firma/imagen",
|
"upload-signature/Image": "Por favor, sube la firma/imagen/estampilla",
|
||||||
"initials": "Iniciales",
|
"initials": "Iniciales",
|
||||||
"API": "API",
|
"API": "API",
|
||||||
"api-token": "Token API",
|
"api-token": "Token API",
|
||||||
@@ -393,7 +393,8 @@
|
|||||||
"radio button": "botón de radio",
|
"radio button": "botón de radio",
|
||||||
"image": "imagen",
|
"image": "imagen",
|
||||||
"email": "correo",
|
"email": "correo",
|
||||||
"number": "número"
|
"number": "número",
|
||||||
|
"draw": "Dibujar"
|
||||||
},
|
},
|
||||||
"fields": "Campos",
|
"fields": "Campos",
|
||||||
"recipients": "Destinatarios",
|
"recipients": "Destinatarios",
|
||||||
@@ -517,7 +518,7 @@
|
|||||||
"placeholder-alert-4": "¡Has enviado exitosamente correos a todos los destinatarios!",
|
"placeholder-alert-4": "¡Has enviado exitosamente correos a todos los destinatarios!",
|
||||||
"placeholder-mail-alert": "Has enviado un correo electrónico con éxito a {{name}}. Los siguientes firmantes recibirán un correo electrónico una vez que {{name}} firme el documento.",
|
"placeholder-mail-alert": "Has enviado un correo electrónico con éxito a {{name}}. Los siguientes firmantes recibirán un correo electrónico una vez que {{name}} firme el documento.",
|
||||||
"placeholder-mail-alert-you": "Los firmantes siguientes recibirán un correo electrónico una vez que usted firme el documento.",
|
"placeholder-mail-alert-you": "Los firmantes siguientes recibirán un correo electrónico una vez que usted firme el documento.",
|
||||||
"placeholder-alert-5": "¿Quieres firmar documentos ahora mismo?",
|
"placeholder-alert-5": "Puede firmar ahora o enviarlo a su correo electrónico para completarlo más tarde.",
|
||||||
"placeholder-alert-6": "¡Por favor, configura el adaptador de correo para enviar correos!",
|
"placeholder-alert-6": "¡Por favor, configura el adaptador de correo para enviar correos!",
|
||||||
"placeholder-alert-7": "¡Por favor, selecciona un firmante para agregar un marcador de posición!",
|
"placeholder-alert-7": "¡Por favor, selecciona un firmante para agregar un marcador de posición!",
|
||||||
"email-subject": "asunto del correo",
|
"email-subject": "asunto del correo",
|
||||||
@@ -589,7 +590,7 @@
|
|||||||
"provide-your-details": "Proporciona tus detalles",
|
"provide-your-details": "Proporciona tus detalles",
|
||||||
"provide-email": "Por favor, proporciona un correo.",
|
"provide-email": "Por favor, proporciona un correo.",
|
||||||
"additional-info": "Información adicional",
|
"additional-info": "Información adicional",
|
||||||
"signature-saved-alert": "Firma guardada exitosamente.",
|
"signature-saved-alert": "guardada exitosamente.",
|
||||||
"saved-successfully": "Guardado con éxito.",
|
"saved-successfully": "Guardado con éxito.",
|
||||||
"fill-field": "Por favor, rellena este campo",
|
"fill-field": "Por favor, rellena este campo",
|
||||||
"error-template": "Error: ¡Plantilla no encontrada!",
|
"error-template": "Error: ¡Plantilla no encontrada!",
|
||||||
@@ -1244,6 +1245,7 @@
|
|||||||
},
|
},
|
||||||
"read-only-date-error": "El widget de fecha de solo lectura debe tener una fecha predeterminada.",
|
"read-only-date-error": "El widget de fecha de solo lectura debe tener una fecha predeterminada.",
|
||||||
"set-date": "Establecer fecha",
|
"set-date": "Establecer fecha",
|
||||||
|
"default-date": "Fecha predeterminada",
|
||||||
"set-today": "Fecha de firma",
|
"set-today": "Fecha de firma",
|
||||||
"enter-name": "Ingrese nombre",
|
"enter-name": "Ingrese nombre",
|
||||||
"enter-email": "Ingrese correo electrónico",
|
"enter-email": "Ingrese correo electrónico",
|
||||||
@@ -1309,5 +1311,35 @@
|
|||||||
"your-credits-usage": "Uso de sus créditos",
|
"your-credits-usage": "Uso de sus créditos",
|
||||||
"remaining": "restantes",
|
"remaining": "restantes",
|
||||||
"used": "usados",
|
"used": "usados",
|
||||||
"your-credits-usage-help": "Esta es la cantidad de créditos consumidos con su clave API."
|
"your-credits-usage-help": "Esta es la cantidad de créditos consumidos con su clave API.",
|
||||||
|
"api-credits-updated": "Los créditos de API se han asignado correctamente.",
|
||||||
|
"min-date": "Fecha mínima",
|
||||||
|
"max-date": "Fecha máxima",
|
||||||
|
"invalid-min-date": "Fecha mínima no válida.",
|
||||||
|
"min-less-max": "La fecha mínima debe ser menor o igual a la fecha máxima.",
|
||||||
|
"invalid-max-date": "Fecha máxima no válida.",
|
||||||
|
"max-less-min": "La fecha máxima debe ser mayor o igual a la fecha mínima.",
|
||||||
|
"date-range": "Rango de fechas",
|
||||||
|
"date-range-help": "Establezca una fecha mínima y/o máxima para restringir la selección. La fecha elegida debe estar dentro del rango.",
|
||||||
|
"option-disabled-by-owner": "El creador del documento ha deshabilitado esta opción",
|
||||||
|
"pen-colors": "Colores del bolígrafo",
|
||||||
|
"pen-colors-help": "Elija qué colores de bolígrafo están disponibles para los widgets de Firma e Iniciales. Marque una casilla para mostrar un color y desmárquela para ocultarlo.",
|
||||||
|
"security-key": "Clave de seguridad",
|
||||||
|
"remove-limit": "Eliminar límite",
|
||||||
|
"removed-api-credits": "El límite de créditos API ha sido eliminado.",
|
||||||
|
"enable-authentication": "Habilitar autenticación",
|
||||||
|
"working": "En funcionamiento",
|
||||||
|
"test-security-key": "Probar clave de seguridad",
|
||||||
|
"generate": "Generar",
|
||||||
|
"regenerate": "Regenerar",
|
||||||
|
"signing-date": "Fecha de firma",
|
||||||
|
"date-widget": "Widget de fecha",
|
||||||
|
"mail-failed": "Algo salió mal al enviar el correo electrónico. Por favor, inténtelo de nuevo.",
|
||||||
|
"mail-status-head": "Siguiente paso: ¿Firmar su documento?",
|
||||||
|
"send-to-email": "Enviar por correo electrónico",
|
||||||
|
"date-pref-help-sub-title": "Las preferencias del widget de fecha le permiten definir la configuración predeterminada del widget de fecha. Estos valores se aplican automáticamente cada vez que añade un nuevo widget de fecha a un documento o plantilla. Aún puede personalizar cualquier widget de fecha individual en cualquier momento haciendo clic en el icono de engranaje.",
|
||||||
|
"date-pref-help-format": "Elija el formato de fecha predeterminado utilizado para los widgets de fecha.",
|
||||||
|
"date-pref-help-default-date": "Establezca un valor de fecha predeterminado para los widgets de fecha.",
|
||||||
|
"date-pref-help-signing-date": "Cuando está habilitado, el widget de fecha utiliza automáticamente la fecha en que el firmante firma el documento.",
|
||||||
|
"date-pref-help-read-only": "Cuando está habilitado, el widget de fecha es de solo lectura para el firmante."
|
||||||
}
|
}
|
||||||
@@ -270,7 +270,7 @@
|
|||||||
"signature": "Signature",
|
"signature": "Signature",
|
||||||
"upload-image": "Télécharger une image",
|
"upload-image": "Télécharger une image",
|
||||||
"clear": "Vider",
|
"clear": "Vider",
|
||||||
"upload-signature/Image": "télécharger-signature/Image",
|
"upload-signature/Image": "télécharger-signature/Image/timbre",
|
||||||
"initials": "Initiales",
|
"initials": "Initiales",
|
||||||
"API": "API",
|
"API": "API",
|
||||||
"api-token": "Jeton API",
|
"api-token": "Jeton API",
|
||||||
@@ -393,7 +393,8 @@
|
|||||||
"radio button": "bouton radio",
|
"radio button": "bouton radio",
|
||||||
"image": "image",
|
"image": "image",
|
||||||
"email": "e-mail",
|
"email": "e-mail",
|
||||||
"number": "nombre"
|
"number": "nombre",
|
||||||
|
"draw": "Dessiner"
|
||||||
},
|
},
|
||||||
"fields": "Des champs",
|
"fields": "Des champs",
|
||||||
"recipients": "Destinataires",
|
"recipients": "Destinataires",
|
||||||
@@ -516,7 +517,7 @@
|
|||||||
"placeholder-alert-4": "Vous avez envoyé avec succès des mails à tous les",
|
"placeholder-alert-4": "Vous avez envoyé avec succès des mails à tous les",
|
||||||
"placeholder-mail-alert": "Vous avez envoyé un e-mail avec succès à {{name}}. Les signataires suivants recevront un e-mail une fois que {{name}} aura signé le document.",
|
"placeholder-mail-alert": "Vous avez envoyé un e-mail avec succès à {{name}}. Les signataires suivants recevront un e-mail une fois que {{name}} aura signé le document.",
|
||||||
"placeholder-mail-alert-you": "Les signataires suivants recevront un e-mail une fois que vous aurez signé le document.",
|
"placeholder-mail-alert-you": "Les signataires suivants recevront un e-mail une fois que vous aurez signé le document.",
|
||||||
"placeholder-alert-5": "Voulez-vous signer des documents maintenant ?",
|
"placeholder-alert-5": "Vous pouvez signer maintenant ou l’envoyer à votre e-mail pour le terminer plus tard.",
|
||||||
"placeholder-alert-6": "Veuillez configurer l'adaptateur de messagerie pour envoyer du courrier !",
|
"placeholder-alert-6": "Veuillez configurer l'adaptateur de messagerie pour envoyer du courrier !",
|
||||||
"placeholder-alert-7": "Veuillez sélectionner le signataire pour ajouter un espace réservé !",
|
"placeholder-alert-7": "Veuillez sélectionner le signataire pour ajouter un espace réservé !",
|
||||||
"email-subject": "Sujet du courriel",
|
"email-subject": "Sujet du courriel",
|
||||||
@@ -588,7 +589,7 @@
|
|||||||
"provide-your-details": "Fournissez vos coordonnées",
|
"provide-your-details": "Fournissez vos coordonnées",
|
||||||
"provide-email": "Veuillez fournir un e-mail.",
|
"provide-email": "Veuillez fournir un e-mail.",
|
||||||
"additional-info": "Information additionnelle",
|
"additional-info": "Information additionnelle",
|
||||||
"signature-saved-alert": "Signature enregistrée avec succès.",
|
"signature-saved-alert": "enregistrée avec succès.",
|
||||||
"saved-successfully": "Enregistré avec succès.",
|
"saved-successfully": "Enregistré avec succès.",
|
||||||
"fill-field": "Veuillez remplir ce champ",
|
"fill-field": "Veuillez remplir ce champ",
|
||||||
"error-template": "Erreur : modèle introuvable ! ",
|
"error-template": "Erreur : modèle introuvable ! ",
|
||||||
@@ -1243,6 +1244,7 @@
|
|||||||
},
|
},
|
||||||
"read-only-date-error": "Le widget de date en lecture seule doit avoir une date par défaut.",
|
"read-only-date-error": "Le widget de date en lecture seule doit avoir une date par défaut.",
|
||||||
"set-date": "Définir la date",
|
"set-date": "Définir la date",
|
||||||
|
"default-date": "Date par défaut",
|
||||||
"set-today": "Date de signature",
|
"set-today": "Date de signature",
|
||||||
"enter-name": "Saisir le nom",
|
"enter-name": "Saisir le nom",
|
||||||
"enter-email": "Saisir l'e-mail",
|
"enter-email": "Saisir l'e-mail",
|
||||||
@@ -1308,5 +1310,35 @@
|
|||||||
"your-credits-usage": "Votre utilisation des crédits",
|
"your-credits-usage": "Votre utilisation des crédits",
|
||||||
"remaining": "restants",
|
"remaining": "restants",
|
||||||
"used": "utilisés",
|
"used": "utilisés",
|
||||||
"your-credits-usage-help": "Ceci est le nombre de crédits consommés avec votre clé API."
|
"your-credits-usage-help": "Ceci est le nombre de crédits consommés avec votre clé API.",
|
||||||
|
"api-credits-updated": "Les crédits API ont été attribués avec succès.",
|
||||||
|
"min-date": "Date minimale",
|
||||||
|
"max-date": "Date maximale",
|
||||||
|
"invalid-min-date": "Date minimale invalide.",
|
||||||
|
"min-less-max": "La date minimale doit être inférieure ou égale à la date maximale.",
|
||||||
|
"invalid-max-date": "Date maximale invalide.",
|
||||||
|
"max-less-min": "La date maximale doit être supérieure ou égale à la date minimale.",
|
||||||
|
"date-range": "Plage de dates",
|
||||||
|
"date-range-help": "Définissez une date minimale et/ou maximale pour restreindre la sélection. La date choisie doit se situer dans cette plage.",
|
||||||
|
"option-disabled-by-owner": "Le créateur du document a désactivé cette option",
|
||||||
|
"pen-colors": "Couleurs du stylo",
|
||||||
|
"pen-colors-help": "Choisissez quelles couleurs de stylo sont disponibles pour les widgets Signature et Initiales. Cochez pour afficher une couleur, décochez pour la masquer.",
|
||||||
|
"security-key": "Clé de sécurité",
|
||||||
|
"remove-limit": "Supprimer la limite",
|
||||||
|
"removed-api-credits": "La limite de crédits API a été supprimée.",
|
||||||
|
"enable-authentication": "Activer l'authentification",
|
||||||
|
"working": "En cours",
|
||||||
|
"test-security-key": "Tester la clé de sécurité",
|
||||||
|
"generate": "Générer",
|
||||||
|
"regenerate": "Régénérer",
|
||||||
|
"signing-date": "Date de signature",
|
||||||
|
"date-widget": "Widget de date",
|
||||||
|
"mail-failed": "Une erreur s'est produite lors de l'envoi de l'e-mail. Veuillez réessayer.",
|
||||||
|
"mail-status-head": "Étape suivante : signer votre document ?",
|
||||||
|
"send-to-email": "Envoyer par e-mail",
|
||||||
|
"date-pref-help-sub-title": "Les préférences du widget de date vous permettent de définir les paramètres par défaut du widget de date. Ces paramètres sont automatiquement appliqués lorsque vous ajoutez un nouveau widget de date à un document ou à un modèle. Vous pouvez toujours personnaliser chaque widget de date individuellement en cliquant sur l'icône d'engrenage.",
|
||||||
|
"date-pref-help-format": "Choisissez le format de date par défaut utilisé pour les widgets de date.",
|
||||||
|
"date-pref-help-default-date": "Définissez une valeur de date par défaut pour les widgets de date.",
|
||||||
|
"date-pref-help-signing-date": "Lorsqu'elle est activée, le widget de date utilise automatiquement la date à laquelle le signataire signe le document.",
|
||||||
|
"date-pref-help-read-only": "Lorsqu'elle est activée, le widget de date est en lecture seule pour le signataire."
|
||||||
}
|
}
|
||||||
@@ -270,7 +270,7 @@
|
|||||||
"signature": "हस्ताक्षर",
|
"signature": "हस्ताक्षर",
|
||||||
"upload-image": " छवि अपलोड करें",
|
"upload-image": " छवि अपलोड करें",
|
||||||
"clear": "स्पष्ट",
|
"clear": "स्पष्ट",
|
||||||
"upload-signature/Image": "कृपया हस्ताक्षर/छवि अपलोड करें",
|
"upload-signature/Image": "कृपया हस्ताक्षर/छवि अपलोड करें/मोहर",
|
||||||
"initials": "हस्ताक्षर",
|
"initials": "हस्ताक्षर",
|
||||||
"API": "एपीआई",
|
"API": "एपीआई",
|
||||||
"api-token": "एपीआई टोकन",
|
"api-token": "एपीआई टोकन",
|
||||||
@@ -393,7 +393,8 @@
|
|||||||
"radio button": "रेडियो बटन",
|
"radio button": "रेडियो बटन",
|
||||||
"image": "छवि",
|
"image": "छवि",
|
||||||
"email": "ईमेल",
|
"email": "ईमेल",
|
||||||
"number": "संख्या"
|
"number": "संख्या",
|
||||||
|
"draw": "आरेखित करें"
|
||||||
},
|
},
|
||||||
"fields": "क्षेत्र",
|
"fields": "क्षेत्र",
|
||||||
"recipients": "प्राप्तकर्ता",
|
"recipients": "प्राप्तकर्ता",
|
||||||
@@ -516,7 +517,7 @@
|
|||||||
"placeholder-alert-4": "आपने सभी प्राप्तकर्ताओं को सफलतापूर्वक मेल भेज दिए हैं!",
|
"placeholder-alert-4": "आपने सभी प्राप्तकर्ताओं को सफलतापूर्वक मेल भेज दिए हैं!",
|
||||||
"placeholder-mail-alert": "आपने {{name}} को सफलतापूर्वक ईमेल भेज दिया है। {{name}} द्वारा दस्तावेज़ पर हस्ताक्षर करने के बाद बाद के हस्ताक्षरकर्ताओं को ईमेल प्राप्त होंगे",
|
"placeholder-mail-alert": "आपने {{name}} को सफलतापूर्वक ईमेल भेज दिया है। {{name}} द्वारा दस्तावेज़ पर हस्ताक्षर करने के बाद बाद के हस्ताक्षरकर्ताओं को ईमेल प्राप्त होंगे",
|
||||||
"placeholder-mail-alert-you": "आपके दस्तावेज़ पर हस्ताक्षर करने के बाद अगले हस्ताक्षरकर्ता को ईमेल प्राप्त होगा।",
|
"placeholder-mail-alert-you": "आपके दस्तावेज़ पर हस्ताक्षर करने के बाद अगले हस्ताक्षरकर्ता को ईमेल प्राप्त होगा।",
|
||||||
"placeholder-alert-5": "क्या आप अभी दस्तावेज़ पर हस्ताक्षर करना चाहते हैं?",
|
"placeholder-alert-5": "आप अभी हस्ताक्षर कर सकते हैं या इसे बाद में पूरा करने के लिए अपने ईमेल पर भेज सकते हैं।",
|
||||||
"placeholder-alert-6": "मेल भेजने के लिए कृपया मेल एडॉप्टर सेटअप करें!",
|
"placeholder-alert-6": "मेल भेजने के लिए कृपया मेल एडॉप्टर सेटअप करें!",
|
||||||
"placeholder-alert-7": "प्लेसहोल्डर जोड़ने के लिए कृपया हस्ताक्षरकर्ता चुनें!",
|
"placeholder-alert-7": "प्लेसहोल्डर जोड़ने के लिए कृपया हस्ताक्षरकर्ता चुनें!",
|
||||||
"email-subject": "ईमेल विषय",
|
"email-subject": "ईमेल विषय",
|
||||||
@@ -588,7 +589,7 @@
|
|||||||
"provide-your-details": "अपना विवरण प्रदान करें",
|
"provide-your-details": "अपना विवरण प्रदान करें",
|
||||||
"provide-email": "कृपया ईमेल प्रदान करें।",
|
"provide-email": "कृपया ईमेल प्रदान करें।",
|
||||||
"additional-info": "अतिरिक्त जानकारी",
|
"additional-info": "अतिरिक्त जानकारी",
|
||||||
"signature-saved-alert": "हस्ताक्षर सफलतापूर्वक सहेजा गया।",
|
"signature-saved-alert": "सफलतापूर्वक सहेजा गया।",
|
||||||
"saved-successfully": "सफलतापूर्वक सहेजा गया।",
|
"saved-successfully": "सफलतापूर्वक सहेजा गया।",
|
||||||
"fill-field": "कृपया इस फ़ील्ड को भरें",
|
"fill-field": "कृपया इस फ़ील्ड को भरें",
|
||||||
"error-template": "त्रुटि: टेम्पलेट नहीं मिला!",
|
"error-template": "त्रुटि: टेम्पलेट नहीं मिला!",
|
||||||
@@ -1243,6 +1244,7 @@
|
|||||||
},
|
},
|
||||||
"read-only-date-error": "रीड-ओनली दिनांक विजेट में एक डिफ़ॉल्ट दिनांक होना आवश्यक है।",
|
"read-only-date-error": "रीड-ओनली दिनांक विजेट में एक डिफ़ॉल्ट दिनांक होना आवश्यक है।",
|
||||||
"set-date": "दिनांक सेट करें",
|
"set-date": "दिनांक सेट करें",
|
||||||
|
"default-date": "डिफ़ॉल्ट तिथि",
|
||||||
"set-today": "हस्ताक्षर की तिथि",
|
"set-today": "हस्ताक्षर की तिथि",
|
||||||
"enter-name": "नाम दर्ज करें",
|
"enter-name": "नाम दर्ज करें",
|
||||||
"enter-email": "ईमेल दर्ज करें",
|
"enter-email": "ईमेल दर्ज करें",
|
||||||
@@ -1308,5 +1310,35 @@
|
|||||||
"your-credits-usage": "आपके क्रेडिट उपयोग",
|
"your-credits-usage": "आपके क्रेडिट उपयोग",
|
||||||
"remaining": "शेष",
|
"remaining": "शेष",
|
||||||
"used": "उपयोग किए गए",
|
"used": "उपयोग किए गए",
|
||||||
"your-credits-usage-help": "यह आपके API कुंजी द्वारा उपभोग किए गए क्रेडिट की संख्या है।"
|
"your-credits-usage-help": "यह आपके API कुंजी द्वारा उपभोग किए गए क्रेडिट की संख्या है।",
|
||||||
|
"api-credits-updated": "API क्रेडिट सफलतापूर्वक आवंटित कर दिए गए हैं।",
|
||||||
|
"min-date": "न्यूनतम तिथि",
|
||||||
|
"max-date": "अधिकतम तिथि",
|
||||||
|
"invalid-min-date": "अमान्य न्यूनतम तिथि।",
|
||||||
|
"min-less-max": "न्यूनतम तिथि अधिकतम तिथि से कम या उसके बराबर होनी चाहिए।",
|
||||||
|
"invalid-max-date": "अमान्य अधिकतम तिथि।",
|
||||||
|
"max-less-min": "अधिकतम तिथि न्यूनतम तिथि से अधिक या उसके बराबर होनी चाहिए।",
|
||||||
|
"date-range": "तिथि सीमा",
|
||||||
|
"date-range-help": "चयन को सीमित करने के लिए न्यूनतम और/या अधिकतम तिथि सेट करें। चयनित तिथि इस सीमा के भीतर होनी चाहिए।",
|
||||||
|
"option-disabled-by-owner": "दस्तावेज़ निर्माता ने इस विकल्प को अक्षम कर दिया है",
|
||||||
|
"pen-colors": "पेन के रंग",
|
||||||
|
"pen-colors-help": "हस्ताक्षर और प्रारंभिक विजेट्स के लिए उपलब्ध पेन रंग चुनें। किसी रंग को दिखाने के लिए चेक करें और छिपाने के लिए अनचेक करें।",
|
||||||
|
"security-key": "सुरक्षा कुंजी",
|
||||||
|
"remove-limit": "सीमा हटाएँ",
|
||||||
|
"removed-api-credits": "API क्रेडिट सीमा हटा दी गई है।",
|
||||||
|
"enable-authentication": "प्रमाणीकरण सक्षम करें",
|
||||||
|
"working": "कार्यरत",
|
||||||
|
"test-security-key": "सुरक्षा कुंजी का परीक्षण करें",
|
||||||
|
"generate": "जनरेट करें",
|
||||||
|
"regenerate": "पुनः जनरेट करें",
|
||||||
|
"signing-date": "हस्ताक्षर तिथि",
|
||||||
|
"date-widget": "तिथि विजेट",
|
||||||
|
"mail-failed": "ईमेल भेजते समय कुछ गलत हो गया। कृपया पुनः प्रयास करें।",
|
||||||
|
"mail-status-head": "अगला कदम: अपने दस्तावेज़ पर हस्ताक्षर करें?",
|
||||||
|
"send-to-email": "ईमेल पर भेजें",
|
||||||
|
"date-pref-help-sub-title": "डेट विजेट प्राथमिकताएँ आपको डेट विजेट के लिए डिफ़ॉल्ट सेटिंग्स निर्धारित करने की अनुमति देती हैं। जब भी आप किसी दस्तावेज़ या टेम्पलेट में नया डेट विजेट जोड़ते हैं, ये डिफ़ॉल्ट सेटिंग्स स्वतः लागू हो जाती हैं। आप गियर आइकन पर क्लिक करके किसी भी डेट विजेट को कभी भी अनुकूलित कर सकते हैं।",
|
||||||
|
"date-pref-help-format": "डेट विजेट के लिए उपयोग किए जाने वाले डिफ़ॉल्ट तिथि प्रारूप का चयन करें।",
|
||||||
|
"date-pref-help-default-date": "डेट विजेट के लिए एक डिफ़ॉल्ट तिथि मान सेट करें।",
|
||||||
|
"date-pref-help-signing-date": "सक्षम होने पर, डेट विजेट स्वतः उस तिथि का उपयोग करता है जब साइनर दस्तावेज़ पर हस्ताक्षर करता है।",
|
||||||
|
"date-pref-help-read-only": "सक्षम होने पर, डेट विजेट साइनर के लिए केवल-पढ़ने योग्य होता है।"
|
||||||
}
|
}
|
||||||
@@ -270,7 +270,7 @@
|
|||||||
"signature": "Firma",
|
"signature": "Firma",
|
||||||
"upload-image": "Carica immagine",
|
"upload-image": "Carica immagine",
|
||||||
"clear": "Cancella",
|
"clear": "Cancella",
|
||||||
"upload-signature/Image": "Carica firma/immagine",
|
"upload-signature/Image": "Carica firma/immagine/timbro",
|
||||||
"initials": "Iniziali",
|
"initials": "Iniziali",
|
||||||
"API": "API",
|
"API": "API",
|
||||||
"api-token": "Token API",
|
"api-token": "Token API",
|
||||||
@@ -393,7 +393,8 @@
|
|||||||
"radio button": "pulsante di opzione",
|
"radio button": "pulsante di opzione",
|
||||||
"image": "immagine",
|
"image": "immagine",
|
||||||
"email": "email",
|
"email": "email",
|
||||||
"number": "numero"
|
"number": "numero",
|
||||||
|
"draw": "Disegno"
|
||||||
},
|
},
|
||||||
"fields": "Campi",
|
"fields": "Campi",
|
||||||
"recipients": "Destinatari",
|
"recipients": "Destinatari",
|
||||||
@@ -516,7 +517,7 @@
|
|||||||
"placeholder-alert-4": "Hai inviato con successo le mail a tutti i destinatari!",
|
"placeholder-alert-4": "Hai inviato con successo le mail a tutti i destinatari!",
|
||||||
"placeholder-mail-alert": "Hai inviato con successo un'e-mail a {{name}}. I firmatari successivi riceveranno un'e-mail una volta che {{name}} avrà firmato il documento.",
|
"placeholder-mail-alert": "Hai inviato con successo un'e-mail a {{name}}. I firmatari successivi riceveranno un'e-mail una volta che {{name}} avrà firmato il documento.",
|
||||||
"placeholder-mail-alert-you": "I firmatari successivi riceveranno un'email dopo che avrai firmato il documento.",
|
"placeholder-mail-alert-you": "I firmatari successivi riceveranno un'email dopo che avrai firmato il documento.",
|
||||||
"placeholder-alert-5": "Vuoi firmare i documenti ora?",
|
"placeholder-alert-5": "Puoi firmare ora oppure inviarlo alla tua email per completarlo in seguito.",
|
||||||
"placeholder-alert-6": "Configura l'adattatore email per inviare mail!",
|
"placeholder-alert-6": "Configura l'adattatore email per inviare mail!",
|
||||||
"placeholder-alert-7": "Seleziona il firmatario per aggiungere un segnaposto!",
|
"placeholder-alert-7": "Seleziona il firmatario per aggiungere un segnaposto!",
|
||||||
"email-subject": "Oggetto email",
|
"email-subject": "Oggetto email",
|
||||||
@@ -588,7 +589,7 @@
|
|||||||
"provide-your-details": "Fornisci i tuoi dettagli",
|
"provide-your-details": "Fornisci i tuoi dettagli",
|
||||||
"provide-email": "Fornisci l'email.",
|
"provide-email": "Fornisci l'email.",
|
||||||
"additional-info": "Informazioni aggiuntive",
|
"additional-info": "Informazioni aggiuntive",
|
||||||
"signature-saved-alert": "Firma salvata con successo.",
|
"signature-saved-alert": "salvata con successo.",
|
||||||
"saved-successfully": "Salvato con successo.",
|
"saved-successfully": "Salvato con successo.",
|
||||||
"fill-field": "Compila questo campo",
|
"fill-field": "Compila questo campo",
|
||||||
"error-template": "Errore: Modello non trovato!",
|
"error-template": "Errore: Modello non trovato!",
|
||||||
@@ -1243,6 +1244,7 @@
|
|||||||
},
|
},
|
||||||
"read-only-date-error": "Il widget data di sola lettura deve avere una data predefinita.",
|
"read-only-date-error": "Il widget data di sola lettura deve avere una data predefinita.",
|
||||||
"set-date": "Imposta data",
|
"set-date": "Imposta data",
|
||||||
|
"default-date": "Data predefinita",
|
||||||
"set-today": "Data di firma",
|
"set-today": "Data di firma",
|
||||||
"enter-name": "Inserisci nome",
|
"enter-name": "Inserisci nome",
|
||||||
"enter-email": "Inserisci e-mail",
|
"enter-email": "Inserisci e-mail",
|
||||||
@@ -1308,5 +1310,35 @@
|
|||||||
"your-credits-usage": "Utilizzo dei tuoi crediti",
|
"your-credits-usage": "Utilizzo dei tuoi crediti",
|
||||||
"remaining": "rimanenti",
|
"remaining": "rimanenti",
|
||||||
"used": "usati",
|
"used": "usati",
|
||||||
"your-credits-usage-help": "Questo è il numero di crediti consumati con la tua chiave API."
|
"your-credits-usage-help": "Questo è il numero di crediti consumati con la tua chiave API.",
|
||||||
|
"api-credits-updated": "I crediti API sono stati assegnati con successo.",
|
||||||
|
"min-date": "Data minima",
|
||||||
|
"max-date": "Data massima",
|
||||||
|
"invalid-min-date": "Data minima non valida.",
|
||||||
|
"min-less-max": "La data minima deve essere minore o uguale alla data massima.",
|
||||||
|
"invalid-max-date": "Data massima non valida.",
|
||||||
|
"max-less-min": "La data massima deve essere maggiore o uguale alla data minima.",
|
||||||
|
"date-range": "Intervallo di date",
|
||||||
|
"date-range-help": "Imposta una data minima e/o massima per limitare la selezione. La data scelta deve rientrare nell'intervallo.",
|
||||||
|
"option-disabled-by-owner": "Il creatore del documento ha disabilitato questa opzione.",
|
||||||
|
"pen-colors": "Colori della penna",
|
||||||
|
"pen-colors-help": "Scegli quali colori della penna sono disponibili per i widget Firma e Iniziali. Seleziona una casella per mostrare un colore e deselezionala per nasconderlo.",
|
||||||
|
"security-key": "Chiave di sicurezza",
|
||||||
|
"remove-limit": "Rimuovi limite",
|
||||||
|
"removed-api-credits": "Il limite dei crediti API è stato rimosso.",
|
||||||
|
"enable-authentication": "Abilita autenticazione",
|
||||||
|
"working": "In funzione",
|
||||||
|
"test-security-key": "Testa la chiave di sicurezza",
|
||||||
|
"generate": "Genera",
|
||||||
|
"regenerate": "Rigenera",
|
||||||
|
"signing-date": "Data di firma",
|
||||||
|
"date-widget": "Widget data",
|
||||||
|
"mail-failed": "Si è verificato un errore durante l'invio dell'e-mail. Per favore riprova.",
|
||||||
|
"mail-status-head": "Passaggio successivo: firmare il tuo documento?",
|
||||||
|
"send-to-email": "Invia tramite email",
|
||||||
|
"date-pref-help-sub-title": "Le preferenze del widget Data consentono di definire le impostazioni predefinite per il widget Data. Queste impostazioni vengono applicate automaticamente ogni volta che si aggiunge un nuovo widget Data a un documento o a un modello. È comunque possibile personalizzare qualsiasi widget Data in qualsiasi momento facendo clic sull'icona a forma di ingranaggio.",
|
||||||
|
"date-pref-help-format": "Scegli il formato di data predefinito utilizzato per i widget Data.",
|
||||||
|
"date-pref-help-default-date": "Imposta un valore di data predefinito per i widget Data.",
|
||||||
|
"date-pref-help-signing-date": "Quando abilitato, il widget Data utilizza automaticamente la data in cui il firmatario firma il documento.",
|
||||||
|
"date-pref-help-read-only": "Quando abilitato, il widget Data è in sola lettura per il firmatario."
|
||||||
}
|
}
|
||||||
Binary file not shown.
@@ -11,6 +11,8 @@ import {
|
|||||||
import {
|
import {
|
||||||
useTranslation
|
useTranslation
|
||||||
} from "react-i18next";
|
} from "react-i18next";
|
||||||
|
import { withSessionValidation } from "../utils";
|
||||||
|
|
||||||
function generatePassword(length) {
|
function generatePassword(length) {
|
||||||
const characters =
|
const characters =
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
@@ -67,7 +69,7 @@ const AddUser = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Define a function to handle form submission
|
// Define a function to handle form submission
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = withSessionValidation(async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (!emailRegex.test(formdata.email)) {
|
if (!emailRegex.test(formdata.email)) {
|
||||||
@@ -130,7 +132,7 @@ const AddUser = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// Define a function to handle the "add yourself" checkbox
|
// Define a function to handle the "add yourself" checkbox
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
|
|||||||
@@ -190,9 +190,7 @@ const BulkSendUi = (props) => {
|
|||||||
const batchQuery = async (Documents) => {
|
const batchQuery = async (Documents) => {
|
||||||
const token =
|
const token =
|
||||||
{ "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
|
{ "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
|
||||||
const functionsUrl = `${localStorage.getItem(
|
const functionsUrl = `${localStorage.getItem("baseUrl")}functions/batchdocuments`;
|
||||||
"baseUrl"
|
|
||||||
)}functions/batchdocuments`;
|
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
@@ -201,13 +199,14 @@ const BulkSendUi = (props) => {
|
|||||||
const params = { Documents: JSON.stringify(Documents) };
|
const params = { Documents: JSON.stringify(Documents) };
|
||||||
try {
|
try {
|
||||||
const res = await axios.post(functionsUrl, params, { headers: headers });
|
const res = await axios.post(functionsUrl, params, { headers: headers });
|
||||||
// console.log("res ", res);
|
|
||||||
if (res.data && res.data.result) {
|
if (res.data && res.data.result) {
|
||||||
props.handleClose("success", Documents?.length);
|
props.handleClose("success", Documents?.length);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Err ", err);
|
const message =
|
||||||
props.handleClose("error", 0);
|
err?.response?.data?.error || err?.message || "something went wrong.";
|
||||||
|
console.error("Error sending documents:", message);
|
||||||
|
props.handleClose("error", 0, message);
|
||||||
} finally {
|
} finally {
|
||||||
setIsSubmit(false);
|
setIsSubmit(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
const DateFormat = ({ selectDate, dateFormatList, handleChangeFormat }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col md:items-center md:flex-row gap-y-3 my-2">
|
||||||
|
<span className="capitalize">{t("format")}: </span>
|
||||||
|
<select
|
||||||
|
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs md:ml-2"
|
||||||
|
defaultValue={""}
|
||||||
|
onChange={(e) => handleChangeFormat(e)}
|
||||||
|
>
|
||||||
|
<option value="" disabled>
|
||||||
|
{t("select-date-format")}
|
||||||
|
</option>
|
||||||
|
{dateFormatList.map((data, ind) => {
|
||||||
|
return (
|
||||||
|
<option className="text-[13px]" value={ind} key={ind}>
|
||||||
|
{data?.date ? data?.date : "nodata"}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
<span className="text-xs text-gray-400 ml-1 uppercase">{selectDate.format}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DateFormat;
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import { forwardRef } from "react";
|
||||||
|
import ReactDatePicker from "react-datepicker";
|
||||||
|
import {
|
||||||
|
getDefaultDate,
|
||||||
|
getMonth,
|
||||||
|
getYear,
|
||||||
|
months,
|
||||||
|
years
|
||||||
|
} from "../constant/Utils";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
const DatePicker = ({
|
||||||
|
selectDate,
|
||||||
|
format,
|
||||||
|
minDate,
|
||||||
|
maxDate,
|
||||||
|
onChange,
|
||||||
|
handleClear
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const CustomInput = forwardRef(({ value, onClick }, ref) => (
|
||||||
|
<div
|
||||||
|
className="border-gray-400 rounded-[50px] border-[1px] px-3 text-xs py-2 focus:outline-none hover:border-base-content "
|
||||||
|
onClick={onClick}
|
||||||
|
ref={ref}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
<i className={`${value ? "ml-[5px]" : ""} fa-light fa-calendar `}></i>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
CustomInput.displayName = "CustomInput";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<span>{t("default-date")}: </span>
|
||||||
|
<ReactDatePicker
|
||||||
|
renderCustomHeader={({ date, changeYear, changeMonth }) => (
|
||||||
|
<div className="flex justify-start md:ml-2">
|
||||||
|
<select
|
||||||
|
className="bg-transparent outline-none"
|
||||||
|
value={months[getMonth(date)]}
|
||||||
|
onChange={({ target: { value } }) =>
|
||||||
|
changeMonth(months.indexOf(value))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{months.map((option) => (
|
||||||
|
<option key={option} value={option}>
|
||||||
|
{option}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<select
|
||||||
|
className="bg-transparent outline-none"
|
||||||
|
value={getYear(date)}
|
||||||
|
onChange={({ target: { value } }) => changeYear(value)}
|
||||||
|
>
|
||||||
|
{years.map((option) => (
|
||||||
|
<option key={option} value={option}>
|
||||||
|
{option}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
closeOnScroll={true}
|
||||||
|
selected={getDefaultDate(selectDate?.date, selectDate?.format)}
|
||||||
|
popperPlacement="top-end"
|
||||||
|
customInput={<CustomInput />}
|
||||||
|
onChange={(date) => onChange(date)}
|
||||||
|
dateFormat={
|
||||||
|
selectDate ? selectDate?.format : format ? format : "MM/dd/yyyy"
|
||||||
|
}
|
||||||
|
portalId="root-portal"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
onClick={() => handleClear()}
|
||||||
|
className="underline text-blue-500 cursor-pointer ml-2"
|
||||||
|
>
|
||||||
|
{t("clear")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DatePicker;
|
||||||
@@ -197,7 +197,7 @@ const Header = ({ isConsole, setIsLoggingOut }) => {
|
|||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
className={`mt-3 z-[1] p-2 shadow op-dropdown-open op-menu op-menu-sm op-dropdown-content text-base-content bg-base-100 rounded-box w-56 ${
|
className={`mt-4 z-[1] p-2 shadow op-dropdown-open op-menu op-menu-sm op-dropdown-content text-base-content bg-base-100 rounded-box w-56 ${
|
||||||
isOpen ? "" : "hidden"
|
isOpen ? "" : "hidden"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { Helmet } from "react-helmet";
|
|
||||||
import { useLocation, matchPath } from "react-router";
|
import { useLocation, matchPath } from "react-router";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
@@ -72,11 +71,11 @@ export default function Title() {
|
|||||||
const manifestUrl = useManifestUrl(appName, logo);
|
const manifestUrl = useManifestUrl(appName, logo);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Helmet>
|
<>
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
<meta name="description" content={title} />
|
<meta name="description" content={title} />
|
||||||
{logo && <link rel="icon" type="image/png" href={logo} />}
|
{logo && <link rel="icon" type="image/png" href={logo} />}
|
||||||
<link rel="manifest" href={manifestUrl} />
|
<link rel="manifest" href={manifestUrl} />
|
||||||
</Helmet>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import getReplacedHashQuery from "../../constant/getReplacedHashQuery";
|
|||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import Tooltip from "../../primitives/Tooltip";
|
import Tooltip from "../../primitives/Tooltip";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { withSessionValidation } from "../../utils";
|
||||||
|
|
||||||
const DashboardCard = (props) => {
|
const DashboardCard = (props) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -14,7 +15,7 @@ const DashboardCard = (props) => {
|
|||||||
const [response, setresponse] = useState("");
|
const [response, setresponse] = useState("");
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const renderData = async () => {
|
const renderData = withSessionValidation(async () => {
|
||||||
if (props.Data.queryType === "function") {
|
if (props.Data.queryType === "function") {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
@@ -186,9 +187,9 @@ const DashboardCard = (props) => {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
const filterRender = async () => {
|
const filterRender = withSessionValidation(async () => {
|
||||||
if (props.FilterData && props.FilterData.queryType === "function") {
|
if (props.FilterData && props.FilterData.queryType === "function") {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
@@ -266,7 +267,7 @@ const DashboardCard = (props) => {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
const setFormat = (val) => {
|
const setFormat = (val) => {
|
||||||
switch (props.Format) {
|
switch (props.Format) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import reportJson from "../../json/ReportJson";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Loader from "../../primitives/Loader";
|
import Loader from "../../primitives/Loader";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { withSessionValidation } from "../../utils";
|
||||||
function DashboardReport(props) {
|
function DashboardReport(props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [List, setList] = useState([]);
|
const [List, setList] = useState([]);
|
||||||
@@ -46,7 +47,7 @@ function DashboardReport(props) {
|
|||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [isNextRecord]);
|
}, [isNextRecord]);
|
||||||
|
|
||||||
const handleSearchChange = async (e) => {
|
const handleSearchChange = withSessionValidation(async (e) => {
|
||||||
const term = e.target.value.toLowerCase();
|
const term = e.target.value.toLowerCase();
|
||||||
setSearchTerm(term);
|
setSearchTerm(term);
|
||||||
if (debounceTimer.current) {
|
if (debounceTimer.current) {
|
||||||
@@ -82,7 +83,7 @@ function DashboardReport(props) {
|
|||||||
}
|
}
|
||||||
}, 300);
|
}, 300);
|
||||||
setIsSearchResult(false);
|
setIsSearchResult(false);
|
||||||
};
|
});
|
||||||
|
|
||||||
const handleSearchPaste = (e) => {
|
const handleSearchPaste = (e) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -98,96 +99,95 @@ function DashboardReport(props) {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getReportData = async (
|
const getReportData = withSessionValidation(
|
||||||
id,
|
async (id, skipUserRecord = 0, limit = 20, term = searchTerm) => {
|
||||||
skipUserRecord = 0,
|
setIsLoader(true);
|
||||||
limit = 20,
|
const json = reportJson(id);
|
||||||
term = searchTerm
|
if (json) {
|
||||||
) => {
|
setActions(json.actions);
|
||||||
setIsLoader(true);
|
setReportName(json.reportName);
|
||||||
const json = reportJson(id);
|
setHeading(json.heading);
|
||||||
if (json) {
|
const currentUser = Parse.User.current().id;
|
||||||
setActions(json.actions);
|
|
||||||
setReportName(json.reportName);
|
|
||||||
setHeading(json.heading);
|
|
||||||
const currentUser = Parse.User.current().id;
|
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
sessiontoken: localStorage.getItem("accesstoken")
|
sessiontoken: localStorage.getItem("accesstoken")
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const skipRecord = id === "5Go51Q7T8r" ? 0 : skipUserRecord;
|
const skipRecord = id === "5Go51Q7T8r" ? 0 : skipUserRecord;
|
||||||
const limitRecord = id === "5Go51Q7T8r" ? 200 : limit;
|
const limitRecord = id === "5Go51Q7T8r" ? 200 : limit;
|
||||||
const params = { reportId: id, skip: skipRecord, limit: limitRecord };
|
const params = { reportId: id, skip: skipRecord, limit: limitRecord };
|
||||||
if (term) {
|
if (term) {
|
||||||
params.searchTerm = term;
|
params.searchTerm = term;
|
||||||
}
|
}
|
||||||
const url = `${localStorage.getItem("baseUrl")}functions/getReport`;
|
const url = `${localStorage.getItem("baseUrl")}functions/getReport`;
|
||||||
const res = await axios.post(url, params, {
|
const res = await axios.post(url, params, {
|
||||||
headers: headers,
|
headers: headers,
|
||||||
signal: abortController.signal // is used to cancel fetch query
|
signal: abortController.signal // is used to cancel fetch query
|
||||||
});
|
});
|
||||||
if (id === "5Go51Q7T8r") {
|
if (id === "5Go51Q7T8r") {
|
||||||
const listData = res.data?.result.filter((x) => x.Signers.length > 0);
|
const listData = res.data?.result.filter(
|
||||||
let arr = [];
|
(x) => x.Signers.length > 0
|
||||||
for (const obj of listData) {
|
|
||||||
const isSigner = obj.Signers?.some(
|
|
||||||
(item) => item.UserId.objectId === currentUser
|
|
||||||
);
|
);
|
||||||
if (isSigner) {
|
let arr = [];
|
||||||
let isRecord;
|
for (const obj of listData) {
|
||||||
if (obj?.AuditTrail && obj?.AuditTrail.length > 0) {
|
const isSigner = obj.Signers?.some(
|
||||||
isRecord = obj?.AuditTrail.some(
|
(item) => item.UserId.objectId === currentUser
|
||||||
(item) =>
|
);
|
||||||
item?.UserPtr?.UserId?.objectId === currentUser &&
|
if (isSigner) {
|
||||||
item.Activity === "Signed"
|
let isRecord;
|
||||||
);
|
if (obj?.AuditTrail && obj?.AuditTrail.length > 0) {
|
||||||
} else {
|
isRecord = obj?.AuditTrail.some(
|
||||||
isRecord = false;
|
(item) =>
|
||||||
}
|
item?.UserPtr?.UserId?.objectId === currentUser &&
|
||||||
if (isRecord === false) {
|
item.Activity === "Signed"
|
||||||
arr.push(obj);
|
);
|
||||||
|
} else {
|
||||||
|
isRecord = false;
|
||||||
|
}
|
||||||
|
if (isRecord === false) {
|
||||||
|
arr.push(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (arr.length === docPerPage) {
|
||||||
if (arr.length === docPerPage) {
|
setIsMoreDocs(true);
|
||||||
setIsMoreDocs(true);
|
} else {
|
||||||
} else {
|
setIsMoreDocs(false);
|
||||||
setIsMoreDocs(false);
|
}
|
||||||
}
|
|
||||||
setList((prevRecord) =>
|
|
||||||
prevRecord.length > 0 ? [...prevRecord, ...arr] : arr
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if (res.data.result.length >= docPerPage) {
|
|
||||||
setIsMoreDocs(true);
|
|
||||||
} else {
|
|
||||||
setIsMoreDocs(false);
|
|
||||||
}
|
|
||||||
setIsNextRecord(false);
|
|
||||||
if (!res.data.result.error) {
|
|
||||||
setList((prevRecord) =>
|
setList((prevRecord) =>
|
||||||
prevRecord.length > 0
|
prevRecord.length > 0 ? [...prevRecord, ...arr] : arr
|
||||||
? [...prevRecord, ...res.data.result]
|
|
||||||
: res.data.result
|
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
if (res.data.result.length >= docPerPage) {
|
||||||
|
setIsMoreDocs(true);
|
||||||
|
} else {
|
||||||
|
setIsMoreDocs(false);
|
||||||
|
}
|
||||||
|
setIsNextRecord(false);
|
||||||
|
if (!res.data.result.error) {
|
||||||
|
setList((prevRecord) =>
|
||||||
|
prevRecord.length > 0
|
||||||
|
? [...prevRecord, ...res.data.result]
|
||||||
|
: res.data.result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setIsLoader(false);
|
||||||
|
} catch (err) {
|
||||||
|
const isCancel = axios.isCancel(err);
|
||||||
|
if (!isCancel) {
|
||||||
|
console.log("err ", err);
|
||||||
|
setIsLoader(false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
setIsLoader(false);
|
|
||||||
} catch (err) {
|
|
||||||
const isCancel = axios.isCancel(err);
|
|
||||||
if (!isCancel) {
|
|
||||||
console.log("err ", err);
|
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
setIsLoader(false);
|
|
||||||
}
|
}
|
||||||
};
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isLoader ? (
|
{isLoader ? (
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import FolderModal from "../shared/fields/FolderModal";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { handleDownloadPdf, isMobile } from "../../constant/Utils";
|
import { handleDownloadPdf, isMobile } from "../../constant/Utils";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
|
import { withSessionValidation } from "../../utils";
|
||||||
|
|
||||||
function DriveBody(props) {
|
function DriveBody(props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -52,13 +53,11 @@ function DriveBody(props) {
|
|||||||
props.setSkip(0);
|
props.setSkip(0);
|
||||||
};
|
};
|
||||||
//function for change doc name and update doc name in _document class
|
//function for change doc name and update doc name in _document class
|
||||||
const handledRenameDoc = async (data) => {
|
const handledRenameDoc = withSessionValidation(async (data) => {
|
||||||
setRename("");
|
setRename("");
|
||||||
const trimmedValue = renameValue.trim();
|
const trimmedValue = renameValue.trim();
|
||||||
if (trimmedValue.length > 0) {
|
if (trimmedValue.length > 0) {
|
||||||
const updateName = {
|
const updateName = { Name: renameValue };
|
||||||
Name: renameValue
|
|
||||||
};
|
|
||||||
const docId = data.objectId;
|
const docId = data.objectId;
|
||||||
const docData = props.pdfData;
|
const docData = props.pdfData;
|
||||||
const updatedData = docData.map((item) => {
|
const updatedData = docData.map((item) => {
|
||||||
@@ -84,14 +83,14 @@ function DriveBody(props) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Err ", err);
|
console.error("Error in rename doc", err);
|
||||||
props.setIsAlert({
|
props.setIsAlert({
|
||||||
isShow: true,
|
isShow: true,
|
||||||
alertMessage: t("something-went-wrong-mssg")
|
alertMessage: t("something-went-wrong-mssg")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
//function for navigate user to microapp-signature component
|
//function for navigate user to microapp-signature component
|
||||||
const checkPdfStatus = async (data) => {
|
const checkPdfStatus = async (data) => {
|
||||||
@@ -157,12 +156,10 @@ function DriveBody(props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
//function for delete document
|
//function for delete document
|
||||||
const handleDeleteDocument = async (docData) => {
|
const handleDeleteDocument = withSessionValidation(async (docData) => {
|
||||||
setIsDeleteDoc({});
|
setIsDeleteDoc({});
|
||||||
const docId = docData.objectId;
|
const docId = docData.objectId;
|
||||||
const data = {
|
const data = { IsArchive: true };
|
||||||
IsArchive: true
|
|
||||||
};
|
|
||||||
|
|
||||||
await axios
|
await axios
|
||||||
.put(
|
.put(
|
||||||
@@ -184,19 +181,19 @@ function DriveBody(props) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log("Err ", err);
|
console.error("Err in delete doc", err);
|
||||||
props.setIsAlert({
|
props.setIsAlert({
|
||||||
isShow: true,
|
isShow: true,
|
||||||
alertMessage: t("something-went-wrong-mssg")
|
alertMessage: t("something-went-wrong-mssg")
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
const handleMoveDocument = async (docData) => {
|
const handleMoveDocument = async (docData) => {
|
||||||
setIsOpenMoveModal(true);
|
setIsOpenMoveModal(true);
|
||||||
setSelectDoc(docData);
|
setSelectDoc(docData);
|
||||||
};
|
};
|
||||||
//function for move document from one folder to another folder
|
//function for move document from one folder to another folder
|
||||||
const handleMoveFolder = async (selectFolderData) => {
|
const handleMoveFolder = withSessionValidation(async (selectFolderData) => {
|
||||||
const selecFolderId = selectDoc?.Folder?.objectId;
|
const selecFolderId = selectDoc?.Folder?.objectId;
|
||||||
const moveFolderId = selectFolderData?.ObjectId;
|
const moveFolderId = selectFolderData?.ObjectId;
|
||||||
let updateDocId = selectDoc?.objectId;
|
let updateDocId = selectDoc?.objectId;
|
||||||
@@ -218,16 +215,12 @@ function DriveBody(props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
updateData = {
|
updateData = { Folder: { __op: "Delete" } };
|
||||||
Folder: { __op: "Delete" }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await axios
|
await axios
|
||||||
.put(
|
.put(
|
||||||
`${localStorage.getItem(
|
`${localStorage.getItem("baseUrl")}classes/contracts_Document/${updateDocId}`,
|
||||||
"baseUrl"
|
|
||||||
)}classes/contracts_Document/${updateDocId}`,
|
|
||||||
updateData,
|
updateData,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -237,7 +230,6 @@ function DriveBody(props) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
.then((Listdata) => {
|
.then((Listdata) => {
|
||||||
const res = Listdata.data;
|
const res = Listdata.data;
|
||||||
if (res) {
|
if (res) {
|
||||||
@@ -248,7 +240,7 @@ function DriveBody(props) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log("err", err);
|
console.error("err in move folder", err);
|
||||||
});
|
});
|
||||||
|
|
||||||
setIsOpenMoveModal(false);
|
setIsOpenMoveModal(false);
|
||||||
@@ -256,7 +248,7 @@ function DriveBody(props) {
|
|||||||
alert(t("folder-already-exist!"));
|
alert(t("folder-already-exist!"));
|
||||||
setIsOpenMoveModal(false);
|
setIsOpenMoveModal(false);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
const handleEnterPress = (e, data) => {
|
const handleEnterPress = (e, data) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
handledRenameDoc(data);
|
handledRenameDoc(data);
|
||||||
@@ -296,7 +288,7 @@ function DriveBody(props) {
|
|||||||
props.setPdfData(updatedData);
|
props.setPdfData(updatedData);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Err ", err);
|
console.error("Err in delete folder", err);
|
||||||
props.setIsAlert({
|
props.setIsAlert({
|
||||||
isShow: true,
|
isShow: true,
|
||||||
alertMessage: t("something-went-wrong-mssg")
|
alertMessage: t("something-went-wrong-mssg")
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { useNavigate } from "react-router";
|
|||||||
|
|
||||||
function CustomizeMail(props) {
|
function CustomizeMail(props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const editorRef = useRef();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const copyUrlRef = useRef(null);
|
const copyUrlRef = useRef(null);
|
||||||
const [isCustomize, setIsCustomize] = useState(false);
|
const [isCustomize, setIsCustomize] = useState(false);
|
||||||
@@ -27,20 +26,17 @@ function CustomizeMail(props) {
|
|||||||
props?.setIsMailModal(false);
|
props?.setIsMailModal(false);
|
||||||
navigate("/report/1MwEuxLEkF");
|
navigate("/report/1MwEuxLEkF");
|
||||||
};
|
};
|
||||||
const handleOnchangeRequest = () => {
|
const handleOnchangeRequest = (value) => {
|
||||||
if (editorRef.current) {
|
props?.setCustomizeMail((prev) => ({
|
||||||
const html = editorRef.current.editor.root.innerHTML;
|
...prev,
|
||||||
props?.setCustomizeMail((prev) => ({
|
body: value
|
||||||
...prev,
|
}));
|
||||||
body: html
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const handleEmailSendToSigners = async () => {
|
const handleEmailSendToSigners = async () => {
|
||||||
setIsLoader(true);
|
setIsLoader(true);
|
||||||
const documentData = await contractDocument(props?.documentId);
|
const documentData = await contractDocument(props?.documentId);
|
||||||
if (documentData && documentData?.length > 0) {
|
if (documentData && documentData?.length > 0) {
|
||||||
props?.setDocumentDetails(documentData[0]);
|
props?.setDocumentDetails && props?.setDocumentDetails(documentData[0]);
|
||||||
if (
|
if (
|
||||||
documentData?.[0]?.SendinOrder &&
|
documentData?.[0]?.SendinOrder &&
|
||||||
documentData?.[0]?.SendinOrder === true
|
documentData?.[0]?.SendinOrder === true
|
||||||
@@ -49,7 +45,7 @@ function CustomizeMail(props) {
|
|||||||
const ownerDetails = documentData[0].Signers.find(
|
const ownerDetails = documentData[0].Signers.find(
|
||||||
(x) => x.Email === ownerEmail
|
(x) => x.Email === ownerEmail
|
||||||
);
|
);
|
||||||
props?.setCurrUserId(ownerDetails?.objectId);
|
props?.setCurrUserId && props?.setCurrUserId(ownerDetails?.objectId);
|
||||||
}
|
}
|
||||||
//function is used to send email to signers for sign the document
|
//function is used to send email to signers for sign the document
|
||||||
const mailRes = await sendEmailToSigners(
|
const mailRes = await sendEmailToSigners(
|
||||||
@@ -94,9 +90,8 @@ function CustomizeMail(props) {
|
|||||||
isCustomize && (
|
isCustomize && (
|
||||||
<>
|
<>
|
||||||
<EmailBody
|
<EmailBody
|
||||||
editorRef={editorRef}
|
requestBody={props?.customizeMail?.body}
|
||||||
requestBody={props?.customizeMail.body}
|
requestSubject={props?.customizeMail?.subject}
|
||||||
requestSubject={props?.customizeMail.subject}
|
|
||||||
handleOnchangeRequest={handleOnchangeRequest}
|
handleOnchangeRequest={handleOnchangeRequest}
|
||||||
setCustomizeMail={props?.setCustomizeMail}
|
setCustomizeMail={props?.setCustomizeMail}
|
||||||
/>
|
/>
|
||||||
@@ -135,7 +130,7 @@ function CustomizeMail(props) {
|
|||||||
!isCustomize && (
|
!isCustomize && (
|
||||||
<span
|
<span
|
||||||
className="op-link op-link-accent text-sm"
|
className="op-link op-link-accent text-sm"
|
||||||
onClick={() => setIsCustomize(!isCustomize)}
|
onClick={() => setIsCustomize(true)}
|
||||||
>
|
>
|
||||||
{t("cutomize-email")}
|
{t("cutomize-email")}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
function DefaultSignature(props) {
|
function DefaultSignature(props) {
|
||||||
@@ -105,9 +105,7 @@ function DefaultSignature(props) {
|
|||||||
</button>
|
</button>
|
||||||
{!props.isDefault && (
|
{!props.isDefault && (
|
||||||
<div className="absolute bg-black/70 text-white w-full h-full flex items-center justify-center text-[11px] cursor-default">
|
<div className="absolute bg-black/70 text-white w-full h-full flex items-center justify-center text-[11px] cursor-default">
|
||||||
<span className="-rotate-45">
|
<span className="-rotate-45">{t("option-disabled-by-owner")}</span>
|
||||||
Document creator has disabled this option
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
import { radioButtonWidget } from "../../constant/Utils";
|
import { radioButtonWidget } from "../../constant/Utils";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -270,7 +270,8 @@ function DropdownWidgetOption(props) {
|
|||||||
</select>
|
</select>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{props.type !== "checkbox" && !isPrefillExist && (
|
{((props.type !== "checkbox" && !isPrefillExist) ||
|
||||||
|
isPrefillExist) && (
|
||||||
<div className="flex flex-row gap-[10px] mt-[0.5rem]">
|
<div className="flex flex-row gap-[10px] mt-[0.5rem]">
|
||||||
{statusArr.map((data, ind) => (
|
{statusArr.map((data, ind) => (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ const EditTemplate = ({
|
|||||||
AllowModifications: template?.AllowModifications || false,
|
AllowModifications: template?.AllowModifications || false,
|
||||||
TimeToCompleteDays: template?.TimeToCompleteDays || 15,
|
TimeToCompleteDays: template?.TimeToCompleteDays || 15,
|
||||||
});
|
});
|
||||||
|
const pensList = ["blue", "red", "black"];
|
||||||
|
const [selectedColors, setSelectedColors] = useState(
|
||||||
|
template?.PenColors || pensList
|
||||||
|
);
|
||||||
const [isUpdate, setIsUpdate] = useState(false);
|
const [isUpdate, setIsUpdate] = useState(false);
|
||||||
const [showConfirm, setShowConfirm] = useState(false);
|
const [showConfirm, setShowConfirm] = useState(false);
|
||||||
const [uploadPdf, setUploadPdf] = useState({
|
const [uploadPdf, setUploadPdf] = useState({
|
||||||
@@ -211,6 +215,7 @@ const EditTemplate = ({
|
|||||||
IsEnableOTP: IsEnableOTP,
|
IsEnableOTP: IsEnableOTP,
|
||||||
IsTourEnabled: isTourEnabled,
|
IsTourEnabled: isTourEnabled,
|
||||||
AllowModifications: allowModify,
|
AllowModifications: allowModify,
|
||||||
|
PenColors: selectedColors,
|
||||||
...reminderDate
|
...reminderDate
|
||||||
};
|
};
|
||||||
onSuccess(data);
|
onSuccess(data);
|
||||||
@@ -245,6 +250,19 @@ const EditTemplate = ({
|
|||||||
handleClose();
|
handleClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleColorsChange = (color) => {
|
||||||
|
setSelectedColors((prev) => {
|
||||||
|
// If user tries to uncheck the last remaining color → block it
|
||||||
|
if (prev.length === 1 && prev.includes(color)) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normal toggle behavior
|
||||||
|
return prev.includes(color)
|
||||||
|
? prev.filter((c) => c !== color) // remove
|
||||||
|
: [...prev, color]; // add
|
||||||
|
});
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen
|
isOpen
|
||||||
@@ -485,6 +503,41 @@ const EditTemplate = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="text-xs mt-3 mb-4">
|
||||||
|
<label htmlFor="penColors">
|
||||||
|
{t("pen-colors")}
|
||||||
|
<a data-tooltip-id="pen-colors-tooltip" className="ml-1">
|
||||||
|
<sup>
|
||||||
|
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
|
||||||
|
</sup>
|
||||||
|
</a>
|
||||||
|
<Tooltip id="pen-colors-tooltip" className="z-[999]">
|
||||||
|
<div className="max-w-[200px] md:max-w-[450px]">
|
||||||
|
<p className="font-bold">{t("pen-colors")}</p>
|
||||||
|
<div>{t("pen-colors-help")}</div>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</label>
|
||||||
|
<div className="ml-[7px] flex flex-col md:flex-row gap-[10px] mb-[0.7rem]">
|
||||||
|
{pensList.map((color) => (
|
||||||
|
<div
|
||||||
|
key={color}
|
||||||
|
className="flex flex-row gap-[5px] items-center"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
className="mr-[2px] op-checkbox op-checkbox-xs"
|
||||||
|
type="checkbox"
|
||||||
|
name="penColors"
|
||||||
|
checked={selectedColors.includes(color)}
|
||||||
|
onChange={() => handleColorsChange(color)}
|
||||||
|
/>
|
||||||
|
<div className="hover:underline underline-offset-2 cursor-default capitalize">
|
||||||
|
{color}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="text-xs mt-3">
|
<div className="text-xs mt-3">
|
||||||
<SignersInput
|
<SignersInput
|
||||||
label={t("Bcc")}
|
label={t("Bcc")}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import React from "react";
|
|
||||||
import Tooltip from "../../primitives/Tooltip";
|
import Tooltip from "../../primitives/Tooltip";
|
||||||
import ReactQuill from "react-quill-new";
|
import ReactQuill from "react-quill-new";
|
||||||
import "../../styles/quill.css";
|
import "../../styles/quill.css";
|
||||||
@@ -37,7 +36,6 @@ export function EmailBody(props) {
|
|||||||
theme="snow"
|
theme="snow"
|
||||||
value={props.requestBody}
|
value={props.requestBody}
|
||||||
placeholder={t("email-placeholder")}
|
placeholder={t("email-placeholder")}
|
||||||
ref={props.editorRef}
|
|
||||||
modules={module1}
|
modules={module1}
|
||||||
formats={formats}
|
formats={formats}
|
||||||
onChange={props.handleOnchangeRequest}
|
onChange={props.handleOnchangeRequest}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
handleToPrint,
|
handleToPrint,
|
||||||
} from "../../constant/Utils";
|
} from "../../constant/Utils";
|
||||||
|
|||||||
@@ -92,23 +92,25 @@ function Placeholder(props) {
|
|||||||
|
|
||||||
//function is used to convert date according to selected format
|
//function is used to convert date according to selected format
|
||||||
const handleGetFormatDate = (data, isDateChange) => {
|
const handleGetFormatDate = (data, isDateChange) => {
|
||||||
|
const format =
|
||||||
|
data?.format ||
|
||||||
|
selectDate?.format ||
|
||||||
|
props.pos?.options?.validation?.format;
|
||||||
const isSpecialDateFormat =
|
const isSpecialDateFormat =
|
||||||
data?.format &&
|
data?.format &&
|
||||||
["dd-MM-yyyy", "dd.MM.yyyy", "dd/MM/yyyy"].includes(data?.format);
|
["dd-MM-yyyy", "dd.MM.yyyy", "dd/MM/yyyy"].includes(format);
|
||||||
let updateDate = data.date;
|
let updateDate = data.date;
|
||||||
let date = "";
|
let date = "";
|
||||||
if (isSpecialDateFormat && updateDate) {
|
if (isSpecialDateFormat && updateDate) {
|
||||||
date = isDateChange
|
date = isDateChange
|
||||||
? moment(updateDate).format(changeDateToMomentFormat(data.format))
|
? moment(updateDate).format(changeDateToMomentFormat(format))
|
||||||
: updateDate;
|
: updateDate;
|
||||||
} else if (updateDate) {
|
} else if (updateDate) {
|
||||||
//using moment package is used to change date as per the format provided in selectDate obj e.g. - MM/dd/yyyy -> 03/12/2024
|
//using moment package is used to change date as per the format provided in selectDate obj e.g. - MM/dd/yyyy -> 03/12/2024
|
||||||
const newDate = new Date(updateDate);
|
const newDate = new Date(updateDate);
|
||||||
date = moment(newDate.getTime()).format(
|
date = moment(newDate.getTime()).format(changeDateToMomentFormat(format));
|
||||||
changeDateToMomentFormat(data?.format)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
setSelectDate({ date: date, format: data?.format });
|
setSelectDate({ date: date, format: format });
|
||||||
return date;
|
return date;
|
||||||
};
|
};
|
||||||
const saveDateSetting = (data) => {
|
const saveDateSetting = (data) => {
|
||||||
@@ -125,6 +127,10 @@ function Placeholder(props) {
|
|||||||
const handleSaveDate = (data, isDateChange) => {
|
const handleSaveDate = (data, isDateChange) => {
|
||||||
const date = isToday ? "today" : handleGetFormatDate(data, isDateChange);
|
const date = isToday ? "today" : handleGetFormatDate(data, isDateChange);
|
||||||
//`onChangeInput` is used to save data related to date in a placeholder field
|
//`onChangeInput` is used to save data related to date in a placeholder field
|
||||||
|
const format =
|
||||||
|
data?.format ||
|
||||||
|
selectDate?.format ||
|
||||||
|
props.pos?.options?.validation?.format;
|
||||||
onChangeInput(
|
onChangeInput(
|
||||||
date,
|
date,
|
||||||
props.pos,
|
props.pos,
|
||||||
@@ -133,10 +139,10 @@ function Placeholder(props) {
|
|||||||
props.setXyPosition,
|
props.setXyPosition,
|
||||||
props.data && props.data.Id,
|
props.data && props.data.Id,
|
||||||
false,
|
false,
|
||||||
data?.format,
|
format,
|
||||||
props.fontSize || props.pos?.options?.fontSize || 12,
|
props.fontSize || props.pos?.options?.fontSize || 12,
|
||||||
props.fontColor || props.pos?.options?.fontColor || "black",
|
props.fontColor || props.pos?.options?.fontColor || "black",
|
||||||
formdata
|
formdata,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -221,7 +227,7 @@ function Placeholder(props) {
|
|||||||
if (props?.currWidgetsDetails?.key === props.pos?.key) {
|
if (props?.currWidgetsDetails?.key === props.pos?.key) {
|
||||||
props.handleLinkUser(props.data.Id);
|
props.handleLinkUser(props.data.Id);
|
||||||
}
|
}
|
||||||
props.setUniqueId(props.data.Id);
|
props.setUniqueId && props.setUniqueId(props.data.Id);
|
||||||
const checkIndex = props.xyPosition.findIndex(
|
const checkIndex = props.xyPosition.findIndex(
|
||||||
(data) => data.Id === props.data.Id
|
(data) => data.Id === props.data.Id
|
||||||
);
|
);
|
||||||
@@ -620,12 +626,12 @@ function Placeholder(props) {
|
|||||||
};
|
};
|
||||||
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
|
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
|
||||||
<div
|
<div
|
||||||
className="border-gray-400 rounded-[50px] border-[1px] px-3 md:ml-2 text-xs py-2 focus:outline-none hover:border-base-content "
|
className="border-gray-400 rounded-[50px] border-[1px] px-3 text-xs py-2 focus:outline-none hover:border-base-content "
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
<i className="fa-light fa-calendar ml-[5px]"></i>
|
<i className={`${value ? "ml-[5px]" : ""} fa-light fa-calendar `}></i>
|
||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
ExampleCustomInput.displayName = "ExampleCustomInput";
|
ExampleCustomInput.displayName = "ExampleCustomInput";
|
||||||
@@ -655,12 +661,14 @@ function Placeholder(props) {
|
|||||||
{props.pos?.options?.response &&
|
{props.pos?.options?.response &&
|
||||||
props.pos.key !== props?.currWidgetsDetails?.key &&
|
props.pos.key !== props?.currWidgetsDetails?.key &&
|
||||||
props.pos.type === textWidget ? (
|
props.pos.type === textWidget ? (
|
||||||
<span
|
<textarea
|
||||||
|
readOnly
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
if (props?.ispublicTemplate) return;
|
||||||
props.setCurrWidgetsDetails &&
|
props.setCurrWidgetsDetails &&
|
||||||
props.setCurrWidgetsDetails(props.pos);
|
props.setCurrWidgetsDetails(props.pos);
|
||||||
props?.setRoleName("prefill");
|
props?.setRoleName && props?.setRoleName("prefill");
|
||||||
props.setUniqueId(props?.data?.Id);
|
props.setUniqueId && props.setUniqueId(props?.data?.Id);
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
fontFamily: "Arial, sans-serif",
|
fontFamily: "Arial, sans-serif",
|
||||||
@@ -671,13 +679,21 @@ function Placeholder(props) {
|
|||||||
...(props.pos?.Height ? { height: props.pos?.Height } : {}),
|
...(props.pos?.Height ? { height: props.pos?.Height } : {}),
|
||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
color: fontColor,
|
color: fontColor,
|
||||||
zIndex: 99
|
zIndex: 99,
|
||||||
|
cursor: getCursor(),
|
||||||
|
resize: "none",
|
||||||
|
background: "transparent",
|
||||||
|
width: props.posWidth(props.pos, props.isSignYourself),
|
||||||
|
whiteSpace: "pre-wrap",
|
||||||
|
overflow: "hidden",
|
||||||
|
outline: "none",
|
||||||
|
border: "none"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
props.pos?.options?.response
|
props.pos?.options?.response
|
||||||
}
|
}
|
||||||
</span>
|
</textarea>
|
||||||
) : (
|
) : (
|
||||||
<Rnd
|
<Rnd
|
||||||
id={props.pos.key}
|
id={props.pos.key}
|
||||||
@@ -737,7 +753,7 @@ function Placeholder(props) {
|
|||||||
props?.data,
|
props?.data,
|
||||||
props?.isNeedSign,
|
props?.isNeedSign,
|
||||||
props?.uniqueId
|
props?.uniqueId
|
||||||
) //handle block color of widget for
|
)
|
||||||
}}
|
}}
|
||||||
onDrag={(_, d) => {
|
onDrag={(_, d) => {
|
||||||
props?.handleTabDrag?.(props.pos.key);
|
props?.handleTabDrag?.(props.pos.key);
|
||||||
@@ -928,17 +944,17 @@ function Placeholder(props) {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</select>
|
</select>
|
||||||
<span className="text-xs text-gray-400 ml-1">
|
<span className="text-xs text-gray-400 ml-1 uppercase">
|
||||||
{selectDate.format}
|
{selectDate.format}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{props?.data?.Role !== "prefill" && props?.isPlaceholder && (
|
{props?.data?.Role !== "prefill" && props?.isPlaceholder && (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col md:flex-row md:items-center gap-2">
|
<div className="flex flex-col md:flex-row md:items-center gap-2">
|
||||||
<span>{t("set-date")} :</span>
|
<span>{t("default-date")} :</span>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
renderCustomHeader={({ date, changeYear, changeMonth }) => (
|
renderCustomHeader={({ date, changeYear, changeMonth }) => (
|
||||||
<div className="flex justify-start md:ml-2 ">
|
<div className="flex justify-start md:ml-2">
|
||||||
<select
|
<select
|
||||||
className="bg-transparent outline-none"
|
className="bg-transparent outline-none"
|
||||||
value={months[getMonth(date)]}
|
value={months[getMonth(date)]}
|
||||||
@@ -992,7 +1008,7 @@ function Placeholder(props) {
|
|||||||
}
|
}
|
||||||
portalId="root-portal"
|
portalId="root-portal"
|
||||||
/>
|
/>
|
||||||
<label className=" flex items-center gap-1 cursor-pointer">
|
<label className="flex items-center gap-1 cursor-pointer mb-0">
|
||||||
<input
|
<input
|
||||||
checked={isToday}
|
checked={isToday}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -1006,42 +1022,41 @@ function Placeholder(props) {
|
|||||||
</label>
|
</label>
|
||||||
<span
|
<span
|
||||||
onClick={() => handleClearDate()}
|
onClick={() => handleClearDate()}
|
||||||
className="underline text-blue-500 cursor-pointer md:ml-2"
|
className="underline text-blue-500 cursor-pointer ml-2"
|
||||||
>
|
>
|
||||||
{t("clear")}
|
{t("clear")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row items-center gap-[10px]">
|
|
||||||
{statusArr.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={ind}
|
|
||||||
className="flex flex-row gap-[5px] items-center"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
className="mr-[2px] op-radio op-radio-xs"
|
|
||||||
type="radio"
|
|
||||||
name="status"
|
|
||||||
onChange={() =>
|
|
||||||
setFormdata({
|
|
||||||
...formdata,
|
|
||||||
status: data.toLowerCase()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
checked={
|
|
||||||
formdata.status.toLowerCase() === data.toLowerCase()
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<div className="text-[13px]">
|
|
||||||
{t(`widget-status.${data}`)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
<div className="flex flex-row items-center gap-[10px]">
|
||||||
|
{statusArr.map((data, ind) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={ind}
|
||||||
|
className="flex flex-row gap-[5px] items-center"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
className="mr-[2px] op-radio op-radio-xs"
|
||||||
|
type="radio"
|
||||||
|
name="status"
|
||||||
|
onChange={() =>
|
||||||
|
setFormdata({
|
||||||
|
...formdata,
|
||||||
|
status: data.toLowerCase()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
checked={
|
||||||
|
formdata.status.toLowerCase() === data.toLowerCase()
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<div className="text-[13px]">
|
||||||
|
{t(`widget-status.${data}`)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
<div className="flex flex-col md:flex-row gap-y-2 md:gap-y-0 gap-x-2">
|
<div className="flex flex-col md:flex-row gap-y-2 md:gap-y-0 gap-x-2">
|
||||||
<div className="flex flex-row items-center">
|
<div className="flex flex-row items-center">
|
||||||
<span className="capitalize">{t("font-size")} :</span>
|
<span className="capitalize">{t("font-size")} :</span>
|
||||||
@@ -1086,9 +1101,10 @@ function Placeholder(props) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{props?.isPlaceholder && props?.data?.Role !== "prefill" && (
|
{props?.isPlaceholder && props?.data?.Role !== "prefill" && (
|
||||||
<label className="flex items-center gap-1 cursor-pointer">
|
<div className="flex items-center gap-1 w-max">
|
||||||
<input
|
<input
|
||||||
name="isReadOnly"
|
name="isReadOnly"
|
||||||
|
id="isReadOnly"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={formdata?.isReadOnly}
|
checked={formdata?.isReadOnly}
|
||||||
className="op-checkbox op-checkbox-xs"
|
className="op-checkbox op-checkbox-xs"
|
||||||
@@ -1099,8 +1115,13 @@ function Placeholder(props) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<span className="capitalize ml-[2px]">{t("read-only")}</span>
|
<label
|
||||||
</label>
|
htmlFor="isReadOnly"
|
||||||
|
className="capitalize ml-[2px] mb-0 cursor-pointer"
|
||||||
|
>
|
||||||
|
{t("read-only")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
|
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
import { handleCopyNextToWidget, randomId } from "../../constant/Utils";
|
import {
|
||||||
|
drawWidget,
|
||||||
|
handleCopyNextToWidget,
|
||||||
|
randomId
|
||||||
|
} from "../../constant/Utils";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { setPrefillImg } from "../../redux/reducers/widgetSlice";
|
import { setPrefillImg } from "../../redux/reducers/widgetSlice";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
|
||||||
function PlaceholderCopy(props) {
|
function PlaceholderCopy(props) {
|
||||||
|
const { prefillImg } = useSelector((state) => state.widget);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const copyType = [
|
const copyType = [
|
||||||
@@ -151,12 +156,17 @@ function PlaceholderCopy(props) {
|
|||||||
if (
|
if (
|
||||||
filterSignerPosition[0]?.Role === "prefill" &&
|
filterSignerPosition[0]?.Role === "prefill" &&
|
||||||
currentPlaceholder?.options?.response &&
|
currentPlaceholder?.options?.response &&
|
||||||
currentPlaceholder?.type === "image"
|
(currentPlaceholder?.type === "image" ||
|
||||||
|
currentPlaceholder?.type === drawWidget)
|
||||||
) {
|
) {
|
||||||
|
const getPrefillImg = prefillImg?.find(
|
||||||
|
(x) => x.id === currentPlaceholder?.key
|
||||||
|
);
|
||||||
|
const base64Img = getPrefillImg?.base64;
|
||||||
dispatch(
|
dispatch(
|
||||||
setPrefillImg({
|
setPrefillImg({
|
||||||
id: newId,
|
id: newId,
|
||||||
base64: currentPlaceholder?.options?.response
|
base64: base64Img
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -254,15 +264,20 @@ function PlaceholderCopy(props) {
|
|||||||
props.setXyPosition,
|
props.setXyPosition,
|
||||||
props?.Id
|
props?.Id
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
filterSignerPosition[0]?.Role === "prefill" &&
|
filterSignerPosition[0]?.Role === "prefill" &&
|
||||||
currentXYposition?.options?.response &&
|
currentXYposition?.options?.response &&
|
||||||
currentXYposition?.type === "image"
|
(currentXYposition?.type === "image" ||
|
||||||
|
currentXYposition?.type === drawWidget)
|
||||||
) {
|
) {
|
||||||
|
const getPrefillImg = prefillImg?.find(
|
||||||
|
(x) => x.id === currentXYposition?.key
|
||||||
|
);
|
||||||
|
const base64Img = getPrefillImg?.base64;
|
||||||
dispatch(
|
dispatch(
|
||||||
setPrefillImg({
|
setPrefillImg({
|
||||||
id: newId,
|
id: newId,
|
||||||
base64: currentXYposition?.options?.response
|
base64: base64Img
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import { useEffect, useMemo, useState, forwardRef } from "react";
|
|
||||||
import {
|
import {
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
forwardRef,
|
||||||
|
useRef
|
||||||
|
} from "react";
|
||||||
|
import {
|
||||||
|
onChangeInput,
|
||||||
getMonth,
|
getMonth,
|
||||||
getYear,
|
getYear,
|
||||||
radioButtonWidget,
|
radioButtonWidget,
|
||||||
@@ -9,9 +15,8 @@ import {
|
|||||||
months,
|
months,
|
||||||
years,
|
years,
|
||||||
selectCheckbox,
|
selectCheckbox,
|
||||||
checkRegularExpress,
|
|
||||||
isBase64,
|
isBase64,
|
||||||
getSignerPages
|
drawWidget
|
||||||
} from "../../constant/Utils";
|
} from "../../constant/Utils";
|
||||||
import DatePicker from "react-datepicker";
|
import DatePicker from "react-datepicker";
|
||||||
import "react-datepicker/dist/react-datepicker.css";
|
import "react-datepicker/dist/react-datepicker.css";
|
||||||
@@ -28,6 +33,7 @@ const widgetCls =
|
|||||||
function PlaceholderType(props) {
|
function PlaceholderType(props) {
|
||||||
const selectWidgetCls = `w-full h-full absolute left-0 top-0 focus:outline-none text-base-content`;
|
const selectWidgetCls = `w-full h-full absolute left-0 top-0 focus:outline-none text-base-content`;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const textRef = useRef();
|
||||||
const prefillImg = useSelector((state) => state.widget.prefillImg);
|
const prefillImg = useSelector((state) => state.widget.prefillImg);
|
||||||
const prefillImgLoad = useSelector((state) => state.widget.prefillImgLoad);
|
const prefillImgLoad = useSelector((state) => state.widget.prefillImgLoad);
|
||||||
const type = props?.pos?.type;
|
const type = props?.pos?.type;
|
||||||
@@ -42,10 +48,8 @@ function PlaceholderType(props) {
|
|||||||
// prefer the latest response value over any default value
|
// prefer the latest response value over any default value
|
||||||
const widgetData =
|
const widgetData =
|
||||||
props.pos?.options?.response ?? props.pos?.options?.defaultValue ?? "";
|
props.pos?.options?.response ?? props.pos?.options?.defaultValue ?? "";
|
||||||
// const widgetTypeTranslation = t(`widgets-name.${props?.pos?.type}`);
|
|
||||||
const [widgetValue, setwidgetValue] = useState();
|
const [widgetValue, setwidgetValue] = useState();
|
||||||
const [selectedCheckbox, setSelectedCheckbox] = useState([]);
|
const [selectedCheckbox, setSelectedCheckbox] = useState([]);
|
||||||
// const [hint, setHint] = useState("");
|
|
||||||
const [imgUrl, setImgUrl] = useState("");
|
const [imgUrl, setImgUrl] = useState("");
|
||||||
const fontSize = props.calculateFont(props.pos.options?.fontSize);
|
const fontSize = props.calculateFont(props.pos.options?.fontSize);
|
||||||
const fontColor = props.pos.options?.fontColor || "black";
|
const fontColor = props.pos.options?.fontColor || "black";
|
||||||
@@ -72,11 +76,6 @@ function PlaceholderType(props) {
|
|||||||
// keep displayed value in sync with the stored response
|
// keep displayed value in sync with the stored response
|
||||||
setwidgetValue(widgetData);
|
setwidgetValue(widgetData);
|
||||||
}
|
}
|
||||||
// if (props.pos?.options?.hint) {
|
|
||||||
// setHint(props.pos?.options.hint);
|
|
||||||
// } else if (props.pos?.options?.validation?.type) {
|
|
||||||
// checkRegularExpress(props.pos?.options?.validation?.type, setHint);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [props.pos, widgetData, type]);
|
}, [props.pos, widgetData, type]);
|
||||||
@@ -138,6 +137,39 @@ function PlaceholderType(props) {
|
|||||||
props?.pos?.type === name[0] ? `${name[0]}${lastWord}` : widgetName;
|
props?.pos?.type === name[0] ? `${name[0]}${lastWord}` : widgetName;
|
||||||
return props?.pos?.options?.hint || title;
|
return props?.pos?.options?.hint || title;
|
||||||
};
|
};
|
||||||
|
//useEffect is used to increase auto height of text/textInput widget when user using multiline option and enter value in next line
|
||||||
|
useEffect(() => {
|
||||||
|
if (!textRef.current) return;
|
||||||
|
if (
|
||||||
|
(type === "text" || type === textInputWidget) &&
|
||||||
|
textRef.current &&
|
||||||
|
widgetValue
|
||||||
|
) {
|
||||||
|
const el = textRef.current;
|
||||||
|
// Count actual number of lines
|
||||||
|
const lines = widgetValue?.split("\n")?.length || props.pos?.Height;
|
||||||
|
// Get line height from computed style
|
||||||
|
const lineHeight = parseInt(window.getComputedStyle(el).lineHeight);
|
||||||
|
|
||||||
|
const textWidgetHeight = lines * lineHeight;
|
||||||
|
// Set widget box height (your logic)
|
||||||
|
onChangeInput(
|
||||||
|
null,
|
||||||
|
props.pos,
|
||||||
|
props?.xyPosition,
|
||||||
|
props.index,
|
||||||
|
props?.setXyPosition,
|
||||||
|
props.data && props.data.Id,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
textWidgetHeight
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [widgetValue]);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "signature":
|
case "signature":
|
||||||
return props.pos.SignUrl ? (
|
return props.pos.SignUrl ? (
|
||||||
@@ -230,17 +262,19 @@ function PlaceholderType(props) {
|
|||||||
return props.isSignYourself || iswidgetEnable ? (
|
return props.isSignYourself || iswidgetEnable ? (
|
||||||
<textarea
|
<textarea
|
||||||
placeholder={formatWidgetName()}
|
placeholder={formatWidgetName()}
|
||||||
rows={1}
|
ref={textRef}
|
||||||
|
rows={50}
|
||||||
value={
|
value={
|
||||||
widgetValue
|
widgetValue
|
||||||
}
|
}
|
||||||
className={`${textWidgetCls} ${isReadOnly ? "select-none" : ""}`}
|
className={`w-full resize-none overflow-hidden text-base-content item-center outline-none ${isReadOnly ? "select-none" : ""}`}
|
||||||
style={{
|
style={{
|
||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
color: fontColor,
|
color: fontColor,
|
||||||
background: isReadOnly ? props.data?.blockColor : "white",
|
background: isReadOnly ? props.data?.blockColor : "white",
|
||||||
pointerEvents: "none"
|
pointerEvents: "none"
|
||||||
}}
|
}}
|
||||||
|
name="text"
|
||||||
readOnly
|
readOnly
|
||||||
disabled={props.isNeedSign && isReadOnly}
|
disabled={props.isNeedSign && isReadOnly}
|
||||||
cols="50"
|
cols="50"
|
||||||
@@ -430,7 +464,7 @@ function PlaceholderType(props) {
|
|||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={textWidgetStyle}
|
style={textWidgetStyle}
|
||||||
className="select-none-cls overflow-hidden"
|
className="select-none-cls overflow-hidden uppercase"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
{props?.selectDate?.format ||
|
{props?.selectDate?.format ||
|
||||||
@@ -530,22 +564,52 @@ function PlaceholderType(props) {
|
|||||||
case textWidget:
|
case textWidget:
|
||||||
return (
|
return (
|
||||||
<textarea
|
<textarea
|
||||||
|
name="text"
|
||||||
|
ref={textRef}
|
||||||
readOnly
|
readOnly
|
||||||
placeholder={t("widgets-name.text")}
|
placeholder={t("widgets-name.text")}
|
||||||
rows={1}
|
rows={50}
|
||||||
value={
|
cols={50}
|
||||||
|
defaultValue={
|
||||||
widgetValue
|
widgetValue
|
||||||
}
|
}
|
||||||
className={textWidgetCls}
|
|
||||||
style={{
|
style={{
|
||||||
fontFamily: "Arial, sans-serif",
|
fontFamily: "Arial, sans-serif",
|
||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
color: fontColor,
|
color: fontColor,
|
||||||
background: "white"
|
background: "white"
|
||||||
}}
|
}}
|
||||||
cols="50"
|
className="w-full resize-none overflow-hidden text-base-content item-center outline-none"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
case drawWidget:
|
||||||
|
return prefillImgLoad[props.pos?.key] ? (
|
||||||
|
<div className="absolute w-full h-full inset-0 flex justify-center items-center bg-white/30 z-50">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
) : widgetValue ? (
|
||||||
|
<img
|
||||||
|
alt="signature"
|
||||||
|
draggable="false"
|
||||||
|
src={widgetValue}
|
||||||
|
className={`${props.pos.signatureType !== "type" ? "object-contain" : ""} w-full h-full select-none-cls`}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className={widgetCls}>
|
||||||
|
{props.pos.type && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: props.pos
|
||||||
|
? props.calculateFontsize(props.pos)
|
||||||
|
: "11px"
|
||||||
|
}}
|
||||||
|
className="font-medium"
|
||||||
|
>
|
||||||
|
{formatWidgetName()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return props.pos.SignUrl ? (
|
return props.pos.SignUrl ? (
|
||||||
<div className="pointer-events-none">
|
<div className="pointer-events-none">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { forwardRef, useEffect, useMemo, useRef, useState } from "react";
|
import React, { forwardRef, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
import {
|
import {
|
||||||
getMonth,
|
getMonth,
|
||||||
@@ -10,6 +10,8 @@ import {
|
|||||||
changeDateToMomentFormat,
|
changeDateToMomentFormat,
|
||||||
convertBase64ToFile,
|
convertBase64ToFile,
|
||||||
generatePdfName,
|
generatePdfName,
|
||||||
|
drawWidget,
|
||||||
|
getBase64MimeType,
|
||||||
isBase64
|
isBase64
|
||||||
} from "../../constant/Utils";
|
} from "../../constant/Utils";
|
||||||
import DatePicker from "react-datepicker";
|
import DatePicker from "react-datepicker";
|
||||||
@@ -27,6 +29,8 @@ import {
|
|||||||
setPrefillImg
|
setPrefillImg
|
||||||
} from "../../redux/reducers/widgetSlice";
|
} from "../../redux/reducers/widgetSlice";
|
||||||
import * as utils from "../../utils";
|
import * as utils from "../../utils";
|
||||||
|
import Draw from "./tab/Draw";
|
||||||
|
import PenColorComponent from "./tab/PenColorComponent";
|
||||||
|
|
||||||
const widgetTitle = "font-medium";
|
const widgetTitle = "font-medium";
|
||||||
|
|
||||||
@@ -72,7 +76,7 @@ const ImageComponent = (props) => {
|
|||||||
<div className="cursor-pointer op-card border-[1px] border-gray-400 flex flex-col w-full h-full justify-center items-center ">
|
<div className="cursor-pointer op-card border-[1px] border-gray-400 flex flex-col w-full h-full justify-center items-center ">
|
||||||
<img
|
<img
|
||||||
alt="print img"
|
alt="print img"
|
||||||
ref={(el) => (imageRefs.current[props?.position.key] = el)} // Assign ref dynamicallys
|
ref={(el) => (imageRefs.current[props?.id] = el)} // Assign ref dynamicallys
|
||||||
src={imgUrl}
|
src={imgUrl}
|
||||||
draggable="false"
|
draggable="false"
|
||||||
className="object-contain h-full w-full aspect-[5/2]"
|
className="object-contain h-full w-full aspect-[5/2]"
|
||||||
@@ -90,19 +94,14 @@ const ImageComponent = (props) => {
|
|||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
className="cursor-pointer op-card border-[1px] op-border-hover flex flex-col overflow-hidden w-full h-full aspect-[5/2] justify-center items-center"
|
className="cursor-pointer op-card border-[1px] op-border-hover flex flex-col overflow-hidden w-full h-full aspect-[5/2] justify-center items-center"
|
||||||
onClick={() => imageRefs.current[props?.position.key]?.click()}
|
onClick={() => imageRefs.current[props?.id]?.click()}
|
||||||
>
|
>
|
||||||
{props?.imageLoaders[props?.position?.key] && (
|
|
||||||
<div className="absolute w-full h-full inset-0 flex justify-center items-center bg-white/30 z-50">
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
onChange={(e) => props?.onImageChange?.(e, props?.position)}
|
onChange={(e) => props?.onImageChange?.(e, props?.position)}
|
||||||
className="filetype"
|
className="filetype"
|
||||||
accept="image/png,image/jpeg"
|
accept="image/png,image/jpeg"
|
||||||
ref={(el) => (imageRefs.current[props?.position.key] = el)} // Assign ref dynamically
|
ref={(el) => (imageRefs.current[props?.id] = el)} // Assign ref dynamically
|
||||||
hidden
|
hidden
|
||||||
/>
|
/>
|
||||||
<i className="fa-light text-base-content fa-cloud-upload-alt text-[25px]"></i>
|
<i className="fa-light text-base-content fa-cloud-upload-alt text-[25px]"></i>
|
||||||
@@ -116,20 +115,18 @@ const ImageComponent = (props) => {
|
|||||||
function PrefillWidgetModal(props) {
|
function PrefillWidgetModal(props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const canvasRefs = useRef({});
|
||||||
|
const [penColor, setPenColor] = useState("blue");
|
||||||
// Track already loaded image keys so they don't increment multiple times
|
// Track already loaded image keys so they don't increment multiple times
|
||||||
const loadedSet = useRef(new Set());
|
const loadedSet = useRef(new Set());
|
||||||
const initializedRef = useRef(false); // prevent rerun on state updates
|
const initializedRef = useRef(false); // prevent rerun on state updates
|
||||||
const [image, setImage] = useState(null);
|
const [image, setImage] = useState(null);
|
||||||
const [imageLoaders, setImageLoaders] = useState({});
|
|
||||||
const [currentWidget, setCurrentWidget] = useState("");
|
const [currentWidget, setCurrentWidget] = useState("");
|
||||||
const [userList, setUserList] = useState([]);
|
const [userList, setUserList] = useState([]);
|
||||||
const [totalImages, setTotalImages] = useState(0);
|
const [totalImages, setTotalImages] = useState(0);
|
||||||
const [loadedImages, setLoadedImages] = useState(0);
|
const [loadedImages, setLoadedImages] = useState(0);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const years = range(1950, getYear(new Date()) + 16, 1);
|
const years = range(1950, getYear(new Date()) + 16, 1);
|
||||||
const isAnyLoaderActive = Object.values(imageLoaders).some(
|
|
||||||
(val) => val === true
|
|
||||||
);
|
|
||||||
|
|
||||||
// useMemo to memoize the calculation of unique widgets
|
// useMemo to memoize the calculation of unique widgets
|
||||||
const uniqueWidget = useMemo(() => {
|
const uniqueWidget = useMemo(() => {
|
||||||
@@ -173,13 +170,14 @@ function PrefillWidgetModal(props) {
|
|||||||
}, [props?.isPrefillModal]);
|
}, [props?.isPrefillModal]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setLoading(true);
|
||||||
//function is used to save all image base64 in redux state to display prefill images
|
//function is used to save all image base64 in redux state to display prefill images
|
||||||
const savePrefillImg = async () => {
|
const savePrefillImg = async () => {
|
||||||
const prefillImg = await utils?.savePrefillImg(props.xyPosition);
|
const prefillImg = await utils?.savePrefillImg(props.xyPosition);
|
||||||
if (Array.isArray(prefillImg)) {
|
if (Array.isArray(prefillImg)) {
|
||||||
prefillImg.forEach((img) => dispatch(setPrefillImg(img)));
|
prefillImg.forEach((img) => dispatch(setPrefillImg(img)));
|
||||||
}
|
}
|
||||||
setImageLoaders({});
|
setLoading(false);
|
||||||
};
|
};
|
||||||
savePrefillImg();
|
savePrefillImg();
|
||||||
}, [props.xyPosition]);
|
}, [props.xyPosition]);
|
||||||
@@ -270,14 +268,15 @@ function PrefillWidgetModal(props) {
|
|||||||
handleWidgetDetails(position, newDate);
|
handleWidgetDetails(position, newDate);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSavePrefillImg = async (widgetDetails) => {
|
const handleSavePrefillImg = async (base64) => {
|
||||||
setImageLoaders((prev) => ({ ...prev, [widgetDetails?.key]: true }));
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const imageName = generatePdfName(16);
|
const imageName = generatePdfName(16);
|
||||||
|
const imgType = image?.imgType || getBase64MimeType(base64);
|
||||||
const imageUrl = await convertBase64ToFile(
|
const imageUrl = await convertBase64ToFile(
|
||||||
imageName,
|
imageName,
|
||||||
image.src,
|
base64 || image.src,
|
||||||
image.imgType
|
imgType
|
||||||
);
|
);
|
||||||
if (imageUrl) {
|
if (imageUrl) {
|
||||||
return imageUrl;
|
return imageUrl;
|
||||||
@@ -293,7 +292,7 @@ function PrefillWidgetModal(props) {
|
|||||||
const getPlaceholder = getPrefill?.placeHolder;
|
const getPlaceholder = getPrefill?.placeHolder;
|
||||||
let imgUrl;
|
let imgUrl;
|
||||||
if (widgetDetails?.type === "image") {
|
if (widgetDetails?.type === "image") {
|
||||||
imgUrl = await handleSavePrefillImg(widgetDetails);
|
imgUrl = await handleSavePrefillImg(response);
|
||||||
}
|
}
|
||||||
const updatedData = getPlaceholder.map((page) => ({
|
const updatedData = getPlaceholder.map((page) => ({
|
||||||
...page,
|
...page,
|
||||||
@@ -391,7 +390,7 @@ function PrefillWidgetModal(props) {
|
|||||||
if (item.options.name === position.options.name) {
|
if (item.options.name === position.options.name) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
SignUrl: "",
|
...(item.SignUrl !== undefined && { SignUrl: "" }),
|
||||||
options: {
|
options: {
|
||||||
...position.options,
|
...position.options,
|
||||||
response: ""
|
response: ""
|
||||||
@@ -419,9 +418,26 @@ function PrefillWidgetModal(props) {
|
|||||||
// (tracks how many images have finished loading)
|
// (tracks how many images have finished loading)
|
||||||
setLoadedImages((prev) => prev + 1);
|
setLoadedImages((prev) => prev + 1);
|
||||||
}
|
}
|
||||||
setImageLoaders({});
|
setLoading(false);
|
||||||
};
|
};
|
||||||
const handleWidgetType = (position) => {
|
//function for set signature url
|
||||||
|
const handleSignatureChange = (drawImage, position) => {
|
||||||
|
handleWidgetDetails(position, drawImage);
|
||||||
|
};
|
||||||
|
const getCanvasRef = (widgetId) => {
|
||||||
|
if (!canvasRefs.current[widgetId]) {
|
||||||
|
canvasRefs.current[widgetId] = React.createRef();
|
||||||
|
}
|
||||||
|
return canvasRefs.current[widgetId];
|
||||||
|
};
|
||||||
|
const clearCanvasById = (widgetId) => {
|
||||||
|
const canvasRef = canvasRefs.current?.[widgetId];
|
||||||
|
|
||||||
|
if (canvasRef?.current) {
|
||||||
|
canvasRef.current.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleWidgetType = (position, id) => {
|
||||||
switch (position?.type) {
|
switch (position?.type) {
|
||||||
case "checkbox":
|
case "checkbox":
|
||||||
return (
|
return (
|
||||||
@@ -533,10 +549,10 @@ function PrefillWidgetModal(props) {
|
|||||||
return (
|
return (
|
||||||
<ImageComponent
|
<ImageComponent
|
||||||
position={position}
|
position={position}
|
||||||
imageLoaders={imageLoaders}
|
|
||||||
onImageChange={onImageChange}
|
onImageChange={onImageChange}
|
||||||
handleImageLoaded={handleImageLoaded}
|
handleImageLoaded={handleImageLoaded}
|
||||||
handleClearImage={handleClearImage}
|
handleClearImage={handleClearImage}
|
||||||
|
id={id}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case radioButtonWidget:
|
case radioButtonWidget:
|
||||||
@@ -567,6 +583,34 @@ function PrefillWidgetModal(props) {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
case drawWidget:
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<span className={widgetTitle}>{position.options?.name}</span>
|
||||||
|
<Draw
|
||||||
|
penColor={penColor}
|
||||||
|
canvasRef={getCanvasRef(position.key)}
|
||||||
|
currWidgetsDetails={position}
|
||||||
|
handleSignatureChange={handleSignatureChange}
|
||||||
|
prefillCls={"prefillCanvas"}
|
||||||
|
/>
|
||||||
|
<div className="flex flex-row justify-between mt-[10px]">
|
||||||
|
<PenColorComponent
|
||||||
|
penColor={penColor}
|
||||||
|
setPenColor={setPenColor}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
onClick={() => {
|
||||||
|
clearCanvasById(position?.key);
|
||||||
|
handleClearImage(position);
|
||||||
|
}}
|
||||||
|
className="flex justify-start text-blue-500 underline cursor-pointer"
|
||||||
|
>
|
||||||
|
{t("clear")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return position?.SignUrl ? (
|
return position?.SignUrl ? (
|
||||||
<div className="pointer-events-none">
|
<div className="pointer-events-none">
|
||||||
@@ -586,6 +630,66 @@ function PrefillWidgetModal(props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleEmbedPrefill = async (item) => {
|
const handleEmbedPrefill = async (item) => {
|
||||||
|
//checking is there any draw widget response have base64 url then generate that base64 to url and save it
|
||||||
|
const prefillWidgets = props.xyPosition?.find((x) => x.Role === "prefill");
|
||||||
|
let updatedXyPosition = [];
|
||||||
|
if (prefillWidgets) {
|
||||||
|
const isDrawWidget = (prefillWidgets.placeHolder ?? []).some((ph) =>
|
||||||
|
(ph?.pos ?? []).some((p) => p?.type === drawWidget)
|
||||||
|
);
|
||||||
|
if (isDrawWidget) {
|
||||||
|
const getPrefill = props.xyPosition.find((x) => x?.Role === "prefill");
|
||||||
|
const getPlaceholder = getPrefill?.placeHolder ?? [];
|
||||||
|
const updatedData = await Promise.all(
|
||||||
|
getPlaceholder.map(async (page) => ({
|
||||||
|
...page,
|
||||||
|
pos: await Promise.all(
|
||||||
|
page.pos.map(async (item) => {
|
||||||
|
if (item?.type === drawWidget) {
|
||||||
|
const widgetResponse = item?.options?.response;
|
||||||
|
|
||||||
|
// Skip if no response
|
||||||
|
if (!widgetResponse) return item;
|
||||||
|
|
||||||
|
// If already URL, do not re-upload
|
||||||
|
if (
|
||||||
|
typeof widgetResponse === "string" &&
|
||||||
|
widgetResponse.startsWith("http")
|
||||||
|
) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert THIS widget's base64 → URL
|
||||||
|
const drawUrl = await handleSavePrefillImg(widgetResponse);
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
options: {
|
||||||
|
...item.options,
|
||||||
|
response: drawUrl
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
updatedXyPosition = props.xyPosition.map((obj) => {
|
||||||
|
if (obj.Role === "prefill") {
|
||||||
|
return {
|
||||||
|
...obj,
|
||||||
|
placeHolder: updatedData
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
|
||||||
|
props.setXyPosition(updatedXyPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await props.handleCreateDocument();
|
await props.handleCreateDocument();
|
||||||
};
|
};
|
||||||
//`loadOptions` function to use show all list of signer in dropdown
|
//`loadOptions` function to use show all list of signer in dropdown
|
||||||
@@ -593,9 +697,9 @@ function PrefillWidgetModal(props) {
|
|||||||
try {
|
try {
|
||||||
const baseURL = localStorage.getItem("baseUrl");
|
const baseURL = localStorage.getItem("baseUrl");
|
||||||
const url = `${baseURL}functions/getsigners`;
|
const url = `${baseURL}functions/getsigners`;
|
||||||
const token = {
|
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
const token =
|
||||||
};
|
{ "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
@@ -658,7 +762,7 @@ function PrefillWidgetModal(props) {
|
|||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-10 gap-y-4 w-full">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-10 gap-y-4 w-full">
|
||||||
{uniqueWidget.map((x, id) => (
|
{uniqueWidget.map((x, id) => (
|
||||||
<div key={id} className="flex flex-col gap-2 w-full">
|
<div key={id} className="flex flex-col gap-2 w-full">
|
||||||
{handleWidgetType(x.widget)}
|
{handleWidgetType(x.widget, id)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -727,7 +831,7 @@ function PrefillWidgetModal(props) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2 mx-4 mb-3">
|
<div className="flex gap-2 mx-4 mb-3">
|
||||||
<button
|
<button
|
||||||
disabled={isAnyLoaderActive || props?.isSubmit}
|
disabled={props?.isSubmit}
|
||||||
className="op-btn op-btn-primary op-btn-sm w-[80px]"
|
className="op-btn op-btn-primary op-btn-sm w-[80px]"
|
||||||
onClick={() => handleEmbedPrefill(props?.item)}
|
onClick={() => handleEmbedPrefill(props?.item)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import {
|
|||||||
textInputWidget,
|
textInputWidget,
|
||||||
cellsWidget,
|
cellsWidget,
|
||||||
textWidget,
|
textWidget,
|
||||||
widgets
|
widgets,
|
||||||
|
drawWidget
|
||||||
} from "../../constant/Utils";
|
} from "../../constant/Utils";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useWidgetDrag } from "../../hook/useWidgetDrag";
|
import { useWidgetDrag } from "../../hook/useWidgetDrag";
|
||||||
@@ -34,7 +35,8 @@ function WidgetComponent(props) {
|
|||||||
{ id: 13, text: "checkbox" },
|
{ id: 13, text: "checkbox" },
|
||||||
{ id: 14, text: "dropdown" },
|
{ id: 14, text: "dropdown" },
|
||||||
{ id: 15, text: radioButtonWidget },
|
{ id: 15, text: radioButtonWidget },
|
||||||
{ id: 16, text: "image" }
|
{ id: 16, text: "image" },
|
||||||
|
{ id: 17, text: drawWidget }
|
||||||
];
|
];
|
||||||
|
|
||||||
// Create all drag refs in one go
|
// Create all drag refs in one go
|
||||||
@@ -65,7 +67,8 @@ function WidgetComponent(props) {
|
|||||||
textInputWidget,
|
textInputWidget,
|
||||||
"date",
|
"date",
|
||||||
"image",
|
"image",
|
||||||
"checkbox"
|
"checkbox",
|
||||||
|
drawWidget
|
||||||
].includes(data.type)
|
].includes(data.type)
|
||||||
);
|
);
|
||||||
// allow only (signature, stamp, initials, text, cells) widget when isAllowModification true and user does not have session token
|
// allow only (signature, stamp, initials, text, cells) widget when isAllowModification true and user does not have session token
|
||||||
@@ -81,18 +84,19 @@ function WidgetComponent(props) {
|
|||||||
"name",
|
"name",
|
||||||
"email",
|
"email",
|
||||||
"job title",
|
"job title",
|
||||||
"company"
|
"company",
|
||||||
|
drawWidget
|
||||||
].includes(data.type)
|
].includes(data.type)
|
||||||
);
|
);
|
||||||
const selfSignWidgets = widgetList.filter(
|
const selfSignWidgets = widgetList.filter(
|
||||||
(data) =>
|
(data) =>
|
||||||
!["dropdown", radioButtonWidget, textInputWidget].includes(data.type)
|
!["dropdown", radioButtonWidget, textInputWidget,drawWidget].includes(data.type)
|
||||||
);
|
);
|
||||||
//if user select prefill role then allow only date,image,text,checkbox,radio,dropdownAdd commentMore actions
|
//if user select prefill role then allow only date,image,text,checkbox,radio,dropdownAdd commentMore actions
|
||||||
//dropdown widget should only be show in template flow
|
//dropdown widget should only be show in template flow
|
||||||
const prefillAllowWidgets = widgetList.filter((data) =>
|
const prefillAllowWidgets = widgetList.filter((data) =>
|
||||||
(props.isPrefillDropdown ? ["dropdown"] : [])
|
(props.isPrefillDropdown ? ["dropdown"] : [])
|
||||||
.concat([radioButtonWidget, textWidget, "date", "image", "checkbox"])
|
.concat([radioButtonWidget, textWidget, "date", "image", "checkbox",drawWidget])
|
||||||
.includes(data.type)
|
.includes(data.type)
|
||||||
);
|
);
|
||||||
//function to show widget on the base of conditionAdd commentMore actions
|
//function to show widget on the base of conditionAdd commentMore actions
|
||||||
@@ -108,7 +112,7 @@ function WidgetComponent(props) {
|
|||||||
return unlogedInUserWidgets;
|
return unlogedInUserWidgets;
|
||||||
}
|
}
|
||||||
} else if (props?.roleName !== "prefill") {
|
} else if (props?.roleName !== "prefill") {
|
||||||
return widgetList.filter((data) => ![textWidget].includes(data.type));
|
return widgetList.filter((data) => ![textWidget,drawWidget].includes(data.type));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleSelectRecipient = () => {
|
const handleSelectRecipient = () => {
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ const WidgetNameModal = (props) => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen={props.isOpen}
|
isOpen={props.isOpen}
|
||||||
@@ -309,8 +310,7 @@ const WidgetNameModal = (props) => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!props?.isSelfSign &&
|
{!props?.isSelfSign &&
|
||||||
!isSignOrInitials &&
|
!isSignOrInitials && (
|
||||||
props?.roleName !== "prefill" && (
|
|
||||||
<div className={showFontControls ? "mb-[0.5rem]" : "mb-[0.75rem]"}>
|
<div className={showFontControls ? "mb-[0.5rem]" : "mb-[0.75rem]"}>
|
||||||
<div className="flex flex-row gap-[10px] mb-[0.5rem]">
|
<div className="flex flex-row gap-[10px] mb-[0.5rem]">
|
||||||
{statusArr.map((data, ind) => {
|
{statusArr.map((data, ind) => {
|
||||||
@@ -373,7 +373,7 @@ const WidgetNameModal = (props) => {
|
|||||||
<label htmlFor="signaturetype" className="text-[14px] mb-[0.7rem]">
|
<label htmlFor="signaturetype" className="text-[14px] mb-[0.7rem]">
|
||||||
{t("allowed-signature-types")}
|
{t("allowed-signature-types")}
|
||||||
</label>
|
</label>
|
||||||
<div className=" ml-[7px] flex flex-col md:flex-row gap-[10px] mb-[0.7rem]">
|
<div className="ml-[7px] flex flex-col md:flex-row gap-[10px] mb-[0.7rem]">
|
||||||
{signatureType.map((type, i) => {
|
{signatureType.map((type, i) => {
|
||||||
return (
|
return (
|
||||||
<div key={i} className="flex flex-row gap-[5px] items-center">
|
<div key={i} className="flex flex-row gap-[5px] items-center">
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
|||||||
|
function DefaultSignature(props) {
|
||||||
|
return (
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<div
|
||||||
|
className={`${props?.currWidgetsDetails?.type === "initials" ? "intialSignatureCanvas" : "signatureCanvas"} border-[1.3px] border-gray-300 rounded-[4px]`}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={props?.defaultSignImg}
|
||||||
|
draggable="false"
|
||||||
|
className="w-full h-full object-contain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DefaultSignature;
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
import SignatureCanvas from "react-signature-canvas";
|
||||||
|
import { drawWidget } from "../../../constant/Utils";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
|
//this component is used for signature widget "Draw tab" and prefill user Draw widget
|
||||||
|
function Draw(props) {
|
||||||
|
const { prefillImg } = useSelector((state) => state.widget);
|
||||||
|
useEffect(() => {
|
||||||
|
handleDrawResponse();
|
||||||
|
}, [prefillImg]);
|
||||||
|
|
||||||
|
//function is used to show draw widget response
|
||||||
|
const handleDrawResponse = async () => {
|
||||||
|
if (
|
||||||
|
props?.currWidgetsDetails?.type === drawWidget &&
|
||||||
|
props?.canvasRef.current
|
||||||
|
) {
|
||||||
|
const getPrefillImg = prefillImg?.find(
|
||||||
|
(x) => x.id === props?.currWidgetsDetails?.key
|
||||||
|
);
|
||||||
|
const base64 = getPrefillImg?.base64;
|
||||||
|
props?.canvasRef.current.fromDataURL(base64);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<SignatureCanvas
|
||||||
|
ref={props?.canvasRef}
|
||||||
|
penColor={props?.penColor}
|
||||||
|
canvasProps={{
|
||||||
|
className: `${
|
||||||
|
props?.prefillCls
|
||||||
|
? "prefillCanvas"
|
||||||
|
: props?.currWidgetsDetails?.type === "initials"
|
||||||
|
? "intialSignatureCanvas"
|
||||||
|
: "signatureCanvas"
|
||||||
|
} border-[1.3px] border-gray-300 rounded-[10px]`
|
||||||
|
}}
|
||||||
|
onEnd={() =>
|
||||||
|
props?.handleSignatureChange(
|
||||||
|
props?.canvasRef.current?.toDataURL(),
|
||||||
|
props?.currWidgetsDetails
|
||||||
|
)
|
||||||
|
}
|
||||||
|
dotSize={1}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Draw;
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { useMemo } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
const ALLOWED_COLORS = ["blue", "red", "black"];
|
||||||
|
|
||||||
|
const COLOR_CLASS = {
|
||||||
|
blue: "text-blue-600",
|
||||||
|
red: "text-red-600",
|
||||||
|
black: "text-black",
|
||||||
|
white: "text-white"
|
||||||
|
};
|
||||||
|
|
||||||
|
function PenColorComponent({
|
||||||
|
providedColors,
|
||||||
|
penColor,
|
||||||
|
convertToImg,
|
||||||
|
fontSelect,
|
||||||
|
typedSignature,
|
||||||
|
setPenColor
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const pensList = useMemo(() => {
|
||||||
|
const allowed = new Set(ALLOWED_COLORS);
|
||||||
|
const filtered = Array.isArray(providedColors)
|
||||||
|
? providedColors
|
||||||
|
.map((c) => String(c).toLowerCase())
|
||||||
|
.filter((c) => allowed.has(c))
|
||||||
|
: [];
|
||||||
|
|
||||||
|
// remove duplicates while preserving order
|
||||||
|
return filtered.length ? [...new Set(filtered)] : ALLOWED_COLORS;
|
||||||
|
}, [providedColors]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-row items-center m-[5px] gap-3">
|
||||||
|
<span className="text-base-content">{t("options")}</span>
|
||||||
|
{pensList.map((color) => {
|
||||||
|
const selected = penColor === color;
|
||||||
|
return (
|
||||||
|
<i
|
||||||
|
key={color}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
aria-label={`Select ${color} pen`}
|
||||||
|
onClick={() => {
|
||||||
|
setPenColor?.(color);
|
||||||
|
convertToImg &&
|
||||||
|
convertToImg?.(fontSelect, typedSignature, color);
|
||||||
|
}}
|
||||||
|
className={`${COLOR_CLASS[color] || "text-base-content"} ${selected ? "border-current" : "border-white"} border-b-[2px] pb-0.5 cursor-pointer text-[16px] fa-light fa-pen-nib`}
|
||||||
|
></i>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export default PenColorComponent;
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
function TypeSignature(props) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="flex justify-between items-center tabWidth rounded-[4px]">
|
||||||
|
<span className="ml-[5px] text-[12px] text-base-content">
|
||||||
|
{props?.currWidgetsDetails?.type === "initials"
|
||||||
|
? t("initial-teb")
|
||||||
|
: t("signature-tab")}
|
||||||
|
:
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
maxLength={props?.currWidgetsDetails?.type === "initials" ? 3 : 30}
|
||||||
|
style={{ fontFamily: props?.fontSelect, color: props?.penColor }}
|
||||||
|
type="text"
|
||||||
|
className="bg-transparent ml-1 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-[20px]"
|
||||||
|
placeholder={
|
||||||
|
props?.currWidgetsDetails?.type === "initials"
|
||||||
|
? t("initial-type")
|
||||||
|
: t("signature-type")
|
||||||
|
}
|
||||||
|
value={props?.typedSignature}
|
||||||
|
onChange={(e) => {
|
||||||
|
props?.setTypedSignature(e.target.value);
|
||||||
|
if (e.target.value?.trim()?.length > 0) {
|
||||||
|
props?.convertToImg(props?.fontSelect, e.target.value);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="border-[1px] border-[#d6d3d3] mt-[10px] rounded-[4px] tabWidth">
|
||||||
|
{props?.fontOptions.map((font, ind) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={ind}
|
||||||
|
style={{
|
||||||
|
cursor: "pointer",
|
||||||
|
fontFamily: font.value,
|
||||||
|
backgroundColor:
|
||||||
|
props?.fontSelect === font.value && "rgb(206 225 247)"
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
props?.setFontSelect(font.value);
|
||||||
|
props?.convertToImg(font.value, props?.typedSignature);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="py-[5px] px-[10px] text-[20px]"
|
||||||
|
style={{ color: props?.penColor }}
|
||||||
|
>
|
||||||
|
{props?.typedSignature
|
||||||
|
? props?.typedSignature
|
||||||
|
: t("Your-Signature")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TypeSignature;
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import React, { useRef } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
function UploadImage(props) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const imageRefs = useRef({});
|
||||||
|
|
||||||
|
const getImageRef = (key) => {
|
||||||
|
if (!imageRefs.current[key]) {
|
||||||
|
imageRefs.current[key] = React.createRef();
|
||||||
|
}
|
||||||
|
return imageRefs.current[key];
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{(props?.isImageSelect || props?.isStampOrImage) && !props?.image ? (
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<div
|
||||||
|
className={`${props?.currWidgetsDetails?.type === "initials" ? "intialSignatureCanvas" : "signatureCanvas"} bg-white border-[1.3px] border-gray-300 flex flex-col justify-center items-center mb-[6px] cursor-pointer`}
|
||||||
|
onClick={() =>
|
||||||
|
getImageRef(props?.currWidgetsDetails?.key).current.click()
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
onChange={props?.onImageChange}
|
||||||
|
className="filetype"
|
||||||
|
accept="image/png,image/jpeg"
|
||||||
|
ref={getImageRef(props?.currWidgetsDetails?.key)}
|
||||||
|
hidden
|
||||||
|
/>
|
||||||
|
<i className="fa-light fa-cloud-upload-alt uploadImgLogo text-base-content"></i>
|
||||||
|
<div className="text-[10px] text-base-content">{t("upload")}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<div
|
||||||
|
className={`${props?.currWidgetsDetails?.type === "initials" ? "intialSignatureCanvas" : "signatureCanvas"} bg-white border-[1.3px] border-gray-300 mb-[6px] overflow-hidden`}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt="print img"
|
||||||
|
ref={getImageRef(props?.currWidgetsDetails?.key)}
|
||||||
|
src={props?.image?.src}
|
||||||
|
draggable="false"
|
||||||
|
className="object-contain h-full w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UploadImage;
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Tooltip } from "react-tooltip";
|
||||||
|
|
||||||
|
//This file is for both Text and textInput widgets
|
||||||
|
export default function TextInput(props) {
|
||||||
|
const [isMultiline, setIsMultiline] = useState();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const handleKeyDown = (e) => {
|
||||||
|
if (!isMultiline && e.key === "Enter") {
|
||||||
|
e.preventDefault(); // disable new line in single-line mode
|
||||||
|
}
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
if (props?.widgetValue) {
|
||||||
|
const isNextLine = props?.widgetValue.includes("\n");
|
||||||
|
if (isNextLine) {
|
||||||
|
setIsMultiline(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [props?.widgetValue]);
|
||||||
|
return (
|
||||||
|
<div style={{ position: "relative", width: "100%" }}>
|
||||||
|
{isMultiline ? (
|
||||||
|
<textarea
|
||||||
|
onBlur={props?.handleInputBlur}
|
||||||
|
ref={props?.widgetRef}
|
||||||
|
value={props?.widgetValue ?? ""} //use an empty string "" as a default
|
||||||
|
onChange={(e) => props?.handleOnchangeTextBox(e)}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
rows={3}
|
||||||
|
placeholder={t("widgets-name.text")}
|
||||||
|
// className={`${textInputcls} resize-none outline-none max-h-[100px] `}
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
padding: "12px 40px 12px 12px",
|
||||||
|
borderRadius: "20px",
|
||||||
|
border: "1px solid #dcdcdc",
|
||||||
|
fontSize: "16px",
|
||||||
|
resize: "none",
|
||||||
|
outline: "none"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<input
|
||||||
|
name="text"
|
||||||
|
ref={props?.widgetRef}
|
||||||
|
type="text"
|
||||||
|
placeholder={t("widgets-name.text")}
|
||||||
|
value={props?.widgetValue ?? ""} //use an empty string "" as a default
|
||||||
|
onChange={(e) => props?.handleOnchangeTextBox(e)}
|
||||||
|
className={`${props?.textInputcls} pr-4`}
|
||||||
|
onBlur={props?.handleInputBlur}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!isMultiline && (
|
||||||
|
<>
|
||||||
|
<i
|
||||||
|
data-tooltip-id="toggle-multiline"
|
||||||
|
className="fa-light fa-file-lines"
|
||||||
|
size={20}
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
right: "12px",
|
||||||
|
top: "50%",
|
||||||
|
transform: "translateY(-50%)",
|
||||||
|
color: "#444",
|
||||||
|
cursor: "pointer"
|
||||||
|
}}
|
||||||
|
onClick={() => setIsMultiline((prev) => !prev)}
|
||||||
|
></i>
|
||||||
|
|
||||||
|
<Tooltip id={"toggle-multiline"}>
|
||||||
|
<span>Toggle Multiline Text</span>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import EditorToolbar, { module1, module2, formats } from "../pdf/EditorToolbar";
|
|||||||
import Tooltip from "../../primitives/Tooltip";
|
import Tooltip from "../../primitives/Tooltip";
|
||||||
import Alert from "../../primitives/Alert";
|
import Alert from "../../primitives/Alert";
|
||||||
import Loader from "../../primitives/Loader";
|
import Loader from "../../primitives/Loader";
|
||||||
|
import { withSessionValidation } from "../../utils";
|
||||||
|
|
||||||
const MailTemplateEditor = ({
|
const MailTemplateEditor = ({
|
||||||
info,
|
info,
|
||||||
@@ -79,7 +80,7 @@ const MailTemplateEditor = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
//function to save completion email template
|
//function to save completion email template
|
||||||
const handleSaveCompletionEmail = async (e) => {
|
const handleSaveCompletionEmail = withSessionValidation(async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
try {
|
try {
|
||||||
const replacedHtmlBody = completionBody.replace(/"/g, "'");
|
const replacedHtmlBody = completionBody.replace(/"/g, "'");
|
||||||
@@ -103,9 +104,9 @@ const MailTemplateEditor = ({
|
|||||||
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
|
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
|
||||||
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
|
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
//function to save request email template
|
//function to save request email template
|
||||||
const handleSaveRequestEmail = async (e) => {
|
const handleSaveRequestEmail = withSessionValidation(async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
try {
|
try {
|
||||||
const replacedHtmlBody = requestBody.replace(/"/g, "'");
|
const replacedHtmlBody = requestBody.replace(/"/g, "'");
|
||||||
@@ -135,10 +136,10 @@ const MailTemplateEditor = ({
|
|||||||
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
|
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
|
||||||
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
|
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
//function to use reset form
|
//function to use reset form
|
||||||
const handleReset = async (request, completion) => {
|
const handleReset = withSessionValidation(async (request, completion) => {
|
||||||
let extUser =
|
let extUser =
|
||||||
localStorage.getItem("Extand_Class") &&
|
localStorage.getItem("Extand_Class") &&
|
||||||
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
@@ -185,7 +186,7 @@ const MailTemplateEditor = ({
|
|||||||
setIsMailLoader((p) => ({ ...p, completion: false }));
|
setIsMailLoader((p) => ({ ...p, completion: false }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
//function for handle ontext change and save again text in delta
|
//function for handle ontext change and save again text in delta
|
||||||
const handleOnchangeRequest = () => {
|
const handleOnchangeRequest = () => {
|
||||||
if (editorRef.current) {
|
if (editorRef.current) {
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
import MailTemplateEditor from "../MailTemplateEditor";
|
||||||
|
|
||||||
|
const EmailTab = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const {
|
||||||
|
tenantInfo
|
||||||
|
} = useSelector((state) => state.user);
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col mb-4">
|
||||||
|
<MailTemplateEditor
|
||||||
|
info={
|
||||||
|
tenantInfo
|
||||||
|
}
|
||||||
|
tenantId={tenantInfo?.objectId}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EmailTab;
|
||||||
@@ -0,0 +1,281 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { formatDate, withSessionValidation } from "../../../utils";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import {
|
||||||
|
setAlertInfo,
|
||||||
|
setLoader,
|
||||||
|
setUserInfo
|
||||||
|
} from "../../../redux/reducers/userReducer";
|
||||||
|
import DatePicker from "../../DatePicker";
|
||||||
|
import DateFormat from "../../DateFormat";
|
||||||
|
import {
|
||||||
|
changeDateToMomentFormat,
|
||||||
|
selectFormat
|
||||||
|
} from "../../../constant/Utils";
|
||||||
|
import moment from "moment";
|
||||||
|
import { Tooltip as ReactTooltip } from "react-tooltip";
|
||||||
|
|
||||||
|
const dateFormatArr = [
|
||||||
|
"L",
|
||||||
|
"DD-MM-YYYY",
|
||||||
|
"YYYY-MM-DD",
|
||||||
|
"MM.DD.YYYY",
|
||||||
|
"MM-DD-YYYY",
|
||||||
|
"MMM DD, YYYY",
|
||||||
|
"LL",
|
||||||
|
"DD MMM, YYYY",
|
||||||
|
"DD MMMM, YYYY",
|
||||||
|
"DD.MM.YYYY",
|
||||||
|
"DD/MM/YYYY"
|
||||||
|
];
|
||||||
|
|
||||||
|
const WidgetsTab = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const { userInfo } = useSelector((state) => state.user);
|
||||||
|
const [selectDate, setSelectDate] = useState({
|
||||||
|
date: "",
|
||||||
|
format: "MM/dd/yyyy"
|
||||||
|
});
|
||||||
|
const [dateFormatList, setDateFormatList] = useState([]);
|
||||||
|
const [dateWidget, setDateWidget] = useState({
|
||||||
|
isSigningDate: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
date: "",
|
||||||
|
format: "MM/dd/yyyy"
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
updateStates();
|
||||||
|
}, [userInfo]);
|
||||||
|
|
||||||
|
const updateStates = () => {
|
||||||
|
const widgetPreferences = userInfo?.WidgetPreferences || [];
|
||||||
|
const dateWidgetPref = widgetPreferences.find((w) => w.type === "date") || {
|
||||||
|
isSigningDate: false,
|
||||||
|
isReadOnly: false
|
||||||
|
};
|
||||||
|
setDateWidget({
|
||||||
|
isSigningDate: !!dateWidgetPref.isSigningDate,
|
||||||
|
isReadOnly: !!dateWidgetPref.isReadOnly,
|
||||||
|
date: dateWidgetPref.date,
|
||||||
|
format: dateWidgetPref.format
|
||||||
|
});
|
||||||
|
setSelectDate({ date: dateWidgetPref.date, format: dateWidgetPref.format });
|
||||||
|
const formatted = moment(
|
||||||
|
dateWidgetPref.date,
|
||||||
|
changeDateToMomentFormat(dateWidgetPref.format),
|
||||||
|
true
|
||||||
|
).toISOString();
|
||||||
|
formatDateList(formatted);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSigningDateChange = (e) => {
|
||||||
|
if (e.target.checked) {
|
||||||
|
setSelectDate({ date: "", format: selectDate.format });
|
||||||
|
}
|
||||||
|
setDateWidget((prev) => ({
|
||||||
|
...prev,
|
||||||
|
date: "",
|
||||||
|
isSigningDate: e.target.checked
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleReadOnlyChange = (e) => {
|
||||||
|
setDateWidget({ ...dateWidget, isReadOnly: e.target.checked });
|
||||||
|
};
|
||||||
|
|
||||||
|
const showAlert = (type, msg) => {
|
||||||
|
dispatch(setAlertInfo({ type, msg }));
|
||||||
|
setTimeout(() => {
|
||||||
|
dispatch(setAlertInfo({ type: "success", msg: "" }));
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
|
// `handleSave` is used save updated value signature type
|
||||||
|
const handleSave = withSessionValidation(async () => {
|
||||||
|
dispatch(setLoader(true));
|
||||||
|
try {
|
||||||
|
if (
|
||||||
|
dateWidget?.isReadOnly &&
|
||||||
|
!selectDate.date &&
|
||||||
|
!dateWidget.isSigningDate
|
||||||
|
) {
|
||||||
|
alert(t("read-only-date-error"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const res = await Parse.Cloud.run("setwidgetpreferences", {
|
||||||
|
dateWidget: dateWidget
|
||||||
|
});
|
||||||
|
if (res) {
|
||||||
|
const widgetPreferences = userInfo?.WidgetPreferences || [];
|
||||||
|
// Normalize booleans (simple + safe)
|
||||||
|
const dateOpt = { type: "date", ...dateWidget };
|
||||||
|
// Upsert: replace if exists, otherwise append
|
||||||
|
const updatedWidgetPreferences =
|
||||||
|
widgetPreferences?.length > 0
|
||||||
|
? widgetPreferences.map((w) => (w.type === "date" ? dateOpt : w))
|
||||||
|
: [...widgetPreferences, dateOpt];
|
||||||
|
const userdata = { ...userInfo };
|
||||||
|
userdata.WidgetPreferences = updatedWidgetPreferences;
|
||||||
|
dispatch(setUserInfo(userdata));
|
||||||
|
showAlert("success", t("saved-successfully"));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Widgets preferences error: ", error);
|
||||||
|
showAlert("danger", error.message);
|
||||||
|
} finally {
|
||||||
|
dispatch(setLoader(false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const handleDateChange = (date) => {
|
||||||
|
//function to save date and format in local array
|
||||||
|
const formattedDate = formatDate({
|
||||||
|
date: date,
|
||||||
|
format: selectDate.format
|
||||||
|
});
|
||||||
|
setDateWidget({
|
||||||
|
...dateWidget,
|
||||||
|
isSigningDate: false,
|
||||||
|
date: formattedDate,
|
||||||
|
format: selectDate.format
|
||||||
|
});
|
||||||
|
setSelectDate({ date: formattedDate, format: selectDate.format });
|
||||||
|
formatDateList(date);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatDateList = (selecteddate) => {
|
||||||
|
let date = selecteddate || new Date();
|
||||||
|
const list = dateFormatArr.map((dateFormat) => {
|
||||||
|
const format = selectFormat(dateFormat);
|
||||||
|
return { date: formatDate({ date, format }), format: format };
|
||||||
|
});
|
||||||
|
setDateFormatList(list);
|
||||||
|
};
|
||||||
|
const handleChangeFormat = (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const selectedIndex = Number(e.target.value);
|
||||||
|
const format = dateFormatList[selectedIndex]?.format;
|
||||||
|
const dateObj =
|
||||||
|
selectDate.date && !dateWidget?.isSigningDate
|
||||||
|
? { date: dateFormatList[selectedIndex]?.date, format: format }
|
||||||
|
: { format: format };
|
||||||
|
setDateWidget((prev) => ({ ...prev, ...dateObj }));
|
||||||
|
setSelectDate((prev) => ({ ...prev, ...dateObj }));
|
||||||
|
};
|
||||||
|
const handleClear = () => {
|
||||||
|
setSelectDate((prev) => ({ ...prev, date: "" }));
|
||||||
|
setDateWidget((prev) => ({ ...prev, date: "" }));
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div id="panel-widgets">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-12 md:gap-x-8 gap-y-6">
|
||||||
|
{/* Left Column - Signature Settings */}
|
||||||
|
<div className="md:col-span-6 flex flex-col">
|
||||||
|
<div>
|
||||||
|
<label className="inline-flex text-[14px] mb-0 font-medium">
|
||||||
|
{t("date-widget")}
|
||||||
|
<a data-tooltip-id="date-widget-tooltip" className="ml-1">
|
||||||
|
<sup>
|
||||||
|
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
|
||||||
|
</sup>
|
||||||
|
</a>
|
||||||
|
<ReactTooltip id="date-widget-tooltip" className="z-[999]">
|
||||||
|
<div className="max-w-[200px] md:max-w-[450px]">
|
||||||
|
<p className="font-bold"> {t("date-widget")}</p>
|
||||||
|
<p>{t("date-pref-help-sub-title")}</p>
|
||||||
|
<div className="p-[5px]">
|
||||||
|
<ol className="list-disc">
|
||||||
|
<li>
|
||||||
|
<span className="font-bold capitalize">
|
||||||
|
{t("format")}:{" "}
|
||||||
|
</span>
|
||||||
|
<span>{t("date-pref-help-format")}</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span className="font-bold capitalize">
|
||||||
|
{t("default-date")}:{" "}
|
||||||
|
</span>
|
||||||
|
<span>{t("date-pref-help-default-date")}</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span className="font-bold capitalize">
|
||||||
|
{t("signing-date")}:{" "}
|
||||||
|
</span>
|
||||||
|
<span>{t("date-pref-help-signing-date")}</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span className="font-bold capitalize">
|
||||||
|
{t("read-only")}:{" "}
|
||||||
|
</span>
|
||||||
|
<span>{t("date-pref-help-read-only")}</span>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ReactTooltip>
|
||||||
|
</label>
|
||||||
|
<DateFormat
|
||||||
|
selectDate={selectDate}
|
||||||
|
dateFormatList={dateFormatList}
|
||||||
|
handleChangeFormat={handleChangeFormat}
|
||||||
|
/>
|
||||||
|
<DatePicker
|
||||||
|
selectDate={selectDate}
|
||||||
|
onChange={handleDateChange}
|
||||||
|
handleClear={handleClear}
|
||||||
|
/>
|
||||||
|
<div className="mt-3 flex flex-col gap-2">
|
||||||
|
<div className="flex flex-row gap-2 items-center">
|
||||||
|
<input
|
||||||
|
className="op-checkbox op-checkbox-xs"
|
||||||
|
type="checkbox"
|
||||||
|
id="date-widget-signingdate"
|
||||||
|
name="isSigningDate"
|
||||||
|
onChange={handleSigningDateChange}
|
||||||
|
checked={dateWidget.isSigningDate}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="date-widget-signingdate"
|
||||||
|
className="text-sm font-medium text-base-content hover:underline underline-offset-2 cursor-pointer capitalize mb-0"
|
||||||
|
title={t("signing-date")}
|
||||||
|
>
|
||||||
|
{t("signing-date")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row gap-2 items-center">
|
||||||
|
<input
|
||||||
|
className="op-checkbox op-checkbox-xs"
|
||||||
|
type="checkbox"
|
||||||
|
id="date-widget-readonly"
|
||||||
|
name="isReadOnly"
|
||||||
|
onChange={handleReadOnlyChange}
|
||||||
|
checked={dateWidget.isReadOnly}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="date-widget-readonly"
|
||||||
|
className="text-sm font-medium text-base-content hover:underline underline-offset-2 cursor-pointer capitalize mb-0"
|
||||||
|
title={t("read-only")}
|
||||||
|
>
|
||||||
|
{t("read-only")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Save Button - Full Width */}
|
||||||
|
<div className="md:col-span-12 flex justify-start mt-3">
|
||||||
|
<button
|
||||||
|
className="op-btn op-btn-primary w-[110px]"
|
||||||
|
onClick={handleSave}
|
||||||
|
>
|
||||||
|
{t("save")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WidgetsTab;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import EmailTab from "./Email";
|
||||||
|
import WidgetsTab from "./Widgets";
|
||||||
|
|
||||||
|
export { EmailTab, WidgetsTab };
|
||||||
@@ -3,6 +3,7 @@ import Parse from "parse";
|
|||||||
import Alert from "../../../primitives/Alert";
|
import Alert from "../../../primitives/Alert";
|
||||||
import Loader from "../../../primitives/Loader";
|
import Loader from "../../../primitives/Loader";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { withSessionValidation } from "../../../utils";
|
||||||
|
|
||||||
const CreateFolder = ({ parentFolderId, onSuccess, folderCls, onBack }) => {
|
const CreateFolder = ({ parentFolderId, onSuccess, folderCls, onBack }) => {
|
||||||
const folderPtr = {
|
const folderPtr = {
|
||||||
@@ -18,7 +19,7 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls, onBack }) => {
|
|||||||
setAlert({ type: type, message: msg });
|
setAlert({ type: type, message: msg });
|
||||||
setTimeout(() => setAlert({ type: type, message: "" }), 1000);
|
setTimeout(() => setAlert({ type: type, message: "" }), 1000);
|
||||||
};
|
};
|
||||||
const handleCreateFolder = async (event) => {
|
const handleCreateFolder = withSessionValidation(async (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
handleLoader(true);
|
handleLoader(true);
|
||||||
if (name) {
|
if (name) {
|
||||||
@@ -41,6 +42,12 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls, onBack }) => {
|
|||||||
template.set("Folder", folderPtr);
|
template.set("Folder", folderPtr);
|
||||||
}
|
}
|
||||||
template.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
|
template.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
|
||||||
|
const ExtCls = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||||
|
template.set("ExtUserPtr", {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: "contracts_Users",
|
||||||
|
objectId: ExtCls[0].objectId
|
||||||
|
});
|
||||||
const res = await template.save();
|
const res = await template.save();
|
||||||
if (res) {
|
if (res) {
|
||||||
handleLoader(false);
|
handleLoader(false);
|
||||||
@@ -52,7 +59,7 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls, onBack }) => {
|
|||||||
handleLoader(false);
|
handleLoader(false);
|
||||||
showToast("info", t("fill-folder-name"));
|
showToast("info", t("fill-folder-name"));
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
const handleLoader = (status) => setIsLoader(status);
|
const handleLoader = (status) => setIsLoader(status);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
import { NavLink } from "react-router";
|
import { NavLink } from "react-router";
|
||||||
|
|
||||||
const Menu = ({ item, isOpen, closeSidebar }) => {
|
const Menu = ({ item, isOpen, closeSidebar }) => {
|
||||||
@@ -7,6 +7,8 @@ const Menu = ({ item, isOpen, closeSidebar }) => {
|
|||||||
"OpenSign™";
|
"OpenSign™";
|
||||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { selectedMenu } = useSelector((state) => state.sidebar);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={item.title} role="none" className="my-0.5">
|
<li key={item.title} role="none" className="my-0.5">
|
||||||
<NavLink
|
<NavLink
|
||||||
@@ -16,11 +18,9 @@ const Menu = ({ item, isOpen, closeSidebar }) => {
|
|||||||
: `/${item.objectId}`
|
: `/${item.objectId}`
|
||||||
}
|
}
|
||||||
className={({ isActive }) =>
|
className={({ isActive }) =>
|
||||||
`${
|
`${isActive && selectedMenu ? "bg-base-300 text-base-content" : ""} flex gap-x-5 items-center justify-start text-left p-3 text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none`
|
||||||
isActive ? " bg-base-300 text-base-content" : ""
|
|
||||||
} flex gap-x-5 items-center justify-start text-left p-3 text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none`
|
|
||||||
}
|
}
|
||||||
onClick={closeSidebar}
|
onClick={() => closeSidebar(item.title)}
|
||||||
tabIndex={isOpen ? 0 : -1}
|
tabIndex={isOpen ? 0 : -1}
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ import sidebarList, { subSetting } from "../../json/menuJson";
|
|||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { useWindowSize } from "../../hook/useWindowSize";
|
import { useWindowSize } from "../../hook/useWindowSize";
|
||||||
import { toggleSidebar } from "../../redux/reducers/sidebarReducer";
|
import {
|
||||||
|
setSelectedMenu,
|
||||||
|
toggleSidebar
|
||||||
|
} from "../../redux/reducers/sidebarReducer";
|
||||||
|
|
||||||
const Sidebar = () => {
|
const Sidebar = () => {
|
||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
@@ -29,6 +32,7 @@ const Sidebar = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const closeSidebar = () => {
|
const closeSidebar = () => {
|
||||||
|
dispatch(setSelectedMenu(true));
|
||||||
if (width <= 1023) {
|
if (width <= 1023) {
|
||||||
dispatch(toggleSidebar(false));
|
dispatch(toggleSidebar(false));
|
||||||
}
|
}
|
||||||
@@ -58,10 +62,12 @@ const Sidebar = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const toggleSubmenu = (title) => {
|
const toggleSubmenu = (title) => {
|
||||||
|
dispatch(setSelectedMenu(false));
|
||||||
setSubmenuOpen({ [title]: !submenuOpen[title] });
|
setSubmenuOpen({ [title]: !submenuOpen[title] });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMenuItem = () => {
|
const handleMenuItem = () => {
|
||||||
|
dispatch(setSelectedMenu(true));
|
||||||
closeSidebar();
|
closeSidebar();
|
||||||
setSubmenuOpen({});
|
setSubmenuOpen({});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
import { NavLink } from "react-router";
|
import { NavLink } from "react-router";
|
||||||
|
|
||||||
const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
|
const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
|
||||||
@@ -8,6 +8,8 @@ const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
|
|||||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { title, icon, children } = item;
|
const { title, icon, children } = item;
|
||||||
|
const { selectedMenu } = useSelector((state) => state.sidebar);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li role="none" className="my-0.5">
|
<li role="none" className="my-0.5">
|
||||||
<button
|
<button
|
||||||
@@ -45,11 +47,9 @@ const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
|
|||||||
: `/${childItem.objectId}`
|
: `/${childItem.objectId}`
|
||||||
}
|
}
|
||||||
className={({ isActive }) =>
|
className={({ isActive }) =>
|
||||||
`${
|
`${isActive && selectedMenu ? "bg-base-300 text-base-content" : ""} pl-4 flex items-center gap-x-5 py-2 text-sm cursor-pointer text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none`
|
||||||
isActive ? "bg-base-300 text-base-content " : ""
|
|
||||||
} pl-4 flex items-center gap-x-5 py-2 text-sm cursor-pointer text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none`
|
|
||||||
}
|
}
|
||||||
onClick={closeSidebar}
|
onClick={() => closeSidebar(childItem.title)}
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
tabIndex={submenuOpen ? 0 : -1}
|
tabIndex={submenuOpen ? 0 : -1}
|
||||||
>
|
>
|
||||||
|
|||||||
+240
-122
@@ -9,7 +9,11 @@ import fontkit from "@pdf-lib/fontkit";
|
|||||||
import { themeColor } from "./const";
|
import { themeColor } from "./const";
|
||||||
import { format, toZonedTime } from "date-fns-tz";
|
import { format, toZonedTime } from "date-fns-tz";
|
||||||
import i18n from "../i18n";
|
import i18n from "../i18n";
|
||||||
import { applyNumberFormulasToPages, buildDownloadFilename } from "../utils";
|
import {
|
||||||
|
applyNumberFormulasToPages,
|
||||||
|
buildDownloadFilename,
|
||||||
|
addPreferenceOpt
|
||||||
|
} from "../utils";
|
||||||
|
|
||||||
export const fontsizeArr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28];
|
export const fontsizeArr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28];
|
||||||
export const fontColorArr = ["red", "black", "blue", "yellow"];
|
export const fontColorArr = ["red", "black", "blue", "yellow"];
|
||||||
@@ -18,6 +22,7 @@ export const isTab = 767 < window.innerWidth < 1023;
|
|||||||
export const isHighResolution = window.innerWidth > 1023;
|
export const isHighResolution = window.innerWidth > 1023;
|
||||||
export const isTabAndMobile = window.innerWidth < 1023;
|
export const isTabAndMobile = window.innerWidth < 1023;
|
||||||
export const textInputWidget = "text input";
|
export const textInputWidget = "text input";
|
||||||
|
export const drawWidget = "draw";
|
||||||
export const textWidget = "text";
|
export const textWidget = "text";
|
||||||
export const radioButtonWidget = "radio button";
|
export const radioButtonWidget = "radio button";
|
||||||
export const cellsWidget = "cells";
|
export const cellsWidget = "cells";
|
||||||
@@ -28,6 +33,11 @@ const appName = "OpenSign™";
|
|||||||
|
|
||||||
export const defaultMailBody = `<p>Hi {{receiver_name}},</p><br><p>We hope this email finds you well. {{sender_name}} has requested you to review and sign {{document_title}}.</p><p>Your signature is crucial to proceed with the next steps as it signifies your agreement and authorization.</p><br><p><a href='{{signing_url}}' rel='noopener noreferrer' target='_blank'>Sign here</a></p><br><br><p>If you have any questions or need further clarification regarding the document or the signing process, please contact the sender.</p><br><p>Thanks</p><p> Team ${appName}</p><br>`;
|
export const defaultMailBody = `<p>Hi {{receiver_name}},</p><br><p>We hope this email finds you well. {{sender_name}} has requested you to review and sign {{document_title}}.</p><p>Your signature is crucial to proceed with the next steps as it signifies your agreement and authorization.</p><br><p><a href='{{signing_url}}' rel='noopener noreferrer' target='_blank'>Sign here</a></p><br><br><p>If you have any questions or need further clarification regarding the document or the signing process, please contact the sender.</p><br><p>Thanks</p><p> Team ${appName}</p><br>`;
|
||||||
export const defaultMailSubject = `{{sender_name}} has requested you to sign {{document_title}}`;
|
export const defaultMailSubject = `{{sender_name}} has requested you to sign {{document_title}}`;
|
||||||
|
export const nonPresentMaskCss = (base) => ({
|
||||||
|
...base,
|
||||||
|
width: "0px",
|
||||||
|
height: "0px"
|
||||||
|
});
|
||||||
|
|
||||||
export const randomId = (digit = 8) => {
|
export const randomId = (digit = 8) => {
|
||||||
// 1. Grab a cryptographically-secure 32-bit random value
|
// 1. Grab a cryptographically-secure 32-bit random value
|
||||||
@@ -351,7 +361,8 @@ export const widgets = [
|
|||||||
iconSize: "19px"
|
iconSize: "19px"
|
||||||
},
|
},
|
||||||
{ type: radioButtonWidget, icon: "fa-light fa-circle-dot", iconSize: "20px" },
|
{ type: radioButtonWidget, icon: "fa-light fa-circle-dot", iconSize: "20px" },
|
||||||
{ type: "image", icon: "fa-light fa-image", iconSize: "20px" }
|
{ type: "image", icon: "fa-light fa-image", iconSize: "20px" },
|
||||||
|
{ type: drawWidget, icon: "fa-light fa-pen-nib", iconSize: "20px" }
|
||||||
];
|
];
|
||||||
|
|
||||||
export const getDate = (dateformat) => {
|
export const getDate = (dateformat) => {
|
||||||
@@ -511,10 +522,15 @@ export const addWidgetOptions = (
|
|||||||
const dateFormat = signer?.DateFormat
|
const dateFormat = signer?.DateFormat
|
||||||
? selectFormat(signer?.DateFormat)
|
? selectFormat(signer?.DateFormat)
|
||||||
: "MM/dd/yyyy";
|
: "MM/dd/yyyy";
|
||||||
|
const options = addPreferenceOpt(signer, "date", role);
|
||||||
return {
|
return {
|
||||||
...defaultOpt,
|
...defaultOpt,
|
||||||
response: role === "prefill" ? getDate(signer?.DateFormat) : "",
|
response: options?.response || "",
|
||||||
validation: { format: dateFormat, type: "date-format" }
|
isReadOnly: options?.isReadOnly || false,
|
||||||
|
validation: {
|
||||||
|
format: options?.format || dateFormat,
|
||||||
|
type: "date-format"
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "image":
|
case "image":
|
||||||
@@ -535,6 +551,8 @@ export const addWidgetOptions = (
|
|||||||
};
|
};
|
||||||
case textWidget:
|
case textWidget:
|
||||||
return defaultOpt;
|
return defaultOpt;
|
||||||
|
case drawWidget:
|
||||||
|
return defaultOpt;
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -544,7 +562,8 @@ export const addWidgetSelfsignOptions = (
|
|||||||
type,
|
type,
|
||||||
getWidgetValue,
|
getWidgetValue,
|
||||||
owner,
|
owner,
|
||||||
placeholder
|
placeholder,
|
||||||
|
isSignyourself
|
||||||
) => {
|
) => {
|
||||||
let defaultOpt;
|
let defaultOpt;
|
||||||
//condition to handle widgets name field
|
//condition to handle widgets name field
|
||||||
@@ -599,10 +618,17 @@ export const addWidgetSelfsignOptions = (
|
|||||||
const dateFormat = owner?.DateFormat
|
const dateFormat = owner?.DateFormat
|
||||||
? selectFormat(owner?.DateFormat)
|
? selectFormat(owner?.DateFormat)
|
||||||
: "MM/dd/yyyy";
|
: "MM/dd/yyyy";
|
||||||
|
const options = addPreferenceOpt(owner, "date", "", isSignyourself);
|
||||||
return {
|
return {
|
||||||
...defaultOpt,
|
...defaultOpt,
|
||||||
response: getDate(owner?.DateFormat),
|
response: options?.response || "",
|
||||||
validation: { format: dateFormat, type: "date-format" }
|
...(!isSignyourself
|
||||||
|
? { isReadOnly: options?.isReadOnly || false }
|
||||||
|
: {}),
|
||||||
|
validation: {
|
||||||
|
format: options?.format || dateFormat,
|
||||||
|
type: "date-format"
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "image":
|
case "image":
|
||||||
@@ -650,10 +676,13 @@ export const defaultWidthHeight = (type) => {
|
|||||||
return { width: 5, height: 10 };
|
return { width: 5, height: 10 };
|
||||||
case textWidget:
|
case textWidget:
|
||||||
return { width: 150, height: 19 };
|
return { width: 150, height: 19 };
|
||||||
|
case drawWidget:
|
||||||
|
return { width: 150, height: 60 };
|
||||||
default:
|
default:
|
||||||
return { width: 150, height: 60 };
|
return { width: 150, height: 60 };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
//convert url to base64
|
||||||
export async function getBase64FromUrl(url, autosign) {
|
export async function getBase64FromUrl(url, autosign) {
|
||||||
const data = await fetch(url);
|
const data = await fetch(url);
|
||||||
const blob = await data.blob();
|
const blob = await data.blob();
|
||||||
@@ -849,6 +878,7 @@ export const signPdfFun = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createDocument = async (
|
export const createDocument = async (
|
||||||
template,
|
template,
|
||||||
placeholders,
|
placeholders,
|
||||||
@@ -900,6 +930,8 @@ export const createDocument = async (
|
|||||||
const RedirectUrl = Doc?.RedirectUrl
|
const RedirectUrl = Doc?.RedirectUrl
|
||||||
? { RedirectUrl: Doc?.RedirectUrl }
|
? { RedirectUrl: Doc?.RedirectUrl }
|
||||||
: {};
|
: {};
|
||||||
|
const PenColors =
|
||||||
|
Doc?.PenColors?.length > 0 ? { PenColors: Doc?.PenColors } : {};
|
||||||
const TemplateId = Doc?.objectId
|
const TemplateId = Doc?.objectId
|
||||||
? {
|
? {
|
||||||
TemplateId: {
|
TemplateId: {
|
||||||
@@ -922,11 +954,7 @@ export const createDocument = async (
|
|||||||
className: "contracts_Users",
|
className: "contracts_Users",
|
||||||
objectId: extUserId
|
objectId: extUserId
|
||||||
},
|
},
|
||||||
CreatedBy: {
|
CreatedBy: { __type: "Pointer", className: "_User", objectId: creatorId },
|
||||||
__type: "Pointer",
|
|
||||||
className: "_User",
|
|
||||||
objectId: creatorId
|
|
||||||
},
|
|
||||||
Signers: signers,
|
Signers: signers,
|
||||||
SendinOrder: Doc?.SendinOrder || false,
|
SendinOrder: Doc?.SendinOrder || false,
|
||||||
AutomaticReminders: Doc?.AutomaticReminders || false,
|
AutomaticReminders: Doc?.AutomaticReminders || false,
|
||||||
@@ -940,7 +968,8 @@ export const createDocument = async (
|
|||||||
...NotifyOnSignatures,
|
...NotifyOnSignatures,
|
||||||
...Bcc,
|
...Bcc,
|
||||||
...RedirectUrl,
|
...RedirectUrl,
|
||||||
...TemplateId
|
...TemplateId,
|
||||||
|
...PenColors
|
||||||
};
|
};
|
||||||
const remindOnceInEvery = Doc?.RemindOnceInEvery;
|
const remindOnceInEvery = Doc?.RemindOnceInEvery;
|
||||||
const TimeToCompleteDays = parseInt(Doc?.TimeToCompleteDays);
|
const TimeToCompleteDays = parseInt(Doc?.TimeToCompleteDays);
|
||||||
@@ -949,23 +978,27 @@ export const createDocument = async (
|
|||||||
if (AutomaticReminders && reminderCount > 15) {
|
if (AutomaticReminders && reminderCount > 15) {
|
||||||
return { status: "error", id: "only-15-reminder-allowed" };
|
return { status: "error", id: "only-15-reminder-allowed" };
|
||||||
}
|
}
|
||||||
|
const url = `${localStorage.getItem("baseUrl")}classes/contracts_Document`;
|
||||||
|
const token = {
|
||||||
|
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
const res = await axios.post(
|
const res = await axios.post(url, data, {
|
||||||
`${localStorage.getItem("baseUrl")}classes/contracts_Document`,
|
headers: {
|
||||||
data,
|
"Content-Type": "application/json",
|
||||||
{
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
headers: {
|
...token
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
if (res) {
|
if (res) {
|
||||||
return { status: "success", id: res.data.objectId, data: res.data };
|
const result = res.data;
|
||||||
|
|
||||||
|
return { status: "success", id: result.objectId, data: result };
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("axois err ", err);
|
const message =
|
||||||
|
err?.response?.data?.error || err?.message || "something went wrong.";
|
||||||
|
console.error("error in create document:", message);
|
||||||
return { status: "error", id: "something-went-wrong-mssg" };
|
return { status: "error", id: "something-went-wrong-mssg" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1037,7 +1070,8 @@ export const onChangeInput = (
|
|||||||
dateFormat,
|
dateFormat,
|
||||||
fontSize,
|
fontSize,
|
||||||
fontColor,
|
fontColor,
|
||||||
dateDetails
|
dateDetails,
|
||||||
|
textWidgetHeight
|
||||||
) => {
|
) => {
|
||||||
const isSigners = xyPosition.some(
|
const isSigners = xyPosition.some(
|
||||||
(data) => data.signerPtr || data.Role === "prefill"
|
(data) => data.signerPtr || data.Role === "prefill"
|
||||||
@@ -1087,6 +1121,16 @@ export const onChangeInput = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} else if (
|
||||||
|
(currentPosition?.type === "text" ||
|
||||||
|
currentPosition?.type === textInputWidget) &&
|
||||||
|
textWidgetHeight &&
|
||||||
|
!value
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
...position,
|
||||||
|
Height: textWidgetHeight
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
...position,
|
...position,
|
||||||
@@ -1137,6 +1181,15 @@ export const onChangeInput = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} else if (
|
||||||
|
currentPosition?.type === "text" &&
|
||||||
|
textWidgetHeight &&
|
||||||
|
!value
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
...positionData,
|
||||||
|
Height: textWidgetHeight
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
...positionData,
|
...positionData,
|
||||||
@@ -1429,19 +1482,26 @@ export function onSaveSign(
|
|||||||
const signImg = typedSignature
|
const signImg = typedSignature
|
||||||
? convertTextToImg(typeFont, typedSignature, fontColor, widgetDims)
|
? convertTextToImg(typeFont, typedSignature, fontColor, widgetDims)
|
||||||
: signatureImg;
|
: signatureImg;
|
||||||
return {
|
if (widgetsType === drawWidget) {
|
||||||
...position,
|
return {
|
||||||
...(type === "type" ? { Width: posWidth } : {}),
|
...position,
|
||||||
...(type === "type" ? { Height: posHeight } : {}),
|
options: { ...position.options, response: signImg }
|
||||||
SignUrl: signImg,
|
};
|
||||||
...(isSignOrInitials && { signatureType: type || "" }),
|
} else {
|
||||||
options: { ...position.options, response: signImg },
|
return {
|
||||||
...(typedSignature && {
|
...position,
|
||||||
typeSignature: typedSignature,
|
...(type === "type" ? { Width: posWidth } : {}),
|
||||||
typeFont: typeFont ?? "Fasthand",
|
...(type === "type" ? { Height: posHeight } : {}),
|
||||||
fontColor: fontColor ?? "blue"
|
SignUrl: signImg,
|
||||||
})
|
...(isSignOrInitials && { signatureType: type || "" }),
|
||||||
};
|
options: { ...position.options, response: signImg },
|
||||||
|
...(typedSignature && {
|
||||||
|
typeSignature: typedSignature,
|
||||||
|
typeFont: typeFont ?? "Fasthand",
|
||||||
|
fontColor: fontColor ?? "blue"
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return position;
|
return position;
|
||||||
});
|
});
|
||||||
@@ -1453,7 +1513,7 @@ export function onSaveSign(
|
|||||||
return obj;
|
return obj;
|
||||||
});
|
});
|
||||||
//condition when draw/upload signature/initials then apply it all related to widgets (draw, typed signature or default signature)
|
//condition when draw/upload signature/initials then apply it all related to widgets (draw, typed signature or default signature)
|
||||||
if (isApplyAll || isAutoSign) {
|
if ((isApplyAll || isAutoSign) && widgetsType !== drawWidget) {
|
||||||
const updatedArray = updateXYposition.map((page) => ({
|
const updatedArray = updateXYposition.map((page) => ({
|
||||||
...page,
|
...page,
|
||||||
pos: page.pos.map((item) => {
|
pos: page.pos.map((item) => {
|
||||||
@@ -1605,7 +1665,9 @@ export function onSaveImage(
|
|||||||
isAutoSign,
|
isAutoSign,
|
||||||
widgetsType,
|
widgetsType,
|
||||||
isApplyAll,
|
isApplyAll,
|
||||||
imgUrl
|
imgUrl,
|
||||||
|
defaultStampImg,
|
||||||
|
defaultStampType
|
||||||
) {
|
) {
|
||||||
// let getIMGWH;
|
// let getIMGWH;
|
||||||
const isSignOrInitials =
|
const isSignOrInitials =
|
||||||
@@ -1616,12 +1678,12 @@ export function onSaveImage(
|
|||||||
if (position.key === signKey) {
|
if (position.key === signKey) {
|
||||||
return {
|
return {
|
||||||
...position,
|
...position,
|
||||||
SignUrl: imgUrl || image.src,
|
SignUrl: imgUrl || image?.src || defaultStampImg,
|
||||||
ImageType: image.imgType,
|
ImageType: image?.imgType || defaultStampType,
|
||||||
...(isSignOrInitials && { signatureType: signatureType || "" }),
|
...(isSignOrInitials && { signatureType: signatureType || "" }),
|
||||||
options: {
|
options: {
|
||||||
...position.options,
|
...position.options,
|
||||||
response: imgUrl || image.src
|
response: imgUrl || image?.src || defaultStampImg
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1643,16 +1705,17 @@ export function onSaveImage(
|
|||||||
item.type === widgetsType && item.type !== "image"
|
item.type === widgetsType && item.type !== "image"
|
||||||
? {
|
? {
|
||||||
...item,
|
...item,
|
||||||
SignUrl: image.src,
|
SignUrl: image?.src || defaultStampImg,
|
||||||
ImageType: image.imgType,
|
ImageType: image?.imgType || defaultStampType,
|
||||||
options: {
|
options: {
|
||||||
...item.options,
|
...item.options,
|
||||||
response: image.src
|
response: image?.src || defaultStampImg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
: item // Otherwise, keep it unchanged
|
: item // Otherwise, keep it unchanged
|
||||||
)
|
)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return updatedArray;
|
return updatedArray;
|
||||||
} else {
|
} else {
|
||||||
return updateXYposition;
|
return updateXYposition;
|
||||||
@@ -1792,6 +1855,26 @@ export const isBase64 = (str) => {
|
|||||||
/^data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+)?;base64,[A-Za-z0-9+/=]+$/;
|
/^data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+)?;base64,[A-Za-z0-9+/=]+$/;
|
||||||
return base64Pattern.test(str);
|
return base64Pattern.test(str);
|
||||||
};
|
};
|
||||||
|
// Break a long word into smaller parts character-by-character
|
||||||
|
const forceBreakLongWord = (word, width, font, fontSize) => {
|
||||||
|
const parts = [];
|
||||||
|
let current = "";
|
||||||
|
|
||||||
|
for (const char of word) {
|
||||||
|
const lineWidth = font.widthOfTextAtSize(current + char, fontSize);
|
||||||
|
|
||||||
|
if (lineWidth <= width) {
|
||||||
|
current += char;
|
||||||
|
} else {
|
||||||
|
parts.push(current);
|
||||||
|
current = char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (current) parts.push(current);
|
||||||
|
|
||||||
|
return parts;
|
||||||
|
};
|
||||||
|
|
||||||
//function for embed all type widgets in document using pdf-lib
|
//function for embed all type widgets in document using pdf-lib
|
||||||
export const embedWidgetsToDoc = async (
|
export const embedWidgetsToDoc = async (
|
||||||
widgets,
|
widgets,
|
||||||
@@ -1831,6 +1914,13 @@ export const embedWidgetsToDoc = async (
|
|||||||
} else {
|
} else {
|
||||||
updateItem = item.pos;
|
updateItem = item.pos;
|
||||||
}
|
}
|
||||||
|
const ImgTypeWidget = [
|
||||||
|
"signature",
|
||||||
|
"stamp",
|
||||||
|
"initials",
|
||||||
|
"image",
|
||||||
|
drawWidget
|
||||||
|
];
|
||||||
const pageNo = item.pageNumber;
|
const pageNo = item.pageNumber;
|
||||||
const widgetsPositionArr = updateItem;
|
const widgetsPositionArr = updateItem;
|
||||||
const pages = pdfDoc.getPages();
|
const pages = pdfDoc.getPages();
|
||||||
@@ -1856,14 +1946,13 @@ export const embedWidgetsToDoc = async (
|
|||||||
images = await Promise.all(
|
images = await Promise.all(
|
||||||
widgetsPositionArr.map(async (widget) => {
|
widgetsPositionArr.map(async (widget) => {
|
||||||
// `SignUrl` this is wrong nomenclature and maintain for older code in this options we save base64 of signature image from sign pad
|
// `SignUrl` this is wrong nomenclature and maintain for older code in this options we save base64 of signature image from sign pad
|
||||||
let signbase64 = widget.SignUrl && widget.SignUrl;
|
let signbase64 = widget?.options?.response;
|
||||||
const widgetDims = { Width: widget.Width, Height: widget.Height };
|
const widgetDims = { Width: widget.Width, Height: widget.Height };
|
||||||
if (signbase64) {
|
if (signbase64 && ImgTypeWidget.includes(widget.type)) {
|
||||||
if (!isBase64(signbase64) && prefillImg) {
|
if (!isBase64(signbase64) && prefillImg) {
|
||||||
const imgData = prefillImg?.find((x) => x?.id === widget?.key);
|
const imgData = prefillImg?.find((x) => x?.id === widget?.key);
|
||||||
signbase64 = imgData?.base64;
|
signbase64 = imgData?.base64;
|
||||||
}
|
}
|
||||||
|
|
||||||
// let arr = signbase64.split(",");
|
// let arr = signbase64.split(",");
|
||||||
// const mime = arr[0].match(/:(.*?);/)[1];
|
// const mime = arr[0].match(/:(.*?);/)[1];
|
||||||
const signatureImg = await convertBase64ToImg(
|
const signatureImg = await convertBase64ToImg(
|
||||||
@@ -1895,9 +1984,7 @@ export const embedWidgetsToDoc = async (
|
|||||||
if (hasError) break; // Stop the inner loop if an error occurred
|
if (hasError) break; // Stop the inner loop if an error occurred
|
||||||
try {
|
try {
|
||||||
let img;
|
let img;
|
||||||
if (
|
if (ImgTypeWidget.includes(position.type)) {
|
||||||
["signature", "stamp", "initials", "image"].includes(position.type)
|
|
||||||
) {
|
|
||||||
if (images[id].mimetype === "image/png") {
|
if (images[id].mimetype === "image/png") {
|
||||||
img = await pdfDoc.embedPng(images[id].arrayBuffer);
|
img = await pdfDoc.embedPng(images[id].arrayBuffer);
|
||||||
} else {
|
} else {
|
||||||
@@ -2080,41 +2167,59 @@ export const embedWidgetsToDoc = async (
|
|||||||
const lines = [];
|
const lines = [];
|
||||||
let currentLine = "";
|
let currentLine = "";
|
||||||
|
|
||||||
for (const word of textContent?.split(" ")) {
|
const words = textContent?.split(" ");
|
||||||
//get text line width
|
for (let word of words) {
|
||||||
const lineWidth = font.widthOfTextAtSize(
|
const testLine = currentLine ? currentLine + " " + word : word;
|
||||||
`${currentLine} ${word}`,
|
const testWidth = font.widthOfTextAtSize(testLine, fontSize);
|
||||||
fontSize
|
|
||||||
);
|
if (testWidth <= width) {
|
||||||
//check text content line width is less or equal to container width
|
currentLine = testLine;
|
||||||
if (lineWidth <= width) {
|
|
||||||
currentLine += ` ${word}`;
|
|
||||||
} else {
|
} else {
|
||||||
lines.push(currentLine.trim());
|
// If single long word
|
||||||
currentLine = `${word}`;
|
if (font.widthOfTextAtSize(word, fontSize) > width) {
|
||||||
|
// Break a long word into smaller parts character-by-character
|
||||||
|
const brokenParts = forceBreakLongWord(
|
||||||
|
word,
|
||||||
|
width,
|
||||||
|
font,
|
||||||
|
fontSize
|
||||||
|
);
|
||||||
|
|
||||||
|
// push currentLine before breaking word
|
||||||
|
if (currentLine.trim()) lines.push(currentLine.trim());
|
||||||
|
|
||||||
|
// push ALL broken parts in order
|
||||||
|
brokenParts.forEach((p) => lines.push(p));
|
||||||
|
|
||||||
|
currentLine = "";
|
||||||
|
} else {
|
||||||
|
// push current line and start new
|
||||||
|
if (currentLine.trim()) lines.push(currentLine.trim());
|
||||||
|
currentLine = word;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lines.push(currentLine.trim());
|
if (currentLine.trim()) lines.push(currentLine.trim());
|
||||||
return lines;
|
return lines;
|
||||||
};
|
};
|
||||||
// Function to break text into lines based on when user go next line on press enter button
|
// Function to break text into lines based on when user go next line on press enter button
|
||||||
const breakTextIntoLines = (textContent, width) => {
|
const breakTextIntoLines = (textContent, width) => {
|
||||||
const lines = [];
|
const finalLines = [];
|
||||||
for (const word of textContent.split("\n")) {
|
const paragraphs = textContent.split("\n"); // preserve user order
|
||||||
const lineWidth = font.widthOfTextAtSize(`${word}`, fontSize);
|
for (const para of paragraphs) {
|
||||||
|
const lineWidth = font.widthOfTextAtSize(para, fontSize);
|
||||||
//checking string length to container width
|
//checking string length to container width
|
||||||
//if string length is less then container width it means user press enter button
|
//if string length is less then container width it means user press enter button
|
||||||
if (lineWidth <= width) {
|
if (lineWidth <= width) {
|
||||||
lines.push(word);
|
// user forced newline
|
||||||
}
|
finalLines.push(para);
|
||||||
//else adjust text content according to width and send it in new line
|
} else {
|
||||||
else {
|
// auto wrap paragraph
|
||||||
const newLine = NewbreakTextIntoLines(word, width);
|
finalLines.push(...NewbreakTextIntoLines(para, width));
|
||||||
lines.push(...newLine);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lines;
|
return finalLines;
|
||||||
};
|
};
|
||||||
//check if text content have `\n` string it means user press enter to go next line and handle condition
|
//check if text content have `\n` string it means user press enter to go next line and handle condition
|
||||||
//else auto adjust text content according to container width
|
//else auto adjust text content according to container width
|
||||||
@@ -3022,13 +3127,17 @@ export const getDefaultSignature = async (objectId) => {
|
|||||||
const defaultInitial = res?.Initials
|
const defaultInitial = res?.Initials
|
||||||
? await getBase64FromUrl(res?.Initials, true)
|
? await getBase64FromUrl(res?.Initials, true)
|
||||||
: "";
|
: "";
|
||||||
|
const defaultStamp = res?.Stamp
|
||||||
|
? await getBase64FromUrl(res?.Stamp, true)
|
||||||
|
: "";
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: "success",
|
status: "success",
|
||||||
res: {
|
res: {
|
||||||
id: result?.id,
|
id: result?.id,
|
||||||
defaultSignature: defaultSignature,
|
defaultSignature: defaultSignature,
|
||||||
defaultInitial: defaultInitial
|
defaultInitial: defaultInitial,
|
||||||
|
defaultStamp: defaultStamp
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -3259,8 +3368,8 @@ export async function handleSignatureType(tenantSignTypes, signatureType) {
|
|||||||
return updatedSignatureType;
|
return updatedSignatureType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// `formatDate` is used to format date to dd-mmm-yyy
|
// `formatDateToDdMmmYyyy` is used to format date to dd-mmm-yyyy
|
||||||
export const formatDate = (date) => {
|
export const formatDateToDdMmmYyyy = (date) => {
|
||||||
// Create a Date object
|
// Create a Date object
|
||||||
const newDate = new Date(date);
|
const newDate = new Date(date);
|
||||||
// Format the date
|
// Format the date
|
||||||
@@ -3405,7 +3514,7 @@ export const mailTemplate = (param) => {
|
|||||||
const appName = "OpenSign™";
|
const appName = "OpenSign™";
|
||||||
const logo = `<div style='padding:10px'><img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' /></div>`;
|
const logo = `<div style='padding:10px'><img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' /></div>`;
|
||||||
|
|
||||||
const opurl = ` <a href='https://www.opensignlabs.com' target=_blank>here</a>.</p></div></div></body></html>`;
|
const opurl = ` <a href="mailto:complaint@opensiglabs.com" target=_blank>here</a>.</p></div></div></body></html>`;
|
||||||
const subject = `${param.senderName} has requested you to sign "${param.title}"`;
|
const subject = `${param.senderName} has requested you to sign "${param.title}"`;
|
||||||
const body =
|
const body =
|
||||||
"<html><head><meta http-equiv='Content-Type' content='text/html;charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background:white;padding-bottom:20px'>" +
|
"<html><head><meta http-equiv='Content-Type' content='text/html;charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background:white;padding-bottom:20px'>" +
|
||||||
@@ -3428,7 +3537,7 @@ export const mailTemplate = (param) => {
|
|||||||
appName +
|
appName +
|
||||||
". For any queries regarding this email, please contact the sender " +
|
". For any queries regarding this email, please contact the sender " +
|
||||||
param.senderMail +
|
param.senderMail +
|
||||||
" directly. If you think this email is inappropriate or spam, you may file a complaint with " +
|
" directly. If you think this email is inappropriate or spam, you may file a complaints with " +
|
||||||
appName +
|
appName +
|
||||||
opurl;
|
opurl;
|
||||||
|
|
||||||
@@ -3927,51 +4036,55 @@ export const sendEmailToSigners = async (
|
|||||||
* @returns {Promise<File>} - A promise that resolves with a new PNG File.
|
* @returns {Promise<File>} - A promise that resolves with a new PNG File.
|
||||||
*/
|
*/
|
||||||
export function convertJpegToPng(base64Image, filename) {
|
export function convertJpegToPng(base64Image, filename) {
|
||||||
const arr = base64Image.split(",");
|
if (base64Image) {
|
||||||
const mimeMatch = arr[0].match(/:(.*?);/);
|
const arr = base64Image.split(",");
|
||||||
if (!mimeMatch) throw new Error("Invalid dataURL");
|
const mimeMatch = arr[0].match(/:(.*?);/);
|
||||||
const mime = mimeMatch[1];
|
if (!mimeMatch) throw new Error("Invalid dataURL");
|
||||||
const type = mime.split("/")[1];
|
const mime = mimeMatch[1];
|
||||||
if (type === "png") {
|
const type = mime.split("/")[1];
|
||||||
return base64Image;
|
if (type === "png") {
|
||||||
} else {
|
return base64Image;
|
||||||
const bstr = atob(arr[1]);
|
} else {
|
||||||
let n = bstr.length;
|
const bstr = atob(arr[1]);
|
||||||
const u8arr = new Uint8Array(n);
|
let n = bstr.length;
|
||||||
while (n--) u8arr[n] = bstr.charCodeAt(n);
|
const u8arr = new Uint8Array(n);
|
||||||
const inputFile = new File([u8arr], `${filename}.${type}`, { type: mime });
|
while (n--) u8arr[n] = bstr.charCodeAt(n);
|
||||||
return new Promise((resolve, reject) => {
|
const inputFile = new File([u8arr], `${filename}.${type}`, {
|
||||||
// ensure it’s JPEG/JPG (you can remove this check if not needed)
|
type: mime
|
||||||
if (!/image\/jpe?g/.test(inputFile.type)) {
|
});
|
||||||
return reject(new Error("Input must be a JPEG or JPG image"));
|
return new Promise((resolve, reject) => {
|
||||||
}
|
// ensure it’s JPEG/JPG (you can remove this check if not needed)
|
||||||
|
if (!/image\/jpe?g/.test(inputFile.type)) {
|
||||||
|
return reject(new Error("Input must be a JPEG or JPG image"));
|
||||||
|
}
|
||||||
|
|
||||||
// Read the file as a data URL
|
// Read the file as a data URL
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onerror = () => reject(new Error("Failed to read the file"));
|
reader.onerror = () => reject(new Error("Failed to read the file"));
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onerror = () => reject(new Error("Failed to load image"));
|
img.onerror = () => reject(new Error("Failed to load image"));
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
// draw image onto a canvas
|
// draw image onto a canvas
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
canvas.width = img.width;
|
canvas.width = img.width;
|
||||||
canvas.height = img.height;
|
canvas.height = img.height;
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
ctx.drawImage(img, 0, 0);
|
ctx.drawImage(img, 0, 0);
|
||||||
|
|
||||||
// directly get PNG as base64 data URL
|
// directly get PNG as base64 data URL
|
||||||
try {
|
try {
|
||||||
const pngDataUrl = canvas.toDataURL("image/png");
|
const pngDataUrl = canvas.toDataURL("image/png");
|
||||||
resolve(pngDataUrl);
|
resolve(pngDataUrl);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject(new Error("Failed to convert canvas to PNG"));
|
reject(new Error("Failed to convert canvas to PNG"));
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
img.src = reader.result;
|
||||||
};
|
};
|
||||||
img.src = reader.result;
|
reader.readAsDataURL(inputFile);
|
||||||
};
|
});
|
||||||
reader.readAsDataURL(inputFile);
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//function is used to get assigned signer's email
|
//function is used to get assigned signer's email
|
||||||
@@ -4080,3 +4193,8 @@ export const handleBackground = (data, isNeedSign, uniqueId) => {
|
|||||||
return "rgba(203, 233, 237, 0.69)";
|
return "rgba(203, 233, 237, 0.69)";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function getBase64MimeType(base64) {
|
||||||
|
const match = base64.match(/^data:(image\/[a-zA-Z0-9+.-]+);base64,/);
|
||||||
|
return match ? match[1] : null;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,19 +5,19 @@ export const templateReportTour = [
|
|||||||
selector: "[data-tut=reactourFirst]",
|
selector: "[data-tut=reactourFirst]",
|
||||||
content: <Trans i18nKey="tour-mssg.report-1" />,
|
content: <Trans i18nKey="tour-mssg.report-1" />,
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "11px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: "[data-tut=reactourSecond]",
|
selector: "[data-tut=reactourSecond]",
|
||||||
content: <Trans i18nKey="tour-mssg.redirect" />,
|
content: <Trans i18nKey="tour-mssg.redirect" />,
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: "[data-tut=tourbulksend]",
|
selector: "[data-tut=tourbulksend]",
|
||||||
content: <Trans i18nKey="tour-mssg.bulksend" />,
|
content: <Trans i18nKey="tour-mssg.bulksend" />,
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: "[data-tut=reactourThird]",
|
selector: "[data-tut=reactourThird]",
|
||||||
@@ -42,6 +42,6 @@ export const templateReportTour = [
|
|||||||
</Trans>
|
</Trans>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
import {
|
||||||
|
nonPresentMaskCss
|
||||||
|
} from "../constant/Utils";
|
||||||
import Header from "../components/Header";
|
import Header from "../components/Header";
|
||||||
import Footer from "../components/Footer";
|
import Footer from "../components/Footer";
|
||||||
import Sidebar from "../components/sidebar/Sidebar";
|
import Sidebar from "../components/sidebar/Sidebar";
|
||||||
@@ -6,7 +9,9 @@ import Tour from "../primitives/Tour";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import { useNavigate, Outlet } from "react-router";
|
import {
|
||||||
|
Outlet
|
||||||
|
} from "react-router";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { sessionStatus } from "../redux/reducers/userReducer";
|
import { sessionStatus } from "../redux/reducers/userReducer";
|
||||||
@@ -16,9 +21,8 @@ const HomeLayout = () => {
|
|||||||
const appName =
|
const appName =
|
||||||
"OpenSign™";
|
"OpenSign™";
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const navigate = useNavigate();
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const arr = useSelector((state) => state.TourSteps);
|
const tourArr = useSelector((state) => state.TourSteps);
|
||||||
const isValidSession = useSelector((state) => state.user.isValidSession);
|
const isValidSession = useSelector((state) => state.user.isValidSession);
|
||||||
const [isLoader, setIsLoader] = useState(true);
|
const [isLoader, setIsLoader] = useState(true);
|
||||||
const [isCloseBtn, setIsCloseBtn] = useState(true);
|
const [isCloseBtn, setIsCloseBtn] = useState(true);
|
||||||
@@ -55,7 +59,7 @@ const HomeLayout = () => {
|
|||||||
dispatch(sessionStatus(true));
|
dispatch(sessionStatus(true));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("catch");
|
console.error("error in authentication:", error?.message);
|
||||||
// Session token is invalid or there was an error
|
// Session token is invalid or there was an error
|
||||||
dispatch(sessionStatus(false));
|
dispatch(sessionStatus(false));
|
||||||
}
|
}
|
||||||
@@ -68,40 +72,36 @@ const HomeLayout = () => {
|
|||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (arr && arr.length > 0) {
|
if (tourArr && tourArr.length > 0) {
|
||||||
handleDynamicSteps();
|
handleDynamicSteps();
|
||||||
} else {
|
} else {
|
||||||
setIsTour(false);
|
setIsTour(false);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [arr]);
|
}, [tourArr]);
|
||||||
|
|
||||||
const handleDynamicSteps = () => {
|
const handleDynamicSteps = () => {
|
||||||
const github = "https://github.com/OpenSignLabs/OpenSign";
|
const github = "https://github.com/OpenSignLabs/OpenSign";
|
||||||
if (arr && arr.length > 0) {
|
if (tourArr && tourArr.length > 0) {
|
||||||
// const resArr = arr;
|
const resArr = tourArr.map((obj, index) => {
|
||||||
const resArr = arr.map((obj, index) => {
|
if (tourArr.length - 1 === index) {
|
||||||
if (arr.length - 1 === index) {
|
return obj;
|
||||||
return { ...obj };
|
|
||||||
} else {
|
} else {
|
||||||
return {
|
return { ...obj, actions: () => setIsCloseBtn(false) };
|
||||||
...obj,
|
|
||||||
actions: () => {
|
|
||||||
setIsCloseBtn(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setTourConfigs([
|
setTourConfigs([
|
||||||
{
|
{
|
||||||
selector: '[data-tut="nonpresentmask"]',
|
selector: '[data-tut="nonpresentmask"]',
|
||||||
content: t("tour-mssg.home-layout-1"),
|
content: t("tour-mssg.home-layout-1"),
|
||||||
position: "center"
|
position: "center",
|
||||||
|
styles: { fontSize: "13px", maskArea: nonPresentMaskCss }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="tourbutton"]',
|
selector: '[data-tut="tourbutton"]',
|
||||||
content: t("tour-mssg.home-layout-2"),
|
content: t("tour-mssg.home-layout-2"),
|
||||||
position: "top"
|
position: "top",
|
||||||
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
...resArr,
|
...resArr,
|
||||||
{
|
{
|
||||||
@@ -122,20 +122,19 @@ const HomeLayout = () => {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
position: "center"
|
position: "center",
|
||||||
|
styles: { fontSize: "13px", maskArea: nonPresentMaskCss }
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
checkTourStatus();
|
checkTourStatus();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const closeTour = async () => {
|
const closeTour = async () => {
|
||||||
// console.log("closeTour");
|
|
||||||
setIsTour(false);
|
setIsTour(false);
|
||||||
const serverUrl = localStorage.getItem("baseUrl");
|
const serverUrl = localStorage.getItem("baseUrl");
|
||||||
const appId = localStorage.getItem("parseAppId");
|
const appId = localStorage.getItem("parseAppId");
|
||||||
const json = JSON.parse(localStorage.getItem("Extand_Class"));
|
const json = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||||
const extUserId = json && json.length > 0 && json[0].objectId;
|
const extUserId = json && json.length > 0 && json[0].objectId;
|
||||||
// console.log("extUserId ", extUserId)
|
|
||||||
|
|
||||||
let updatedTourStatus = [];
|
let updatedTourStatus = [];
|
||||||
if (tourStatusArr.length > 0) {
|
if (tourStatusArr.length > 0) {
|
||||||
@@ -209,15 +208,15 @@ const HomeLayout = () => {
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
<Tour
|
{isTour && (
|
||||||
onRequestClose={closeTour}
|
<Tour
|
||||||
steps={tourConfigs}
|
onRequestClose={closeTour}
|
||||||
isOpen={isTour}
|
steps={tourConfigs}
|
||||||
disableKeyboardNavigation={["esc"]}
|
isOpen={isTour}
|
||||||
// disableInteraction={true}
|
// scrollOffset={-100}
|
||||||
scrollOffset={-100}
|
showCloseButton={isCloseBtn}
|
||||||
showCloseButton={isCloseBtn}
|
/>
|
||||||
/>
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ const Dashboard = () => {
|
|||||||
return {
|
return {
|
||||||
selector: `[data-tut=${col.widget.data.tourSection}]`,
|
selector: `[data-tut=${col.widget.data.tourSection}]`,
|
||||||
content: t(`tour-mssg.${col.widget.label}`),
|
content: t(`tour-mssg.${col.widget.label}`),
|
||||||
position: "top"
|
position: "top",
|
||||||
|
styles: { fontSize: "13px" }
|
||||||
// style: { backgroundColor: "#abd4d2" },
|
// style: { backgroundColor: "#abd4d2" },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import Loader from "../primitives/Loader";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { sessionStatus } from "../redux/reducers/userReducer";
|
import { sessionStatus } from "../redux/reducers/userReducer";
|
||||||
|
import { withSessionValidation } from "../utils";
|
||||||
|
|
||||||
// `Form` render all type of Form on this basis of their provided in path
|
// `Form` render all type of Form on this basis of their provided in path
|
||||||
function Form() {
|
function Form() {
|
||||||
@@ -84,6 +85,8 @@ const Forms = (props) => {
|
|||||||
const [isCorrectPass, setIsCorrectPass] = useState(true);
|
const [isCorrectPass, setIsCorrectPass] = useState(true);
|
||||||
const [isAdvanceOpt, setIsAdvanceOpt] = useState(false);
|
const [isAdvanceOpt, setIsAdvanceOpt] = useState(false);
|
||||||
const [bcc, setBcc] = useState([]);
|
const [bcc, setBcc] = useState([]);
|
||||||
|
const pensList = ["blue", "red", "black"];
|
||||||
|
const [selectedColors, setSelectedColors] = useState(pensList);
|
||||||
|
|
||||||
const handleStrInput = (e) => {
|
const handleStrInput = (e) => {
|
||||||
setIsCorrectPass(true);
|
setIsCorrectPass(true);
|
||||||
@@ -130,7 +133,7 @@ const Forms = (props) => {
|
|||||||
e.target.value = "";
|
e.target.value = "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleFileInput = async (e) => {
|
const handleFileInput = withSessionValidation(async (e) => {
|
||||||
setpercentage(0);
|
setpercentage(0);
|
||||||
try {
|
try {
|
||||||
const files = Array.from(e.target.files);
|
const files = Array.from(e.target.files);
|
||||||
@@ -351,7 +354,7 @@ const Forms = (props) => {
|
|||||||
setSelectedFiles([]);
|
setSelectedFiles([]);
|
||||||
removeFile(e);
|
removeFile(e);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
// `isValidURL` is used to check valid webhook url
|
// `isValidURL` is used to check valid webhook url
|
||||||
function isValidURL(value) {
|
function isValidURL(value) {
|
||||||
try {
|
try {
|
||||||
@@ -361,7 +364,7 @@ const Forms = (props) => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = withSessionValidation(async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (fileupload) {
|
if (fileupload) {
|
||||||
@@ -417,6 +420,8 @@ const Forms = (props) => {
|
|||||||
object.set("RemindOnceInEvery", remindOnceInEvery);
|
object.set("RemindOnceInEvery", remindOnceInEvery);
|
||||||
object.set("IsTourEnabled", isTourEnabled);
|
object.set("IsTourEnabled", isTourEnabled);
|
||||||
object.set("TimeToCompleteDays", TimeToCompleteDays);
|
object.set("TimeToCompleteDays", TimeToCompleteDays);
|
||||||
|
object.set("PenColors", selectedColors);
|
||||||
|
|
||||||
object.set("AllowModifications", false);
|
object.set("AllowModifications", false);
|
||||||
object.set("IsEnableOTP", false);
|
object.set("IsEnableOTP", false);
|
||||||
if (formData.NotifyOnSignatures !== undefined) {
|
if (formData.NotifyOnSignatures !== undefined) {
|
||||||
@@ -456,6 +461,7 @@ const Forms = (props) => {
|
|||||||
if (res) {
|
if (res) {
|
||||||
setSigners([]);
|
setSigners([]);
|
||||||
setBcc([]);
|
setBcc([]);
|
||||||
|
setSelectedColors(pensList);
|
||||||
setFolder({ ObjectId: "", Name: "" });
|
setFolder({ ObjectId: "", Name: "" });
|
||||||
const notifySign =
|
const notifySign =
|
||||||
extUserData?.NotifyOnSignatures !== undefined
|
extUserData?.NotifyOnSignatures !== undefined
|
||||||
@@ -507,7 +513,7 @@ const Forms = (props) => {
|
|||||||
} else {
|
} else {
|
||||||
alert(t("file-alert-3"));
|
alert(t("file-alert-3"));
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
const handleFolder = (data) => {
|
const handleFolder = (data) => {
|
||||||
setFolder(data);
|
setFolder(data);
|
||||||
@@ -538,6 +544,7 @@ const Forms = (props) => {
|
|||||||
setIsReset(true);
|
setIsReset(true);
|
||||||
setSigners([]);
|
setSigners([]);
|
||||||
setBcc([]);
|
setBcc([]);
|
||||||
|
setSelectedColors(pensList);
|
||||||
setFolder({ ObjectId: "", Name: "" });
|
setFolder({ ObjectId: "", Name: "" });
|
||||||
const notifySign =
|
const notifySign =
|
||||||
extUserData?.NotifyOnSignatures !== undefined
|
extUserData?.NotifyOnSignatures !== undefined
|
||||||
@@ -651,6 +658,20 @@ const Forms = (props) => {
|
|||||||
setFormData((obj) => ({ ...obj, NotifyOnSignatures: value }));
|
setFormData((obj) => ({ ...obj, NotifyOnSignatures: value }));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleColorsChange = (color) => {
|
||||||
|
setSelectedColors((prev) => {
|
||||||
|
// If user tries to uncheck the last remaining color → block it
|
||||||
|
if (prev.length === 1 && prev.includes(color)) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normal toggle behavior
|
||||||
|
return prev.includes(color)
|
||||||
|
? prev.filter((c) => c !== color) // remove
|
||||||
|
: [...prev, color]; // add
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`${isSubmit ? "" : "shadow-md rounded-box my-[2px] p-3 bg-base-100 text-base-content"}`}
|
className={`${isSubmit ? "" : "shadow-md rounded-box my-[2px] p-3 bg-base-100 text-base-content"}`}
|
||||||
@@ -1214,6 +1235,46 @@ const Forms = (props) => {
|
|||||||
onInput={(e) => e.target.setCustomValidity("")}
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{props.title !== "Sign Yourself" && (
|
||||||
|
<div className="text-xs mt-3">
|
||||||
|
<label htmlFor="penColors">
|
||||||
|
{t("pen-colors")}
|
||||||
|
<a
|
||||||
|
data-tooltip-id="pen-colors-tooltip"
|
||||||
|
className="ml-1"
|
||||||
|
>
|
||||||
|
<sup>
|
||||||
|
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
|
||||||
|
</sup>
|
||||||
|
</a>
|
||||||
|
<Tooltip id="pen-colors-tooltip" className="z-[999]">
|
||||||
|
<div className="max-w-[200px] md:max-w-[450px]">
|
||||||
|
<p className="font-bold">{t("pen-colors")}</p>
|
||||||
|
<div>{t("pen-colors-help")}</div>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</label>
|
||||||
|
<div className="ml-[7px] flex flex-col md:flex-row gap-[10px] mb-[0.7rem]">
|
||||||
|
{pensList.map((color) => (
|
||||||
|
<div
|
||||||
|
key={color}
|
||||||
|
className="flex flex-row gap-[5px] items-center"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
className="mr-[2px] op-checkbox op-checkbox-xs"
|
||||||
|
type="checkbox"
|
||||||
|
name="penColors"
|
||||||
|
checked={selectedColors.includes(color)}
|
||||||
|
onChange={() => handleColorsChange(color)}
|
||||||
|
/>
|
||||||
|
<div className="hover:underline underline-offset-2 cursor-default capitalize">
|
||||||
|
{color}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,7 +12,15 @@ import { SaveFileSize } from "../constant/saveFileSize";
|
|||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { sanitizeFileName } from "../utils";
|
import { sanitizeFileName, withSessionValidation } from "../utils";
|
||||||
|
|
||||||
|
const COLOR_CLASS = {
|
||||||
|
blue: "text-blue-600",
|
||||||
|
red: "text-red-600",
|
||||||
|
black: "text-black",
|
||||||
|
white: "text-white"
|
||||||
|
};
|
||||||
|
|
||||||
const ManageSign = () => {
|
const ManageSign = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [penColor, setPenColor] = useState("blue");
|
const [penColor, setPenColor] = useState("blue");
|
||||||
@@ -29,10 +37,12 @@ const ManageSign = () => {
|
|||||||
const [isInitials, setIsInitials] = useState(false);
|
const [isInitials, setIsInitials] = useState(false);
|
||||||
const [id, setId] = useState("");
|
const [id, setId] = useState("");
|
||||||
const [imgInitials, setImgInitials] = useState("");
|
const [imgInitials, setImgInitials] = useState("");
|
||||||
|
const [stamp, setStamp] = useState();
|
||||||
const canvasRef = useRef(null);
|
const canvasRef = useRef(null);
|
||||||
const imageRef = useRef(null);
|
const imageRef = useRef(null);
|
||||||
const initailsRef = useRef(null);
|
const initailsRef = useRef(null);
|
||||||
const imgInitialsRef = useRef(null);
|
const imgInitialsRef = useRef(null);
|
||||||
|
const stampRef = useRef(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchUserSign();
|
fetchUserSign();
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
@@ -63,6 +73,9 @@ const ManageSign = () => {
|
|||||||
setIsInitials(true);
|
setIsInitials(true);
|
||||||
setImgInitials(res?.Initials);
|
setImgInitials(res?.Initials);
|
||||||
}
|
}
|
||||||
|
if (res && res?.Stamp) {
|
||||||
|
setStamp(res?.Stamp);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (User?.get("name")) {
|
if (User?.get("name")) {
|
||||||
const sanitizename = generateTitleFromFilename(User?.get("name"));
|
const sanitizename = generateTitleFromFilename(User?.get("name"));
|
||||||
@@ -127,7 +140,7 @@ const ManageSign = () => {
|
|||||||
setIsValue(false);
|
setIsValue(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = withSessionValidation(async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const isUrl = image?.includes("https") || image?.includes("http");
|
const isUrl = image?.includes("https") || image?.includes("http");
|
||||||
if (!isvalue) {
|
if (!isvalue) {
|
||||||
@@ -171,15 +184,28 @@ const ManageSign = () => {
|
|||||||
} else {
|
} else {
|
||||||
initialsUrl = imgInitials;
|
initialsUrl = imgInitials;
|
||||||
}
|
}
|
||||||
|
const isStampUrl = stamp?.includes("https") || stamp?.includes("http");
|
||||||
|
|
||||||
|
let stampFile;
|
||||||
|
if (stamp && !isStampUrl) {
|
||||||
|
stampFile = base64StringtoFile(stamp, `${replaceSpace}_stamp`);
|
||||||
|
}
|
||||||
|
let stampUrl;
|
||||||
|
if (stampFile && !isStampUrl) {
|
||||||
|
stampUrl = await uploadFile(stampFile);
|
||||||
|
} else {
|
||||||
|
stampUrl = stamp;
|
||||||
|
}
|
||||||
if (imgUrl) {
|
if (imgUrl) {
|
||||||
await saveEntry({
|
await saveEntry({
|
||||||
name: signName,
|
name: signName,
|
||||||
url: imgUrl,
|
url: imgUrl,
|
||||||
initialsUrl: initialsUrl
|
initialsUrl: initialsUrl,
|
||||||
|
stampUrl: stampUrl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
function base64StringtoFile(base64String, filename) {
|
function base64StringtoFile(base64String, filename) {
|
||||||
let arr = base64String.split(","),
|
let arr = base64String.split(","),
|
||||||
// type of uploaded image
|
// type of uploaded image
|
||||||
@@ -232,7 +258,8 @@ const ManageSign = () => {
|
|||||||
userId: User,
|
userId: User,
|
||||||
initials: obj.initialsUrl,
|
initials: obj.initialsUrl,
|
||||||
id: id,
|
id: id,
|
||||||
title: obj.name
|
title: obj.name,
|
||||||
|
stamp: obj?.stampUrl
|
||||||
});
|
});
|
||||||
setIsAlert({ type: "success", message: t("signature-saved-alert") });
|
setIsAlert({ type: "success", message: t("signature-saved-alert") });
|
||||||
return res;
|
return res;
|
||||||
@@ -274,6 +301,28 @@ const ManageSign = () => {
|
|||||||
setIsValue(false);
|
setIsValue(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const handleClearStamp = () => {
|
||||||
|
if (stampRef.current) {
|
||||||
|
stampRef.current.clear();
|
||||||
|
}
|
||||||
|
if (stampRef.current) {
|
||||||
|
stampRef.current.value = "";
|
||||||
|
}
|
||||||
|
setStamp("");
|
||||||
|
if (image) {
|
||||||
|
setIsValue(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onStampChange = async (event) => {
|
||||||
|
if (event.target.files && event.target.files[0]) {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
const base64Img = await toDataUrl(file);
|
||||||
|
setStamp(base64Img);
|
||||||
|
setIsValue(true);
|
||||||
|
} else {
|
||||||
|
setStamp("");
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="relative h-full bg-base-100 text-base-content flex shadow-md rounded-box overflow-auto">
|
<div className="relative h-full bg-base-100 text-base-content flex shadow-md rounded-box overflow-auto">
|
||||||
{isLoader && (
|
{isLoader && (
|
||||||
@@ -287,9 +336,9 @@ const ManageSign = () => {
|
|||||||
<div className="text-[20px] font-semibold m-[10px] md:m-0 mb-2">
|
<div className="text-[20px] font-semibold m-[10px] md:m-0 mb-2">
|
||||||
{t("my-signature")}
|
{t("my-signature")}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col md:flex-row gap-0 md:gap-[12px]">
|
<div className="flex flex-col md:flex-row gap-2 md:gap-5">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
|
<span className="font-medium select-none flex mb-[10px]">
|
||||||
{t("signature")}
|
{t("signature")}
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
@@ -300,7 +349,7 @@ const ManageSign = () => {
|
|||||||
ref={imageRef}
|
ref={imageRef}
|
||||||
hidden
|
hidden
|
||||||
/>
|
/>
|
||||||
<div className="relative">
|
<div>
|
||||||
{image ? (
|
{image ? (
|
||||||
<div className="mysignatureCanvas relative border-[2px] border-[#888] rounded-box overflow-hidden">
|
<div className="mysignatureCanvas relative border-[2px] border-[#888] rounded-box overflow-hidden">
|
||||||
<img
|
<img
|
||||||
@@ -323,23 +372,24 @@ const ManageSign = () => {
|
|||||||
dotSize={1}
|
dotSize={1}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="penContainerDefault flex flex-row justify-between">
|
<div className="flex flex-row justify-between w-full">
|
||||||
<div>
|
<div>
|
||||||
{!image && (
|
{!image && (
|
||||||
<div className="flex flex-row gap-1.5 m-[5px]">
|
<div className="flex flex-row gap-1 m-[5px]">
|
||||||
{allColor.map((data, key) => {
|
{allColor.map((color, key) => {
|
||||||
|
const selected = penColor === color;
|
||||||
return (
|
return (
|
||||||
<i
|
<i
|
||||||
key={key}
|
key={key}
|
||||||
onClick={() => setPenColor(allColor[key])}
|
onClick={() => setPenColor(color)}
|
||||||
className={`border-b-[2px] ${key === 0 && penColor === "blue" ? "border-blue-600" : key === 1 && penColor === "red" ? "border-red-500" : key === 2 && penColor === "black" ? "border-black" : "border-white"} text-[${data}] text-[16px] fa-light fa-pen-nib`}
|
className={`${COLOR_CLASS[color] ?? ""} ${selected ? "border-current" : "border-white"} cursor-pointer border-b-[2px] pb-[2px] text-[16px] fa-light fa-pen-nib`}
|
||||||
></i>
|
></i>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row gap-2 text-sm md:text-base mr-1">
|
<div className="flex flex-row gap-2 text-sm pr-2">
|
||||||
<div
|
<div
|
||||||
type="button"
|
type="button"
|
||||||
className="op-link"
|
className="op-link"
|
||||||
@@ -364,7 +414,8 @@ const ManageSign = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative">
|
|
||||||
|
<div>
|
||||||
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
|
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
|
||||||
{t("initials")}
|
{t("initials")}
|
||||||
</span>
|
</span>
|
||||||
@@ -396,26 +447,29 @@ const ManageSign = () => {
|
|||||||
dotSize={1}
|
dotSize={1}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="flex flex-row justify-between w-[183px]">
|
<div
|
||||||
|
className={`${isInitials ? "justify-between" : ""} flex flex-row gap-1`}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
{!isInitials && (
|
{!isInitials && (
|
||||||
<div className="flex flex-row gap-1.5 m-[5px]">
|
<div className="flex flex-row gap-1 m-[5px]">
|
||||||
{allColor.map((data, key) => {
|
{allColor.map((color, key) => {
|
||||||
|
const selected = initialPen === color;
|
||||||
return (
|
return (
|
||||||
<i
|
<i
|
||||||
key={key}
|
key={key}
|
||||||
onClick={() => setInitialPen(allColor[key])}
|
onClick={() => setInitialPen(color)}
|
||||||
className={`border-b-[2px] ${key === 0 && initialPen === "blue" ? "border-blue-600" : key === 1 && initialPen === "red" ? "border-red-500" : key === 2 && initialPen === "black" ? "border-black" : "border-white"} text-[${data}] text-[16px] fa-light fa-pen-nib`}
|
className={`${COLOR_CLASS[color] ?? ""} ${selected ? "border-current" : "border-white"} cursor-pointer border-b-[2px] pb-[2px] text-[16px] fa-light fa-pen-nib`}
|
||||||
></i>
|
></i>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row gap-1">
|
<div className="flex flex-row gap-1.5 text-sm">
|
||||||
<div
|
<div
|
||||||
type="button"
|
type="button"
|
||||||
className="op-link text-sm md:text-base mr-1"
|
className="op-link"
|
||||||
onClick={() => handleUploadInitials()}
|
onClick={() => handleUploadInitials()}
|
||||||
>
|
>
|
||||||
{t("upload")}
|
{t("upload")}
|
||||||
@@ -423,7 +477,7 @@ const ManageSign = () => {
|
|||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
type="button"
|
type="button"
|
||||||
className="op-link text-sm md:text-base mr-1"
|
className="op-link"
|
||||||
onClick={() => handleClearInitials()}
|
onClick={() => handleClearInitials()}
|
||||||
>
|
>
|
||||||
{t("clear")}
|
{t("clear")}
|
||||||
@@ -433,6 +487,48 @@ const ManageSign = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
|
||||||
|
Stamp
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div
|
||||||
|
onClick={() => stampRef.current.click()}
|
||||||
|
className="mystampCanvas opensigndark:bg-[#1f2937] cursor-pointer border-[2px] opensigncss:border-[#888] opensigndark:border-[#4b5563] rounded-box flex flex-col overflow-hidden w-full h-full aspect-[5/2] justify-center items-center mr-2"
|
||||||
|
>
|
||||||
|
{stamp ? (
|
||||||
|
<img
|
||||||
|
alt="signature"
|
||||||
|
src={stamp}
|
||||||
|
className="w-full h-full object-contain"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<input
|
||||||
|
onChange={onStampChange}
|
||||||
|
type="file"
|
||||||
|
className="filetype"
|
||||||
|
accept="image/png,image/jpeg"
|
||||||
|
hidden
|
||||||
|
ref={stampRef}
|
||||||
|
/>
|
||||||
|
<i className="fa-light text-base-content fa-cloud-upload-alt text-[28px]"></i>
|
||||||
|
<div className="text-[15px] text-base-content">
|
||||||
|
{t("upload")}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end pr-3">
|
||||||
|
<div
|
||||||
|
type="button"
|
||||||
|
className="op-link text-sm"
|
||||||
|
onClick={() => handleClearStamp()}
|
||||||
|
>
|
||||||
|
{t("clear")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="pt-3 ml-2 md:ml-0">
|
<div className="pt-3 ml-2 md:ml-0">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState, useRef, useCallback } from "react";
|
import React, { useEffect, useState, useRef, useCallback } from "react";
|
||||||
import { lazyWithRetry } from "../utils";
|
import { lazyWithRetry, withSessionValidation } from "../utils";
|
||||||
import "../styles/opensigndrive.css";
|
import "../styles/opensigndrive.css";
|
||||||
import {
|
import {
|
||||||
getThemeIconColor,
|
getThemeIconColor,
|
||||||
@@ -20,7 +20,7 @@ const DriveBody = lazyWithRetry(
|
|||||||
() => import("../components/opensigndrive/DriveBody")
|
() => import("../components/opensigndrive/DriveBody")
|
||||||
);
|
);
|
||||||
const dropdowncss =
|
const dropdowncss =
|
||||||
"absolute right-0 py-2 text-[1rem] text-left bg-white border-[1px] border-gray-300 min-w-1 hover:bg-gray-300 rounded-[0.25rem] z-[800]";
|
"absolute right-0 py-2 text-[1rem] text-left bg-base-100 border-[1px] border-gray-300 min-w-1 rounded-[0.25rem] z-[800]";
|
||||||
const AppLoader = () => {
|
const AppLoader = () => {
|
||||||
return (
|
return (
|
||||||
<div className="h-[100vh] flex justify-center items-center">
|
<div className="h-[100vh] flex justify-center items-center">
|
||||||
@@ -98,7 +98,7 @@ function Opensigndrive() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="reactourSecond"]',
|
selector: '[data-tut="reactourSecond"]',
|
||||||
@@ -109,7 +109,7 @@ function Opensigndrive() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="reactourThird"]',
|
selector: '[data-tut="reactourThird"]',
|
||||||
@@ -120,7 +120,7 @@ function Opensigndrive() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="reactourForth"]',
|
selector: '[data-tut="reactourForth"]',
|
||||||
@@ -131,7 +131,7 @@ function Opensigndrive() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
const getDetails = async () => {
|
const getDetails = async () => {
|
||||||
@@ -161,7 +161,7 @@ function Opensigndrive() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "bottom",
|
position: "bottom",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="reactourSixth"]',
|
selector: '[data-tut="reactourSixth"]',
|
||||||
@@ -172,7 +172,7 @@ function Opensigndrive() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "bottom",
|
position: "bottom",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="reactourSeventh"]',
|
selector: '[data-tut="reactourSeventh"]',
|
||||||
@@ -183,7 +183,7 @@ function Opensigndrive() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "bottom",
|
position: "bottom",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
let newTour = [...tourConfigs, ...addMoreTour];
|
let newTour = [...tourConfigs, ...addMoreTour];
|
||||||
@@ -279,7 +279,7 @@ function Opensigndrive() {
|
|||||||
setNewFolderName(value);
|
setNewFolderName(value);
|
||||||
};
|
};
|
||||||
//function for create folder
|
//function for create folder
|
||||||
const handleAddFolder = async (e) => {
|
const handleAddFolder = withSessionValidation(async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (newFolderName) {
|
if (newFolderName) {
|
||||||
setIsFolderLoader(true);
|
setIsFolderLoader(true);
|
||||||
@@ -313,7 +313,12 @@ function Opensigndrive() {
|
|||||||
const template = new Parse.Object(foldercls);
|
const template = new Parse.Object(foldercls);
|
||||||
template.set("Name", newFolderName);
|
template.set("Name", newFolderName);
|
||||||
template.set("Type", "Folder");
|
template.set("Type", "Folder");
|
||||||
|
const ExtCls = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||||
|
template.set("ExtUserPtr", {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: "contracts_Users",
|
||||||
|
objectId: ExtCls[0].objectId
|
||||||
|
});
|
||||||
if (parentId) {
|
if (parentId) {
|
||||||
template.set("Folder", folderPtr);
|
template.set("Folder", folderPtr);
|
||||||
}
|
}
|
||||||
@@ -338,7 +343,7 @@ function Opensigndrive() {
|
|||||||
} else {
|
} else {
|
||||||
setError(t("fill-field"));
|
setError(t("fill-field"));
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
//function to use sorting document list according to type and order
|
//function to use sorting document list according to type and order
|
||||||
const sortedBy = (appInfo, type, order) => {
|
const sortedBy = (appInfo, type, order) => {
|
||||||
@@ -688,7 +693,7 @@ function Opensigndrive() {
|
|||||||
</div>
|
</div>
|
||||||
{/* Mobile search toggle */}
|
{/* Mobile search toggle */}
|
||||||
<button
|
<button
|
||||||
className="md:hidden p-2 flex justify-center items-center focus:outline-none rounded-md hover:bg-gray-200 text-[18px]"
|
className="md:hidden p-2 flex justify-center items-center focus:outline-none rounded-md hover:bg-base-300 text-[18px]"
|
||||||
aria-label="Search"
|
aria-label="Search"
|
||||||
onClick={() => setMobileSearchOpen((open) => !open)}
|
onClick={() => setMobileSearchOpen((open) => !open)}
|
||||||
>
|
>
|
||||||
@@ -699,7 +704,7 @@ function Opensigndrive() {
|
|||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
id="folder-menu"
|
id="folder-menu"
|
||||||
className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} hidden md:block cursor-pointer hover:bg-gray-200 p-2 rounded-md`}
|
className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} hidden md:block cursor-pointer hover:bg-base-300 p-2 rounded-md`}
|
||||||
onClick={handleFolderOptions}
|
onClick={handleFolderOptions}
|
||||||
>
|
>
|
||||||
<div data-tut="reactourSecond">
|
<div data-tut="reactourSecond">
|
||||||
@@ -749,7 +754,7 @@ function Opensigndrive() {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
data-tut="reactourThird"
|
data-tut="reactourThird"
|
||||||
className="cursor-pointer flex flex-row items-center justify-center p-2 hover:bg-gray-200 rounded-md"
|
className="cursor-pointer flex flex-row items-center justify-center p-2 hover:bg-base-300 rounded-md"
|
||||||
data-toggle="dropdown"
|
data-toggle="dropdown"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
@@ -767,9 +772,7 @@ function Opensigndrive() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={
|
className={`${isShowSort ? "dropdown-menu show" : "dropdown-menu"} bg-base-100 border-[1px] border-gray-300`}
|
||||||
isShowSort ? "dropdown-menu show" : "dropdown-menu"
|
|
||||||
}
|
|
||||||
aria-labelledby="dropdownMenuButton"
|
aria-labelledby="dropdownMenuButton"
|
||||||
aria-expanded={isShowSort ? "true" : "false"}
|
aria-expanded={isShowSort ? "true" : "false"}
|
||||||
>
|
>
|
||||||
@@ -817,7 +820,7 @@ function Opensigndrive() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="cursor-pointer p-2 hover:bg-gray-200 rounded-md flex justify-center items-center"
|
className="cursor-pointer p-2 hover:bg-base-300 rounded-md flex justify-center items-center"
|
||||||
data-tut="reactourForth"
|
data-tut="reactourForth"
|
||||||
onClick={handleViewOption}
|
onClick={handleViewOption}
|
||||||
>
|
>
|
||||||
@@ -833,7 +836,7 @@ function Opensigndrive() {
|
|||||||
onClick={() => setIsOptions(!isOptions)}
|
onClick={() => setIsOptions(!isOptions)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="p-3 flex items-center justify-center cursor-pointer rounded-md hover:bg-gray-200"
|
className="p-3 flex items-center justify-center cursor-pointer rounded-md hover:bg-base-300"
|
||||||
data-tut="reactourSecond"
|
data-tut="reactourSecond"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import {
|
|||||||
setDefaultSignImg,
|
setDefaultSignImg,
|
||||||
resetWidgetState,
|
resetWidgetState,
|
||||||
setPrefillImg,
|
setPrefillImg,
|
||||||
setTypedSignFont
|
setTypedSignFont,
|
||||||
|
setMyStamp
|
||||||
} from "../redux/reducers/widgetSlice";
|
} from "../redux/reducers/widgetSlice";
|
||||||
import {
|
import {
|
||||||
contractDocument,
|
contractDocument,
|
||||||
@@ -155,12 +156,10 @@ function PdfRequestFiles(
|
|||||||
const [assignedWidgetId, setAssignedWidgetId] = useState([]);
|
const [assignedWidgetId, setAssignedWidgetId] = useState([]);
|
||||||
const [showSignPagenumber, setShowSignPagenumber] = useState([]);
|
const [showSignPagenumber, setShowSignPagenumber] = useState([]);
|
||||||
const [owner, setOwner] = useState({});
|
const [owner, setOwner] = useState({});
|
||||||
const [tenant, setTenant] = useState({});
|
|
||||||
const [tenantMailTemplate, setTenantMailTemplate] = useState({
|
const [tenantMailTemplate, setTenantMailTemplate] = useState({
|
||||||
body: "",
|
body: "",
|
||||||
subject: ""
|
subject: ""
|
||||||
});
|
});
|
||||||
const [isOptionalDetails, setIsOptionalDetails] = useState(false);
|
|
||||||
const isMobile = window.innerWidth < 767;
|
const isMobile = window.innerWidth < 767;
|
||||||
let isGuestSignFlow = false;
|
let isGuestSignFlow = false;
|
||||||
let sendmail;
|
let sendmail;
|
||||||
@@ -245,7 +244,6 @@ function PdfRequestFiles(
|
|||||||
const filterSignTypes = signatureType?.filter(
|
const filterSignTypes = signatureType?.filter(
|
||||||
(x) => x.enabled === true
|
(x) => x.enabled === true
|
||||||
);
|
);
|
||||||
setTenant(tenantDetails || {});
|
|
||||||
if (tenantDetails?.RequestBody) {
|
if (tenantDetails?.RequestBody) {
|
||||||
setTenantMailTemplate({
|
setTenantMailTemplate({
|
||||||
body: tenantDetails?.RequestBody,
|
body: tenantDetails?.RequestBody,
|
||||||
@@ -532,6 +530,7 @@ function PdfRequestFiles(
|
|||||||
const initials = defaultSignRes?.res?.defaultInitial || "";
|
const initials = defaultSignRes?.res?.defaultInitial || "";
|
||||||
dispatch(setDefaultSignImg(sign));
|
dispatch(setDefaultSignImg(sign));
|
||||||
dispatch(setMyInitial(initials));
|
dispatch(setMyInitial(initials));
|
||||||
|
dispatch(setMyStamp(defaultSignRes?.res?.defaultStamp));
|
||||||
} else {
|
} else {
|
||||||
dispatch(setSaveSignCheckbox({ isVisible: true }));
|
dispatch(setSaveSignCheckbox({ isVisible: true }));
|
||||||
}
|
}
|
||||||
@@ -1103,7 +1102,7 @@ function PdfRequestFiles(
|
|||||||
? t("signature-validate-alert", { minRequiredCount })
|
? t("signature-validate-alert", { minRequiredCount })
|
||||||
: t("signature-validate-alert-2"),
|
: t("signature-validate-alert-2"),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
//function for get pdf page details
|
//function for get pdf page details
|
||||||
@@ -1260,7 +1259,7 @@ function PdfRequestFiles(
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="reactourFirst"]',
|
selector: '[data-tut="reactourFirst"]',
|
||||||
@@ -1272,7 +1271,7 @@ function PdfRequestFiles(
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="pdfArea"]',
|
selector: '[data-tut="pdfArea"]',
|
||||||
@@ -1284,7 +1283,7 @@ function PdfRequestFiles(
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="pdftools"]',
|
selector: '[data-tut="pdftools"]',
|
||||||
@@ -1296,7 +1295,7 @@ function PdfRequestFiles(
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="reactourFifth"]',
|
selector: '[data-tut="reactourFifth"]',
|
||||||
@@ -1308,7 +1307,7 @@ function PdfRequestFiles(
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
const signedByStep = {
|
const signedByStep = {
|
||||||
@@ -1321,7 +1320,7 @@ function PdfRequestFiles(
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
};
|
};
|
||||||
//checking if signed by user component exist then add signed by tour step
|
//checking if signed by user component exist then add signed by tour step
|
||||||
const signedBy =
|
const signedBy =
|
||||||
@@ -1340,7 +1339,7 @@ function PdfRequestFiles(
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
};
|
};
|
||||||
//checking if AllowModifications is true then add allow widgets panel tour step
|
//checking if AllowModifications is true then add allow widgets panel tour step
|
||||||
const allModifyWidgets = {
|
const allModifyWidgets = {
|
||||||
@@ -1353,7 +1352,7 @@ function PdfRequestFiles(
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//handle signed by panel index if signed by exist then 2 else 1 to add tour step
|
//handle signed by panel index if signed by exist then 2 else 1 to add tour step
|
||||||
@@ -1823,6 +1822,7 @@ function PdfRequestFiles(
|
|||||||
!alreadySign &&
|
!alreadySign &&
|
||||||
requestSignTourFunction()}
|
requestSignTourFunction()}
|
||||||
<Tour
|
<Tour
|
||||||
|
key={`tour-min-required-${minRequiredCount || 0}`}
|
||||||
showNumber={false}
|
showNumber={false}
|
||||||
showNavigation={false}
|
showNavigation={false}
|
||||||
showNavigationNumber={false}
|
showNavigationNumber={false}
|
||||||
@@ -2224,6 +2224,7 @@ function PdfRequestFiles(
|
|||||||
setUniqueId={setUniqueId}
|
setUniqueId={setUniqueId}
|
||||||
signatureTypes={signatureType}
|
signatureTypes={signatureType}
|
||||||
allowCellResize={false}
|
allowCellResize={false}
|
||||||
|
penColors={pdfDetails?.[0]?.PenColors}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<DownloadPdfZip
|
<DownloadPdfZip
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import SignerListPlace from "../components/pdf/SignerListPlace";
|
|||||||
import Header from "../components/pdf/PdfHeader";
|
import Header from "../components/pdf/PdfHeader";
|
||||||
import ShareButton from "../primitives/ShareButton";
|
import ShareButton from "../primitives/ShareButton";
|
||||||
import {
|
import {
|
||||||
replaceMailVaribles,
|
|
||||||
pdfNewWidthFun,
|
pdfNewWidthFun,
|
||||||
contractDocument,
|
contractDocument,
|
||||||
contractUsers,
|
contractUsers,
|
||||||
@@ -39,7 +38,6 @@ import {
|
|||||||
handleSignatureType,
|
handleSignatureType,
|
||||||
getBase64FromUrl,
|
getBase64FromUrl,
|
||||||
generatePdfName,
|
generatePdfName,
|
||||||
mailTemplate,
|
|
||||||
getOriginalWH,
|
getOriginalWH,
|
||||||
defaultMailBody,
|
defaultMailBody,
|
||||||
defaultMailSubject
|
defaultMailSubject
|
||||||
@@ -60,13 +58,13 @@ import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
|||||||
import HandleError from "../primitives/HandleError";
|
import HandleError from "../primitives/HandleError";
|
||||||
import LoaderWithMsg from "../primitives/LoaderWithMsg";
|
import LoaderWithMsg from "../primitives/LoaderWithMsg";
|
||||||
import LinkUserModal from "../primitives/LinkUserModal";
|
import LinkUserModal from "../primitives/LinkUserModal";
|
||||||
import { EmailBody } from "../components/pdf/EmailBody";
|
|
||||||
import LottieWithLoader from "../primitives/DotLottieReact";
|
import LottieWithLoader from "../primitives/DotLottieReact";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
import WidgetsValueModal from "../components/pdf/WidgetsValueModal";
|
import WidgetsValueModal from "../components/pdf/WidgetsValueModal";
|
||||||
import * as utils from "../utils";
|
import * as utils from "../utils";
|
||||||
import { resetWidgetState, setPrefillImg } from "../redux/reducers/widgetSlice";
|
import { resetWidgetState, setPrefillImg } from "../redux/reducers/widgetSlice";
|
||||||
import EditDocument from "../components/pdf/EditTemplate";
|
import EditDocument from "../components/pdf/EditTemplate";
|
||||||
|
import CustomizeMail from "../components/pdf/CustomizeMail";
|
||||||
|
|
||||||
function PlaceHolderSign() {
|
function PlaceHolderSign() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -75,16 +73,10 @@ function PlaceHolderSign() {
|
|||||||
const prefillImg = useSelector((state) => state.widget.prefillImg);
|
const prefillImg = useSelector((state) => state.widget.prefillImg);
|
||||||
const isShowModal = useSelector((state) => state.widget.isShowModal);
|
const isShowModal = useSelector((state) => state.widget.isShowModal);
|
||||||
const editorRef = useRef();
|
const editorRef = useRef();
|
||||||
const { state } = useLocation();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [defaultBody, setDefaultBody] = useState("");
|
const [isMailModal, setIsMailModal] = useState(false);
|
||||||
const [defaultSubject, setDefaultSubject] = useState("");
|
const [customizeMail, setCustomizeMail] = useState({ body: "", subject: "" });
|
||||||
const [requestSubject, setRequestSubject] = useState("");
|
const [defaultMail, setDefaultMail] = useState({ body: "", subject: "" });
|
||||||
const [requestBody, setRequestBody] = useState("");
|
|
||||||
const [tenantMailTemplate, setTenantMailTemplate] = useState({
|
|
||||||
body: "",
|
|
||||||
subject: ""
|
|
||||||
});
|
|
||||||
const [pdfDetails, setPdfDetails] = useState([]);
|
const [pdfDetails, setPdfDetails] = useState([]);
|
||||||
const [isMailSend, setIsMailSend] = useState(false);
|
const [isMailSend, setIsMailSend] = useState(false);
|
||||||
const [allPages, setAllPages] = useState(null);
|
const [allPages, setAllPages] = useState(null);
|
||||||
@@ -149,7 +141,6 @@ function PlaceHolderSign() {
|
|||||||
status: false,
|
status: false,
|
||||||
message: ""
|
message: ""
|
||||||
});
|
});
|
||||||
const [isCustomize, setIsCustomize] = useState(false);
|
|
||||||
const [zoomPercent, setZoomPercent] = useState(0);
|
const [zoomPercent, setZoomPercent] = useState(0);
|
||||||
const [scale, setScale] = useState(1);
|
const [scale, setScale] = useState(1);
|
||||||
const [pdfBase64Url, setPdfBase64Url] = useState("");
|
const [pdfBase64Url, setPdfBase64Url] = useState("");
|
||||||
@@ -185,12 +176,6 @@ function PlaceHolderSign() {
|
|||||||
);
|
);
|
||||||
if (user) {
|
if (user) {
|
||||||
try {
|
try {
|
||||||
const defaultRequestBody = defaultMailBody;
|
|
||||||
const defaultSubject = defaultMailSubject;
|
|
||||||
setDefaultBody(defaultRequestBody);
|
|
||||||
setDefaultSubject(defaultSubject);
|
|
||||||
setRequestBody(defaultRequestBody);
|
|
||||||
setRequestSubject(defaultSubject);
|
|
||||||
const tenantDetails = await getTenantDetails(user?.objectId);
|
const tenantDetails = await getTenantDetails(user?.objectId);
|
||||||
if (tenantDetails && tenantDetails === "user does not exist!") {
|
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||||
alert(t("user-not-exist"));
|
alert(t("user-not-exist"));
|
||||||
@@ -199,14 +184,22 @@ function PlaceHolderSign() {
|
|||||||
const filterSignTypes = signatureType?.filter(
|
const filterSignTypes = signatureType?.filter(
|
||||||
(x) => x.enabled === true
|
(x) => x.enabled === true
|
||||||
);
|
);
|
||||||
if (tenantDetails?.RequestBody) {
|
const extUser =
|
||||||
setRequestBody(tenantDetails?.RequestBody);
|
localStorage.getItem("Extand_Class") &&
|
||||||
setRequestSubject(tenantDetails?.RequestSubject);
|
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
setTenantMailTemplate({
|
const subject = tenantDetails?.RequestSubject ?? "";
|
||||||
body: tenantDetails?.RequestBody,
|
const body = tenantDetails?.RequestBody ?? "";
|
||||||
subject: tenantDetails?.RequestSubject
|
//customize mail state is handle to when user want to customize already set tenant email format then use that format
|
||||||
});
|
const userSubject =
|
||||||
}
|
subject;
|
||||||
|
const userBody =
|
||||||
|
body;
|
||||||
|
|
||||||
|
setCustomizeMail({
|
||||||
|
subject: userSubject ?? defaultMailSubject,
|
||||||
|
body: userBody ?? defaultMailBody
|
||||||
|
});
|
||||||
|
setDefaultMail({ subject: userSubject, body: userBody });
|
||||||
return filterSignTypes;
|
return filterSignTypes;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -320,9 +313,9 @@ function PlaceHolderSign() {
|
|||||||
updatedPdfDetails[0].SignatureType = updatedSignatureType;
|
updatedPdfDetails[0].SignatureType = updatedSignatureType;
|
||||||
setPdfDetails(updatedPdfDetails);
|
setPdfDetails(updatedPdfDetails);
|
||||||
if (documentData?.[0]?.RequestBody && documentData?.[0]?.RequestSubject) {
|
if (documentData?.[0]?.RequestBody && documentData?.[0]?.RequestSubject) {
|
||||||
setTenantMailTemplate({
|
setDefaultMail({
|
||||||
body: documentData?.[0]?.RequestBody,
|
subject: documentData?.[0]?.RequestSubject,
|
||||||
subject: documentData?.[0]?.RequestSubject
|
body: documentData?.[0]?.RequestBody
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@@ -873,7 +866,6 @@ function PlaceHolderSign() {
|
|||||||
});
|
});
|
||||||
const isSignYourSelfFlow = false;
|
const isSignYourSelfFlow = false;
|
||||||
try {
|
try {
|
||||||
const docId = pdfDetails[0]?.objectId;
|
|
||||||
//pdfOriginalWH contained all pdf's pages width,height & pagenumber in array format
|
//pdfOriginalWH contained all pdf's pages width,height & pagenumber in array format
|
||||||
const pdfBase64 = await embedWidgetsToDoc(
|
const pdfBase64 = await embedWidgetsToDoc(
|
||||||
placeholder,
|
placeholder,
|
||||||
@@ -925,12 +917,16 @@ function PlaceHolderSign() {
|
|||||||
//if empty widget exist and user try to send document then throw tour message
|
//if empty widget exist and user try to send document then throw tour message
|
||||||
for (const placeholder of getPlaceholder || []) {
|
for (const placeholder of getPlaceholder || []) {
|
||||||
const requiredWidgets = placeholder.pos.filter(
|
const requiredWidgets = placeholder.pos.filter(
|
||||||
(position) => position.type !== "checkbox"
|
(position) => position?.options?.status === "required"
|
||||||
);
|
);
|
||||||
for (const widget of requiredWidgets) {
|
for (const widget of requiredWidgets) {
|
||||||
const hasResponse = widget?.options?.response;
|
const response =
|
||||||
const hasDefault = widget?.options?.defaultValue;
|
widget?.options?.response || widget?.options?.defaultValue;
|
||||||
if (!hasResponse && !hasDefault && !isPrefillEmpty) {
|
const isEmptyResponse =
|
||||||
|
!response ||
|
||||||
|
(typeof response === "string" && response.trim() === "") ||
|
||||||
|
(Array.isArray(response) && response.length === 0);
|
||||||
|
if (isEmptyResponse && !isPrefillEmpty) {
|
||||||
isPrefillEmpty = true;
|
isPrefillEmpty = true;
|
||||||
unfilledTextWidgetId = widget.key;
|
unfilledTextWidgetId = widget.key;
|
||||||
setPageNumber(placeholder.pageNumber);
|
setPageNumber(placeholder.pageNumber);
|
||||||
@@ -1035,7 +1031,7 @@ function PlaceHolderSign() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
//function to use save placeholder details in contracts_document
|
//function to use save placeholder details in contracts_document
|
||||||
const saveDocumentDetails = async () => {
|
const saveDocumentDetails = utils.withSessionValidation(async () => {
|
||||||
setIsUiLoading(true);
|
setIsUiLoading(true);
|
||||||
let signerMail = signersdata.slice();
|
let signerMail = signersdata.slice();
|
||||||
// For "Send in order", only consider the first signer
|
// For "Send in order", only consider the first signer
|
||||||
@@ -1094,7 +1090,6 @@ function PlaceHolderSign() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
setIsMailSend(true);
|
|
||||||
setIsLoading({ isLoad: false });
|
setIsLoading({ isLoad: false });
|
||||||
setIsUiLoading(false);
|
setIsUiLoading(false);
|
||||||
setIsSendAlert({ mssg: "confirm", alert: true });
|
setIsSendAlert({ mssg: "confirm", alert: true });
|
||||||
@@ -1103,6 +1098,17 @@ function PlaceHolderSign() {
|
|||||||
updatedPdfDetails[0].Name = docTitle;
|
updatedPdfDetails[0].Name = docTitle;
|
||||||
setPdfDetails(updatedPdfDetails);
|
setPdfDetails(updatedPdfDetails);
|
||||||
}
|
}
|
||||||
|
const ownerId = pdfDetails[0].ExtUserPtr?.UserId?.objectId;
|
||||||
|
const firstSigner = signersdata[0];
|
||||||
|
const isOwner = firstSigner?.UserId?.objectId === ownerId;
|
||||||
|
const currentUserMail = Parse.User.current()?.getEmail();
|
||||||
|
const isCurrentUser = signerMail?.[0]?.Email === currentUserMail;
|
||||||
|
if (pdfDetails[0]?.SendinOrder && isOwner) {
|
||||||
|
setIsSend(true);
|
||||||
|
setIsCurrUser(isCurrentUser);
|
||||||
|
} else {
|
||||||
|
setIsMailModal(true);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("error", e);
|
console.log("error", e);
|
||||||
alert(t("something-went-wrong-mssg"));
|
alert(t("something-went-wrong-mssg"));
|
||||||
@@ -1110,7 +1116,7 @@ function PlaceHolderSign() {
|
|||||||
} else {
|
} else {
|
||||||
setIsUiLoading(false);
|
setIsUiLoading(false);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
const copytoclipboard = (text) => {
|
const copytoclipboard = (text) => {
|
||||||
copytoData(text);
|
copytoData(text);
|
||||||
@@ -1152,215 +1158,24 @@ function PlaceHolderSign() {
|
|||||||
className="flex flex-row items-center op-link op-link-primary"
|
className="flex flex-row items-center op-link op-link-primary"
|
||||||
>
|
>
|
||||||
<i className="fa-light fa-copy" />
|
<i className="fa-light fa-copy" />
|
||||||
<span className=" hidden md:block ml-1 ">{t("copy-link")}</span>
|
<span className="hidden md:block ml-1 ">{t("copy-link")}</span>
|
||||||
</button>
|
</button>
|
||||||
<ShareButton
|
<ShareButton
|
||||||
title={t("sign-url")}
|
title={t("sign-url")}
|
||||||
text={t("sign-url")}
|
text={t("sign-url")}
|
||||||
url={data.url}
|
url={data.url}
|
||||||
>
|
>
|
||||||
<i className="fa-light fa-share-from-square op-link data-[theme=opensigndark]:op-link-primary data-[theme=opensigncss]:op-link-secondary no-underline"></i>
|
<i className="fa-light fa-share-from-square op-link opensigncss:op-link-secondary opensigndark:op-link-primary no-underline"></i>
|
||||||
</ShareButton>
|
</ShareButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const sendEmailToSigners = async () => {
|
|
||||||
let htmlReqBody;
|
|
||||||
setIsUiLoading(true);
|
|
||||||
setIsSendAlert({});
|
|
||||||
let sendMail;
|
|
||||||
const expireDate = pdfDetails?.[0].ExpiryDate.iso;
|
|
||||||
const newDate = new Date(expireDate);
|
|
||||||
const localExpireDate = newDate.toLocaleDateString("en-US", {
|
|
||||||
day: "numeric",
|
|
||||||
month: "long",
|
|
||||||
year: "numeric"
|
|
||||||
});
|
|
||||||
|
|
||||||
let senderEmail =
|
|
||||||
pdfDetails?.[0]?.ExtUserPtr?.Email;
|
|
||||||
let senderPhone = pdfDetails?.[0]?.ExtUserPtr?.Phone;
|
|
||||||
let signerMail = signersdata.slice();
|
|
||||||
if (pdfDetails?.[0]?.SendinOrder && pdfDetails?.[0]?.SendinOrder === true) {
|
|
||||||
signerMail.splice(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < signerMail.length; i++) {
|
|
||||||
try {
|
|
||||||
let url = `${localStorage.getItem("baseUrl")}functions/sendmailv3`;
|
|
||||||
const headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
|
||||||
};
|
|
||||||
const objectId = signerMail[i].objectId;
|
|
||||||
const hostUrl = window.location.origin;
|
|
||||||
//encode this url value `${pdfDetails?.[0].objectId}/${signerMail[i].Email}/${objectId}` to base64 using `btoa` function
|
|
||||||
const encodeBase64 = btoa(
|
|
||||||
`${pdfDetails?.[0].objectId}/${signerMail[i].Email}/${objectId}`
|
|
||||||
);
|
|
||||||
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
|
||||||
const orgName = pdfDetails[0]?.ExtUserPtr.Company
|
|
||||||
? pdfDetails[0].ExtUserPtr.Company
|
|
||||||
: "";
|
|
||||||
const senderName =
|
|
||||||
pdfDetails?.[0].ExtUserPtr.Name;
|
|
||||||
const documentName = `${pdfDetails?.[0].Name}`;
|
|
||||||
let replaceVar;
|
|
||||||
|
|
||||||
if (
|
|
||||||
requestBody &&
|
|
||||||
requestSubject &&
|
|
||||||
isCustomize
|
|
||||||
) {
|
|
||||||
const replacedRequestBody = requestBody.replace(/"/g, "'");
|
|
||||||
htmlReqBody =
|
|
||||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
|
|
||||||
replacedRequestBody +
|
|
||||||
"</body> </html>";
|
|
||||||
|
|
||||||
const variables = {
|
|
||||||
document_title: documentName,
|
|
||||||
note: pdfDetails?.[0]?.Note,
|
|
||||||
sender_name: senderName,
|
|
||||||
sender_mail: senderEmail,
|
|
||||||
sender_phone: senderPhone || "",
|
|
||||||
receiver_name: signerMail[i]?.Name || "",
|
|
||||||
receiver_email: signerMail[i].Email,
|
|
||||||
receiver_phone: signerMail[i]?.Phone || "",
|
|
||||||
expiry_date: localExpireDate,
|
|
||||||
company_name: orgName,
|
|
||||||
signing_url: signPdf
|
|
||||||
};
|
|
||||||
replaceVar = replaceMailVaribles(
|
|
||||||
requestSubject,
|
|
||||||
htmlReqBody,
|
|
||||||
variables
|
|
||||||
);
|
|
||||||
} else if (
|
|
||||||
tenantMailTemplate?.body &&
|
|
||||||
tenantMailTemplate?.subject
|
|
||||||
) {
|
|
||||||
const mailBody = tenantMailTemplate?.body;
|
|
||||||
const mailSubject = tenantMailTemplate?.subject;
|
|
||||||
const replacedRequestBody = mailBody.replace(/"/g, "'");
|
|
||||||
const htmlReqBody =
|
|
||||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
|
|
||||||
replacedRequestBody +
|
|
||||||
"</body> </html>";
|
|
||||||
const variables = {
|
|
||||||
document_title: documentName,
|
|
||||||
note: pdfDetails?.[0]?.Note,
|
|
||||||
sender_name: senderName,
|
|
||||||
sender_mail: senderEmail,
|
|
||||||
sender_phone: senderPhone || "",
|
|
||||||
receiver_name: signerMail[i]?.Name || "",
|
|
||||||
receiver_email: signerMail[i].Email,
|
|
||||||
receiver_phone: signerMail[i]?.Phone || "",
|
|
||||||
expiry_date: localExpireDate,
|
|
||||||
company_name: orgName,
|
|
||||||
signing_url: signPdf
|
|
||||||
};
|
|
||||||
replaceVar = replaceMailVaribles(mailSubject, htmlReqBody, variables);
|
|
||||||
}
|
|
||||||
const mailparam = {
|
|
||||||
senderName: senderName,
|
|
||||||
note: pdfDetails?.[0]?.Note || "",
|
|
||||||
senderMail: senderEmail,
|
|
||||||
title: documentName,
|
|
||||||
organization: orgName,
|
|
||||||
localExpireDate: localExpireDate,
|
|
||||||
signingUrl: signPdf
|
|
||||||
};
|
|
||||||
let params = {
|
|
||||||
extUserId: owner?.objectId,
|
|
||||||
recipient: signerMail[i].Email,
|
|
||||||
subject: replaceVar?.subject
|
|
||||||
? replaceVar?.subject
|
|
||||||
: mailTemplate(mailparam).subject,
|
|
||||||
replyto: senderEmail,
|
|
||||||
from:
|
|
||||||
senderEmail,
|
|
||||||
html: replaceVar?.body
|
|
||||||
? replaceVar?.body
|
|
||||||
: mailTemplate(mailparam).body
|
|
||||||
};
|
|
||||||
|
|
||||||
sendMail = await axios.post(url, params, { headers: headers });
|
|
||||||
} catch (error) {
|
|
||||||
console.log("error", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sendMail?.data?.result?.status === "success") {
|
|
||||||
setMailStatus("success");
|
|
||||||
try {
|
|
||||||
let data;
|
|
||||||
if (
|
|
||||||
requestBody &&
|
|
||||||
requestSubject &&
|
|
||||||
isCustomize
|
|
||||||
) {
|
|
||||||
data = {
|
|
||||||
RequestBody: htmlReqBody,
|
|
||||||
RequestSubject: requestSubject,
|
|
||||||
SendMail: true
|
|
||||||
};
|
|
||||||
} else if (
|
|
||||||
tenantMailTemplate?.body &&
|
|
||||||
tenantMailTemplate?.subject
|
|
||||||
) {
|
|
||||||
data = {
|
|
||||||
RequestBody: tenantMailTemplate?.body,
|
|
||||||
RequestSubject: tenantMailTemplate?.subject,
|
|
||||||
SendMail: true
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
data = { SendMail: true };
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await axios.put(
|
|
||||||
`${localStorage.getItem(
|
|
||||||
"baseUrl"
|
|
||||||
)}classes/contracts_Document/${documentId}`,
|
|
||||||
data,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
console.log("axois err ", err);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log("error", e);
|
|
||||||
}
|
|
||||||
setIsSend(true);
|
|
||||||
setIsMailSend(true);
|
|
||||||
setIsLoading({ isLoad: false });
|
|
||||||
setIsUiLoading(false);
|
|
||||||
} else if (sendMail?.data?.result?.status === "quota-reached") {
|
|
||||||
setMailStatus("quotareached");
|
|
||||||
setIsSend(true);
|
|
||||||
setIsMailSend(true);
|
|
||||||
setIsUiLoading(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setMailStatus("failed");
|
|
||||||
setIsSend(true);
|
|
||||||
setIsMailSend(true);
|
|
||||||
setIsUiLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleDontShow = (isChecked) => {
|
const handleDontShow = (isChecked) => {
|
||||||
setIsDontShow(isChecked);
|
setIsDontShow(isChecked);
|
||||||
};
|
};
|
||||||
//here you can add your messages in content and selector is key of particular steps
|
//here you can add your messages in content and selector is key of particular steps
|
||||||
|
|
||||||
const tourConfig = [
|
const tourConfig = [
|
||||||
{
|
{
|
||||||
selector: '[data-tut="prefillTour"]',
|
selector: '[data-tut="prefillTour"]',
|
||||||
@@ -1372,7 +1187,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="recipientArea"]',
|
selector: '[data-tut="recipientArea"]',
|
||||||
@@ -1384,7 +1199,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="addRecipient"]',
|
selector: '[data-tut="addRecipient"]',
|
||||||
@@ -1396,7 +1211,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="addWidgets"]',
|
selector: '[data-tut="addWidgets"]',
|
||||||
@@ -1408,7 +1223,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="pdfArea"]',
|
selector: '[data-tut="pdfArea"]',
|
||||||
@@ -1420,7 +1235,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="pdftools"]',
|
selector: '[data-tut="pdftools"]',
|
||||||
@@ -1432,7 +1247,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="headerArea"]',
|
selector: '[data-tut="headerArea"]',
|
||||||
@@ -1444,7 +1259,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -1461,6 +1276,9 @@ function PlaceHolderSign() {
|
|||||||
isHideLabel,
|
isHideLabel,
|
||||||
layout
|
layout
|
||||||
) => {
|
) => {
|
||||||
|
const isPrefill = signerPos.some(
|
||||||
|
(x) => x?.Role === "prefill" && x.Id === uniqueId
|
||||||
|
);
|
||||||
const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
|
const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
|
||||||
if (filterSignerPos.length > 0) {
|
if (filterSignerPos.length > 0) {
|
||||||
const getPlaceHolder = filterSignerPos[0].placeHolder;
|
const getPlaceHolder = filterSignerPos[0].placeHolder;
|
||||||
@@ -1526,16 +1344,21 @@ function PlaceHolderSign() {
|
|||||||
...position.options,
|
...position.options,
|
||||||
name: dropdownName,
|
name: dropdownName,
|
||||||
values: dropdownOptions,
|
values: dropdownOptions,
|
||||||
validation: {
|
...(!isPrefill
|
||||||
minRequiredCount: minCount,
|
? {
|
||||||
maxRequiredCount: maxCount
|
validation: {
|
||||||
},
|
minRequiredCount: minCount,
|
||||||
|
maxRequiredCount: maxCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
defaultValue: defaultValue,
|
defaultValue: defaultValue,
|
||||||
layout: layout,
|
layout: layout,
|
||||||
isReadOnly: isReadOnly || false,
|
isReadOnly: isReadOnly || false,
|
||||||
isHideLabel: isHideLabel || false,
|
isHideLabel: isHideLabel || false,
|
||||||
fontSize: textSize || 12,
|
fontSize: textSize || 12,
|
||||||
fontColor: textColor || "black"
|
fontColor: textColor || "black",
|
||||||
|
...(isPrefill ? { status } : {})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1641,13 +1464,16 @@ function PlaceHolderSign() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (["signature"].includes(position.type)) {
|
else if (["signature", "initials"].includes(position.type)) {
|
||||||
return {
|
return {
|
||||||
...position,
|
...position,
|
||||||
options: {
|
options: {
|
||||||
...position.options,
|
...position.options,
|
||||||
name: defaultdata.name,
|
name: defaultdata.name,
|
||||||
hint: defaultdata?.hint || ""
|
hint: defaultdata?.hint || "",
|
||||||
|
...(defaultdata?.penColors?.length > 0 && {
|
||||||
|
penColors: defaultdata?.penColors
|
||||||
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@@ -1844,7 +1670,7 @@ function PlaceHolderSign() {
|
|||||||
selector: '[data-tut="assignSigner"]',
|
selector: '[data-tut="assignSigner"]',
|
||||||
content: t("attach-signer-tour"),
|
content: t("attach-signer-tour"),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
const prefillWidgetTour = [
|
const prefillWidgetTour = [
|
||||||
@@ -1852,7 +1678,7 @@ function PlaceHolderSign() {
|
|||||||
selector: '[data-tut="IsSigned"]',
|
selector: '[data-tut="IsSigned"]',
|
||||||
content: t("text-field-tour"),
|
content: t("text-field-tour"),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
const signatureWidgetTour = [
|
const signatureWidgetTour = [
|
||||||
@@ -1860,7 +1686,7 @@ function PlaceHolderSign() {
|
|||||||
selector: '[data-tut="isSignatureWidget"]',
|
selector: '[data-tut="isSignatureWidget"]',
|
||||||
content: t("signature-field-widget", { signersName }),
|
content: t("signature-field-widget", { signersName }),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -1963,6 +1789,10 @@ function PlaceHolderSign() {
|
|||||||
const RedirectUrl = updateDocument?.[0]?.RedirectUrl
|
const RedirectUrl = updateDocument?.[0]?.RedirectUrl
|
||||||
? { RedirectUrl: updateDocument?.[0]?.RedirectUrl }
|
? { RedirectUrl: updateDocument?.[0]?.RedirectUrl }
|
||||||
: {};
|
: {};
|
||||||
|
const penColors =
|
||||||
|
updateDocument?.[0]?.PenColors?.length > 0
|
||||||
|
? { PenColors: updateDocument?.[0]?.PenColors }
|
||||||
|
: {};
|
||||||
const data = {
|
const data = {
|
||||||
...(updateDocument?.[0]?.URL ? { URL: updateDocument?.[0]?.URL } : {}),
|
...(updateDocument?.[0]?.URL ? { URL: updateDocument?.[0]?.URL } : {}),
|
||||||
Name: updateDocument?.[0]?.Name || "",
|
Name: updateDocument?.[0]?.Name || "",
|
||||||
@@ -1979,6 +1809,7 @@ function PlaceHolderSign() {
|
|||||||
: false,
|
: false,
|
||||||
TimeToCompleteDays:
|
TimeToCompleteDays:
|
||||||
parseInt(updateDocument?.[0]?.TimeToCompleteDays) || 15,
|
parseInt(updateDocument?.[0]?.TimeToCompleteDays) || 15,
|
||||||
|
...penColors,
|
||||||
...Bcc,
|
...Bcc,
|
||||||
...RedirectUrl
|
...RedirectUrl
|
||||||
};
|
};
|
||||||
@@ -2017,8 +1848,6 @@ function PlaceHolderSign() {
|
|||||||
onRequestClose={closeTour}
|
onRequestClose={closeTour}
|
||||||
steps={tourConfig}
|
steps={tourConfig}
|
||||||
isOpen={placeholderTour}
|
isOpen={placeholderTour}
|
||||||
rounded={5}
|
|
||||||
closeWithMask={false}
|
|
||||||
/>
|
/>
|
||||||
<Tour
|
<Tour
|
||||||
onRequestClose={() => setSignerExistModal(false)}
|
onRequestClose={() => setSignerExistModal(false)}
|
||||||
@@ -2071,90 +1900,17 @@ function PlaceHolderSign() {
|
|||||||
pdfDetails={pdfDetails}
|
pdfDetails={pdfDetails}
|
||||||
/>
|
/>
|
||||||
<div className=" w-full md:w-[95%] ">
|
<div className=" w-full md:w-[95%] ">
|
||||||
{/* this modal is used show alert set placeholder for all signers before send mail */}
|
|
||||||
<ModalUi
|
|
||||||
isOpen={isSendAlert.alert && isSendAlert.mssg === "confirm"}
|
|
||||||
title={isSendAlert.mssg === "confirm" && t("send-mail")}
|
|
||||||
handleClose={() => handleCloseSendmailModal()}
|
|
||||||
>
|
|
||||||
<div className="max-h-96 overflow-y-scroll scroll-hide p-[20px] text-base-content">
|
|
||||||
{isSendAlert.mssg === "confirm" && (
|
|
||||||
<>
|
|
||||||
{!isCustomize && <span>{t("placeholder-alert-3")}</span>}
|
|
||||||
{
|
|
||||||
isCustomize && (
|
|
||||||
<>
|
|
||||||
<EmailBody
|
|
||||||
editorRef={editorRef}
|
|
||||||
requestBody={requestBody}
|
|
||||||
requestSubject={requestSubject}
|
|
||||||
handleOnchangeRequest={handleOnchangeRequest}
|
|
||||||
setRequestSubject={setRequestSubject}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
className="flex justify-end items-center gap-1 mt-2 op-link op-link-primary"
|
|
||||||
onClick={() => {
|
|
||||||
setRequestBody(defaultBody);
|
|
||||||
setRequestSubject(defaultSubject);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span>{t("reset-to-default")}</span>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
<div className="flex flex-row items-center gap-2 md:gap-6 mt-2">
|
|
||||||
<div className="flex flex-row gap-2">
|
|
||||||
<button
|
|
||||||
onClick={() => sendEmailToSigners()}
|
|
||||||
className="op-btn op-btn-primary font-[500] text-sm shadow"
|
|
||||||
>
|
|
||||||
{t("send")}
|
|
||||||
</button>
|
|
||||||
{isCustomize && (
|
|
||||||
<button
|
|
||||||
onClick={() => setIsCustomize(false)}
|
|
||||||
className="op-btn op-btn-ghost font-[500] text-sm"
|
|
||||||
>
|
|
||||||
{t("close")}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{
|
|
||||||
!isCustomize && (
|
|
||||||
<span
|
|
||||||
className="op-link op-link-accent text-sm"
|
|
||||||
onClick={() => setIsCustomize(!isCustomize)}
|
|
||||||
>
|
|
||||||
{t("cutomize-email")}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{isSendAlert.mssg === "confirm" && (
|
|
||||||
<>
|
|
||||||
<div className="flex justify-center items-center mt-3">
|
|
||||||
<span className="h-[1px] w-[20%] bg-[#ccc]"></span>
|
|
||||||
<span className="ml-[5px] mr-[5px]">{t("or")}</span>
|
|
||||||
<span className="h-[1px] w-[20%] bg-[#ccc]"></span>
|
|
||||||
</div>
|
|
||||||
<div className="my-3">{handleShareList()}</div>
|
|
||||||
<p id="copyUrl" ref={copyUrlRef} className="hidden"></p>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</ModalUi>
|
|
||||||
{/* this modal is used show send mail message and after send mail success message */}
|
{/* this modal is used show send mail message and after send mail success message */}
|
||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen={isSend}
|
isOpen={isSend}
|
||||||
title={
|
title={
|
||||||
mailStatus === "success"
|
!pdfDetails[0]?.SendinOrder
|
||||||
? t("mails-sent")
|
? mailStatus === "success"
|
||||||
: mailStatus === "quotareached"
|
? t("mails-sent")
|
||||||
? t("quota-mail-head")
|
: mailStatus === "quotareached"
|
||||||
: t("mail-not-delivered")
|
? t("quota-mail-head")
|
||||||
|
: t("mail-not-delivered")
|
||||||
|
: t("mail-status-head")
|
||||||
}
|
}
|
||||||
handleClose={() => {
|
handleClose={() => {
|
||||||
setIsSend(false);
|
setIsSend(false);
|
||||||
@@ -2163,70 +1919,103 @@ function PlaceHolderSign() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="h-[100%] p-[20px] text-base-content">
|
<div className="h-[100%] p-[20px] text-base-content">
|
||||||
{mailStatus === "success" ? (
|
<div className="flex flex-col items-center gap-5">
|
||||||
<div className="text-center mb-[10px]">
|
<div>
|
||||||
<LottieWithLoader />
|
{mailStatus === "success" ? (
|
||||||
{pdfDetails[0].SendinOrder ? (
|
<div className="text-center mb-[10px]">
|
||||||
<p>
|
<LottieWithLoader />
|
||||||
{isCurrUser
|
{pdfDetails[0].SendinOrder ? (
|
||||||
? t("placeholder-mail-alert-you")
|
<p>
|
||||||
: t("placeholder-mail-alert", {
|
{isCurrUser
|
||||||
name: signersdata[0]?.Name
|
? t("placeholder-mail-alert-you")
|
||||||
})}
|
: t("placeholder-mail-alert", {
|
||||||
</p>
|
name: signersdata[0]?.Name
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
<p>{t("placeholder-alert-4")}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : mailStatus === "quotareached" ? (
|
||||||
|
<div className="flex flex-col gap-y-3">
|
||||||
|
<div className="my-3">{handleShareList()}</div>
|
||||||
|
</div>
|
||||||
|
) : mailStatus === "failed" ? (
|
||||||
|
<p>{t("mail-failed")} </p>
|
||||||
) : (
|
) : (
|
||||||
<p>{t("placeholder-alert-4")}</p>
|
<div className="mb-[10px]">
|
||||||
|
{!pdfDetails[0]?.SendinOrder &&
|
||||||
|
(mailStatus === "dailyquotareached" ? (
|
||||||
|
<p>{t("daily-quota-reached")}</p>
|
||||||
|
) : (
|
||||||
|
<p>{t("placeholder-alert-6")}</p>
|
||||||
|
))}
|
||||||
|
{isCurrUser && (
|
||||||
|
<span className="mt-1">
|
||||||
|
{t("placeholder-alert-5")}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{isCurrUser && <p>{t("placeholder-alert-5")}</p>}
|
|
||||||
</div>
|
{mailStatus !== "quotareached" && (
|
||||||
) : mailStatus === "quotareached" ? (
|
<div
|
||||||
<div className="flex flex-col gap-y-3">
|
className={
|
||||||
<div className="my-3">{handleShareList()}</div>
|
mailStatus === "success"
|
||||||
</div>
|
? "flex justify-center mt-1"
|
||||||
) : (
|
: "flex items-center justify-center mt-7"
|
||||||
<div className="mb-[10px]">
|
}
|
||||||
{mailStatus === "dailyquotareached" ? (
|
|
||||||
<p>{t("daily-quota-reached")}</p>
|
|
||||||
) : (
|
|
||||||
<p>{t("placeholder-alert-6")}</p>
|
|
||||||
)}
|
|
||||||
{isCurrUser && (
|
|
||||||
<p className="mt-1">{t("placeholder-alert-5")}</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{!mailStatus && (
|
|
||||||
<div className="w-full h-[1px] bg-[#9f9f9f] my-[15px]"></div>
|
|
||||||
)}
|
|
||||||
{mailStatus !== "quotareached" && (
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
mailStatus === "success"
|
|
||||||
? "flex justify-center mt-1"
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{isCurrUser && (
|
|
||||||
<button
|
|
||||||
onClick={() => handleRecipientSign()}
|
|
||||||
type="button"
|
|
||||||
className="op-btn op-btn-primary mr-1"
|
|
||||||
>
|
>
|
||||||
{t("yes")}
|
{isCurrUser && (
|
||||||
</button>
|
<button
|
||||||
|
onClick={() => handleRecipientSign()}
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-primary mr-1"
|
||||||
|
>
|
||||||
|
{t("sign-now")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
setIsSend(false);
|
||||||
|
setSignerPos([]);
|
||||||
|
navigate("/report/1MwEuxLEkF");
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-ghost text-base-content"
|
||||||
|
>
|
||||||
|
{isCurrUser ? t("no") : t("close")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
setIsSend(false);
|
|
||||||
setSignerPos([]);
|
|
||||||
navigate("/report/1MwEuxLEkF");
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className="op-btn op-btn-ghost text-base-content"
|
|
||||||
>
|
|
||||||
{isCurrUser ? t("no") : t("close")}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
{mailStatus !== "success" &&
|
||||||
|
isCurrUser &&
|
||||||
|
pdfDetails[0]?.SendinOrder && (
|
||||||
|
<div className="op-divider text-base-content mx-[0%] my-1 font-medium">
|
||||||
|
{t("or")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{mailStatus !== "success" &&
|
||||||
|
pdfDetails[0]?.SendinOrder &&
|
||||||
|
isCurrUser && (
|
||||||
|
<div
|
||||||
|
className="op-btn op-btn-outline w-[50%] md:w-[35%] mt-1"
|
||||||
|
onClick={() => {
|
||||||
|
setIsSend(false);
|
||||||
|
setIsMailModal(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="fa-regular fa-envelope"
|
||||||
|
style={{ color: "#002864", fontSize: "19px" }}
|
||||||
|
></i>{" "}
|
||||||
|
<span>{t("send-to-email")}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{!mailStatus && (
|
||||||
|
<div className="op-divider text-base-content mx-[0%] mt-3"></div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
@@ -2473,6 +2262,18 @@ function PlaceHolderSign() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<CustomizeMail
|
||||||
|
setIsMailModal={setIsMailModal}
|
||||||
|
setCustomizeMail={setCustomizeMail}
|
||||||
|
documentId={documentId}
|
||||||
|
signerList={signersdata}
|
||||||
|
setIsSend={setIsSend}
|
||||||
|
setMailStatus={setMailStatus}
|
||||||
|
customizeMail={customizeMail}
|
||||||
|
defaultMail={defaultMail}
|
||||||
|
isMailModal={isMailModal}
|
||||||
|
handleShareList={handleShareList}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isShowModal[currWidgetsDetails?.key] && (
|
{isShowModal[currWidgetsDetails?.key] && (
|
||||||
@@ -2489,6 +2290,8 @@ function PlaceHolderSign() {
|
|||||||
isSave={true}
|
isSave={true}
|
||||||
setUniqueId={setUniqueId}
|
setUniqueId={setUniqueId}
|
||||||
signatureTypes={signatureType}
|
signatureTypes={signatureType}
|
||||||
|
penColors={pdfDetails?.[0]?.PenColors}
|
||||||
|
role={roleName}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ModalUi
|
<ModalUi
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import Tooltip from "../primitives/Tooltip";
|
|||||||
import {
|
import {
|
||||||
getTenantDetails,
|
getTenantDetails,
|
||||||
handleSignatureType,
|
handleSignatureType,
|
||||||
openInNewTab,
|
|
||||||
signatureTypes,
|
signatureTypes,
|
||||||
usertimezone
|
usertimezone
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
@@ -16,17 +15,25 @@ import TimezoneSelector from "../components/preferences/TimezoneSelector";
|
|||||||
import DateFormatSelector from "../components/preferences/DateFormatSelector";
|
import DateFormatSelector from "../components/preferences/DateFormatSelector";
|
||||||
import FilenameFormatSelector from "../components/preferences/FilenameFormatSelector";
|
import FilenameFormatSelector from "../components/preferences/FilenameFormatSelector";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import MailTemplateEditor from "../components/preferences/MailTemplateEditor";
|
import { withSessionValidation } from "../utils";
|
||||||
|
import { WidgetsTab, EmailTab } from "../components/preferences/tabs";
|
||||||
|
import {
|
||||||
|
setUserInfo,
|
||||||
|
setTenantInfo,
|
||||||
|
setLoader,
|
||||||
|
setTopLoader,
|
||||||
|
setAlertInfo
|
||||||
|
} from "../redux/reducers/userReducer";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
|
||||||
const Preferences = () => {
|
const Preferences = () => {
|
||||||
const appName =
|
const appName =
|
||||||
"OpenSign™";
|
"OpenSign™";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const Extand_Class = localStorage.getItem("Extand_Class");
|
const dispatch = useDispatch();
|
||||||
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
const { isLoader, isTopLoader, alertInfo } = useSelector(
|
||||||
const [isalert, setIsAlert] = useState({ type: "success", msg: "" });
|
(state) => state.user
|
||||||
const [isTopLoader, setIsTopLoader] = useState(false);
|
);
|
||||||
const [isLoader, setIsLoader] = useState(false);
|
|
||||||
const [signatureType, setSignatureType] = useState([]);
|
const [signatureType, setSignatureType] = useState([]);
|
||||||
const [errMsg, setErrMsg] = useState("");
|
const [errMsg, setErrMsg] = useState("");
|
||||||
const [isNotifyOnSignatures, setIsNotifyOnSignatures] = useState();
|
const [isNotifyOnSignatures, setIsNotifyOnSignatures] = useState();
|
||||||
@@ -44,22 +51,28 @@ const Preferences = () => {
|
|||||||
const [is12HourTime, setIs12HourTime] = useState(false);
|
const [is12HourTime, setIs12HourTime] = useState(false);
|
||||||
const [isLTVEnabled, setIsLTVEnabled] = useState(false);
|
const [isLTVEnabled, setIsLTVEnabled] = useState(false);
|
||||||
const [fileNameFormat, setFileNameFormat] = useState("DOCNAME");
|
const [fileNameFormat, setFileNameFormat] = useState("DOCNAME");
|
||||||
const [userInfo, setUserInfo] = useState({});
|
|
||||||
const [tenantInfo, setTenantInfo] = useState({});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchSignType();
|
fetchSignType();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const fetchSignType = async () => {
|
const showAlert = (type, msg) => {
|
||||||
setIsTopLoader(true);
|
dispatch(setAlertInfo({ type, msg }));
|
||||||
|
setTimeout(() => {
|
||||||
|
dispatch(setAlertInfo({ type: "success", msg: "" }));
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchSignType = withSessionValidation(async () => {
|
||||||
|
dispatch(setTopLoader(true));
|
||||||
const EmailTab = [
|
const EmailTab = [
|
||||||
{ name: "email", title: t("email"), icon: "fa-light fa-envelope" }
|
{ name: "email", title: t("email"), icon: "fa-light fa-envelope" }
|
||||||
];
|
];
|
||||||
|
|
||||||
const arr = [
|
const arr = [
|
||||||
generaltab,
|
generaltab,
|
||||||
|
{ name: "widgets", title: t("widgets"), icon: "fa-light fa-list" },
|
||||||
...EmailTab,
|
...EmailTab,
|
||||||
];
|
];
|
||||||
setTab(arr);
|
setTab(arr);
|
||||||
@@ -70,7 +83,7 @@ const Preferences = () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
const tenantDetails = await getTenantDetails(user?.objectId);
|
const tenantDetails = await getTenantDetails(user?.objectId);
|
||||||
setTenantInfo(tenantDetails);
|
dispatch(setTenantInfo(tenantDetails));
|
||||||
const signatureType = tenantDetails?.SignatureType || [];
|
const signatureType = tenantDetails?.SignatureType || [];
|
||||||
const tenantSignTypes = signatureType?.filter((x) => x.enabled === true);
|
const tenantSignTypes = signatureType?.filter((x) => x.enabled === true);
|
||||||
const extUser = await axios.post(
|
const extUser = await axios.post(
|
||||||
@@ -84,69 +97,74 @@ const Preferences = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const getUser = extUser.data?.result;
|
const getUser = extUser?.data?.result;
|
||||||
if (getUser) {
|
if (!getUser) {
|
||||||
const _getUser = JSON.parse(JSON.stringify(getUser));
|
setErrMsg(t("something-went-wrong-mssg"));
|
||||||
setUserInfo(_getUser);
|
return;
|
||||||
setIsNotifyOnSignatures(
|
|
||||||
_getUser?.NotifyOnSignatures !== undefined
|
|
||||||
? _getUser?.NotifyOnSignatures
|
|
||||||
: true
|
|
||||||
);
|
|
||||||
setTimezone(_getUser?.Timezone || usertimezone);
|
|
||||||
if (tenantSignTypes?.length > 0) {
|
|
||||||
const signatureType = _getUser?.SignatureType || signatureTypes;
|
|
||||||
const updatedSignatureType = await handleSignatureType(
|
|
||||||
tenantSignTypes,
|
|
||||||
signatureType
|
|
||||||
);
|
|
||||||
setSignatureType(updatedSignatureType);
|
|
||||||
} else {
|
|
||||||
const SignatureType = _getUser?.SignatureType || signatureTypes;
|
|
||||||
setSignatureType(SignatureType);
|
|
||||||
}
|
|
||||||
setSendinOrder(
|
|
||||||
_getUser?.SendinOrder !== undefined ? _getUser?.SendinOrder : true
|
|
||||||
);
|
|
||||||
setIsTourEnabled(
|
|
||||||
_getUser?.IsTourEnabled !== undefined ? _getUser?.IsTourEnabled : true
|
|
||||||
);
|
|
||||||
setDateFormat(
|
|
||||||
_getUser?.DateFormat !== undefined
|
|
||||||
? _getUser?.DateFormat
|
|
||||||
: "MM/DD/YYYY"
|
|
||||||
);
|
|
||||||
setIs12HourTime(
|
|
||||||
_getUser?.Is12HourTime !== undefined ? _getUser?.Is12HourTime : false
|
|
||||||
);
|
|
||||||
setIsLTVEnabled(
|
|
||||||
_getUser?.IsLTVEnabled !== undefined ? _getUser?.IsLTVEnabled : false
|
|
||||||
);
|
|
||||||
const downloadFilenameFormat =
|
|
||||||
_getUser?.DownloadFilenameFormat || "DOCNAME";
|
|
||||||
setFileNameFormat(downloadFilenameFormat);
|
|
||||||
}
|
}
|
||||||
|
const _getUser = JSON.parse(JSON.stringify(getUser));
|
||||||
|
dispatch(setUserInfo(_getUser));
|
||||||
|
setIsNotifyOnSignatures(
|
||||||
|
_getUser?.NotifyOnSignatures !== undefined
|
||||||
|
? _getUser?.NotifyOnSignatures
|
||||||
|
: true
|
||||||
|
);
|
||||||
|
setTimezone(_getUser?.Timezone || usertimezone);
|
||||||
|
if (tenantSignTypes?.length > 0) {
|
||||||
|
const signatureType = _getUser?.SignatureType || signatureTypes;
|
||||||
|
const updatedSignatureType = await handleSignatureType(
|
||||||
|
tenantSignTypes,
|
||||||
|
signatureType
|
||||||
|
);
|
||||||
|
setSignatureType(updatedSignatureType);
|
||||||
|
} else {
|
||||||
|
setSignatureType(_getUser?.SignatureType || signatureTypes);
|
||||||
|
}
|
||||||
|
setSendinOrder(
|
||||||
|
_getUser?.SendinOrder !== undefined ? _getUser?.SendinOrder : true
|
||||||
|
);
|
||||||
|
setIsTourEnabled(
|
||||||
|
_getUser?.IsTourEnabled !== undefined ? _getUser?.IsTourEnabled : true
|
||||||
|
);
|
||||||
|
setDateFormat(
|
||||||
|
_getUser?.DateFormat !== undefined ? _getUser?.DateFormat : "MM/DD/YYYY"
|
||||||
|
);
|
||||||
|
setIs12HourTime(
|
||||||
|
_getUser?.Is12HourTime !== undefined ? _getUser?.Is12HourTime : false
|
||||||
|
);
|
||||||
|
setIsLTVEnabled(
|
||||||
|
_getUser?.IsLTVEnabled !== undefined ? _getUser?.IsLTVEnabled : false
|
||||||
|
);
|
||||||
|
const downloadFilenameFormat =
|
||||||
|
_getUser?.DownloadFilenameFormat || "DOCNAME";
|
||||||
|
setFileNameFormat(downloadFilenameFormat);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error while getting user details: ", err);
|
console.error("Error while getting user details: ", err);
|
||||||
setErrMsg(t("something-went-wrong-mssg"));
|
setErrMsg(t("something-went-wrong-mssg"));
|
||||||
} finally {
|
} finally {
|
||||||
setIsTopLoader(false);
|
dispatch(setTopLoader(false));
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// `handleCheckboxChange` is trigger when user enable/disable checkbox of respective type
|
// `handleCheckboxChange` is trigger when user enable/disable checkbox of respective type
|
||||||
const handleCheckboxChange = (index) => {
|
const handleCheckboxChange = (index) => {
|
||||||
// Create a copy of the signatureType array
|
// // Create a copy of the signatureType array
|
||||||
const updatedSignatureType = [...signatureType];
|
// const updatedSignatureType = [...signatureType];
|
||||||
// Toggle the enabled value for the clicked item
|
// // Toggle the enabled value for the clicked item
|
||||||
updatedSignatureType[index].enabled = !updatedSignatureType[index].enabled;
|
// updatedSignatureType[index].enabled = !updatedSignatureType[index].enabled;
|
||||||
// Update the state with the modified array
|
// // Update the state with the modified array
|
||||||
setSignatureType(updatedSignatureType);
|
// setSignatureType(updatedSignatureType);
|
||||||
|
|
||||||
|
setSignatureType((prev) =>
|
||||||
|
prev.map((item, i) =>
|
||||||
|
i === index ? { ...item, enabled: !item.enabled } : item
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// `handleSave` is used save updated value signature type
|
// `handleSave` is used save updated value signature type
|
||||||
const handleSave = async () => {
|
const handleSave = withSessionValidation(async () => {
|
||||||
setIsLoader(true);
|
dispatch(setLoader(true));
|
||||||
const Timezone = timezone || usertimezone;
|
const Timezone = timezone || usertimezone;
|
||||||
if (
|
if (
|
||||||
signatureType.length > 0 ||
|
signatureType.length > 0 ||
|
||||||
@@ -160,20 +178,12 @@ const Preferences = () => {
|
|||||||
enabledSignTypes?.length === 1 &&
|
enabledSignTypes?.length === 1 &&
|
||||||
enabledSignTypes[0]?.name === "default";
|
enabledSignTypes[0]?.name === "default";
|
||||||
if (enabledSignTypes.length === 0) {
|
if (enabledSignTypes.length === 0) {
|
||||||
setIsAlert({
|
showAlert("danger", t("at-least-one-signature-type"));
|
||||||
type: "danger",
|
dispatch(setLoader(false));
|
||||||
msg: t("at-least-one-signature-type")
|
|
||||||
});
|
|
||||||
setIsLoader(false);
|
|
||||||
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 2000);
|
|
||||||
return;
|
return;
|
||||||
} else if (isDefaultSignTypeOnly) {
|
} else if (isDefaultSignTypeOnly) {
|
||||||
setIsAlert({
|
showAlert("danger", t("expect-default-one-signature-type"));
|
||||||
type: "danger",
|
dispatch(setLoader(false));
|
||||||
msg: t("expect-default-one-signature-type")
|
|
||||||
});
|
|
||||||
setIsLoader(false);
|
|
||||||
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 2000);
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
params = { ...params, SignatureType: signatureType };
|
params = { ...params, SignatureType: signatureType };
|
||||||
@@ -194,7 +204,7 @@ const Preferences = () => {
|
|||||||
};
|
};
|
||||||
const updateRes = await Parse.Cloud.run("updatepreferences", params);
|
const updateRes = await Parse.Cloud.run("updatepreferences", params);
|
||||||
if (updateRes) {
|
if (updateRes) {
|
||||||
setIsAlert({ type: "success", msg: t("saved-successfully") });
|
showAlert("success", t("saved-successfully"));
|
||||||
let extUser =
|
let extUser =
|
||||||
localStorage.getItem("Extand_Class") &&
|
localStorage.getItem("Extand_Class") &&
|
||||||
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
@@ -211,13 +221,11 @@ const Preferences = () => {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error updating signature type: ", err);
|
console.error("Error updating signature type: ", err);
|
||||||
setIsAlert({ type: "danger", msg: err.message });
|
showAlert("danger", err.message);
|
||||||
}
|
}
|
||||||
|
dispatch(setLoader(false));
|
||||||
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
|
|
||||||
setIsLoader(false);
|
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// `handleNotifySignChange` is trigger when user change radio of notify on signatures
|
// `handleNotifySignChange` is trigger when user change radio of notify on signatures
|
||||||
const handleNotifySignChange = (value) => {
|
const handleNotifySignChange = (value) => {
|
||||||
@@ -231,7 +239,7 @@ const Preferences = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{isalert.msg && <Alert type={isalert.type}>{isalert.msg}</Alert>}
|
{alertInfo.msg && <Alert type={alertInfo.type}>{alertInfo.msg}</Alert>}
|
||||||
{isTopLoader ? (
|
{isTopLoader ? (
|
||||||
<div className="flex justify-center items-center h-screen">
|
<div className="flex justify-center items-center h-screen">
|
||||||
<Loader />
|
<Loader />
|
||||||
@@ -265,20 +273,25 @@ const Preferences = () => {
|
|||||||
onClick={() => setactiveTab(ind)}
|
onClick={() => setactiveTab(ind)}
|
||||||
key={ind}
|
key={ind}
|
||||||
role="tab"
|
role="tab"
|
||||||
className={`${activeTab === ind ? "op-tab-active" : ""} op-tab text-xs md:text-base pb-2 md:pb-0 transition-all `}
|
className={` op-tab text-xs md:text-base pb-2 md:pb-0 transition-all`}
|
||||||
aria-selected={activeTab === ind}
|
aria-selected={activeTab === ind}
|
||||||
aria-controls={`panel-${tabData.title}`}
|
aria-controls={`panel-${tabData.title}`}
|
||||||
>
|
>
|
||||||
<i className={tabData.icon}></i>
|
<i className={tabData.icon}></i>
|
||||||
<span className="ml-1 md:ml-2">{tabData.title}</span>
|
<span
|
||||||
|
className={`${activeTab === ind ? "block" : "hidden"} md:block ml-1`}
|
||||||
|
title={tabData?.title}
|
||||||
|
>
|
||||||
|
{tabData.title}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
id="panel-general"
|
id={`panel-${activeTab}`}
|
||||||
className="px-6 pt-4 pb-6"
|
className="px-6 pt-4 pb-6"
|
||||||
aria-labelledby="tab-general"
|
aria-labelledby={`tab-${activeTab}`}
|
||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
>
|
>
|
||||||
{tabName(activeTab) === "general" && (
|
{tabName(activeTab) === "general" && (
|
||||||
@@ -312,7 +325,9 @@ const Preferences = () => {
|
|||||||
<div className="p-[5px] ml-2">
|
<div className="p-[5px] ml-2">
|
||||||
<ol className="list-disc">
|
<ol className="list-disc">
|
||||||
<li>
|
<li>
|
||||||
<span className="font-bold">Draw: </span>
|
<span className="font-bold">
|
||||||
|
{t("draw")}:{" "}
|
||||||
|
</span>
|
||||||
<span>
|
<span>
|
||||||
{t("allowed-signature-types-help.l1")}
|
{t("allowed-signature-types-help.l1")}
|
||||||
</span>
|
</span>
|
||||||
@@ -324,7 +339,9 @@ const Preferences = () => {
|
|||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span className="font-bold">Upload: </span>
|
<span className="font-bold">
|
||||||
|
{t("upload")}:{" "}
|
||||||
|
</span>
|
||||||
<span>
|
<span>
|
||||||
{t("allowed-signature-types-help.l3")}
|
{t("allowed-signature-types-help.l3")}
|
||||||
</span>
|
</span>
|
||||||
@@ -620,20 +637,8 @@ const Preferences = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{tabName(activeTab) === "email" && (
|
{tabName(activeTab) === "widgets" && <WidgetsTab />}
|
||||||
<div className="flex flex-col mb-4">
|
{tabName(activeTab) === "email" && <EmailTab />}
|
||||||
<MailTemplateEditor
|
|
||||||
info={
|
|
||||||
tenantInfo
|
|
||||||
}
|
|
||||||
tenantId={tenantInfo?.objectId}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{tabName(activeTab) === "security" && (
|
|
||||||
<>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import ColumnSelector from "../components/ColumnSelector";
|
|||||||
import TemplatesReport from "../reports/template/TemplatesReport";
|
import TemplatesReport from "../reports/template/TemplatesReport";
|
||||||
import DocumentsReport from "../reports/document/DocumentsReport";
|
import DocumentsReport from "../reports/document/DocumentsReport";
|
||||||
import { templateReportTour } from "../json/ReportTour";
|
import { templateReportTour } from "../json/ReportTour";
|
||||||
|
import { withSessionValidation } from "../utils";
|
||||||
|
|
||||||
const Report = () => {
|
const Report = () => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
@@ -31,6 +32,7 @@ const Report = () => {
|
|||||||
const [columnLabels, setColumnLabels] = useState({});
|
const [columnLabels, setColumnLabels] = useState({});
|
||||||
const [defaultColumns, setDefaultColumns] = useState([]);
|
const [defaultColumns, setDefaultColumns] = useState([]);
|
||||||
const [isColumnModal, setIsColumnModal] = useState(false);
|
const [isColumnModal, setIsColumnModal] = useState(false);
|
||||||
|
const [searchLoader, setSearchLoader] = useState(false);
|
||||||
const debounceTimer = useRef(null);
|
const debounceTimer = useRef(null);
|
||||||
// Number of documents to display per page (should always be half of docLimit for proper pagination)
|
// Number of documents to display per page (should always be half of docLimit for proper pagination)
|
||||||
const docPerPage = 10;
|
const docPerPage = 10;
|
||||||
@@ -73,13 +75,14 @@ const Report = () => {
|
|||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [isNextRecord]);
|
}, [isNextRecord]);
|
||||||
|
|
||||||
const handleSearchChange = async (e) => {
|
const handleSearchChange = withSessionValidation(async (e) => {
|
||||||
const term = e.target.value.toLowerCase();
|
const term = e.target.value.toLowerCase();
|
||||||
setSearchTerm(term);
|
setSearchTerm(term);
|
||||||
if (debounceTimer.current) {
|
if (debounceTimer.current) {
|
||||||
clearTimeout(debounceTimer.current);
|
clearTimeout(debounceTimer.current);
|
||||||
}
|
}
|
||||||
debounceTimer.current = setTimeout(async () => {
|
debounceTimer.current = setTimeout(async () => {
|
||||||
|
setSearchLoader(true);
|
||||||
try {
|
try {
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -98,13 +101,15 @@ const Report = () => {
|
|||||||
setIsMoreDocs(data.length >= docPerPage);
|
setIsMoreDocs(data.length >= docPerPage);
|
||||||
setIsNextRecord(false);
|
setIsNextRecord(false);
|
||||||
setIsSearchResult(true);
|
setIsSearchResult(true);
|
||||||
|
setSearchLoader(false);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Search error:", err);
|
console.error("Search error:", err);
|
||||||
|
setSearchLoader(false);
|
||||||
}
|
}
|
||||||
}, 300);
|
}, 300);
|
||||||
setIsSearchResult(false);
|
setIsSearchResult(false);
|
||||||
};
|
});
|
||||||
|
|
||||||
const handleSearchPaste = (e) => {
|
const handleSearchPaste = (e) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -119,113 +124,113 @@ const Report = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
const getReportData = async (
|
const getReportData = withSessionValidation(
|
||||||
skipUserRecord = 0,
|
async (skipUserRecord = 0, limit = 20, term = searchTerm) => {
|
||||||
limit = 20,
|
// setIsLoader(true);
|
||||||
term = searchTerm
|
const json = reportJson(id);
|
||||||
) => {
|
if (json) {
|
||||||
// setIsLoader(true);
|
setActions(json.actions);
|
||||||
const json = reportJson(id);
|
const savedCols = JSON.parse(
|
||||||
if (json) {
|
localStorage.getItem("reportColumns") || "{}"
|
||||||
setActions(json.actions);
|
);
|
||||||
const savedCols = JSON.parse(
|
const visible = savedCols[id]?.visible || json.heading;
|
||||||
localStorage.getItem("reportColumns") || "{}"
|
const labels = savedCols[id]?.labels || {};
|
||||||
);
|
if (!savedCols[id] || id === "contacts") {
|
||||||
const visible = savedCols[id]?.visible || json.heading;
|
savedCols[id] = { visible: json.heading, labels: {} };
|
||||||
const labels = savedCols[id]?.labels || {};
|
localStorage.setItem("reportColumns", JSON.stringify(savedCols));
|
||||||
if (!savedCols[id] || id === "contacts") {
|
}
|
||||||
savedCols[id] = { visible: json.heading, labels: {} };
|
setVisibleColumns(visible);
|
||||||
localStorage.setItem("reportColumns", JSON.stringify(savedCols));
|
setColumnLabels(labels);
|
||||||
}
|
setHeading(visible);
|
||||||
setVisibleColumns(visible);
|
setDefaultColumns(json.heading);
|
||||||
setColumnLabels(labels);
|
setReportName(json.reportName);
|
||||||
setHeading(visible);
|
setReportHelp(json?.helpMsg);
|
||||||
setDefaultColumns(json.heading);
|
const currentUser = Parse.User.current().id;
|
||||||
setReportName(json.reportName);
|
|
||||||
setReportHelp(json?.helpMsg);
|
|
||||||
const currentUser = Parse.User.current().id;
|
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
sessiontoken: localStorage.getItem("accesstoken")
|
sessiontoken: localStorage.getItem("accesstoken")
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const skipRecord = id === "4Hhwbp482K" ? 0 : skipUserRecord;
|
const skipRecord = id === "4Hhwbp482K" ? 0 : skipUserRecord;
|
||||||
const limitRecord = id === "4Hhwbp482K" ? 200 : limit;
|
const limitRecord = id === "4Hhwbp482K" ? 200 : limit;
|
||||||
const params = { reportId: id, skip: skipRecord, limit: limitRecord };
|
const params = { reportId: id, skip: skipRecord, limit: limitRecord };
|
||||||
if (term) {
|
if (term) {
|
||||||
params.searchTerm = term;
|
params.searchTerm = term;
|
||||||
}
|
}
|
||||||
const url = `${localStorage.getItem("baseUrl")}functions/getReport`;
|
const url = `${localStorage.getItem("baseUrl")}functions/getReport`;
|
||||||
const res = await axios.post(url, params, {
|
const res = await axios.post(url, params, {
|
||||||
headers: headers,
|
headers: headers,
|
||||||
signal: abortController.signal // is used to cancel fetch query
|
signal: abortController.signal // is used to cancel fetch query
|
||||||
});
|
});
|
||||||
const extraHeads =
|
const extraHeads =
|
||||||
id === "4Hhwbp482K" ? [...extraCols, "Expiry Date"] : extraCols;
|
id === "4Hhwbp482K" ? [...extraCols, "Expiry Date"] : extraCols;
|
||||||
setAllColumns(Array.from(new Set([...json.heading, ...extraHeads])));
|
setAllColumns(Array.from(new Set([...json.heading, ...extraHeads])));
|
||||||
if (id === "6TeaPr321t") {
|
if (id === "6TeaPr321t") {
|
||||||
setTourData(templateReportTour);
|
setTourData(templateReportTour);
|
||||||
}
|
}
|
||||||
if (id === "4Hhwbp482K") {
|
if (id === "4Hhwbp482K") {
|
||||||
const listData = res.data?.result.filter((x) => x.Signers.length > 0);
|
const listData = res.data?.result.filter(
|
||||||
let arr = [];
|
(x) => x.Signers.length > 0
|
||||||
for (const obj of listData) {
|
|
||||||
const isSigner = obj?.Signers?.some(
|
|
||||||
(item) => item.UserId.objectId === currentUser
|
|
||||||
);
|
);
|
||||||
if (isSigner) {
|
let arr = [];
|
||||||
let isRecord;
|
for (const obj of listData) {
|
||||||
if (obj?.AuditTrail && obj?.AuditTrail.length > 0) {
|
const isSigner = obj?.Signers?.some(
|
||||||
isRecord = obj?.AuditTrail.some(
|
(item) => item.UserId.objectId === currentUser
|
||||||
(item) =>
|
);
|
||||||
item?.UserPtr?.UserId?.objectId === currentUser &&
|
if (isSigner) {
|
||||||
item.Activity === "Signed"
|
let isRecord;
|
||||||
);
|
if (obj?.AuditTrail && obj?.AuditTrail.length > 0) {
|
||||||
} else {
|
isRecord = obj?.AuditTrail.some(
|
||||||
isRecord = false;
|
(item) =>
|
||||||
}
|
item?.UserPtr?.UserId?.objectId === currentUser &&
|
||||||
if (isRecord === false) {
|
item.Activity === "Signed"
|
||||||
arr.push(obj);
|
);
|
||||||
|
} else {
|
||||||
|
isRecord = false;
|
||||||
|
}
|
||||||
|
if (isRecord === false) {
|
||||||
|
arr.push(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (arr.length === docPerPage) {
|
||||||
if (arr.length === docPerPage) {
|
setIsMoreDocs(true);
|
||||||
setIsMoreDocs(true);
|
} else {
|
||||||
} else {
|
setIsMoreDocs(false);
|
||||||
setIsMoreDocs(false);
|
}
|
||||||
}
|
|
||||||
setList((prevRecord) =>
|
|
||||||
prevRecord.length > 0 ? [...prevRecord, ...arr] : arr
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if (res.data.result.length >= docPerPage) {
|
|
||||||
setIsMoreDocs(true);
|
|
||||||
} else {
|
|
||||||
setIsMoreDocs(false);
|
|
||||||
}
|
|
||||||
if (!res.data.result.error) {
|
|
||||||
setIsNextRecord(false);
|
|
||||||
setList((prevRecord) =>
|
setList((prevRecord) =>
|
||||||
prevRecord.length > 0
|
prevRecord.length > 0 ? [...prevRecord, ...arr] : arr
|
||||||
? [...prevRecord, ...res.data.result]
|
|
||||||
: res.data.result
|
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
if (res.data.result.length >= docPerPage) {
|
||||||
|
setIsMoreDocs(true);
|
||||||
|
} else {
|
||||||
|
setIsMoreDocs(false);
|
||||||
|
}
|
||||||
|
if (!res.data.result.error) {
|
||||||
|
setIsNextRecord(false);
|
||||||
|
setList((prevRecord) =>
|
||||||
|
prevRecord.length > 0
|
||||||
|
? [...prevRecord, ...res.data.result]
|
||||||
|
: res.data.result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setIsLoader(false);
|
||||||
|
} catch (err) {
|
||||||
|
const isCancel = axios.isCancel(err);
|
||||||
|
if (!isCancel) {
|
||||||
|
console.log("err ", err);
|
||||||
|
setIsLoader(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
} catch (err) {
|
|
||||||
const isCancel = axios.isCancel(err);
|
|
||||||
if (!isCancel) {
|
|
||||||
console.log("err ", err);
|
|
||||||
setIsLoader(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
setIsLoader(false);
|
|
||||||
}
|
}
|
||||||
};
|
);
|
||||||
|
|
||||||
const commonProps = {
|
const commonProps = {
|
||||||
ReportName: reportName,
|
ReportName: reportName,
|
||||||
@@ -243,6 +248,7 @@ const Report = () => {
|
|||||||
handleSearchPaste,
|
handleSearchPaste,
|
||||||
isSearchResult,
|
isSearchResult,
|
||||||
columnLabels,
|
columnLabels,
|
||||||
|
searchLoader,
|
||||||
openColumnModal: () => setIsColumnModal(true)
|
openColumnModal: () => setIsColumnModal(true)
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ import {
|
|||||||
setDefaultSignImg,
|
setDefaultSignImg,
|
||||||
setIsShowModal,
|
setIsShowModal,
|
||||||
resetWidgetState,
|
resetWidgetState,
|
||||||
setTypedSignFont
|
setTypedSignFont,
|
||||||
|
setMyStamp
|
||||||
} from "../redux/reducers/widgetSlice";
|
} from "../redux/reducers/widgetSlice";
|
||||||
import WidgetsValueModal from "../components/pdf/WidgetsValueModal";
|
import WidgetsValueModal from "../components/pdf/WidgetsValueModal";
|
||||||
import WidgetNameModal from "../components/pdf/WidgetNameModal";
|
import WidgetNameModal from "../components/pdf/WidgetNameModal";
|
||||||
@@ -192,7 +193,6 @@ function SignYourSelf() {
|
|||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [divRef.current, isSidebar]);
|
}, [divRef.current, isSidebar]);
|
||||||
|
|
||||||
//function for get document details for perticular signer with signer'object id
|
//function for get document details for perticular signer with signer'object id
|
||||||
const getDocumentDetails = async (showComplete) => {
|
const getDocumentDetails = async (showComplete) => {
|
||||||
try {
|
try {
|
||||||
@@ -267,6 +267,7 @@ function SignYourSelf() {
|
|||||||
);
|
);
|
||||||
dispatch(setDefaultSignImg(defaultSignRes?.res?.defaultSignature));
|
dispatch(setDefaultSignImg(defaultSignRes?.res?.defaultSignature));
|
||||||
dispatch(setMyInitial(defaultSignRes?.res?.defaultInitial));
|
dispatch(setMyInitial(defaultSignRes?.res?.defaultInitial));
|
||||||
|
dispatch(setMyStamp(defaultSignRes?.res?.defaultStamp));
|
||||||
} else {
|
} else {
|
||||||
dispatch(setSaveSignCheckbox({ isVisible: true }));
|
dispatch(setSaveSignCheckbox({ isVisible: true }));
|
||||||
}
|
}
|
||||||
@@ -380,7 +381,8 @@ function SignYourSelf() {
|
|||||||
dragTypeValue,
|
dragTypeValue,
|
||||||
getWidgetValue,
|
getWidgetValue,
|
||||||
owner,
|
owner,
|
||||||
xyPosition
|
xyPosition,
|
||||||
|
true
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
dropData.push(dropObj);
|
dropData.push(dropObj);
|
||||||
@@ -433,7 +435,9 @@ function SignYourSelf() {
|
|||||||
dragTypeValue,
|
dragTypeValue,
|
||||||
getWidgetValue,
|
getWidgetValue,
|
||||||
owner,
|
owner,
|
||||||
xyPosition
|
xyPosition,
|
||||||
|
pdfDetails?.[0],
|
||||||
|
true
|
||||||
),
|
),
|
||||||
scale: containerScale
|
scale: containerScale
|
||||||
};
|
};
|
||||||
@@ -892,7 +896,7 @@ function SignYourSelf() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="reactourSecond"]',
|
selector: '[data-tut="reactourSecond"]',
|
||||||
@@ -904,7 +908,7 @@ function SignYourSelf() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="pdftools"]',
|
selector: '[data-tut="pdftools"]',
|
||||||
@@ -916,7 +920,7 @@ function SignYourSelf() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -1215,7 +1219,7 @@ function SignYourSelf() {
|
|||||||
selector: '[data-tut="IsSigned"]',
|
selector: '[data-tut="IsSigned"]',
|
||||||
content: t("signature-validate-alert-2"),
|
content: t("signature-validate-alert-2"),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ import {
|
|||||||
getOriginalWH,
|
getOriginalWH,
|
||||||
defaultMailBody,
|
defaultMailBody,
|
||||||
defaultMailSubject,
|
defaultMailSubject,
|
||||||
handleDeleteWidget
|
handleDeleteWidget,
|
||||||
|
nonPresentMaskCss
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import RenderPdf from "../components/pdf/RenderPdf";
|
import RenderPdf from "../components/pdf/RenderPdf";
|
||||||
import "../styles/AddUser.css";
|
import "../styles/AddUser.css";
|
||||||
@@ -63,15 +64,11 @@ import Alert from "../primitives/Alert";
|
|||||||
import LottieWithLoader from "../primitives/DotLottieReact";
|
import LottieWithLoader from "../primitives/DotLottieReact";
|
||||||
import * as utils from "../utils";
|
import * as utils from "../utils";
|
||||||
import CustomizeMail from "../components/pdf/CustomizeMail";
|
import CustomizeMail from "../components/pdf/CustomizeMail";
|
||||||
import {
|
import { resetWidgetState, setPrefillImg } from "../redux/reducers/widgetSlice";
|
||||||
resetWidgetState,
|
|
||||||
setPrefillImg
|
|
||||||
} from "../redux/reducers/widgetSlice.js";
|
|
||||||
import ShareButton from "../primitives/ShareButton";
|
import ShareButton from "../primitives/ShareButton";
|
||||||
|
|
||||||
const TemplatePlaceholder = () => {
|
const TemplatePlaceholder = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const journey = "Use Template";
|
|
||||||
const { templateId } = useParams();
|
const { templateId } = useParams();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const prefillImg = useSelector((state) => state.widget.prefillImg);
|
const prefillImg = useSelector((state) => state.widget.prefillImg);
|
||||||
@@ -235,7 +232,7 @@ const TemplatePlaceholder = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// `fetchTemplate` function in used to get Template from server and setPlaceholder ,setSigner if present
|
// `fetchTemplate` function in used to get Template from server and setPlaceholder ,setSigner if present
|
||||||
const fetchTemplate = async () => {
|
const fetchTemplate = utils.withSessionValidation(async () => {
|
||||||
try {
|
try {
|
||||||
const tenantSignTypes = await fetchTenantDetails();
|
const tenantSignTypes = await fetchTenantDetails();
|
||||||
const params = { templateId: templateId };
|
const params = { templateId: templateId };
|
||||||
@@ -419,7 +416,7 @@ const TemplatePlaceholder = () => {
|
|||||||
setHandleError(t("something-went-wrong-mssg"));
|
setHandleError(t("something-went-wrong-mssg"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
//function for setting position after drop signature button over pdf
|
//function for setting position after drop signature button over pdf
|
||||||
const addPositionOfSignature = (item, monitor) => {
|
const addPositionOfSignature = (item, monitor) => {
|
||||||
@@ -629,7 +626,7 @@ const TemplatePlaceholder = () => {
|
|||||||
selector: '[data-tut="reactourAddbtn"]',
|
selector: '[data-tut="reactourAddbtn"]',
|
||||||
content: t("add-user-template"),
|
content: t("add-user-template"),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -958,30 +955,31 @@ const TemplatePlaceholder = () => {
|
|||||||
);
|
);
|
||||||
if (res?.status === "unfilled") {
|
if (res?.status === "unfilled") {
|
||||||
setIsUiLoading(false);
|
setIsUiLoading(false);
|
||||||
const emptyWidget = res?.emptyResponseObjects.map((item, index) => (
|
const emptyWidget = res?.emptyResponseObjects
|
||||||
<span className="font-medium" key={index}>
|
?.map((item) => item.options.name)
|
||||||
{item.options.name}
|
?.join(", ");
|
||||||
</span>
|
const timeInMiliSec = 6000;
|
||||||
));
|
|
||||||
showAlert(
|
showAlert(
|
||||||
"danger",
|
"danger",
|
||||||
<>
|
t("prefill-unfilled-widget", {
|
||||||
The following required field(s) cannot be left empty:{" "}
|
emptyWidget: emptyWidget ? `[${emptyWidget}]` : ""
|
||||||
{emptyWidget.map((item, index) => (
|
}),
|
||||||
<span key={index}>
|
timeInMiliSec
|
||||||
{index > 0 && ", "}
|
|
||||||
{item}
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
. Please fill them out to proceed.
|
|
||||||
</>,
|
|
||||||
6000
|
|
||||||
);
|
);
|
||||||
} else if (res?.status === "unattach signer") {
|
} else if (res?.status === "unattach signer") {
|
||||||
setIsUiLoading(false);
|
setIsUiLoading(false);
|
||||||
showAlert("danger", "please attach all role to signer");
|
showAlert("danger", "please attach all role to signer");
|
||||||
} else if (res?.status === "success") {
|
} else if (res?.status === "success") {
|
||||||
setDocumentId(res.id);
|
setDocumentId(res.id);
|
||||||
|
const ownerId = pdfDetails[0].ExtUserPtr?.UserId?.objectId;
|
||||||
|
const firstSigner = signersdata[0];
|
||||||
|
const isOwner = firstSigner?.UserId?.objectId === ownerId;
|
||||||
|
if (pdfDetails[0]?.SendinOrder && isOwner) {
|
||||||
|
setCurrUserId(firstSigner?.objectId);
|
||||||
|
setIsSend(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setIsMailModal(true);
|
setIsMailModal(true);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -996,7 +994,7 @@ const TemplatePlaceholder = () => {
|
|||||||
pdfDetails,
|
pdfDetails,
|
||||||
signerPos,
|
signerPos,
|
||||||
signersdata,
|
signersdata,
|
||||||
updatedPdfUrl
|
updatedPdfUrl,
|
||||||
);
|
);
|
||||||
if (res.status === "success") {
|
if (res.status === "success") {
|
||||||
navigate(`/placeHolderSign/${res.id}`, {
|
navigate(`/placeHolderSign/${res.id}`, {
|
||||||
@@ -1025,7 +1023,7 @@ const TemplatePlaceholder = () => {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="reactourAddbtn"]',
|
selector: '[data-tut="reactourAddbtn"]',
|
||||||
@@ -1038,19 +1036,31 @@ const TemplatePlaceholder = () => {
|
|||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
observe: '[data-tut="reactourAddbtn--observe"]',
|
observe: '[data-tut="reactourAddbtn--observe"]',
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// selector: '[data-tut="addWidgets"]',
|
||||||
|
// content: () => (
|
||||||
|
// <TourContentWithBtn
|
||||||
|
// message={t("tour-mssg.template-placeholder-2")}
|
||||||
|
// isDontShowCheckbox={!checkTourStatus}
|
||||||
|
// isChecked={handleDontShow}
|
||||||
|
// />
|
||||||
|
// ),
|
||||||
|
// position: "top",
|
||||||
|
// styles: { fontSize: "13px" }
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
selector: '[data-tut="addWidgets"]',
|
selector: '[data-tut="nonpresentmask"]',
|
||||||
content: () => (
|
content: () => (
|
||||||
<TourContentWithBtn
|
<TourContentWithBtn
|
||||||
message={t("tour-mssg.template-placeholder-2")}
|
message={t("tour-mssg.template-placeholder-2")}
|
||||||
isDontShowCheckbox={!checkTourStatus}
|
|
||||||
isChecked={handleDontShow}
|
isChecked={handleDontShow}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "center",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px", maskArea: nonPresentMaskCss },
|
||||||
|
action: () => handleCloseRoleModal()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="pdftools"]',
|
selector: '[data-tut="pdftools"]',
|
||||||
@@ -1062,7 +1072,7 @@ const TemplatePlaceholder = () => {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="headerArea"]',
|
selector: '[data-tut="headerArea"]',
|
||||||
@@ -1074,7 +1084,7 @@ const TemplatePlaceholder = () => {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -1277,6 +1287,10 @@ const TemplatePlaceholder = () => {
|
|||||||
const RedirectUrl = updateTemplate?.[0]?.RedirectUrl
|
const RedirectUrl = updateTemplate?.[0]?.RedirectUrl
|
||||||
? { RedirectUrl: updateTemplate?.[0]?.RedirectUrl }
|
? { RedirectUrl: updateTemplate?.[0]?.RedirectUrl }
|
||||||
: {};
|
: {};
|
||||||
|
const penColors =
|
||||||
|
updateTemplate?.[0]?.PenColors?.length > 0
|
||||||
|
? { PenColors: updateTemplate?.[0]?.PenColors }
|
||||||
|
: {};
|
||||||
const data = {
|
const data = {
|
||||||
...(updateTemplate?.[0]?.URL ? { URL: updateTemplate?.[0]?.URL } : {}),
|
...(updateTemplate?.[0]?.URL ? { URL: updateTemplate?.[0]?.URL } : {}),
|
||||||
Name: updateTemplate?.[0]?.Name || "",
|
Name: updateTemplate?.[0]?.Name || "",
|
||||||
@@ -1293,6 +1307,7 @@ const TemplatePlaceholder = () => {
|
|||||||
: false,
|
: false,
|
||||||
TimeToCompleteDays:
|
TimeToCompleteDays:
|
||||||
parseInt(updateTemplate?.[0]?.TimeToCompleteDays) || 15,
|
parseInt(updateTemplate?.[0]?.TimeToCompleteDays) || 15,
|
||||||
|
...penColors,
|
||||||
...Bcc,
|
...Bcc,
|
||||||
...RedirectUrl
|
...RedirectUrl
|
||||||
};
|
};
|
||||||
@@ -1324,6 +1339,9 @@ const TemplatePlaceholder = () => {
|
|||||||
isHideLabel,
|
isHideLabel,
|
||||||
layout
|
layout
|
||||||
) => {
|
) => {
|
||||||
|
const isPrefill = signerPos.some(
|
||||||
|
(x) => x?.Role === "prefill" && x.Id === uniqueId
|
||||||
|
);
|
||||||
const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
|
const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
|
||||||
if (filterSignerPos.length > 0) {
|
if (filterSignerPos.length > 0) {
|
||||||
const getPlaceHolder = filterSignerPos[0].placeHolder;
|
const getPlaceHolder = filterSignerPos[0].placeHolder;
|
||||||
@@ -1391,16 +1409,21 @@ const TemplatePlaceholder = () => {
|
|||||||
...position.options,
|
...position.options,
|
||||||
name: dropdownName,
|
name: dropdownName,
|
||||||
values: dropdownOptions,
|
values: dropdownOptions,
|
||||||
validation: {
|
...(!isPrefill
|
||||||
minRequiredCount: minCount,
|
? {
|
||||||
maxRequiredCount: maxCount
|
validation: {
|
||||||
},
|
minRequiredCount: minCount,
|
||||||
|
maxRequiredCount: maxCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
layout: layout,
|
layout: layout,
|
||||||
isReadOnly: isReadOnly || false,
|
isReadOnly: isReadOnly || false,
|
||||||
defaultValue: defaultValue,
|
defaultValue: defaultValue,
|
||||||
isHideLabel: isHideLabel || false,
|
isHideLabel: isHideLabel || false,
|
||||||
fontSize: textSize || 12,
|
fontSize: textSize || 12,
|
||||||
fontColor: textColor || "black"
|
fontColor: textColor || "black",
|
||||||
|
...(isPrefill ? { status } : {})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1507,13 +1530,16 @@ const TemplatePlaceholder = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (["signature"].includes(position.type)) {
|
else if (["signature", "initials"].includes(position.type)) {
|
||||||
return {
|
return {
|
||||||
...position,
|
...position,
|
||||||
options: {
|
options: {
|
||||||
...position.options,
|
...position.options,
|
||||||
name: defaultdata.name,
|
name: defaultdata.name,
|
||||||
hint: defaultdata?.hint || ""
|
hint: defaultdata?.hint || "",
|
||||||
|
...(defaultdata?.penColors?.length > 0 && {
|
||||||
|
penColors: defaultdata?.penColors
|
||||||
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@@ -1621,7 +1647,7 @@ const TemplatePlaceholder = () => {
|
|||||||
selector: '[data-tut="isSignatureWidget"]',
|
selector: '[data-tut="isSignatureWidget"]',
|
||||||
content: t("signature-field-widget", { signersName }),
|
content: t("signature-field-widget", { signersName }),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
const showAlert = (type, message, duration = 1500) => {
|
const showAlert = (type, message, duration = 1500) => {
|
||||||
@@ -1633,7 +1659,7 @@ const TemplatePlaceholder = () => {
|
|||||||
selector: '[data-tut="IsSigned"]',
|
selector: '[data-tut="IsSigned"]',
|
||||||
content: t("text-field-tour"),
|
content: t("text-field-tour"),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
const copytoclipboard = (text) => {
|
const copytoclipboard = (text) => {
|
||||||
@@ -1692,7 +1718,6 @@ const TemplatePlaceholder = () => {
|
|||||||
setIsCreateDocModal(true);
|
setIsCreateDocModal(true);
|
||||||
setIsUiLoading(false);
|
setIsUiLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUseButton = async () => {
|
const handleUseButton = async () => {
|
||||||
setIsCreateDocModal(false);
|
setIsCreateDocModal(false);
|
||||||
//this function is used to open modal to show signers list
|
//this function is used to open modal to show signers list
|
||||||
@@ -1701,8 +1726,9 @@ const TemplatePlaceholder = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRecipientSign = (docId, currUserId) => {
|
const handleRecipientSign = (docId, currUserId) => {
|
||||||
|
const docObjId = docId || documentId;
|
||||||
if (currUserId) {
|
if (currUserId) {
|
||||||
navigate(`/recipientSignPdf/${docId}/${currUserId}`);
|
navigate(`/recipientSignPdf/${docObjId}/${currUserId}`);
|
||||||
} else {
|
} else {
|
||||||
navigate(`/recipientSignPdf/${docId}`);
|
navigate(`/recipientSignPdf/${docId}`);
|
||||||
}
|
}
|
||||||
@@ -2150,6 +2176,8 @@ const TemplatePlaceholder = () => {
|
|||||||
isSave={true}
|
isSave={true}
|
||||||
setUniqueId={setUniqueId}
|
setUniqueId={setUniqueId}
|
||||||
signatureTypes={signatureType}
|
signatureTypes={signatureType}
|
||||||
|
penColors={pdfDetails?.[0]?.PenColors}
|
||||||
|
role={roleName}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<RotateAlert
|
<RotateAlert
|
||||||
@@ -2174,11 +2202,13 @@ const TemplatePlaceholder = () => {
|
|||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen={isSend}
|
isOpen={isSend}
|
||||||
title={
|
title={
|
||||||
mailStatus === "success"
|
!pdfDetails[0]?.SendinOrder
|
||||||
? t("mails-sent")
|
? mailStatus === "success"
|
||||||
: mailStatus === "quotareached"
|
? t("mails-sent")
|
||||||
? t("quota-mail-head")
|
: mailStatus === "quotareached"
|
||||||
: t("mail-not-delivered")
|
? t("quota-mail-head")
|
||||||
|
: t("mail-not-delivered")
|
||||||
|
: t("mail-status-head")
|
||||||
}
|
}
|
||||||
handleClose={() => {
|
handleClose={() => {
|
||||||
setIsSend(false);
|
setIsSend(false);
|
||||||
@@ -2186,66 +2216,103 @@ const TemplatePlaceholder = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="h-[100%] p-[20px] text-base-content">
|
<div className="h-[100%] p-[20px] text-base-content">
|
||||||
{mailStatus === "success" ? (
|
<div className="flex flex-col items-center gap-5">
|
||||||
<div className="text-center mb-[10px]">
|
<div>
|
||||||
<LottieWithLoader />
|
{mailStatus === "success" ? (
|
||||||
{documentDetails.SendinOrder ? (
|
<div className="text-center mb-[10px]">
|
||||||
<p>
|
<LottieWithLoader />
|
||||||
{currUserId
|
{documentDetails.SendinOrder ? (
|
||||||
? t("placeholder-mail-alert-you")
|
<p>
|
||||||
: t("placeholder-mail-alert", {
|
{currUserId
|
||||||
name: signersdata[0]?.Name
|
? t("placeholder-mail-alert-you")
|
||||||
})}
|
: t("placeholder-mail-alert", {
|
||||||
</p>
|
name: signersdata[0]?.Name
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
<p>{t("placeholder-alert-4")}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : mailStatus === "quotareached" ? (
|
||||||
|
<div className="flex flex-col gap-y-3">
|
||||||
|
<div className="my-3">{handleShareList()}</div>
|
||||||
|
</div>
|
||||||
|
) : mailStatus === "failed" ? (
|
||||||
|
<p>{t("mail-failed")} </p>
|
||||||
) : (
|
) : (
|
||||||
<p>{t("placeholder-alert-4")}</p>
|
<div className="mb-[10px]">
|
||||||
|
{!pdfDetails[0]?.SendinOrder &&
|
||||||
|
(mailStatus === "dailyquotareached" ? (
|
||||||
|
<p>{t("daily-quota-reached")}</p>
|
||||||
|
) : (
|
||||||
|
<p>{t("placeholder-alert-6")}</p>
|
||||||
|
))}
|
||||||
|
{currUserId && (
|
||||||
|
<span className="mt-1">{t("placeholder-alert-5")}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{currUserId && <p>{t("placeholder-alert-5")}</p>}
|
{mailStatus !== "quotareached" && (
|
||||||
</div>
|
<div
|
||||||
) : mailStatus === "quotareached" ? (
|
className={
|
||||||
<div className="flex flex-col gap-y-3">
|
mailStatus === "success"
|
||||||
<div className="my-3">{handleShareList()}</div>
|
? "flex justify-center mt-1"
|
||||||
</div>
|
: "flex items-center justify-center mt-7"
|
||||||
) : (
|
|
||||||
<div className="mb-[10px]">
|
|
||||||
{mailStatus === "dailyquotareached" ? (
|
|
||||||
<p>{t("daily-quota-reached")}</p>
|
|
||||||
) : (
|
|
||||||
<p>{t("placeholder-alert-6")}</p>
|
|
||||||
)}
|
|
||||||
{currUserId && <p className="mt-1">{t("placeholder-alert-5")}</p>}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{!mailStatus && (
|
|
||||||
<div className="w-full h-[1px] bg-[#9f9f9f] my-[15px]"></div>
|
|
||||||
)}
|
|
||||||
{mailStatus !== "quotareached" && (
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
mailStatus === "success" ? "flex justify-center mt-1" : ""
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{currUserId && (
|
|
||||||
<button
|
|
||||||
onClick={() =>
|
|
||||||
handleRecipientSign(documentDetails?.objectId, currUserId)
|
|
||||||
}
|
}
|
||||||
type="button"
|
|
||||||
className="op-btn op-btn-primary mr-1"
|
|
||||||
>
|
>
|
||||||
{t("yes")}
|
{currUserId && (
|
||||||
</button>
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
handleRecipientSign(
|
||||||
|
documentDetails?.objectId,
|
||||||
|
currUserId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-primary mr-1"
|
||||||
|
>
|
||||||
|
{t("sign-now")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
navigate("/report/1MwEuxLEkF");
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-ghost text-base-content"
|
||||||
|
>
|
||||||
|
{currUserId ? t("no") : t("close")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
navigate("/report/1MwEuxLEkF");
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className="op-btn op-btn-ghost text-base-content"
|
|
||||||
>
|
|
||||||
{currUserId ? t("no") : t("close")}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
{mailStatus !== "success" &&
|
||||||
|
currUserId &&
|
||||||
|
pdfDetails[0]?.SendinOrder && (
|
||||||
|
<div className="op-divider text-base-content mx-[0%] my-1 font-medium">
|
||||||
|
{t("or")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{mailStatus !== "success" &&
|
||||||
|
currUserId &&
|
||||||
|
pdfDetails[0]?.SendinOrder && (
|
||||||
|
<div
|
||||||
|
className="op-btn op-btn-outline w-[50%] md:w-[35%] mt-1"
|
||||||
|
onClick={() => {
|
||||||
|
setIsSend(false);
|
||||||
|
setIsMailModal(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="fa-regular fa-envelope"
|
||||||
|
style={{ color: "#002864", fontSize: "19px" }}
|
||||||
|
></i>{" "}
|
||||||
|
<span>{t("send-to-email")}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{!mailStatus && (
|
||||||
|
<div className="op-divider text-base-content mx-[0%] mt-3"></div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import DeleteUserModal from "../primitives/DeleteUserModal";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import PasswordResetModal from "../primitives/PasswordResetModal";
|
import PasswordResetModal from "../primitives/PasswordResetModal";
|
||||||
import { usersActions } from "../json/ReportJson";
|
import { usersActions } from "../json/ReportJson";
|
||||||
|
import { withSessionValidation } from "../utils";
|
||||||
|
|
||||||
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"];
|
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"];
|
||||||
const UserList = () => {
|
const UserList = () => {
|
||||||
@@ -168,7 +169,7 @@ const UserList = () => {
|
|||||||
};
|
};
|
||||||
const handleClose = () => setIsActiveModal({});
|
const handleClose = () => setIsActiveModal({});
|
||||||
|
|
||||||
const handleToggleSubmit = async (user) => {
|
const handleToggleSubmit = withSessionValidation(async (user) => {
|
||||||
const index = userList.findIndex((obj) => obj.objectId === user.objectId);
|
const index = userList.findIndex((obj) => obj.objectId === user.objectId);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
setIsActiveModal({});
|
setIsActiveModal({});
|
||||||
@@ -193,7 +194,7 @@ const UserList = () => {
|
|||||||
setIsActLoader({});
|
setIsActLoader({});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
const handleToggleBtn = (user) => {
|
const handleToggleBtn = (user) => {
|
||||||
setIsActiveModal({ [user.objectId]: true });
|
setIsActiveModal({ [user.objectId]: true });
|
||||||
};
|
};
|
||||||
@@ -204,7 +205,7 @@ const UserList = () => {
|
|||||||
setTimeout(() => setIsAlert({ type: "success", msg: "" }), timer);
|
setTimeout(() => setIsAlert({ type: "success", msg: "" }), timer);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteAccount = async (item) => {
|
const handleDeleteAccount = withSessionValidation(async (item) => {
|
||||||
setDeleting(true);
|
setDeleting(true);
|
||||||
if (item?.UserId?.objectId) {
|
if (item?.UserId?.objectId) {
|
||||||
const url = localStorage.getItem("baseUrl")?.replace(/\/app\/?$/, "/");
|
const url = localStorage.getItem("baseUrl")?.replace(/\/app\/?$/, "/");
|
||||||
@@ -230,16 +231,16 @@ const UserList = () => {
|
|||||||
setDeleteUserRes(t("something-went-wrong-mssg"));
|
setDeleteUserRes(t("something-went-wrong-mssg"));
|
||||||
setDeleting(false);
|
setDeleting(false);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
const handleCloseModal = () => {
|
const handleCloseModal = () => {
|
||||||
setIsActModal({});
|
setIsActModal({});
|
||||||
setDeleteUserRes("");
|
setDeleteUserRes("");
|
||||||
setDeleting(false);
|
setDeleting(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleActionBtn = async (act, item) => {
|
const handleActionBtn = withSessionValidation(async (act, item) => {
|
||||||
setIsActModal({ [`${act.action}_${item.objectId}`]: true });
|
setIsActModal({ [`${act.action}_${item.objectId}`]: true });
|
||||||
};
|
});
|
||||||
const handleBtnVisibility = (act, item) => {
|
const handleBtnVisibility = (act, item) => {
|
||||||
if (act.restrictAdmin) {
|
if (act.restrictAdmin) {
|
||||||
if (item?.UserRole === "contracts_Admin") {
|
if (item?.UserRole === "contracts_Admin") {
|
||||||
@@ -264,7 +265,7 @@ const UserList = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function submitPassword(userId, password) {
|
const submitPassword = withSessionValidation(async (userId, password) => {
|
||||||
setIsLoader(true);
|
setIsLoader(true);
|
||||||
setIsActModal({});
|
setIsActModal({});
|
||||||
try {
|
try {
|
||||||
@@ -277,7 +278,7 @@ const UserList = () => {
|
|||||||
} finally {
|
} finally {
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
{isLoader && (
|
{isLoader && (
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import { Navigate, useNavigate } from "react-router";
|
|||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import { SaveFileSize } from "../constant/saveFileSize";
|
import { SaveFileSize } from "../constant/saveFileSize";
|
||||||
import dp from "../assets/images/dp.png";
|
import dp from "../assets/images/dp.png";
|
||||||
import { sanitizeFileName } from "../utils";
|
import { sanitizeFileName, withSessionValidation } from "../utils";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Tooltip from "../primitives/Tooltip";
|
import Tooltip from "../primitives/Tooltip";
|
||||||
import {
|
import {
|
||||||
getSecureUrl,
|
getSecureUrl,
|
||||||
handleSendOTP,
|
handleSendOTP
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
@@ -124,7 +124,7 @@ function UserProfile() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// `updateExtUser` is used to update user details in extended class
|
// `updateExtUser` is used to update user details in extended class
|
||||||
const updateExtUser = async (obj) => {
|
const updateExtUser = withSessionValidation(async (obj) => {
|
||||||
try {
|
try {
|
||||||
const extData = JSON.parse(localStorage.getItem("Extand_Class"));
|
const extData = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||||
const ExtUserId = extData?.[0]?.objectId;
|
const ExtUserId = extData?.[0]?.objectId;
|
||||||
@@ -152,10 +152,10 @@ function UserProfile() {
|
|||||||
const json = JSON.parse(JSON.stringify([res]));
|
const json = JSON.parse(JSON.stringify([res]));
|
||||||
const extRes = JSON.stringify(json);
|
const extRes = JSON.stringify(json);
|
||||||
localStorage.setItem("Extand_Class", extRes);
|
localStorage.setItem("Extand_Class", extRes);
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
console.log("error in save data in contracts_Users class");
|
console.log("error in save data in contracts_Users class", err);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
// file upload function
|
// file upload function
|
||||||
const fileUpload = async (file) => {
|
const fileUpload = async (file) => {
|
||||||
if (file) {
|
if (file) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// below code is used to handle undefined Promise.withResolvers for safari
|
// below code is used to handle undefined Promise.withResolvers for safari for react-pdf
|
||||||
if (typeof Promise.withResolvers === "undefined") {
|
if (typeof Promise.withResolvers === "undefined") {
|
||||||
Promise.withResolvers = function () {
|
Promise.withResolvers = function () {
|
||||||
let resolve, reject;
|
let resolve, reject;
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import Loader from "./Loader";
|
import Loader from "./Loader";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { getTenantDetails } from "../constant/Utils";
|
import { getTenantDetails } from "../constant/Utils";
|
||||||
import { emailRegex } from "../constant/const";
|
import { emailRegex } from "../constant/const";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { sessionStatus } from "../redux/reducers/userReducer";
|
||||||
|
|
||||||
const AddContact = (props) => {
|
const AddContact = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [phone, setPhone] = useState("");
|
const [phone, setPhone] = useState("");
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
@@ -108,6 +112,7 @@ const AddContact = (props) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
|
dispatch(sessionStatus(false));
|
||||||
alert(t("something-went-wrong-mssg"));
|
alert(t("something-went-wrong-mssg"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,7 +144,9 @@ const AddContact = (props) => {
|
|||||||
)}
|
)}
|
||||||
<div className="w-full mx-auto p-[8px]">
|
<div className="w-full mx-auto p-[8px]">
|
||||||
{!props?.isDisableTitle && (
|
{!props?.isDisableTitle && (
|
||||||
<div className="text-[14px] font-[700] text-base-content mb-1">{t("add-contact")}</div>
|
<div className="text-[14px] font-[700] text-base-content mb-1">
|
||||||
|
{t("add-contact")}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{isUserExist && props?.isAddYourSelfCheckbox && (
|
{isUserExist && props?.isAddYourSelfCheckbox && (
|
||||||
<div className="mb-[0.75rem] flex items-center mt-1">
|
<div className="mb-[0.75rem] flex items-center mt-1">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { formatDate } from "../constant/Utils";
|
import { formatDateToDdMmmYyyy } from "../constant/Utils";
|
||||||
import SignerCell from "./SignerCell";
|
import SignerCell from "./SignerCell";
|
||||||
|
|
||||||
function isValidDateString(str) {
|
function isValidDateString(str) {
|
||||||
@@ -14,12 +14,12 @@ const formatRow = (row) => {
|
|||||||
if (Array.isArray(row)) {
|
if (Array.isArray(row)) {
|
||||||
return row.map((x) => x.Name).join(", ");
|
return row.map((x) => x.Name).join(", ");
|
||||||
} else if (typeof row === "object" && row !== null) {
|
} else if (typeof row === "object" && row !== null) {
|
||||||
return row?.iso ? formatDate(row?.iso) : row?.Name || "-";
|
return row?.iso ? formatDateToDdMmmYyyy(row?.iso) : row?.Name || "-";
|
||||||
} else if (typeof row === "boolean" && row !== null) {
|
} else if (typeof row === "boolean" && row !== null) {
|
||||||
return row ? row?.toString() : "false";
|
return row ? row?.toString() : "false";
|
||||||
} else if (isValidDateString(row) && row !== null) {
|
} else if (isValidDateString(row) && row !== null) {
|
||||||
// handle createdAt and updatedAt
|
// handle createdAt and updatedAt
|
||||||
return formatDate(row) || "-";
|
return formatDateToDdMmmYyyy(row) || "-";
|
||||||
} else {
|
} else {
|
||||||
return row || "-";
|
return row || "-";
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ export const RenderReportCell = ({
|
|||||||
<div className="font-semibold break-words">{rowData?.Name}</div>
|
<div className="font-semibold break-words">{rowData?.Name}</div>
|
||||||
{rowData?.ExpiryDate?.iso && (
|
{rowData?.ExpiryDate?.iso && (
|
||||||
<div className="text-gray-500">
|
<div className="text-gray-500">
|
||||||
{t("expires")} {formatDate(rowData?.ExpiryDate?.iso)}
|
{t("expires")} {formatDateToDdMmmYyyy(rowData?.ExpiryDate?.iso)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
@@ -133,25 +133,29 @@ export const RenderReportCell = ({
|
|||||||
case "Created Date":
|
case "Created Date":
|
||||||
return (
|
return (
|
||||||
<td key={col} className="p-2 text-center">
|
<td key={col} className="p-2 text-center">
|
||||||
{rowData?.createdAt ? formatDate(rowData?.createdAt) : "-"}
|
{rowData?.createdAt ? formatDateToDdMmmYyyy(rowData?.createdAt) : "-"}
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
case "Updated Date":
|
case "Updated Date":
|
||||||
return (
|
return (
|
||||||
<td key={col} className="p-2 text-center">
|
<td key={col} className="p-2 text-center">
|
||||||
{rowData?.updatedAt ? formatDate(rowData?.updatedAt) : "-"}
|
{rowData?.updatedAt ? formatDateToDdMmmYyyy(rowData?.updatedAt) : "-"}
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
case "Expiry Date":
|
case "Expiry Date":
|
||||||
return (
|
return (
|
||||||
<td key={col} className="p-2 text-center">
|
<td key={col} className="p-2 text-center">
|
||||||
{rowData?.ExpiryDate ? formatDate(rowData?.ExpiryDate?.iso) : "-"}
|
{rowData?.ExpiryDate
|
||||||
|
? formatDateToDdMmmYyyy(rowData?.ExpiryDate?.iso)
|
||||||
|
: "-"}
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
case "Sent Date":
|
case "Sent Date":
|
||||||
return (
|
return (
|
||||||
<td key={col} className="p-2 text-center">
|
<td key={col} className="p-2 text-center">
|
||||||
{rowData?.DocSentAt ? formatDate(rowData?.DocSentAt?.iso) : "-"}
|
{rowData?.DocSentAt
|
||||||
|
? formatDateToDdMmmYyyy(rowData?.DocSentAt?.iso)
|
||||||
|
: "-"}
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
case "Signers":
|
case "Signers":
|
||||||
|
|||||||
@@ -1,33 +1,84 @@
|
|||||||
import ReactTour from "reactour";
|
import { TourProvider, useTour } from "@reactour/tour";
|
||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
import {
|
||||||
|
clearAllBodyScrollLocks,
|
||||||
|
disableBodyScroll,
|
||||||
|
enableBodyScroll
|
||||||
|
} from "body-scroll-lock";
|
||||||
|
|
||||||
|
function TourStateSync({ isOpen, onRequestClose }) {
|
||||||
|
const { isOpen: contextIsOpen, setIsOpen } = useTour();
|
||||||
|
const previousIsOpen = useRef(contextIsOpen);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsOpen(isOpen);
|
||||||
|
}, [isOpen, setIsOpen]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (previousIsOpen.current && !contextIsOpen && onRequestClose) {
|
||||||
|
onRequestClose();
|
||||||
|
}
|
||||||
|
previousIsOpen.current = contextIsOpen;
|
||||||
|
}, [contextIsOpen, onRequestClose]);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export default function Tour({
|
export default function Tour({
|
||||||
steps,
|
steps,
|
||||||
isOpen,
|
isOpen,
|
||||||
rounded,
|
rounded = 5,
|
||||||
className,
|
className,
|
||||||
showNumber,
|
showNumber,
|
||||||
closeWithMask = false,
|
|
||||||
onRequestClose,
|
onRequestClose,
|
||||||
showNavigation,
|
showNavigation,
|
||||||
showCloseButton,
|
showCloseButton,
|
||||||
showNavigationNumber,
|
showNavigationNumber
|
||||||
disableKeyboardNavigation
|
|
||||||
}) {
|
}) {
|
||||||
const radius = rounded || 5;
|
function disableBody() {
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
disableBodyScroll(document.body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function enableBody() {
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
enableBodyScroll(document.body);
|
||||||
|
clearAllBodyScrollLocks();
|
||||||
|
}
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<ReactTour
|
<TourProvider
|
||||||
className={className}
|
className={className}
|
||||||
steps={steps}
|
steps={steps}
|
||||||
isOpen={isOpen}
|
defaultOpen={isOpen}
|
||||||
rounded={radius}
|
// scrollOffset={-100} // available only for v1
|
||||||
scrollOffset={-100}
|
inViewThreshold={{ y: 150 }}
|
||||||
closeWithMask={closeWithMask}
|
onClickMask={() => {}}
|
||||||
disableKeyboardNavigation={disableKeyboardNavigation}
|
disableKeyboardNavigation={["esc"]}
|
||||||
showCloseButton={showCloseButton}
|
showBadge={showNumber}
|
||||||
onRequestClose={onRequestClose}
|
|
||||||
showNumber={showNumber}
|
|
||||||
showNavigation={showNavigation}
|
showNavigation={showNavigation}
|
||||||
showNavigationNumber={showNavigationNumber}
|
showPrevNextButtons={showNavigation}
|
||||||
/>
|
showDots={showNavigationNumber ?? showNavigation}
|
||||||
|
showCloseButton={showCloseButton}
|
||||||
|
padding={rounded}
|
||||||
|
onClickClose={(clickProps) => {
|
||||||
|
clickProps.setIsOpen(false);
|
||||||
|
}}
|
||||||
|
styles={{
|
||||||
|
popover: (base) => ({
|
||||||
|
...base,
|
||||||
|
borderRadius: rounded,
|
||||||
|
padding: "18px",
|
||||||
|
fontSize: "13px"
|
||||||
|
}),
|
||||||
|
maskArea: (base) => ({ ...base, rx: rounded }),
|
||||||
|
close: (base) => ({ ...base, right: 10, top: 10, outline: "none" })
|
||||||
|
}}
|
||||||
|
afterOpen={disableBody}
|
||||||
|
beforeClose={enableBody}
|
||||||
|
scrollSmooth
|
||||||
|
>
|
||||||
|
<TourStateSync isOpen={isOpen} onRequestClose={onRequestClose} />
|
||||||
|
</TourProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { createSlice } from "@reduxjs/toolkit";
|
|||||||
|
|
||||||
const sidebarSlice = createSlice({
|
const sidebarSlice = createSlice({
|
||||||
name: "sidebar",
|
name: "sidebar",
|
||||||
initialState: { isOpen: true },
|
initialState: { isOpen: true, selectedMenu: true },
|
||||||
reducers: {
|
reducers: {
|
||||||
toggleSidebar: (state, action) => {
|
toggleSidebar: (state, action) => {
|
||||||
if (typeof action.payload === "undefined") {
|
if (typeof action.payload === "undefined") {
|
||||||
@@ -12,9 +12,12 @@ const sidebarSlice = createSlice({
|
|||||||
// payload provided → use it directly
|
// payload provided → use it directly
|
||||||
state.isOpen = action.payload;
|
state.isOpen = action.payload;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
setSelectedMenu: (state, action) => {
|
||||||
|
state.selectedMenu = action.payload;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const { toggleSidebar } = sidebarSlice.actions;
|
export const { toggleSidebar, setSelectedMenu } = sidebarSlice.actions;
|
||||||
export default sidebarSlice.reducer;
|
export default sidebarSlice.reducer;
|
||||||
|
|||||||
@@ -1,15 +1,47 @@
|
|||||||
import { createSlice } from "@reduxjs/toolkit";
|
import { createSlice } from "@reduxjs/toolkit";
|
||||||
const initialState = { isValidSession: true };
|
const initialState = {
|
||||||
|
userInfo: {},
|
||||||
|
isValidSession: true,
|
||||||
|
isLoader: false,
|
||||||
|
isTopLoader: false,
|
||||||
|
tenantInfo: {},
|
||||||
|
alertInfo: { type: "success", msg: "" }
|
||||||
|
};
|
||||||
const userReducer = createSlice({
|
const userReducer = createSlice({
|
||||||
name: "user",
|
name: "user",
|
||||||
initialState: initialState,
|
initialState: initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
|
setUserInfo: (state, action) => {
|
||||||
|
state.userInfo = action.payload;
|
||||||
|
},
|
||||||
sessionStatus: (state, action) => {
|
sessionStatus: (state, action) => {
|
||||||
state.isValidSession = action.payload;
|
state.isValidSession = action.payload;
|
||||||
|
},
|
||||||
|
setTenantInfo: (state, action) => {
|
||||||
|
state.tenantInfo = action.payload;
|
||||||
|
},
|
||||||
|
setLoader: (state, action) => {
|
||||||
|
state.isLoader = action.payload;
|
||||||
|
},
|
||||||
|
setTopLoader: (state, action) => {
|
||||||
|
state.isTopLoader = action.payload;
|
||||||
|
},
|
||||||
|
setAlertInfo: (state, action) => {
|
||||||
|
state.alertInfo = {
|
||||||
|
type: action.payload?.type,
|
||||||
|
msg: action.payload?.msg
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const { sessionStatus } = userReducer.actions;
|
export const {
|
||||||
|
setUserInfo,
|
||||||
|
sessionStatus,
|
||||||
|
setTenantInfo,
|
||||||
|
setLoader,
|
||||||
|
setTopLoader,
|
||||||
|
setAlertInfo
|
||||||
|
} = userReducer.actions;
|
||||||
|
|
||||||
export default userReducer.reducer;
|
export default userReducer.reducer;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const initialState = {
|
|||||||
signatureTypes: null,
|
signatureTypes: null,
|
||||||
defaultSignImg: null,
|
defaultSignImg: null,
|
||||||
myInitial: null,
|
myInitial: null,
|
||||||
|
myStamp: null,
|
||||||
lastIndex: "",
|
lastIndex: "",
|
||||||
scrollTriggerId: "",
|
scrollTriggerId: "",
|
||||||
prefillImg: [],
|
prefillImg: [],
|
||||||
@@ -63,6 +64,9 @@ const widgetSlice = createSlice({
|
|||||||
setPrefillImgLoad: (state, action) => {
|
setPrefillImgLoad: (state, action) => {
|
||||||
state.prefillImgLoad = action.payload;
|
state.prefillImgLoad = action.payload;
|
||||||
},
|
},
|
||||||
|
setMyStamp: (state, action) => {
|
||||||
|
state.myStamp = action.payload;
|
||||||
|
},
|
||||||
resetWidgetState: () => initialState
|
resetWidgetState: () => initialState
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -78,7 +82,8 @@ export const {
|
|||||||
setScrollTriggerId,
|
setScrollTriggerId,
|
||||||
setPrefillImg,
|
setPrefillImg,
|
||||||
setPrefillImgLoad,
|
setPrefillImgLoad,
|
||||||
setTypedSignFont
|
setTypedSignFont,
|
||||||
|
setMyStamp
|
||||||
} = widgetSlice.actions;
|
} = widgetSlice.actions;
|
||||||
|
|
||||||
export default widgetSlice.reducer;
|
export default widgetSlice.reducer;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { serverUrl_fn } from "../../constant/appinfo";
|
|||||||
import { useElSize } from "../../hook/useElSize";
|
import { useElSize } from "../../hook/useElSize";
|
||||||
import ImportContact from "./ImportContact";
|
import ImportContact from "./ImportContact";
|
||||||
import AddContact from "../../primitives/AddContact";
|
import AddContact from "../../primitives/AddContact";
|
||||||
|
import { withSessionValidation } from "../../utils";
|
||||||
|
|
||||||
const Contactbook = (props) => {
|
const Contactbook = (props) => {
|
||||||
const titleRef = useRef(null);
|
const titleRef = useRef(null);
|
||||||
@@ -110,7 +111,7 @@ const Contactbook = (props) => {
|
|||||||
}
|
}
|
||||||
}, [isMoreDocs, pageNumbers, currentPage, setIsNextRecord]);
|
}, [isMoreDocs, pageNumbers, currentPage, setIsNextRecord]);
|
||||||
|
|
||||||
const handleActionBtn = async (act, item) => {
|
const handleActionBtn = withSessionValidation(async (act, item) => {
|
||||||
if (act.action === "delete") {
|
if (act.action === "delete") {
|
||||||
setIsDeleteModal({ [item.objectId]: true });
|
setIsDeleteModal({ [item.objectId]: true });
|
||||||
} else if (act.action === "option") {
|
} else if (act.action === "option") {
|
||||||
@@ -119,7 +120,7 @@ const Contactbook = (props) => {
|
|||||||
setContact(item);
|
setContact(item);
|
||||||
setIsModal({ [`edit_${item.objectId}`]: true });
|
setIsModal({ [`edit_${item.objectId}`]: true });
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
// Get current list
|
// Get current list
|
||||||
const indexOfLastDoc = currentPage * props.docPerPage;
|
const indexOfLastDoc = currentPage * props.docPerPage;
|
||||||
const indexOfFirstDoc = indexOfLastDoc - props.docPerPage;
|
const indexOfFirstDoc = indexOfLastDoc - props.docPerPage;
|
||||||
@@ -163,7 +164,7 @@ const Contactbook = (props) => {
|
|||||||
props.setList((prevData) => [data, ...prevData]);
|
props.setList((prevData) => [data, ...prevData]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async (item) => {
|
const handleDelete = withSessionValidation(async (item) => {
|
||||||
setIsDeleteModal({});
|
setIsDeleteModal({});
|
||||||
setActLoader({ [`${item.objectId}`]: true });
|
setActLoader({ [`${item.objectId}`]: true });
|
||||||
try {
|
try {
|
||||||
@@ -191,7 +192,7 @@ const Contactbook = (props) => {
|
|||||||
showAlert("danger", t("something-went-wrong-mssg"));
|
showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setIsDeleteModal({});
|
setIsDeleteModal({});
|
||||||
};
|
};
|
||||||
@@ -336,6 +337,7 @@ const Contactbook = (props) => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody className="text-[12px]">
|
<tbody className="text-[12px]">
|
||||||
{props.List?.length > 0 &&
|
{props.List?.length > 0 &&
|
||||||
|
!props.searchLoader &&
|
||||||
currentList.map((item, index) => (
|
currentList.map((item, index) => (
|
||||||
<tr className="last:border-none border-y-[1px]" key={index}>
|
<tr className="last:border-none border-y-[1px]" key={index}>
|
||||||
{props.heading.includes("Sr.No") && (
|
{props.heading.includes("Sr.No") && (
|
||||||
@@ -409,18 +411,27 @@ const Contactbook = (props) => {
|
|||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{props.List?.length <= 0 && (
|
{(props.searchLoader || props.List?.length <= 0) && (
|
||||||
<div className="flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4">
|
<div className="flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4">
|
||||||
<div className="w-[60px] h-[60px] overflow-hidden">
|
{props.searchLoader ? (
|
||||||
<img
|
<>
|
||||||
className="w-full h-full object-contain"
|
<Loader />
|
||||||
src={pad}
|
<div className="text-sm ">{t("loading-mssg")}</div>
|
||||||
alt={t("no-data-avaliable")}
|
</>
|
||||||
/>
|
) : (
|
||||||
</div>
|
<>
|
||||||
<div className="text-sm font-semibold">
|
<div className="w-[60px] h-[60px] overflow-hidden">
|
||||||
{t("no-data-avaliable")}
|
<img
|
||||||
</div>
|
className="w-full h-full object-contain"
|
||||||
|
src={pad}
|
||||||
|
alt={t("no-data-avaliable")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-sm font-semibold">
|
||||||
|
{t("no-data-avaliable")}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { useEffect, useState } from "react";
|
|||||||
import Loader from "../../primitives/Loader";
|
import Loader from "../../primitives/Loader";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
|
import { withSessionValidation } from "../../utils";
|
||||||
|
|
||||||
const EditContactForm = (props) => {
|
const EditContactForm = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [isLoader, setIsLoader] = useState(false);
|
const [isLoader, setIsLoader] = useState(false);
|
||||||
@@ -27,9 +29,10 @@ const EditContactForm = (props) => {
|
|||||||
setFormData((prev) => ({ ...prev, [e.target.name]: e.target.value }));
|
setFormData((prev) => ({ ...prev, [e.target.name]: e.target.value }));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = withSessionValidation(async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
if (props.handleEditContact) {
|
if (props.handleEditContact) {
|
||||||
try {
|
try {
|
||||||
setIsLoader(true);
|
setIsLoader(true);
|
||||||
@@ -64,7 +67,7 @@ const EditContactForm = (props) => {
|
|||||||
props.handleClose && props.handleClose();
|
props.handleClose && props.handleClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
return (
|
return (
|
||||||
<div className="h-full p-[20px]">
|
<div className="h-full p-[20px]">
|
||||||
{isLoader && (
|
{isLoader && (
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { useState, useEffect, useRef } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import * as XLSX from "xlsx";
|
import * as XLSX from "xlsx";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import { emailRegex } from "../../constant/const";
|
import { emailRegex } from "../../constant/const";
|
||||||
|
import { withSessionValidation } from "../../utils";
|
||||||
|
|
||||||
const ImportContact = ({ setLoader, onImport, showAlert }) => {
|
const ImportContact = ({ setLoader, onImport, showAlert }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -178,7 +179,7 @@ const ImportContact = ({ setLoader, onImport, showAlert }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// `handleImportData` is used to create batch in contact
|
// `handleImportData` is used to create batch in contact
|
||||||
const handleImportData = async (e) => {
|
const handleImportData = withSessionValidation(async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setLoader(true);
|
setLoader(true);
|
||||||
@@ -213,10 +214,10 @@ const ImportContact = ({ setLoader, onImport, showAlert }) => {
|
|||||||
setImportedData([]);
|
setImportedData([]);
|
||||||
setInvalidRecords(0);
|
setInvalidRecords(0);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleImportData} className="p-[20px] h-full ">
|
<form onSubmit={handleImportData} className="p-[20px] h-full">
|
||||||
<div className="text-xs">
|
<div className="text-xs">
|
||||||
<label className="block ml-2">
|
<label className="block ml-2">
|
||||||
{t("contacts-file")}
|
{t("contacts-file")}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import Parse from "parse";
|
|||||||
import {
|
import {
|
||||||
copytoData,
|
copytoData,
|
||||||
fetchUrl,
|
fetchUrl,
|
||||||
formatDate,
|
|
||||||
getSignedUrl,
|
getSignedUrl,
|
||||||
getTenantDetails,
|
getTenantDetails,
|
||||||
handleSignatureType,
|
handleSignatureType,
|
||||||
@@ -46,7 +45,6 @@ const DocumentsReport = (props) => {
|
|||||||
const copyUrlRef = useRef(null);
|
const copyUrlRef = useRef(null);
|
||||||
const titleRef = useRef(null);
|
const titleRef = useRef(null);
|
||||||
const titleElement = useElSize(titleRef);
|
const titleElement = useElSize(titleRef);
|
||||||
const journey = "Use Template";
|
|
||||||
const appName =
|
const appName =
|
||||||
"OpenSign™";
|
"OpenSign™";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -187,7 +185,7 @@ const DocumentsReport = (props) => {
|
|||||||
}, [isMoreDocs, pageNumbers, currentPage, setIsNextRecord]);
|
}, [isMoreDocs, pageNumbers, currentPage, setIsNextRecord]);
|
||||||
|
|
||||||
//function to fetch tenant Details
|
//function to fetch tenant Details
|
||||||
const fetchTenantDetails = async () => {
|
const fetchTenantDetails = utils.withSessionValidation(async () => {
|
||||||
const user = JSON.parse(
|
const user = JSON.parse(
|
||||||
localStorage.getItem(
|
localStorage.getItem(
|
||||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
@@ -226,14 +224,14 @@ const DocumentsReport = (props) => {
|
|||||||
} else {
|
} else {
|
||||||
alert(t("user-not-exist"));
|
alert(t("user-not-exist"));
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// `handleURL` is used to open microapp
|
// `handleURL` is used to open microapp
|
||||||
const handleURL = async (item, act) => {
|
const handleURL = async (item, act) => {
|
||||||
navigate(`/${act.redirectUrl}?docId=${item?.objectId}`);
|
navigate(`/${act.redirectUrl}?docId=${item?.objectId}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchTemplate = async (templateId) => {
|
const fetchTemplate = utils.withSessionValidation(async (templateId) => {
|
||||||
try {
|
try {
|
||||||
const params = {
|
const params = {
|
||||||
templateId: templateId,
|
templateId: templateId,
|
||||||
@@ -259,24 +257,26 @@ const DocumentsReport = (props) => {
|
|||||||
setActLoader({});
|
setActLoader({});
|
||||||
console.log("Error to fetch template in report", e);
|
console.log("Error to fetch template in report", e);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
//function is called when there ther no any prefill role widget exist then create direct document and navigate
|
//function is called when there ther no any prefill role widget exist then create direct document and navigate
|
||||||
const navigatePageToDoc = async (templateRes, placeholder, signer) => {
|
const navigatePageToDoc = utils.withSessionValidation(
|
||||||
setIsPrefillModal({});
|
async (templateRes, placeholder, signer) => {
|
||||||
const res = await createDocument(
|
setIsPrefillModal({});
|
||||||
[templateRes || templateDeatils],
|
const res = await createDocument(
|
||||||
placeholder || xyPosition,
|
[templateRes || templateDeatils],
|
||||||
signer || signerList,
|
placeholder || xyPosition,
|
||||||
templateRes?.URL || templateDeatils?.URL
|
signer || signerList,
|
||||||
);
|
templateRes?.URL || templateDeatils?.URL,
|
||||||
if (res.status === "success") {
|
);
|
||||||
navigate(`/placeHolderSign/${res.id}`, {
|
if (res.status === "success") {
|
||||||
state: { title: "Use Template" }
|
navigate(`/placeHolderSign/${res.id}`, {
|
||||||
});
|
state: { title: "Use Template" }
|
||||||
} else {
|
});
|
||||||
alert(t("something-went-wrong-mssg"));
|
} else {
|
||||||
|
alert(t("something-went-wrong-mssg"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
);
|
||||||
const handleUseTemplate = async (templateId, item) => {
|
const handleUseTemplate = async (templateId, item) => {
|
||||||
try {
|
try {
|
||||||
const templateDeatils = await fetchTemplate(templateId);
|
const templateDeatils = await fetchTemplate(templateId);
|
||||||
@@ -305,7 +305,7 @@ const DocumentsReport = (props) => {
|
|||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleActionBtn = async (act, item) => {
|
const handleActionBtn = utils.withSessionValidation(async (act, item) => {
|
||||||
if (act.action === "redirect") {
|
if (act.action === "redirect") {
|
||||||
handleURL(item, act);
|
handleURL(item, act);
|
||||||
} else if (act.action === "delete") {
|
} else if (act.action === "delete") {
|
||||||
@@ -331,7 +331,7 @@ const DocumentsReport = (props) => {
|
|||||||
} else if (act.action === "extendexpiry") {
|
} else if (act.action === "extendexpiry") {
|
||||||
setIsModal({ [`extendexpiry_${item.objectId}`]: true });
|
setIsModal({ [`extendexpiry_${item.objectId}`]: true });
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
|
|
||||||
// Get current list
|
// Get current list
|
||||||
@@ -354,7 +354,7 @@ const DocumentsReport = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async (item) => {
|
const handleDelete = utils.withSessionValidation(async (item) => {
|
||||||
setIsDeleteModal({});
|
setIsDeleteModal({});
|
||||||
setActLoader({ [`${item.objectId}`]: true });
|
setActLoader({ [`${item.objectId}`]: true });
|
||||||
try {
|
try {
|
||||||
@@ -382,7 +382,7 @@ const DocumentsReport = (props) => {
|
|||||||
showAlert("danger", t("something-went-wrong-mssg"));
|
showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setIsRevoke({});
|
setIsRevoke({});
|
||||||
setIsDeleteModal({});
|
setIsDeleteModal({});
|
||||||
@@ -431,7 +431,7 @@ const DocumentsReport = (props) => {
|
|||||||
setCopied({ [email]: true });
|
setCopied({ [email]: true });
|
||||||
};
|
};
|
||||||
//function to handle revoke/decline docment
|
//function to handle revoke/decline docment
|
||||||
const handleRevoke = async (item) => {
|
const handleRevoke = utils.withSessionValidation(async (item) => {
|
||||||
const senderUser = localStorage.getItem(
|
const senderUser = localStorage.getItem(
|
||||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
);
|
);
|
||||||
@@ -479,7 +479,7 @@ const DocumentsReport = (props) => {
|
|||||||
showAlert("danger", t("something-went-wrong-mssg"));
|
showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
|
|
||||||
// `handleDownload` is used to get valid doc url available in completed report
|
// `handleDownload` is used to get valid doc url available in completed report
|
||||||
const handleDownload = async (item) => {
|
const handleDownload = async (item) => {
|
||||||
@@ -637,7 +637,7 @@ const DocumentsReport = (props) => {
|
|||||||
setMail((prev) => ({ ...prev, subject: res.subject, body: res.body }));
|
setMail((prev) => ({ ...prev, subject: res.subject, body: res.body }));
|
||||||
setIsNextStep({ [user.Id]: true });
|
setIsNextStep({ [user.Id]: true });
|
||||||
};
|
};
|
||||||
const handleResendMail = async (e, doc, user) => {
|
const handleResendMail = utils.withSessionValidation(async (e, doc, user) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setActLoader({ [user?.Id]: true });
|
setActLoader({ [user?.Id]: true });
|
||||||
const url = `${localStorage.getItem("baseUrl")}functions/sendmailv3`;
|
const url = `${localStorage.getItem("baseUrl")}functions/sendmailv3`;
|
||||||
@@ -674,7 +674,7 @@ const DocumentsReport = (props) => {
|
|||||||
setUserDetails({});
|
setUserDetails({});
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
const fetchUserStatus = (user, doc) => {
|
const fetchUserStatus = (user, doc) => {
|
||||||
const email = user.email ? user.email : user.signerPtr.Email;
|
const email = user.email ? user.email : user.signerPtr.Email;
|
||||||
const audit = doc?.AuditTrail?.find((x) => x.UserPtr.Email === email);
|
const audit = doc?.AuditTrail?.find((x) => x.UserPtr.Email === email);
|
||||||
@@ -709,7 +709,7 @@ const DocumentsReport = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdateExpiry = async (e, item) => {
|
const handleUpdateExpiry = utils.withSessionValidation(async (e, item) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (expiryDate) {
|
if (expiryDate) {
|
||||||
@@ -760,10 +760,10 @@ const DocumentsReport = (props) => {
|
|||||||
} else {
|
} else {
|
||||||
showAlert("danger", t("expiry-date-error"), 2000);
|
showAlert("danger", t("expiry-date-error"), 2000);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// `handleRenameDoc` is used to update document name
|
// `handleRenameDoc` is used to update document name
|
||||||
const handleRenameDoc = async (item) => {
|
const handleRenameDoc = utils.withSessionValidation(async (item) => {
|
||||||
setActLoader({ [item.objectId]: true });
|
setActLoader({ [item.objectId]: true });
|
||||||
setIsModal({});
|
setIsModal({});
|
||||||
const className = "contracts_Document";
|
const className = "contracts_Document";
|
||||||
@@ -783,7 +783,7 @@ const DocumentsReport = (props) => {
|
|||||||
showAlert("danger", t("something-went-wrong-mssg"), 2000);
|
showAlert("danger", t("something-went-wrong-mssg"), 2000);
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
const handleBtnVisibility = (act, item) => {
|
const handleBtnVisibility = (act, item) => {
|
||||||
if (!act.restrictBtn) {
|
if (!act.restrictBtn) {
|
||||||
return true;
|
return true;
|
||||||
@@ -799,7 +799,7 @@ const DocumentsReport = (props) => {
|
|||||||
setError("");
|
setError("");
|
||||||
setIsModal({});
|
setIsModal({});
|
||||||
};
|
};
|
||||||
const handleSaveAsTemplate = async (doc) => {
|
const handleSaveAsTemplate = utils.withSessionValidation(async (doc) => {
|
||||||
try {
|
try {
|
||||||
const params = { docId: doc?.objectId };
|
const params = { docId: doc?.objectId };
|
||||||
const templateRes = await Parse.Cloud.run("saveastemplate", params);
|
const templateRes = await Parse.Cloud.run("saveastemplate", params);
|
||||||
@@ -810,7 +810,7 @@ const DocumentsReport = (props) => {
|
|||||||
} finally {
|
} finally {
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
const handleCloseTemplate = () => {
|
const handleCloseTemplate = () => {
|
||||||
setTemplateId("");
|
setTemplateId("");
|
||||||
setIsSuccess({});
|
setIsSuccess({});
|
||||||
@@ -821,37 +821,39 @@ const DocumentsReport = (props) => {
|
|||||||
|
|
||||||
// `handleBulkSendTemplate` is used to open modal as well as fetch template
|
// `handleBulkSendTemplate` is used to open modal as well as fetch template
|
||||||
// and show Ui on the basis template response
|
// and show Ui on the basis template response
|
||||||
const handleBulkSendTemplate = async (templateId, docId) => {
|
const handleBulkSendTemplate = utils.withSessionValidation(
|
||||||
setIsBulkSend({ [docId]: true });
|
async (templateId, docId) => {
|
||||||
setIsLoader({ [docId]: true });
|
setIsBulkSend({ [docId]: true });
|
||||||
try {
|
setIsLoader({ [docId]: true });
|
||||||
const axiosRes = await fetchTemplate(templateId);
|
try {
|
||||||
const templateRes = axiosRes.data && axiosRes.data.result;
|
const axiosRes = await fetchTemplate(templateId);
|
||||||
const isPrefillExist = templateRes?.Placeholders.some(
|
const templateRes = axiosRes.data && axiosRes.data.result;
|
||||||
(x) => x.Role === "prefill"
|
const isPrefillExist = templateRes?.Placeholders.some(
|
||||||
);
|
(x) => x.Role === "prefill"
|
||||||
if (isPrefillExist) {
|
|
||||||
setIsBulkSend({});
|
|
||||||
setIsLoader({});
|
|
||||||
showAlert("danger", t("prefill-bulk-error"));
|
|
||||||
} else {
|
|
||||||
const tenantSignTypes = await fetchTenantDetails();
|
|
||||||
const docSignTypes = templateRes?.SignatureType || signatureTypes;
|
|
||||||
const updatedSignatureType = await handleSignatureType(
|
|
||||||
tenantSignTypes,
|
|
||||||
docSignTypes
|
|
||||||
);
|
);
|
||||||
setSignatureType(updatedSignatureType);
|
if (isPrefillExist) {
|
||||||
setPlaceholders(templateRes?.Placeholders);
|
setIsBulkSend({});
|
||||||
setTemplateDetails(templateRes);
|
setIsLoader({});
|
||||||
setIsLoader({});
|
showAlert("danger", t("prefill-bulk-error"));
|
||||||
|
} else {
|
||||||
|
const tenantSignTypes = await fetchTenantDetails();
|
||||||
|
const docSignTypes = templateRes?.SignatureType || signatureTypes;
|
||||||
|
const updatedSignatureType = await handleSignatureType(
|
||||||
|
tenantSignTypes,
|
||||||
|
docSignTypes
|
||||||
|
);
|
||||||
|
setSignatureType(updatedSignatureType);
|
||||||
|
setPlaceholders(templateRes?.Placeholders);
|
||||||
|
setTemplateDetails(templateRes);
|
||||||
|
setIsLoader({});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in fetch template in bulk modal", err);
|
||||||
|
setIsBulkSend({});
|
||||||
|
showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
console.log("err in fetch template in bulk modal", err);
|
|
||||||
setIsBulkSend({});
|
|
||||||
showAlert("danger", t("something-went-wrong-mssg"));
|
|
||||||
}
|
}
|
||||||
};
|
);
|
||||||
|
|
||||||
const handleResendClose = () => {
|
const handleResendClose = () => {
|
||||||
setIsResendMail({});
|
setIsResendMail({});
|
||||||
@@ -859,7 +861,7 @@ const DocumentsReport = (props) => {
|
|||||||
setUserDetails({});
|
setUserDetails({});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRecreateDoc = async (item) => {
|
const handleRecreateDoc = utils.withSessionValidation(async (item) => {
|
||||||
setActLoader({ [item.objectId]: true });
|
setActLoader({ [item.objectId]: true });
|
||||||
try {
|
try {
|
||||||
const res = await Parse.Cloud.run("recreatedoc", {
|
const res = await Parse.Cloud.run("recreatedoc", {
|
||||||
@@ -876,7 +878,7 @@ const DocumentsReport = (props) => {
|
|||||||
} finally {
|
} finally {
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
const restrictBtn = (item, act) => {
|
const restrictBtn = (item, act) => {
|
||||||
return item.IsSignyourself && act.action === "recreatedocument"
|
return item.IsSignyourself && act.action === "recreatedocument"
|
||||||
@@ -944,12 +946,14 @@ const DocumentsReport = (props) => {
|
|||||||
);
|
);
|
||||||
if (res?.status === "unfilled") {
|
if (res?.status === "unfilled") {
|
||||||
const emptyWidget = res?.emptyResponseObjects
|
const emptyWidget = res?.emptyResponseObjects
|
||||||
.map((item) => `[ ${item.options.name}]`)
|
?.map((item) => item.options.name)
|
||||||
.join(", ");
|
?.join(", ");
|
||||||
const timeInMiliSec = 6000;
|
const timeInMiliSec = 6000;
|
||||||
showAlert(
|
showAlert(
|
||||||
"danger",
|
"danger",
|
||||||
t("prefill-unfilled-widget", { emptyWidget: emptyWidget }),
|
t("prefill-unfilled-widget", {
|
||||||
|
emptyWidget: emptyWidget ? `[${emptyWidget}]` : ""
|
||||||
|
}),
|
||||||
timeInMiliSec
|
timeInMiliSec
|
||||||
);
|
);
|
||||||
} else if (res?.status === "unattach signer") {
|
} else if (res?.status === "unattach signer") {
|
||||||
@@ -1151,6 +1155,7 @@ const DocumentsReport = (props) => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody className="text-[12px]">
|
<tbody className="text-[12px]">
|
||||||
{props.List?.length > 0 &&
|
{props.List?.length > 0 &&
|
||||||
|
!props.searchLoader &&
|
||||||
currentList.map((item, index) => (
|
currentList.map((item, index) => (
|
||||||
<tr
|
<tr
|
||||||
className={`${
|
className={`${
|
||||||
@@ -1706,22 +1711,31 @@ const DocumentsReport = (props) => {
|
|||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{props.List?.length <= 0 && (
|
{(props.searchLoader || props.List?.length <= 0) && (
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
isDashboard ? "h-[317px]" : ""
|
isDashboard ? "h-[317px]" : ""
|
||||||
} flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`}
|
} flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`}
|
||||||
>
|
>
|
||||||
<div className="w-[60px] h-[60px] overflow-hidden">
|
{props.searchLoader ? (
|
||||||
<img
|
<>
|
||||||
className="w-full h-full object-contain"
|
<Loader />
|
||||||
src={pad}
|
<div className="text-sm ">{t("loading-mssg")}</div>
|
||||||
alt="img"
|
</>
|
||||||
/>
|
) : (
|
||||||
</div>
|
<>
|
||||||
<div className="text-sm font-semibold">
|
<div className="w-[60px] h-[60px] overflow-hidden">
|
||||||
{t("no-data-avaliable")}
|
<img
|
||||||
</div>
|
className="w-full h-full object-contain"
|
||||||
|
src={pad}
|
||||||
|
alt={t("no-data-avaliable")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-sm font-semibold">
|
||||||
|
{t("no-data-avaliable")}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import {
|
|||||||
handleSignatureType,
|
handleSignatureType,
|
||||||
replaceMailVaribles,
|
replaceMailVaribles,
|
||||||
signatureTypes,
|
signatureTypes,
|
||||||
openInNewTab,
|
|
||||||
createDocument,
|
createDocument,
|
||||||
defaultMailBody,
|
defaultMailBody,
|
||||||
defaultMailSubject
|
defaultMailSubject
|
||||||
@@ -30,19 +29,22 @@ import "../../styles/quill.css";
|
|||||||
import BulkSendUi from "../../components/BulkSendUi";
|
import BulkSendUi from "../../components/BulkSendUi";
|
||||||
import Loader from "../../primitives/Loader";
|
import Loader from "../../primitives/Loader";
|
||||||
import { serverUrl_fn } from "../../constant/appinfo";
|
import { serverUrl_fn } from "../../constant/appinfo";
|
||||||
import { Trans, useTranslation } from "react-i18next";
|
import {
|
||||||
|
useTranslation
|
||||||
|
} from "react-i18next";
|
||||||
import { useElSize } from "../../hook/useElSize";
|
import { useElSize } from "../../hook/useElSize";
|
||||||
import LottieWithLoader from "../../primitives/DotLottieReact";
|
import LottieWithLoader from "../../primitives/DotLottieReact";
|
||||||
import PrefillWidgetModal from "../../components/pdf/PrefillWidgetsModal";
|
import PrefillWidgetModal from "../../components/pdf/PrefillWidgetsModal";
|
||||||
import * as utils from "../../utils";
|
import * as utils from "../../utils";
|
||||||
import { useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { RenderReportCell } from "../../primitives/RenderReportCell";
|
import { RenderReportCell } from "../../primitives/RenderReportCell";
|
||||||
import CustomizeMail from "../../components/pdf/CustomizeMail";
|
import CustomizeMail from "../../components/pdf/CustomizeMail";
|
||||||
|
import { resetWidgetState } from "../../redux/reducers/widgetSlice";
|
||||||
|
|
||||||
const TemplatesReport = (props) => {
|
const TemplatesReport = (props) => {
|
||||||
const copyUrlRef = useRef(null);
|
const copyUrlRef = useRef(null);
|
||||||
const titleRef = useRef(null);
|
const titleRef = useRef(null);
|
||||||
const journey = "Use Template";
|
const dispatch = useDispatch();
|
||||||
const titleElement = useElSize(titleRef);
|
const titleElement = useElSize(titleRef);
|
||||||
const prefillImg = useSelector((state) => state.widget.prefillImg);
|
const prefillImg = useSelector((state) => state.widget.prefillImg);
|
||||||
const appName =
|
const appName =
|
||||||
@@ -92,8 +94,9 @@ const TemplatesReport = (props) => {
|
|||||||
const [isMailModal, setIsMailModal] = useState(false);
|
const [isMailModal, setIsMailModal] = useState(false);
|
||||||
const [customizeMail, setCustomizeMail] = useState({ body: "", subject: "" });
|
const [customizeMail, setCustomizeMail] = useState({ body: "", subject: "" });
|
||||||
const [defaultMail, setDefaultMail] = useState({ body: "", subject: "" });
|
const [defaultMail, setDefaultMail] = useState({ body: "", subject: "" });
|
||||||
const [currUserId, setCurrUserId] = useState(false);
|
const [currUserId, setCurrUserId] = useState("");
|
||||||
const [documentDetails, setDocumentDetails] = useState();
|
const [documentDetails, setDocumentDetails] = useState();
|
||||||
|
const [docId, setDocId] = useState();
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -160,6 +163,7 @@ const TemplatesReport = (props) => {
|
|||||||
const pageNumbers = getPaginationRange();
|
const pageNumbers = getPaginationRange();
|
||||||
// below useEffect reset currenpage to 1 if user change route
|
// below useEffect reset currenpage to 1 if user change route
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
dispatch(resetWidgetState([]));
|
||||||
checkTourStatus();
|
checkTourStatus();
|
||||||
fetchTeamList();
|
fetchTeamList();
|
||||||
return () => setCurrentPage(1);
|
return () => setCurrentPage(1);
|
||||||
@@ -206,7 +210,7 @@ const TemplatesReport = (props) => {
|
|||||||
}, [isMoreDocs, pageNumbers, currentPage, setIsNextRecord]);
|
}, [isMoreDocs, pageNumbers, currentPage, setIsNextRecord]);
|
||||||
|
|
||||||
//function to fetch tenant Details
|
//function to fetch tenant Details
|
||||||
const fetchTenantDetails = async () => {
|
const fetchTenantDetails = utils.withSessionValidation(async () => {
|
||||||
const user = JSON.parse(
|
const user = JSON.parse(
|
||||||
localStorage.getItem(
|
localStorage.getItem(
|
||||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
@@ -230,7 +234,7 @@ const TemplatesReport = (props) => {
|
|||||||
} else {
|
} else {
|
||||||
alert(t("user-not-exist"));
|
alert(t("user-not-exist"));
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// `handleURL` is used to open microapp
|
// `handleURL` is used to open microapp
|
||||||
const handleURL = async (item, act) => {
|
const handleURL = async (item, act) => {
|
||||||
@@ -276,7 +280,7 @@ const TemplatesReport = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchTemplate = async (templateId) => {
|
const fetchTemplate = utils.withSessionValidation(async (templateId) => {
|
||||||
try {
|
try {
|
||||||
const params = {
|
const params = {
|
||||||
templateId: templateId,
|
templateId: templateId,
|
||||||
@@ -301,26 +305,28 @@ const TemplatesReport = (props) => {
|
|||||||
showAlert("danger", t("something-went-wrong-mssg"));
|
showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
//function is called when there ther no any prefill role widget exist then create direct document and navigate
|
//function is called when there ther no any prefill role widget exist then create direct document and navigate
|
||||||
const navigatePageToDoc = async (templateRes, placeholder, signer) => {
|
const navigatePageToDoc = utils.withSessionValidation(
|
||||||
setIsPrefillModal({});
|
async (templateRes, placeholder, signer) => {
|
||||||
const res = await createDocument(
|
setIsPrefillModal({});
|
||||||
[templateRes || templateDetails],
|
const res = await createDocument(
|
||||||
placeholder || xyPosition,
|
[templateRes || templateDetails],
|
||||||
signer || signerList,
|
placeholder || xyPosition,
|
||||||
templateRes?.URL || templateDetails?.URL
|
signer || signerList,
|
||||||
);
|
templateRes?.URL || templateDetails?.URL,
|
||||||
if (res.status === "success") {
|
);
|
||||||
navigate(`/placeHolderSign/${res.id}`, {
|
if (res.status === "success") {
|
||||||
state: { title: "Use Template" }
|
navigate(`/placeHolderSign/${res.id}`, {
|
||||||
});
|
state: { title: "Use Template" }
|
||||||
} else {
|
});
|
||||||
alert(t("something-went-wrong-mssg"));
|
} else {
|
||||||
|
alert(t("something-went-wrong-mssg"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
);
|
||||||
|
|
||||||
const handleActionBtn = async (act, item) => {
|
const handleActionBtn = utils.withSessionValidation(async (act, item) => {
|
||||||
setIsTour(false);
|
setIsTour(false);
|
||||||
if (act.action === "redirect") {
|
if (act.action === "redirect") {
|
||||||
handleURL(item, act);
|
handleURL(item, act);
|
||||||
@@ -362,7 +368,7 @@ const TemplatesReport = (props) => {
|
|||||||
} else if (act.action === "extendexpiry") {
|
} else if (act.action === "extendexpiry") {
|
||||||
setIsModal({ [`extendexpiry_${item.objectId}`]: true });
|
setIsModal({ [`extendexpiry_${item.objectId}`]: true });
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
// Get current list
|
// Get current list
|
||||||
const indexOfLastDoc = currentPage * props.docPerPage;
|
const indexOfLastDoc = currentPage * props.docPerPage;
|
||||||
const indexOfFirstDoc = indexOfLastDoc - props.docPerPage;
|
const indexOfFirstDoc = indexOfLastDoc - props.docPerPage;
|
||||||
@@ -383,7 +389,7 @@ const TemplatesReport = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async (item) => {
|
const handleDelete = utils.withSessionValidation(async (item) => {
|
||||||
setIsDeleteModal({});
|
setIsDeleteModal({});
|
||||||
setActLoader({ [`${item.objectId}`]: true });
|
setActLoader({ [`${item.objectId}`]: true });
|
||||||
try {
|
try {
|
||||||
@@ -411,7 +417,7 @@ const TemplatesReport = (props) => {
|
|||||||
showAlert("danger", t("something-went-wrong-mssg"));
|
showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
const handleClose = (
|
const handleClose = (
|
||||||
) => {
|
) => {
|
||||||
setIsDeleteModal({});
|
setIsDeleteModal({});
|
||||||
@@ -608,7 +614,7 @@ const TemplatesReport = (props) => {
|
|||||||
};
|
};
|
||||||
// `handleNextBtn` is used to open edit mail template screen in resend mail modal
|
// `handleNextBtn` is used to open edit mail template screen in resend mail modal
|
||||||
// as well as replace variable with original one
|
// as well as replace variable with original one
|
||||||
const handleNextBtn = (user, doc) => {
|
const handleNextBtn = utils.withSessionValidation((user, doc) => {
|
||||||
const userdata = {
|
const userdata = {
|
||||||
Name: user?.signerPtr?.Name,
|
Name: user?.signerPtr?.Name,
|
||||||
Email: user.email ? user?.email : user.signerPtr?.Email,
|
Email: user.email ? user?.email : user.signerPtr?.Email,
|
||||||
@@ -655,8 +661,8 @@ const TemplatesReport = (props) => {
|
|||||||
const res = replaceMailVaribles(subject, body, variables);
|
const res = replaceMailVaribles(subject, body, variables);
|
||||||
setMail((prev) => ({ ...prev, subject: res.subject, body: res.body }));
|
setMail((prev) => ({ ...prev, subject: res.subject, body: res.body }));
|
||||||
setIsNextStep({ [user.Id]: true });
|
setIsNextStep({ [user.Id]: true });
|
||||||
};
|
});
|
||||||
const handleResendMail = async (e, doc, user) => {
|
const handleResendMail = utils.withSessionValidation(async (e, doc, user) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setActLoader({ [user?.Id]: true });
|
setActLoader({ [user?.Id]: true });
|
||||||
const url = `${localStorage.getItem("baseUrl")}functions/sendmailv3`;
|
const url = `${localStorage.getItem("baseUrl")}functions/sendmailv3`;
|
||||||
@@ -693,7 +699,7 @@ const TemplatesReport = (props) => {
|
|||||||
setUserDetails({});
|
setUserDetails({});
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
const fetchUserStatus = (user, doc) => {
|
const fetchUserStatus = (user, doc) => {
|
||||||
const email = user.email ? user.email : user.signerPtr.Email;
|
const email = user.email ? user.email : user.signerPtr.Email;
|
||||||
const audit = doc?.AuditTrail?.find((x) => x.UserPtr.Email === email);
|
const audit = doc?.AuditTrail?.find((x) => x.UserPtr.Email === email);
|
||||||
@@ -762,7 +768,7 @@ const TemplatesReport = (props) => {
|
|||||||
|
|
||||||
|
|
||||||
// `handleShareWith` is used to save teams in sharedWith field
|
// `handleShareWith` is used to save teams in sharedWith field
|
||||||
const handleShareWith = async (e, template) => {
|
const handleShareWith = utils.withSessionValidation(async (e, template) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIsShareWith({});
|
setIsShareWith({});
|
||||||
@@ -785,10 +791,10 @@ const TemplatesReport = (props) => {
|
|||||||
} finally {
|
} finally {
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// `handleCreateDuplicate` is used to create duplicate from current entry using objectId
|
// `handleCreateDuplicate` is used to create duplicate from current entry using objectId
|
||||||
const handleCreateDuplicate = async (item) => {
|
const handleCreateDuplicate = utils.withSessionValidation(async (item) => {
|
||||||
setActLoader({ [item.objectId]: true });
|
setActLoader({ [item.objectId]: true });
|
||||||
setIsModal({});
|
setIsModal({});
|
||||||
try {
|
try {
|
||||||
@@ -806,9 +812,9 @@ const TemplatesReport = (props) => {
|
|||||||
} finally {
|
} finally {
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
// `handleRenameDoc` is used to update document name
|
// `handleRenameDoc` is used to update document name
|
||||||
const handleRenameDoc = async (item) => {
|
const handleRenameDoc = utils.withSessionValidation(async (item) => {
|
||||||
setActLoader({ [item.objectId]: true });
|
setActLoader({ [item.objectId]: true });
|
||||||
setIsModal({});
|
setIsModal({});
|
||||||
const className = "contracts_Template";
|
const className = "contracts_Template";
|
||||||
@@ -829,7 +835,7 @@ const TemplatesReport = (props) => {
|
|||||||
showAlert("danger", t("something-went-wrong-mssg"), 2000);
|
showAlert("danger", t("something-went-wrong-mssg"), 2000);
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
const handleCloseModal = () => {
|
const handleCloseModal = () => {
|
||||||
setIsModal({});
|
setIsModal({});
|
||||||
@@ -885,7 +891,7 @@ const TemplatesReport = (props) => {
|
|||||||
setXyPosition([]);
|
setXyPosition([]);
|
||||||
};
|
};
|
||||||
//`handlePrefillWidgetCreateDoc` is used to embed prefill all widgets on document, create document, and send document
|
//`handlePrefillWidgetCreateDoc` is used to embed prefill all widgets on document, create document, and send document
|
||||||
const handlePrefillWidgetCreateDoc = async () => {
|
const handlePrefillWidgetCreateDoc = utils.withSessionValidation(async () => {
|
||||||
setIsSubmit(true);
|
setIsSubmit(true);
|
||||||
const scale = 1;
|
const scale = 1;
|
||||||
const res = await utils?.handleCheckPrefillCreateDoc(
|
const res = await utils?.handleCheckPrefillCreateDoc(
|
||||||
@@ -900,12 +906,14 @@ const TemplatesReport = (props) => {
|
|||||||
);
|
);
|
||||||
if (res?.status === "unfilled") {
|
if (res?.status === "unfilled") {
|
||||||
const emptyWidget = res?.emptyResponseObjects
|
const emptyWidget = res?.emptyResponseObjects
|
||||||
.map((item) => `[ ${item.options.name}]`)
|
?.map((item) => item.options.name)
|
||||||
.join(", ");
|
?.join(", ");
|
||||||
const timeInMiliSec = 6000;
|
const timeInMiliSec = 6000;
|
||||||
showAlert(
|
showAlert(
|
||||||
"danger",
|
"danger",
|
||||||
t("prefill-unfilled-widget", { emptyWidget: emptyWidget }),
|
t("prefill-unfilled-widget", {
|
||||||
|
emptyWidget: emptyWidget ? `[${emptyWidget}]` : ""
|
||||||
|
}),
|
||||||
timeInMiliSec
|
timeInMiliSec
|
||||||
);
|
);
|
||||||
} else if (res?.status === "unattach signer") {
|
} else if (res?.status === "unattach signer") {
|
||||||
@@ -913,12 +921,21 @@ const TemplatesReport = (props) => {
|
|||||||
} else if (res?.status === "success") {
|
} else if (res?.status === "success") {
|
||||||
setDocumentId(res.id);
|
setDocumentId(res.id);
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
setIsMailModal(true);
|
|
||||||
const user = JSON.parse(
|
const user = JSON.parse(
|
||||||
localStorage.getItem(
|
localStorage.getItem(
|
||||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
const ownerId = templateDetails.ExtUserPtr?.UserId?.objectId;
|
||||||
|
const firstSigner = signerList[0];
|
||||||
|
const isOwner = firstSigner?.UserId?.objectId === ownerId;
|
||||||
|
setDocId(res.id);
|
||||||
|
if (templateDetails?.SendinOrder && isOwner) {
|
||||||
|
setCurrUserId(firstSigner?.objectId);
|
||||||
|
setIsSend(true);
|
||||||
|
} else {
|
||||||
|
setIsMailModal(true);
|
||||||
|
}
|
||||||
if (user) {
|
if (user) {
|
||||||
try {
|
try {
|
||||||
const tenantDetails = await getTenantDetails(user?.objectId);
|
const tenantDetails = await getTenantDetails(user?.objectId);
|
||||||
@@ -949,7 +966,7 @@ const TemplatesReport = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
setIsSubmit(false);
|
setIsSubmit(false);
|
||||||
};
|
});
|
||||||
//function show signer list and share link to share signUrl
|
//function show signer list and share link to share signUrl
|
||||||
const handleShareList = () => {
|
const handleShareList = () => {
|
||||||
const shareLinkList = [];
|
const shareLinkList = [];
|
||||||
@@ -1130,6 +1147,7 @@ const TemplatesReport = (props) => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody className="text-[12px]">
|
<tbody className="text-[12px]">
|
||||||
{props.List?.length > 0 &&
|
{props.List?.length > 0 &&
|
||||||
|
!props.searchLoader &&
|
||||||
currentList.map((item, index) => (
|
currentList.map((item, index) => (
|
||||||
<tr
|
<tr
|
||||||
className={`${
|
className={`${
|
||||||
@@ -1542,22 +1560,31 @@ const TemplatesReport = (props) => {
|
|||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{props.List?.length <= 0 && (
|
{(props.searchLoader || props.List?.length <= 0) && (
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
isDashboard ? "h-[317px]" : ""
|
isDashboard ? "h-[317px]" : ""
|
||||||
} flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`}
|
} flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`}
|
||||||
>
|
>
|
||||||
<div className="w-[60px] h-[60px] overflow-hidden">
|
{props.searchLoader ? (
|
||||||
<img
|
<>
|
||||||
className="w-full h-full object-contain"
|
<Loader />
|
||||||
src={pad}
|
<div className="text-sm ">{t("loading-mssg")}</div>
|
||||||
alt="img"
|
</>
|
||||||
/>
|
) : (
|
||||||
</div>
|
<>
|
||||||
<div className="text-sm font-semibold">
|
<div className="w-[60px] h-[60px] overflow-hidden">
|
||||||
{t("no-data-avaliable")}
|
<img
|
||||||
</div>
|
className="w-full h-full object-contain"
|
||||||
|
src={pad}
|
||||||
|
alt={t("no-data-avaliable")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-sm font-semibold">
|
||||||
|
{t("no-data-avaliable")}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -1608,11 +1635,13 @@ const TemplatesReport = (props) => {
|
|||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen={isSend}
|
isOpen={isSend}
|
||||||
title={
|
title={
|
||||||
mailStatus === "success"
|
!templateDetails?.SendinOrder
|
||||||
? t("mails-sent")
|
? mailStatus === "success"
|
||||||
: mailStatus === "quotareached"
|
? t("mails-sent")
|
||||||
? t("quota-mail-head")
|
: mailStatus === "quotareached"
|
||||||
: t("mail-not-delivered")
|
? t("quota-mail-head")
|
||||||
|
: t("mail-not-delivered")
|
||||||
|
: t("mail-status-head")
|
||||||
}
|
}
|
||||||
handleClose={() => {
|
handleClose={() => {
|
||||||
setIsSend(false);
|
setIsSend(false);
|
||||||
@@ -1620,68 +1649,102 @@ const TemplatesReport = (props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="h-[100%] p-[20px] text-base-content">
|
<div className="h-[100%] p-[20px] text-base-content">
|
||||||
{mailStatus === "success" ? (
|
<div className="flex flex-col items-center gap-5">
|
||||||
<div className="text-center mb-[10px]">
|
<div>
|
||||||
<LottieWithLoader />
|
{mailStatus === "success" ? (
|
||||||
{documentDetails.SendinOrder ? (
|
<div className="text-center mb-[10px]">
|
||||||
<p>
|
<LottieWithLoader />
|
||||||
{currUserId
|
{documentDetails.SendinOrder ? (
|
||||||
? t("placeholder-mail-alert-you")
|
<p>
|
||||||
: t("placeholder-mail-alert", {
|
{currUserId
|
||||||
name: signerList[0]?.Name
|
? t("placeholder-mail-alert-you")
|
||||||
})}
|
: t("placeholder-mail-alert", {
|
||||||
</p>
|
name: signerList[0]?.Name
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
<p>{t("placeholder-alert-4")}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : mailStatus === "quotareached" ? (
|
||||||
|
<div className="flex flex-col gap-y-3">
|
||||||
|
<div className="my-3">{handleShareList()}</div>
|
||||||
|
</div>
|
||||||
|
) : mailStatus === "failed" ? (
|
||||||
|
<p>{t("mail-failed")} </p>
|
||||||
) : (
|
) : (
|
||||||
<p>{t("placeholder-alert-4")}</p>
|
<div className="mb-[10px]">
|
||||||
|
{!templateDetails?.SendinOrder &&
|
||||||
|
(mailStatus === "dailyquotareached" ? (
|
||||||
|
<p>{t("daily-quota-reached")}</p>
|
||||||
|
) : (
|
||||||
|
<p>{t("placeholder-alert-6")}</p>
|
||||||
|
))}
|
||||||
|
{currUserId && (
|
||||||
|
<span className="mt-1">{t("placeholder-alert-5")}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{currUserId && <p>{t("placeholder-alert-5")}</p>}
|
|
||||||
</div>
|
{mailStatus !== "quotareached" && mailStatus !== "failed" && (
|
||||||
) : mailStatus === "quotareached" ? (
|
<div
|
||||||
<div className="flex flex-col gap-y-3">
|
className={
|
||||||
<div className="my-3">{handleShareList()}</div>
|
mailStatus === "success"
|
||||||
</div>
|
? "flex justify-center mt-1"
|
||||||
) : (
|
: "flex items-center justify-center mt-7"
|
||||||
<div className="mb-[10px]">
|
|
||||||
{mailStatus === "dailyquotareached" ? (
|
|
||||||
<p>{t("daily-quota-reached")}</p>
|
|
||||||
) : (
|
|
||||||
<p>{t("placeholder-alert-6")}</p>
|
|
||||||
)}
|
|
||||||
{currUserId && (
|
|
||||||
<p className="mt-1">{t("placeholder-alert-5")}</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{!mailStatus && (
|
|
||||||
<div className="w-full h-[1px] bg-[#9f9f9f] my-[15px]"></div>
|
|
||||||
)}
|
|
||||||
{mailStatus !== "quotareached" && (
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
mailStatus === "success" ? "flex justify-center mt-1" : ""
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{currUserId && (
|
|
||||||
<button
|
|
||||||
onClick={() =>
|
|
||||||
handleRecipientSign(documentDetails?.objectId, currUserId)
|
|
||||||
}
|
}
|
||||||
type="button"
|
|
||||||
className="op-btn op-btn-primary mr-1"
|
|
||||||
>
|
>
|
||||||
{t("yes")}
|
{currUserId && (
|
||||||
</button>
|
<button
|
||||||
|
onClick={() => handleRecipientSign(docId, currUserId)}
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-primary mr-1"
|
||||||
|
>
|
||||||
|
{t("sign-now")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
navigate("/report/1MwEuxLEkF");
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-ghost text-base-content"
|
||||||
|
>
|
||||||
|
{currUserId ? t("no") : t("close")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
navigate("/report/1MwEuxLEkF");
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className="op-btn op-btn-ghost text-base-content"
|
|
||||||
>
|
|
||||||
{currUserId ? t("no") : t("close")}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
{mailStatus !== "success" &&
|
||||||
|
currUserId &&
|
||||||
|
templateDetails?.SendinOrder && (
|
||||||
|
<div className="op-divider text-base-content mx-[0%] my-1 font-medium">
|
||||||
|
{t("or")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{mailStatus !== "success" &&
|
||||||
|
currUserId &&
|
||||||
|
templateDetails?.SendinOrder && (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className="op-btn op-btn-outline w-[50%] md:w-[35%] mt-1"
|
||||||
|
onClick={() => {
|
||||||
|
setIsSend(false);
|
||||||
|
setIsMailModal(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="fa-regular fa-envelope"
|
||||||
|
style={{ color: "#002864", fontSize: "19px" }}
|
||||||
|
></i>{" "}
|
||||||
|
<span>{t("send-to-email")}</span>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{!mailStatus && (
|
||||||
|
<div className="op-divider text-base-content mx-[0%] mt-3"></div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
|
|||||||
@@ -31,7 +31,10 @@
|
|||||||
border: 1px solid #007bff;
|
border: 1px solid #007bff;
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
}
|
}
|
||||||
|
.prefillCanvas {
|
||||||
|
width: 205px;
|
||||||
|
height: 81px;
|
||||||
|
}
|
||||||
.signatureCanvas {
|
.signatureCanvas {
|
||||||
width: 440px;
|
width: 440px;
|
||||||
height: 167px;
|
height: 167px;
|
||||||
@@ -44,8 +47,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mysignatureCanvas {
|
.mysignatureCanvas {
|
||||||
width: 456px;
|
width: 370px;
|
||||||
height: 180px;
|
height: 146px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mystampCanvas {
|
||||||
|
width: 370px;
|
||||||
|
height: 146px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intialSignature {
|
||||||
|
border: 2px solid #888;
|
||||||
|
background-color: rgb(255, 255, 255);
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="opensigndark"] .tabWidth {
|
[data-theme="opensigndark"] .tabWidth {
|
||||||
@@ -70,13 +85,6 @@
|
|||||||
/* blue-500 */
|
/* blue-500 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.intialSignature {
|
|
||||||
border: 2px solid #888;
|
|
||||||
background-color: rgb(255, 255, 255);
|
|
||||||
width: 180px;
|
|
||||||
height: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Dark mode support for initials box in /managesign */
|
/* Dark mode support for initials box in /managesign */
|
||||||
[data-theme="opensigndark"] .intialSignature {
|
[data-theme="opensigndark"] .intialSignature {
|
||||||
background-color: #1f2937 !important;
|
background-color: #1f2937 !important;
|
||||||
@@ -117,10 +125,6 @@
|
|||||||
border-color: #4b5563 !important;
|
border-color: #4b5563 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.penContainerDefault {
|
|
||||||
width: 460px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -450,7 +454,7 @@ option {
|
|||||||
to prevent sudden quick movement (as the
|
to prevent sudden quick movement (as the
|
||||||
navigation bar gets a new position at the top of the
|
navigation bar gets a new position at the top of the
|
||||||
page (position:fixed and top:0) */
|
page (position:fixed and top:0) */
|
||||||
.stickyHead+.content {
|
.stickyHead + .content {
|
||||||
padding-top: 60px;
|
padding-top: 60px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -466,11 +470,12 @@ option {
|
|||||||
height: 118px;
|
height: 118px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabWidth {
|
.mystampCanvas {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
height: 118px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.penContainerDefault {
|
.tabWidth {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,18 +503,17 @@ option {
|
|||||||
width: 280px;
|
width: 280px;
|
||||||
height: 111px;
|
height: 111px;
|
||||||
}
|
}
|
||||||
|
.mystampCanvas {
|
||||||
|
width: 280px;
|
||||||
|
height: 111px;
|
||||||
|
}
|
||||||
|
|
||||||
.tabWidth {
|
.tabWidth {
|
||||||
width: 280px;
|
width: 280px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.penContainerDefault {
|
|
||||||
width: 280px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signTab {
|
.signTab {
|
||||||
font-weight: 500 !important;
|
font-weight: 500 !important;
|
||||||
|
|
||||||
font-size: 10px !important;
|
font-size: 10px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,12 +532,12 @@ option {
|
|||||||
width: 230px;
|
width: 230px;
|
||||||
height: 91px;
|
height: 91px;
|
||||||
}
|
}
|
||||||
|
.mystampCanvas {
|
||||||
.tabWidth {
|
|
||||||
width: 230px;
|
width: 230px;
|
||||||
|
height: 91px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.penContainerDefault {
|
.tabWidth {
|
||||||
width: 230px;
|
width: 230px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ export * from "./sanitizeFileName";
|
|||||||
export * from "./lazyWithRetry";
|
export * from "./lazyWithRetry";
|
||||||
export * from "./upgradeProgress";
|
export * from "./upgradeProgress";
|
||||||
export * from "./widgetUtils";
|
export * from "./widgetUtils";
|
||||||
|
export * from "./withSessionValidation";
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import {
|
|||||||
generatePdfName,
|
generatePdfName,
|
||||||
embedWidgetsToDoc,
|
embedWidgetsToDoc,
|
||||||
randomId,
|
randomId,
|
||||||
getBase64FromUrl
|
getBase64FromUrl,
|
||||||
|
drawWidget
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import { PDFDocument } from "pdf-lib";
|
import { PDFDocument } from "pdf-lib";
|
||||||
|
|
||||||
@@ -98,9 +99,9 @@ export const isValidPrefill = (prefillData) => {
|
|||||||
const emptyResponseObjects = getPlaceholder.flatMap((page) =>
|
const emptyResponseObjects = getPlaceholder.flatMap((page) =>
|
||||||
page.pos.filter(
|
page.pos.filter(
|
||||||
(item) =>
|
(item) =>
|
||||||
item?.type !== "checkbox" &&
|
|
||||||
!item?.options?.defaultValue &&
|
!item?.options?.defaultValue &&
|
||||||
!item?.options?.response
|
!item?.options?.response &&
|
||||||
|
item?.options?.status === "required"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (emptyResponseObjects.length > 0) {
|
if (emptyResponseObjects.length > 0) {
|
||||||
@@ -161,6 +162,8 @@ export const handleCheckPrefillCreateDoc = async (
|
|||||||
);
|
);
|
||||||
if (res.status === "success") {
|
if (res.status === "success") {
|
||||||
return res;
|
return res;
|
||||||
|
} else if (res.status === "error") {
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const res = { status: "unattach signer" };
|
const res = { status: "unattach signer" };
|
||||||
@@ -173,21 +176,29 @@ export const savePrefillImg = async (Placeholders) => {
|
|||||||
const prefillData = Placeholders?.find((x) => x.Role === "prefill");
|
const prefillData = Placeholders?.find((x) => x.Role === "prefill");
|
||||||
if (prefillData) {
|
if (prefillData) {
|
||||||
const allImageFields = prefillData?.placeHolder.flatMap((p) =>
|
const allImageFields = prefillData?.placeHolder.flatMap((p) =>
|
||||||
p.pos.filter((item) => item.type === "image")
|
p.pos.filter((item) => item.type === "image" || item.type === drawWidget)
|
||||||
|
);
|
||||||
|
const hasImageType = allImageFields.some(
|
||||||
|
(p) => p.type === "image" || p.type === drawWidget
|
||||||
);
|
);
|
||||||
const hasImageType = allImageFields.some((p) => p.type === "image");
|
|
||||||
if (hasImageType) {
|
if (hasImageType) {
|
||||||
const imgArr = [];
|
const imgArr = [];
|
||||||
for (const ph of prefillData?.placeHolder || []) {
|
for (const ph of prefillData?.placeHolder || []) {
|
||||||
for (const pos of ph?.pos || []) {
|
for (const pos of ph?.pos || []) {
|
||||||
if (pos?.type === "image" && pos?.SignUrl) {
|
if (
|
||||||
|
(pos?.type === "image" || pos?.type === drawWidget) &&
|
||||||
|
pos?.options?.response
|
||||||
|
) {
|
||||||
const addSuffix = true;
|
const addSuffix = true;
|
||||||
const base64 = await getBase64FromUrl(pos?.SignUrl, addSuffix);
|
const base64 = await getBase64FromUrl(
|
||||||
|
pos?.options?.response,
|
||||||
|
addSuffix
|
||||||
|
);
|
||||||
imgArr.push({
|
imgArr.push({
|
||||||
id: pos?.key,
|
id: pos?.key,
|
||||||
base64: base64
|
base64: base64
|
||||||
});
|
});
|
||||||
} else if (pos?.type === "image") {
|
} else if (pos?.type === "image" || pos?.type === drawWidget) {
|
||||||
imgArr.push({
|
imgArr.push({
|
||||||
id: pos?.key,
|
id: pos?.key,
|
||||||
base64: ""
|
base64: ""
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { generateTitleFromFilename } from "../constant/Utils";
|
import { generateTitleFromFilename, selectFormat } from "../constant/Utils";
|
||||||
import { base64StringtoFile, uploadFile } from "./fileUtils";
|
import { base64StringtoFile, uploadFile } from "./fileUtils";
|
||||||
import { sanitizeFileName } from "./sanitizeFileName";
|
import { sanitizeFileName } from "./sanitizeFileName";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
@@ -13,7 +13,9 @@ export const saveToMySign = async (widget) => {
|
|||||||
const fileName =
|
const fileName =
|
||||||
widget?.type === "signature"
|
widget?.type === "signature"
|
||||||
? `${replaceSpace}__sign`
|
? `${replaceSpace}__sign`
|
||||||
: `${replaceSpace}__initials`;
|
: widget?.type === "initials"
|
||||||
|
? `${replaceSpace}__initials`
|
||||||
|
: `${replaceSpace}_stamp`;
|
||||||
const file = base64StringtoFile(base64, fileName);
|
const file = base64StringtoFile(base64, fileName);
|
||||||
const fileUrl = await uploadFile(file, User?.id);
|
const fileUrl = await uploadFile(file, User?.id);
|
||||||
// below code is used to save or update default signature, initials, stamp
|
// below code is used to save or update default signature, initials, stamp
|
||||||
@@ -25,6 +27,8 @@ export const saveToMySign = async (widget) => {
|
|||||||
params.initials = fileUrl; // save initials image url
|
params.initials = fileUrl; // save initials image url
|
||||||
} else if (widget?.type === "signature") {
|
} else if (widget?.type === "signature") {
|
||||||
params.signature = fileUrl; // save signature image url
|
params.signature = fileUrl; // save signature image url
|
||||||
|
} else if (widget?.type === "stamp") {
|
||||||
|
params.stamp = fileUrl; // save stamp image url
|
||||||
}
|
}
|
||||||
const signRes = await Parse.Cloud.run("savesignature", params);
|
const signRes = await Parse.Cloud.run("savesignature", params);
|
||||||
return { base64File: base64, id: signRes?.id };
|
return { base64File: base64, id: signRes?.id };
|
||||||
@@ -113,3 +117,125 @@ export const applyNumberFormulasToPages = (pages = []) => {
|
|||||||
// Return the cloned, updated pages
|
// Return the cloned, updated pages
|
||||||
return clonedPages;
|
return clonedPages;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getInitials = (name) => {
|
||||||
|
if (!name) return "";
|
||||||
|
|
||||||
|
// Trim and split by any amount of whitespace
|
||||||
|
const parts = name.trim().split(/\s+/);
|
||||||
|
|
||||||
|
// Only one word → return first letter of that word
|
||||||
|
if (parts.length === 1) {
|
||||||
|
return parts[0][0].toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// More than one word → take first and second words
|
||||||
|
const first = parts[0];
|
||||||
|
const second = parts[1];
|
||||||
|
|
||||||
|
return `${first[0].toUpperCase()} ${second[0].toUpperCase()}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to check if a string is valid Base64 (supports data URL)
|
||||||
|
export const isValidBase64 = (str) => {
|
||||||
|
if (!str || typeof str !== "string") return false;
|
||||||
|
|
||||||
|
// Remove data URL prefix if present
|
||||||
|
const cleanedStr = str.split(",").pop()?.trim();
|
||||||
|
if (!cleanedStr) return false;
|
||||||
|
|
||||||
|
// Length must be divisible by 4
|
||||||
|
if (cleanedStr.length % 4 !== 0) return false;
|
||||||
|
|
||||||
|
// Base64 or Base64URL regex
|
||||||
|
const base64Regex =
|
||||||
|
/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
||||||
|
|
||||||
|
if (!base64Regex.test(cleanedStr)) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// atob throws if invalid
|
||||||
|
atob(cleanedStr);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export const addPreferenceOpt = (owner, type, role, isSignyourself) => {
|
||||||
|
const widget = owner?.WidgetPreferences?.find((w) => w.type === type) || {};
|
||||||
|
switch (type) {
|
||||||
|
case "date": {
|
||||||
|
const signingDate = widget?.isSigningDate ? "today" : widget?.date || "";
|
||||||
|
const isReadOnly = widget?.isReadOnly || false;
|
||||||
|
const isPrefill = role && role === "prefill";
|
||||||
|
const format =
|
||||||
|
widget?.format || selectFormat(owner?.DateFormat) || "MM/DD/YYYY";
|
||||||
|
const prefillDate = new Date();
|
||||||
|
const response = isPrefill
|
||||||
|
? formatDate({ date: prefillDate, format: format })
|
||||||
|
: signingDate || "";
|
||||||
|
const option =
|
||||||
|
isSignyourself || isPrefill ? {} : { isReadOnly: isReadOnly };
|
||||||
|
return {
|
||||||
|
response: response,
|
||||||
|
...option,
|
||||||
|
format: widget?.format || "MM/dd/yyyy"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export function formatDate(dateObj) {
|
||||||
|
const format = dateObj?.format?.toLowerCase();
|
||||||
|
const date = new Date(dateObj.date);
|
||||||
|
|
||||||
|
// zero-padded day and month
|
||||||
|
const dd = String(date.getDate()).padStart(2, "0");
|
||||||
|
const mm = String(date.getMonth() + 1).padStart(2, "0");
|
||||||
|
const yyyy = date.getFullYear();
|
||||||
|
|
||||||
|
// month names
|
||||||
|
const shortNames = [
|
||||||
|
"Jan",
|
||||||
|
"Feb",
|
||||||
|
"Mar",
|
||||||
|
"Apr",
|
||||||
|
"May",
|
||||||
|
"Jun",
|
||||||
|
"Jul",
|
||||||
|
"Aug",
|
||||||
|
"Sep",
|
||||||
|
"Oct",
|
||||||
|
"Nov",
|
||||||
|
"Dec"
|
||||||
|
];
|
||||||
|
const longNames = [
|
||||||
|
"January",
|
||||||
|
"February",
|
||||||
|
"March",
|
||||||
|
"April",
|
||||||
|
"May",
|
||||||
|
"June",
|
||||||
|
"July",
|
||||||
|
"August",
|
||||||
|
"September",
|
||||||
|
"October",
|
||||||
|
"November",
|
||||||
|
"December"
|
||||||
|
];
|
||||||
|
const mmm = shortNames[date.getMonth()];
|
||||||
|
const mmmm = longNames[date.getMonth()];
|
||||||
|
|
||||||
|
// a map of token → replacement
|
||||||
|
const tokens = { yyyy: yyyy, mm: mm, dd: dd, mmm: mmm, mmmm: mmmm };
|
||||||
|
|
||||||
|
// Replace longer tokens first
|
||||||
|
return format
|
||||||
|
.replace(/yyyy/, tokens.yyyy)
|
||||||
|
.replace(/mmmm/, tokens.mmmm)
|
||||||
|
.replace(/mmm/, tokens.mmm)
|
||||||
|
.replace(/mm/, tokens.mm)
|
||||||
|
.replace(/dd/, tokens.dd);
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { sessionStatus } from "../redux/reducers/userReducer";
|
||||||
|
import { store } from "../redux/store";
|
||||||
|
import Parse from "parse";
|
||||||
|
|
||||||
|
export function withSessionValidation(fn) {
|
||||||
|
return async (...args) => {
|
||||||
|
try {
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
const user =
|
||||||
|
typeof Parse !== "undefined" ? Parse.User?.current?.() : null;
|
||||||
|
const sessionToken = user?.getSessionToken?.();
|
||||||
|
|
||||||
|
if (!tenantId || !sessionToken) {
|
||||||
|
store.dispatch(sessionStatus(false));
|
||||||
|
throw new Error("invalid session token");
|
||||||
|
}
|
||||||
|
|
||||||
|
return await fn(...args);
|
||||||
|
} catch (error) {
|
||||||
|
if (error?.message === "invalid session token") {
|
||||||
|
console.error("invalid session or missing tenantId", error);
|
||||||
|
store.dispatch(sessionStatus(false));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
throw error; // important: don't silently swallow errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -6,7 +6,11 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
require("daisyui"),
|
require("daisyui"),
|
||||||
function ({ addUtilities, theme }) {
|
function ({ addUtilities, addVariant }) {
|
||||||
|
// ✅ Variants that match html[data-theme="..."] (or any ancestor with data-theme)
|
||||||
|
addVariant("opensigncss", '[data-theme="opensigncss"] &');
|
||||||
|
addVariant("opensigndark", '[data-theme="opensigndark"] &');
|
||||||
|
|
||||||
addUtilities({
|
addUtilities({
|
||||||
// Prevent iOS long-press popup
|
// Prevent iOS long-press popup
|
||||||
".touch-callout-none": {
|
".touch-callout-none": {
|
||||||
|
|||||||
@@ -160,6 +160,17 @@ export const smtpsecure = process.env.SMTP_PORT && process.env.SMTP_PORT !== '46
|
|||||||
export const smtpenable =
|
export const smtpenable =
|
||||||
process.env.SMTP_ENABLE && process.env.SMTP_ENABLE.toLowerCase() === 'true' ? true : false;
|
process.env.SMTP_ENABLE && process.env.SMTP_ENABLE.toLowerCase() === 'true' ? true : false;
|
||||||
export const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
export const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||||
|
export function signPayload(payload, secret) {
|
||||||
|
if (payload && secret) {
|
||||||
|
const signature = crypto
|
||||||
|
.createHmac('sha256', secret)
|
||||||
|
.update(JSON.stringify(payload))
|
||||||
|
.digest('hex');
|
||||||
|
return { 'x-webhook-signature': signature };
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// `generateId` is used to unique Id for fileAdapter
|
// `generateId` is used to unique Id for fileAdapter
|
||||||
export function generateId(length) {
|
export function generateId(length) {
|
||||||
@@ -172,35 +183,6 @@ export function generateId(length) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format date and time for the selected timezone
|
|
||||||
export const formatTimeInTimezone = (date, timezone) => {
|
|
||||||
const nyDate = timezone && toZonedTime(date, timezone);
|
|
||||||
const generatedDate = timezone
|
|
||||||
? format(nyDate, 'EEE, dd MMM yyyy HH:mm:ss zzz', { timeZone: timezone })
|
|
||||||
: new Date(date).toUTCString();
|
|
||||||
return generatedDate;
|
|
||||||
};
|
|
||||||
|
|
||||||
// `getSecureUrl` is used to return local secure url if local files
|
|
||||||
export const getSecureUrl = url => {
|
|
||||||
const fileUrl = new URL(url)?.pathname?.includes('files');
|
|
||||||
if (fileUrl) {
|
|
||||||
try {
|
|
||||||
const file = getSignedLocalUrl(url);
|
|
||||||
if (file) {
|
|
||||||
return { url: file };
|
|
||||||
} else {
|
|
||||||
return { url: '' };
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log('err while fileupload ', err);
|
|
||||||
return { url: '' };
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return { url: url };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FlattenPdf is used to remove existing widgets if present any and flatten pdf.
|
* FlattenPdf is used to remove existing widgets if present any and flatten pdf.
|
||||||
* @param {string | Uint8Array | ArrayBuffer} pdfFile - pdf file.
|
* @param {string | Uint8Array | ArrayBuffer} pdfFile - pdf file.
|
||||||
@@ -238,13 +220,42 @@ export const flattenPdf = async pdfFile => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Format date and time for the selected timezone
|
||||||
|
export const formatTimeInTimezone = (date, timezone) => {
|
||||||
|
const nyDate = timezone && toZonedTime(date, timezone);
|
||||||
|
const generatedDate = timezone
|
||||||
|
? format(nyDate, 'EEE, dd MMM yyyy HH:mm:ss zzz', { timeZone: timezone })
|
||||||
|
: new Date(date).toUTCString();
|
||||||
|
return generatedDate;
|
||||||
|
};
|
||||||
|
|
||||||
|
// `getSecureUrl` is used to return local secure url if local files
|
||||||
|
export const getSecureUrl = url => {
|
||||||
|
const fileUrl = new URL(url)?.pathname?.includes('files');
|
||||||
|
if (fileUrl) {
|
||||||
|
try {
|
||||||
|
const file = getSignedLocalUrl(url);
|
||||||
|
if (file) {
|
||||||
|
return { url: file };
|
||||||
|
} else {
|
||||||
|
return { url: '' };
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err while fileupload ', err);
|
||||||
|
return { url: '' };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { url: url };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const mailTemplate = param => {
|
export const mailTemplate = param => {
|
||||||
const themeColor = '#47a3ad';
|
const themeColor = '#47a3ad';
|
||||||
const subject = `${param.senderName} has requested you to sign "${param.title}"`;
|
const subject = `${param.senderName} has requested you to sign "${param.title}"`;
|
||||||
const AppName = appName;
|
const AppName = appName;
|
||||||
const logo = `<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' />`;
|
const logo = `<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' />`;
|
||||||
|
|
||||||
const opurl = ` <a href='www.opensignlabs.com' target=_blank>here</a>`;
|
const opurl = ` <a href='mailto:complaint@opensiglabs.com' target=_blank>here</a>`;
|
||||||
|
|
||||||
const body =
|
const body =
|
||||||
"<html><head><meta http-equiv='Content-Type' content='text/html;charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background:white;padding-bottom:20px'><div style='padding:10px'>" +
|
"<html><head><meta http-equiv='Content-Type' content='text/html;charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background:white;padding-bottom:20px'><div style='padding:10px'>" +
|
||||||
@@ -267,7 +278,7 @@ export const mailTemplate = param => {
|
|||||||
AppName +
|
AppName +
|
||||||
'. For any queries regarding this email, please contact the sender ' +
|
'. For any queries regarding this email, please contact the sender ' +
|
||||||
param.senderMail +
|
param.senderMail +
|
||||||
` directly. If you think this email is inappropriate or spam, you may file a complaint with ${AppName}${opurl}.</p></div></div></body></html>`;
|
` directly. If you think this email is inappropriate or spam, you may file a complaints with ${AppName}${opurl}.</p></div></div></body></html>`;
|
||||||
|
|
||||||
return { subject, body };
|
return { subject, body };
|
||||||
};
|
};
|
||||||
@@ -358,34 +369,27 @@ export const handleValidImage = async Placeholder => {
|
|||||||
for (const item of placeholder.placeHolder || []) {
|
for (const item of placeholder.placeHolder || []) {
|
||||||
const updatedPos = [];
|
const updatedPos = [];
|
||||||
for (const posItem of item.pos || []) {
|
for (const posItem of item.pos || []) {
|
||||||
if (posItem?.type === 'image' && posItem?.SignUrl) {
|
if (
|
||||||
const validUrl = await getPresignedUrl(posItem?.SignUrl);
|
(posItem?.type === 'image' || posItem?.type === 'draw') &&
|
||||||
|
posItem?.options?.response
|
||||||
|
) {
|
||||||
|
const validUrl = await getPresignedUrl(posItem?.options?.response);
|
||||||
updatedPos.push({
|
updatedPos.push({
|
||||||
...posItem,
|
...posItem,
|
||||||
SignUrl: validUrl,
|
...(item.SignUrl !== undefined && { SignUrl: validUrl }),
|
||||||
options: { ...posItem.options, response: validUrl },
|
options: { ...posItem.options, response: validUrl },
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
updatedPos.push(posItem);
|
updatedPos.push(posItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updatedRole.push({
|
updatedRole.push({ ...item, pos: updatedPos });
|
||||||
...item,
|
|
||||||
pos: updatedPos,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedPlaceholders.push({
|
updatedPlaceholders.push({ ...placeholder, signerPtr, placeHolder: updatedRole });
|
||||||
...placeholder,
|
|
||||||
signerPtr,
|
|
||||||
placeHolder: updatedRole,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
// Not prefill role, just push as-is
|
// Not prefill role, just push as-is
|
||||||
updatedPlaceholders.push({
|
updatedPlaceholders.push({ ...placeholder, signerPtr });
|
||||||
...placeholder,
|
|
||||||
signerPtr,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return updatedPlaceholders;
|
return updatedPlaceholders;
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ import manageSign from './parsefunction/manageSign.js';
|
|||||||
import getSignature from './parsefunction/getSignature.js';
|
import getSignature from './parsefunction/getSignature.js';
|
||||||
import updateEmailTemplates from './parsefunction/updateEmailTemplates.js';
|
import updateEmailTemplates from './parsefunction/updateEmailTemplates.js';
|
||||||
import triggerEvent from './parsefunction/triggerEvent.js';
|
import triggerEvent from './parsefunction/triggerEvent.js';
|
||||||
|
import setWidgetPreferences from './parsefunction/setWidgetPreferences.js';
|
||||||
|
|
||||||
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
|
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
|
||||||
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
|
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
|
||||||
@@ -134,3 +135,4 @@ Parse.Cloud.define('managesign', manageSign);
|
|||||||
Parse.Cloud.define('getdefaultsignature', getSignature);
|
Parse.Cloud.define('getdefaultsignature', getSignature);
|
||||||
Parse.Cloud.define('updateemailtemplates', updateEmailTemplates);
|
Parse.Cloud.define('updateemailtemplates', updateEmailTemplates);
|
||||||
Parse.Cloud.define('triggerevent', triggerEvent);
|
Parse.Cloud.define('triggerevent', triggerEvent);
|
||||||
|
Parse.Cloud.define('setwidgetpreferences', setWidgetPreferences);
|
||||||
|
|||||||
@@ -2,59 +2,23 @@ async function DocumentAftersave(request) {
|
|||||||
try {
|
try {
|
||||||
if (!request.original) {
|
if (!request.original) {
|
||||||
console.log('new entry is insert in contracts_Document');
|
console.log('new entry is insert in contracts_Document');
|
||||||
const createdAt = request.object.get('createdAt');
|
const obj = request.object;
|
||||||
const Folder = request.object.get('Type');
|
const objId = obj?.id;
|
||||||
|
const createdAt = obj?.get?.('createdAt');
|
||||||
|
const folder = obj?.get?.('Type');
|
||||||
const ip = request?.headers?.['x-real-ip'] || '';
|
const ip = request?.headers?.['x-real-ip'] || '';
|
||||||
const originIp = request?.object?.get('OriginIp') || '';
|
const originIp = obj?.get?.('OriginIp') || '';
|
||||||
if (createdAt && Folder === undefined) {
|
if (createdAt) {
|
||||||
// console.log("IN If condition")
|
await updateDocumentMeta({ objId, createdAt, folder, ip, originIp });
|
||||||
const TimeToCompleteDays = request.object.get('TimeToCompleteDays') || 15;
|
|
||||||
const ExpiryDate = new Date(createdAt);
|
|
||||||
ExpiryDate.setDate(ExpiryDate.getDate() + TimeToCompleteDays);
|
|
||||||
const documentQuery = new Parse.Query('contracts_Document');
|
|
||||||
documentQuery.include('ExtUserPtr.TenantId');
|
|
||||||
const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true });
|
|
||||||
updateQuery.set('ExpiryDate', ExpiryDate);
|
|
||||||
if (!originIp) {
|
|
||||||
updateQuery.set('OriginIp', ip);
|
|
||||||
}
|
|
||||||
const AutoReminder = request?.object?.get('AutomaticReminders') || false;
|
|
||||||
if (AutoReminder) {
|
|
||||||
const RemindOnceInEvery = request?.object?.get('RemindOnceInEvery') || 5;
|
|
||||||
const ReminderDate = new Date(createdAt);
|
|
||||||
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
|
||||||
updateQuery.set('NextReminderDate', ReminderDate);
|
|
||||||
}
|
|
||||||
await updateQuery.save(null, { useMasterKey: true });
|
|
||||||
} else if (createdAt && Folder === 'AIDoc') {
|
|
||||||
const TimeToCompleteDays = request.object.get('TimeToCompleteDays');
|
|
||||||
const ExpiryDate = new Date(createdAt);
|
|
||||||
ExpiryDate.setDate(ExpiryDate.getDate() + TimeToCompleteDays);
|
|
||||||
const documentQuery = new Parse.Query('contracts_Document');
|
|
||||||
documentQuery.include('ExtUserPtr.TenantId');
|
|
||||||
const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true });
|
|
||||||
updateQuery.set('ExpiryDate', ExpiryDate);
|
|
||||||
if (!originIp) {
|
|
||||||
updateQuery.set('OriginIp', ip);
|
|
||||||
}
|
|
||||||
const AutoReminder = request?.object?.get('AutomaticReminders') || false;
|
|
||||||
if (AutoReminder) {
|
|
||||||
const RemindOnceInEvery = request?.object?.get('RemindOnceInEvery') || 5;
|
|
||||||
const ReminderDate = new Date(createdAt);
|
|
||||||
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
|
||||||
updateQuery.set('NextReminderDate', ReminderDate);
|
|
||||||
}
|
|
||||||
await updateQuery.save(null, { useMasterKey: true });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const signers = request.object.get('Signers');
|
const signers = obj?.get?.('Signers');
|
||||||
|
const hasSigners = Array.isArray(signers) && signers.length > 0;
|
||||||
// update acl of New Document If There are signers present in array
|
// update acl of New Document If There are signers present in array
|
||||||
if (signers && signers.length > 0) {
|
if (hasSigners) {
|
||||||
await updateAclDoc(request.object.id);
|
await updateAclDoc(objId);
|
||||||
} else {
|
} else if (objId && request?.user) {
|
||||||
if (request?.object?.id && request.user) {
|
await updateSelfDoc(objId);
|
||||||
await updateSelfDoc(request.object.id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (request?.user) {
|
if (request?.user) {
|
||||||
@@ -73,17 +37,49 @@ async function DocumentAftersave(request) {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateDocumentMeta({ objId, createdAt, folder, ip, originIp }) {
|
||||||
|
const documentQuery = new Parse.Query('contracts_Document');
|
||||||
|
documentQuery.include('ExtUserPtr.TenantId');
|
||||||
|
|
||||||
|
const doc = await documentQuery.get(objId, { useMasterKey: true });
|
||||||
|
if (folder === undefined || folder === 'AIDoc') {
|
||||||
|
// ExpiryDate
|
||||||
|
const timeToCompleteDays =
|
||||||
|
folder === undefined
|
||||||
|
? doc.get('TimeToCompleteDays') || 15 // keep your default=15 only for "undefined folder"
|
||||||
|
: doc.get('TimeToCompleteDays'); // keep original behavior for AIDoc (no forced default)
|
||||||
|
|
||||||
|
if (typeof timeToCompleteDays === 'number' && createdAt) {
|
||||||
|
const expiryDate = new Date(createdAt);
|
||||||
|
expiryDate.setDate(expiryDate.getDate() + timeToCompleteDays);
|
||||||
|
doc.set('ExpiryDate', expiryDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OriginIp
|
||||||
|
if (!originIp) {
|
||||||
|
doc.set('OriginIp', ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Automatic reminders
|
||||||
|
const autoReminder = doc.get('AutomaticReminders') || false;
|
||||||
|
if (autoReminder && createdAt) {
|
||||||
|
const remindOnceInEvery = doc.get('RemindOnceInEvery') || 5;
|
||||||
|
const reminderDate = new Date(createdAt);
|
||||||
|
reminderDate.setDate(reminderDate.getDate() + remindOnceInEvery);
|
||||||
|
doc.set('NextReminderDate', reminderDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await doc.save(null, { useMasterKey: true });
|
||||||
|
}
|
||||||
|
|
||||||
async function updateAclDoc(objId) {
|
async function updateAclDoc(objId) {
|
||||||
// console.log("In side updateAclDoc func")
|
|
||||||
// console.log(objId)
|
|
||||||
const Query = new Parse.Query('contracts_Document');
|
const Query = new Parse.Query('contracts_Document');
|
||||||
Query.include('Signers');
|
Query.include('Signers');
|
||||||
Query.include('ExtUserPtr.TenantId');
|
Query.include('ExtUserPtr.TenantId');
|
||||||
Query.include('CreatedBy');
|
Query.include('CreatedBy');
|
||||||
const updateACL = await Query.get(objId, { useMasterKey: true });
|
const updateACL = await Query.get(objId, { useMasterKey: true });
|
||||||
const res = JSON.parse(JSON.stringify(updateACL));
|
const res = JSON.parse(JSON.stringify(updateACL));
|
||||||
// console.log("res");
|
|
||||||
// console.log(JSON.stringify(res));
|
|
||||||
const UsersPtr = res.Signers.map(item => item.UserId);
|
const UsersPtr = res.Signers.map(item => item.UserId);
|
||||||
|
|
||||||
if (res.Signers[0].ExtUserPtr) {
|
if (res.Signers[0].ExtUserPtr) {
|
||||||
@@ -97,8 +93,6 @@ async function DocumentAftersave(request) {
|
|||||||
updateACL.set('Signers', ExtUserSigners);
|
updateACL.set('Signers', ExtUserSigners);
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log("UsersPtr")
|
|
||||||
// console.log(JSON.stringify(UsersPtr))
|
|
||||||
const newACL = new Parse.ACL();
|
const newACL = new Parse.ACL();
|
||||||
newACL.setPublicReadAccess(false);
|
newACL.setPublicReadAccess(false);
|
||||||
newACL.setPublicWriteAccess(false);
|
newACL.setPublicWriteAccess(false);
|
||||||
@@ -116,14 +110,11 @@ async function DocumentAftersave(request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function updateSelfDoc(objId) {
|
async function updateSelfDoc(objId) {
|
||||||
// console.log(objId)
|
|
||||||
const Query = new Parse.Query('contracts_Document');
|
const Query = new Parse.Query('contracts_Document');
|
||||||
Query.include('CreatedBy');
|
Query.include('CreatedBy');
|
||||||
Query.include('ExtUserPtr.TenantId');
|
Query.include('ExtUserPtr.TenantId');
|
||||||
const updateACL = await Query.get(objId, { useMasterKey: true });
|
const updateACL = await Query.get(objId, { useMasterKey: true });
|
||||||
const res = JSON.parse(JSON.stringify(updateACL));
|
const res = JSON.parse(JSON.stringify(updateACL));
|
||||||
// console.log("res");
|
|
||||||
// console.log(JSON.stringify(res));
|
|
||||||
const newACL = new Parse.ACL();
|
const newACL = new Parse.ACL();
|
||||||
newACL.setPublicReadAccess(false);
|
newACL.setPublicReadAccess(false);
|
||||||
newACL.setPublicWriteAccess(false);
|
newACL.setPublicWriteAccess(false);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { MAX_DESCRIPTION_LENGTH, MAX_NAME_LENGTH, MAX_NOTE_LENGTH } from '../../Utils.js';
|
import { MAX_DESCRIPTION_LENGTH, MAX_NAME_LENGTH, MAX_NOTE_LENGTH } from '../../Utils.js';
|
||||||
|
import { setDocumentCount } from '../../utils/CountUtils.js';
|
||||||
|
|
||||||
async function DocumentBeforesave(request) {
|
async function DocumentBeforesave(request) {
|
||||||
if (!request.original) {
|
if (!request.original) {
|
||||||
@@ -33,24 +34,8 @@ async function DocumentBeforesave(request) {
|
|||||||
|
|
||||||
// Check if SignedUrl field has been added (transition from undefined to defined)
|
// Check if SignedUrl field has been added (transition from undefined to defined)
|
||||||
if (oldDocument && !oldDocument?.get('SignedUrl') && document?.get('SignedUrl')) {
|
if (oldDocument && !oldDocument?.get('SignedUrl') && document?.get('SignedUrl')) {
|
||||||
// Update count in contracts_Users class
|
if (oldDocument?.get('ExtUserPtr')?.id) {
|
||||||
const query = new Parse.Query('contracts_Users');
|
setDocumentCount(oldDocument?.get('ExtUserPtr')?.id);
|
||||||
query.equalTo('objectId', oldDocument.get('ExtUserPtr').id);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const contractUser = await query.first({ useMasterKey: true });
|
|
||||||
if (contractUser) {
|
|
||||||
contractUser.increment('DocumentCount', 1);
|
|
||||||
await contractUser.save(null, { useMasterKey: true });
|
|
||||||
} else {
|
|
||||||
// Create new entry if not found
|
|
||||||
const ContractsUsers = Parse.Object.extend('contracts_Users');
|
|
||||||
const newContractUser = new ContractsUsers();
|
|
||||||
newContractUser.set('DocumentCount', 1);
|
|
||||||
await newContractUser.save(null, { useMasterKey: true });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log('Error updating document count in contracts_Users: ' + error.message);
|
|
||||||
}
|
}
|
||||||
if (document?.get('Signers') && document.get('Signers').length > 0) {
|
if (document?.get('Signers') && document.get('Signers').length > 0) {
|
||||||
document.set('DocSentAt', new Date());
|
document.set('DocSentAt', new Date());
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export default async function forwardDoc(request) {
|
|||||||
let mailRes;
|
let mailRes;
|
||||||
for (let i = 0; i < recipients.length; i++) {
|
for (let i = 0; i < recipients.length; i++) {
|
||||||
const logo = `<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>`;
|
const logo = `<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>`;
|
||||||
const opurl = ` <a href='www.opensignlabs.com' target=_blank>here</a>`;
|
const opurl = ` <a href='mailto:complaint@opensiglabs.com' target=_blank>here</a>`;
|
||||||
const themeColor = '#47a3ad';
|
const themeColor = '#47a3ad';
|
||||||
|
|
||||||
let params = {
|
let params = {
|
||||||
@@ -52,7 +52,7 @@ export default async function forwardDoc(request) {
|
|||||||
`${logo}</div><div style='padding:2px;font-family:system-ui;background-color:${themeColor}'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document Copy</p></div><div>` +
|
`${logo}</div><div style='padding:2px;font-family:system-ui;background-color:${themeColor}'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document Copy</p></div><div>` +
|
||||||
`<p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document <strong>${docName}</strong> is attached to this email. Kindly download the document from the attachment.</p>` +
|
`<p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document <strong>${docName}</strong> is attached to this email. Kindly download the document from the attachment.</p>` +
|
||||||
`</div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, please contact the sender ${replyTo} directly. ` +
|
`</div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, please contact the sender ${replyTo} directly. ` +
|
||||||
`If you think this email is inappropriate or spam, you may file a complaint with ${TenantAppName}${opurl}.</p></div></div></body></html>`,
|
`If you think this email is inappropriate or spam, you may file a complaints with ${TenantAppName}${opurl}.</p></div></div></body></html>`,
|
||||||
};
|
};
|
||||||
mailRes = await axios.post(`${cloudServerUrl}/functions/sendmailv3`, params, {
|
mailRes = await axios.post(`${cloudServerUrl}/functions/sendmailv3`, params, {
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -8,12 +8,16 @@ async function SignatureAfterFind(request) {
|
|||||||
const obj = request.objects[0];
|
const obj = request.objects[0];
|
||||||
const ImageURL = obj?.get('ImageURL') && obj?.get('ImageURL');
|
const ImageURL = obj?.get('ImageURL') && obj?.get('ImageURL');
|
||||||
const Initials = obj?.get('Initials') && obj?.get('Initials');
|
const Initials = obj?.get('Initials') && obj?.get('Initials');
|
||||||
|
const Stamp = obj?.get('Stamp') && obj?.get('Stamp');
|
||||||
if (ImageURL) {
|
if (ImageURL) {
|
||||||
obj.set('ImageURL', getPresignedUrl(ImageURL));
|
obj.set('ImageURL', getPresignedUrl(ImageURL));
|
||||||
}
|
}
|
||||||
if (Initials) {
|
if (Initials) {
|
||||||
obj.set('Initials', getPresignedUrl(Initials));
|
obj.set('Initials', getPresignedUrl(Initials));
|
||||||
}
|
}
|
||||||
|
if (Stamp) {
|
||||||
|
obj.set('Stamp', getPresignedUrl(Stamp));
|
||||||
|
}
|
||||||
return [obj];
|
return [obj];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,12 +27,16 @@ async function SignatureAfterFind(request) {
|
|||||||
const obj = request.objects[0];
|
const obj = request.objects[0];
|
||||||
const ImageURL = obj?.get('ImageURL') && obj?.get('ImageURL');
|
const ImageURL = obj?.get('ImageURL') && obj?.get('ImageURL');
|
||||||
const Initials = obj?.get('Initials') && obj?.get('Initials');
|
const Initials = obj?.get('Initials') && obj?.get('Initials');
|
||||||
|
const Stamp = obj?.get('Stamp') && obj?.get('Stamp');
|
||||||
if (ImageURL) {
|
if (ImageURL) {
|
||||||
obj.set('ImageURL', presignedlocalUrl(ImageURL));
|
obj.set('ImageURL', presignedlocalUrl(ImageURL));
|
||||||
}
|
}
|
||||||
if (Initials) {
|
if (Initials) {
|
||||||
obj.set('Initials', presignedlocalUrl(Initials));
|
obj.set('Initials', presignedlocalUrl(Initials));
|
||||||
}
|
}
|
||||||
|
if (Stamp) {
|
||||||
|
obj.set('Stamp', presignedlocalUrl(Stamp));
|
||||||
|
}
|
||||||
return [obj];
|
return [obj];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,27 +2,20 @@ export default async function TemplateAfterSave(request) {
|
|||||||
try {
|
try {
|
||||||
if (!request.original) {
|
if (!request.original) {
|
||||||
console.log('new entry is insert in contracts_Template');
|
console.log('new entry is insert in contracts_Template');
|
||||||
// update acl of New Document If There are signers present in array
|
const obj = request.object;
|
||||||
const signers = request.object.get('Signers');
|
const objId = obj?.id;
|
||||||
const AutoReminder = request?.object?.get('AutomaticReminders') || false;
|
|
||||||
const ip = request?.headers?.['x-real-ip'] || '';
|
const ip = request?.headers?.['x-real-ip'] || '';
|
||||||
const originIp = request?.object?.get('OriginIp') || '';
|
const originIp = obj?.get?.('OriginIp') || '';
|
||||||
if (AutoReminder) {
|
const createdAt = obj?.get?.('createdAt');
|
||||||
const RemindOnceInEvery = request?.object?.get('RemindOnceInEvery') || 5;
|
|
||||||
const ReminderDate = new Date(request?.object?.get('createdAt'));
|
// update acl of New template If There are signers present in array
|
||||||
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
const signers = obj?.get('Signers');
|
||||||
request.object.set('NextReminderDate', ReminderDate);
|
const hasSigners = Array.isArray(signers) && signers.length > 0;
|
||||||
}
|
updateTemplateMeta({ objId, createdAt, ip, originIp });
|
||||||
if (!originIp) {
|
if (hasSigners) {
|
||||||
request.object.set('OriginIp', ip);
|
await updateAclDoc(objId);
|
||||||
}
|
} else if (objId && request?.user) {
|
||||||
await request.object.save(null, { useMasterKey: true });
|
await updateSelfDoc(objId);
|
||||||
if (signers && signers.length > 0) {
|
|
||||||
await updateAclDoc(request.object.id);
|
|
||||||
} else {
|
|
||||||
if (request?.object?.id && request?.user) {
|
|
||||||
await updateSelfDoc(request.object.id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (request?.user) {
|
if (request?.user) {
|
||||||
@@ -41,17 +34,33 @@ export default async function TemplateAfterSave(request) {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateTemplateMeta({ objId, createdAt, ip, originIp }) {
|
||||||
|
const templateQuery = new Parse.Query('contracts_Template');
|
||||||
|
templateQuery.include('ExtUserPtr.TenantId');
|
||||||
|
|
||||||
|
const obj = await templateQuery.get(objId, { useMasterKey: true });
|
||||||
|
|
||||||
|
// Automatic reminders
|
||||||
|
const AutoReminder = obj?.get('AutomaticReminders') || false;
|
||||||
|
if (AutoReminder) {
|
||||||
|
const RemindOnceInEvery = obj?.get('RemindOnceInEvery') || 5;
|
||||||
|
const ReminderDate = new Date(createdAt);
|
||||||
|
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
||||||
|
obj.set('NextReminderDate', ReminderDate);
|
||||||
|
}
|
||||||
|
if (!originIp) {
|
||||||
|
obj.set('OriginIp', ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
await obj.save(null, { useMasterKey: true });
|
||||||
|
}
|
||||||
async function updateAclDoc(objId) {
|
async function updateAclDoc(objId) {
|
||||||
// console.log("In side updateAclDoc func")
|
|
||||||
// console.log(objId)
|
|
||||||
const Query = new Parse.Query('contracts_Template');
|
const Query = new Parse.Query('contracts_Template');
|
||||||
Query.include('Signers');
|
Query.include('Signers');
|
||||||
Query.include('CreatedBy');
|
Query.include('CreatedBy');
|
||||||
Query.include('ExtUserPtr.TenantId');
|
Query.include('ExtUserPtr.TenantId');
|
||||||
const updateACL = await Query.get(objId, { useMasterKey: true });
|
const updateACL = await Query.get(objId, { useMasterKey: true });
|
||||||
const res = JSON.parse(JSON.stringify(updateACL));
|
const res = JSON.parse(JSON.stringify(updateACL));
|
||||||
// console.log("res");
|
|
||||||
// console.log(JSON.stringify(res));
|
|
||||||
const UsersPtr = res.Signers.map(item => item.UserId);
|
const UsersPtr = res.Signers.map(item => item.UserId);
|
||||||
|
|
||||||
if (res.Signers[0].ExtUserPtr) {
|
if (res.Signers[0].ExtUserPtr) {
|
||||||
@@ -65,8 +74,6 @@ export default async function TemplateAfterSave(request) {
|
|||||||
updateACL.set('Signers', ExtUserSigners);
|
updateACL.set('Signers', ExtUserSigners);
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log("UsersPtr")
|
|
||||||
// console.log(JSON.stringify(UsersPtr))
|
|
||||||
const newACL = new Parse.ACL();
|
const newACL = new Parse.ACL();
|
||||||
newACL.setPublicReadAccess(false);
|
newACL.setPublicReadAccess(false);
|
||||||
newACL.setPublicWriteAccess(false);
|
newACL.setPublicWriteAccess(false);
|
||||||
@@ -85,15 +92,11 @@ export default async function TemplateAfterSave(request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function updateSelfDoc(objId) {
|
async function updateSelfDoc(objId) {
|
||||||
// console.log("Inside updateSelfDoc func")
|
|
||||||
|
|
||||||
const Query = new Parse.Query('contracts_Template');
|
const Query = new Parse.Query('contracts_Template');
|
||||||
Query.include('CreatedBy');
|
Query.include('CreatedBy');
|
||||||
Query.include('ExtUserPtr.TenantId');
|
Query.include('ExtUserPtr.TenantId');
|
||||||
const updateACL = await Query.get(objId, { useMasterKey: true });
|
const updateACL = await Query.get(objId, { useMasterKey: true });
|
||||||
const res = JSON.parse(JSON.stringify(updateACL));
|
const res = JSON.parse(JSON.stringify(updateACL));
|
||||||
// console.log("res");
|
|
||||||
// console.log(JSON.stringify(res));
|
|
||||||
const newACL = new Parse.ACL();
|
const newACL = new Parse.ACL();
|
||||||
newACL.setPublicReadAccess(false);
|
newACL.setPublicReadAccess(false);
|
||||||
newACL.setPublicWriteAccess(false);
|
newACL.setPublicWriteAccess(false);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { MAX_DESCRIPTION_LENGTH, MAX_NAME_LENGTH, MAX_NOTE_LENGTH } from '../../Utils.js';
|
import { MAX_DESCRIPTION_LENGTH, MAX_NAME_LENGTH, MAX_NOTE_LENGTH } from '../../Utils.js';
|
||||||
|
import { setTemplateCount } from '../../utils/CountUtils.js';
|
||||||
|
|
||||||
async function TemplateBeforeSave(request) {
|
async function TemplateBeforeSave(request) {
|
||||||
if (!request.original) {
|
if (!request.original) {
|
||||||
@@ -31,24 +32,8 @@ async function TemplateBeforeSave(request) {
|
|||||||
// below code is used to update template when user sent template or self signed
|
// below code is used to update template when user sent template or self signed
|
||||||
const template = request.object;
|
const template = request.object;
|
||||||
|
|
||||||
// Update count in contracts_Users class
|
if (template?.get('ExtUserPtr')?.id) {
|
||||||
const query = new Parse.Query('contracts_Users');
|
setTemplateCount(template?.get('ExtUserPtr')?.id);
|
||||||
query.equalTo('objectId', template.get('ExtUserPtr').id);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const contractUser = await query.first({ useMasterKey: true });
|
|
||||||
if (contractUser) {
|
|
||||||
contractUser.increment('TemplateCount', 1);
|
|
||||||
await contractUser.save(null, { useMasterKey: true });
|
|
||||||
} else {
|
|
||||||
// Create new entry if not found
|
|
||||||
const ContractsUsers = Parse.Object.extend('contracts_Users');
|
|
||||||
const newContractUser = new ContractsUsers();
|
|
||||||
newContractUser.set('TemplateCount', 1);
|
|
||||||
await newContractUser.save(null, { useMasterKey: true });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log('Error updating template count in contracts_Users: ' + error.message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { cloudServerUrl, mailTemplate, replaceMailVaribles, serverAppId } from '../../Utils.js';
|
import { cloudServerUrl, mailTemplate, replaceMailVaribles, serverAppId } from '../../Utils.js';
|
||||||
|
import { setDocumentCount } from '../../utils/CountUtils.js';
|
||||||
|
|
||||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||||
const appId = serverAppId;
|
const appId = serverAppId;
|
||||||
async function deductcount(docsCount, extUserId) {
|
async function deductcount(docsCount, extUserId) {
|
||||||
try {
|
try {
|
||||||
const extCls = new Parse.Object('contracts_Users');
|
if (extUserId) {
|
||||||
extCls.id = extUserId;
|
setDocumentCount(extUserId);
|
||||||
extCls.increment('DocumentCount', docsCount);
|
}
|
||||||
const resExt = await extCls.save(null, { useMasterKey: true });
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('Err in deduct in quick send', err);
|
console.log('Err in deduct in quick send', err);
|
||||||
}
|
}
|
||||||
@@ -101,11 +102,7 @@ async function sendMail(document, publicUrl) {
|
|||||||
}
|
}
|
||||||
async function batchQuery(userId, Documents, Ip, parseConfig, type, publicUrl) {
|
async function batchQuery(userId, Documents, Ip, parseConfig, type, publicUrl) {
|
||||||
const extCls = new Parse.Query('contracts_Users');
|
const extCls = new Parse.Query('contracts_Users');
|
||||||
extCls.equalTo('UserId', {
|
extCls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
|
||||||
__type: 'Pointer',
|
|
||||||
className: '_User',
|
|
||||||
objectId: userId,
|
|
||||||
});
|
|
||||||
const resExt = await extCls.first({ useMasterKey: true });
|
const resExt = await extCls.first({ useMasterKey: true });
|
||||||
if (resExt) {
|
if (resExt) {
|
||||||
const _resExt = JSON.parse(JSON.stringify(resExt));
|
const _resExt = JSON.parse(JSON.stringify(resExt));
|
||||||
@@ -189,6 +186,7 @@ async function batchQuery(userId, Documents, Ip, parseConfig, type, publicUrl) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
|
...(x?.PenColors?.length > 0 ? { PenColors: x?.PenColors } : {}),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ async function sendDeclineMail(doc, publicUrl, userId, reason) {
|
|||||||
const TenantAppName = appName;
|
const TenantAppName = appName;
|
||||||
const logo =
|
const logo =
|
||||||
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
|
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
|
||||||
const opurl = ` <a href=www.opensignlabs.com target=_blank>here</a>`;
|
const opurl = ` <a href='mailto:complaint@opensiglabs.com' target=_blank>here</a>`;
|
||||||
const removePrefill =
|
const removePrefill =
|
||||||
doc?.Placeholders?.length > 0 && doc?.Placeholders?.filter(x => x?.Role !== 'prefill');
|
doc?.Placeholders?.length > 0 && doc?.Placeholders?.filter(x => x?.Role !== 'prefill');
|
||||||
const signUser =
|
const signUser =
|
||||||
@@ -36,7 +36,7 @@ async function sendDeclineMail(doc, publicUrl, userId, reason) {
|
|||||||
`<p>${pdfName} has been declined by ${signerName} "${signerEmail}" on ${new Date().toLocaleDateString()}.</p>` +
|
`<p>${pdfName} has been declined by ${signerName} "${signerEmail}" on ${new Date().toLocaleDateString()}.</p>` +
|
||||||
`<p>Decline Reason: ${reason || 'Not specified'}</p>` +
|
`<p>Decline Reason: ${reason || 'Not specified'}</p>` +
|
||||||
`<p><a href=${viewDocUrl} target=_blank>View Document</a></p></div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, ` +
|
`<p><a href=${viewDocUrl} target=_blank>View Document</a></p></div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, ` +
|
||||||
`please contact the sender ${creatorEmail} directly. If you think this email is inappropriate or spam, you may file a complaint with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
|
`please contact the sender ${creatorEmail} directly. If you think this email is inappropriate or spam, you may file a complaints with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
extUserId: sender.objectId,
|
extUserId: sender.objectId,
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import { cloudServerUrl, serverAppId } from '../../Utils.js';
|
import { cloudServerUrl, serverAppId } from '../../Utils.js';
|
||||||
import reportJson from './reportsJson.js';
|
import reportJson, { applySearch } from './reportsJson.js';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
function buildClassesUrl({ serverUrl, clsName, paramsObj, keys, orderBy, skip, limit, include }) {
|
||||||
// Escape regex special characters. Copied from filterDocs.js
|
const url = new URL(`${serverUrl}/classes/${clsName}`);
|
||||||
function escapeRegExp(str) {
|
url.searchParams.set('where', JSON.stringify(paramsObj));
|
||||||
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
url.searchParams.set('keys', keys.join(','));
|
||||||
|
url.searchParams.set('order', orderBy);
|
||||||
|
url.searchParams.set('skip', String(skip));
|
||||||
|
url.searchParams.set('limit', String(limit));
|
||||||
|
if (include) url.searchParams.set('include', include);
|
||||||
|
return url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function getReport(request) {
|
export default async function getReport(request) {
|
||||||
const reportId = request.params.reportId;
|
const reportId = request.params.reportId;
|
||||||
const limit = request.params.limit;
|
const limit = request.params.limit;
|
||||||
@@ -25,78 +29,76 @@ export default async function getReport(request) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const userId = userRes.data && userRes.data.objectId;
|
const userId = userRes.data && userRes.data.objectId;
|
||||||
if (userId) {
|
if (!userId) {
|
||||||
const json = reportId && reportJson(reportId, userId);
|
return { error: 'Invalid session token' };
|
||||||
const clsName = json?.reportClass ? json.reportClass : 'contracts_Document';
|
}
|
||||||
if (json) {
|
const json = reportId && reportJson(reportId, userId);
|
||||||
const { params, keys } = json;
|
if (json) {
|
||||||
const orderBy = '-updatedAt';
|
let paramsObj = { ...(json.params || {}) };
|
||||||
const strKeys = keys.join();
|
if (reportId == '6TeaPr321t') {
|
||||||
let paramsObj = { ...params };
|
const extUserQuery = new Parse.Query('contracts_Users');
|
||||||
if (reportId == '6TeaPr321t') {
|
extUserQuery.equalTo('Email', userRes.data.email);
|
||||||
const extUserQuery = new Parse.Query('contracts_Users');
|
extUserQuery.include('TeamIds');
|
||||||
extUserQuery.equalTo('Email', userRes.data.email);
|
const extUser = await extUserQuery.first({ useMasterKey: true });
|
||||||
extUserQuery.include('TeamIds');
|
const userPtr = { __type: 'Pointer', className: '_User', objectId: userId };
|
||||||
const extUser = await extUserQuery.first({ useMasterKey: true });
|
if (!extUser) {
|
||||||
if (extUser) {
|
paramsObj = { ...paramsObj, CreatedBy: userPtr };
|
||||||
const _extUser = JSON.parse(JSON.stringify(extUser));
|
|
||||||
if (_extUser?.TeamIds && _extUser.TeamIds?.length > 0) {
|
|
||||||
let teamArr = [];
|
|
||||||
_extUser?.TeamIds?.forEach(x => (teamArr = [...teamArr, ...x.Ancestors]));
|
|
||||||
paramsObj = {
|
|
||||||
...paramsObj,
|
|
||||||
$or: [
|
|
||||||
{ SharedWith: { $in: teamArr } },
|
|
||||||
{
|
|
||||||
ExtUserPtr: {
|
|
||||||
__type: 'Pointer',
|
|
||||||
className: 'contracts_Users',
|
|
||||||
objectId: extUser.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
SharedWithUsers: {
|
|
||||||
__type: 'Pointer',
|
|
||||||
className: 'contracts_Users',
|
|
||||||
objectId: extUser.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
paramsObj = {
|
|
||||||
...paramsObj,
|
|
||||||
CreatedBy: { __type: 'Pointer', className: '_User', objectId: userId },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (searchTerm) {
|
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||||
const escaped = escapeRegExp(searchTerm);
|
const extPtr = { __type: 'Pointer', className: 'contracts_Users', objectId: extUser.id };
|
||||||
|
if (_extUser?.TeamIds && _extUser.TeamIds?.length > 0) {
|
||||||
|
// Collect ancestors efficiently + de-dupe
|
||||||
|
const teamSet = new Set();
|
||||||
|
for (const team of _extUser?.TeamIds) {
|
||||||
|
const ancestors = team.Ancestors || [];
|
||||||
|
for (const a of ancestors) teamSet.add(a);
|
||||||
|
}
|
||||||
|
const teamArr = [...teamSet];
|
||||||
paramsObj = {
|
paramsObj = {
|
||||||
...paramsObj,
|
...paramsObj,
|
||||||
Name: { $regex: `.*${escaped}.*`, $options: 'i' },
|
$or: [
|
||||||
|
{ SharedWith: { $in: teamArr } },
|
||||||
|
{ ExtUserPtr: extPtr },
|
||||||
|
{ SharedWithUsers: extPtr },
|
||||||
|
],
|
||||||
};
|
};
|
||||||
}
|
|
||||||
const strParams = JSON.stringify(paramsObj);
|
|
||||||
const headers = {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-Parse-Application-Id': appId,
|
|
||||||
'X-Parse-Master-Key': masterKey,
|
|
||||||
};
|
|
||||||
const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr,Placeholders.signerPtr,ExtUserPtr.TenantId`;
|
|
||||||
const res = await axios.get(url, { headers: headers });
|
|
||||||
if (res.data && res.data.results) {
|
|
||||||
return res.data.results;
|
|
||||||
} else {
|
} else {
|
||||||
return [];
|
paramsObj = { ...paramsObj, CreatedBy: userPtr };
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return { error: 'Report is not available!' };
|
|
||||||
}
|
}
|
||||||
|
paramsObj = applySearch({ reportId, baseWhere: paramsObj, searchTerm });
|
||||||
|
const headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Parse-Application-Id': appId,
|
||||||
|
'X-Parse-Master-Key': masterKey,
|
||||||
|
};
|
||||||
|
|
||||||
|
const clsName = json?.reportClass ? json.reportClass : 'contracts_Document';
|
||||||
|
const orderBy = '-updatedAt';
|
||||||
|
const include = 'AuditTrail.UserPtr,Placeholders.signerPtr,ExtUserPtr.TenantId';
|
||||||
|
|
||||||
|
const url = buildClassesUrl({
|
||||||
|
serverUrl,
|
||||||
|
clsName,
|
||||||
|
paramsObj,
|
||||||
|
keys: json.keys || [],
|
||||||
|
orderBy,
|
||||||
|
skip,
|
||||||
|
limit,
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
const res = await axios.get(url, { headers: headers });
|
||||||
|
if (res.data && res.data.results) {
|
||||||
|
return res.data.results;
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { error: 'Report is not available!' };
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err', err.message);
|
const message = err?.response?.data?.error || err?.message || 'Something went wrong';
|
||||||
|
console.log('getreport error:', message);
|
||||||
if (err.code == 209) {
|
if (err.code == 209) {
|
||||||
return { error: 'Invalid session token' };
|
return { error: 'Invalid session token' };
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export default async function manageSign(request) {
|
export default async function manageSign(request) {
|
||||||
const { signature, userId, initials, id, title } = request.params;
|
const { signature, userId, initials, id, title, stamp } = request.params;
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Missing userId parameter.');
|
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Missing userId parameter.');
|
||||||
@@ -16,6 +16,7 @@ export default async function manageSign(request) {
|
|||||||
signatureCls.set('Initials', initials ? initials : '');
|
signatureCls.set('Initials', initials ? initials : '');
|
||||||
signatureCls.set('ImageURL', signature ? signature : '');
|
signatureCls.set('ImageURL', signature ? signature : '');
|
||||||
signatureCls.set('SignatureName', title ? title : '');
|
signatureCls.set('SignatureName', title ? title : '');
|
||||||
|
signatureCls.set('Stamp', stamp ? stamp : '');
|
||||||
if (userPtr) {
|
if (userPtr) {
|
||||||
signatureCls.set('UserId', userPtr);
|
signatureCls.set('UserId', userPtr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ async function sendNotifyMail(doc, signUser, mailProvider, publicUrl) {
|
|||||||
const TenantAppName = appName;
|
const TenantAppName = appName;
|
||||||
const logo =
|
const logo =
|
||||||
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
|
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
|
||||||
const opurl = ` <a href=www.opensignlabs.com target=_blank>here</a>`;
|
const opurl = ` <a href='mailto:complaint@opensiglabs.com' target=_blank>here</a>`;
|
||||||
const auditTrailCount = doc?.AuditTrail?.filter(x => x.Activity === 'Signed')?.length || 0;
|
const auditTrailCount = doc?.AuditTrail?.filter(x => x.Activity === 'Signed')?.length || 0;
|
||||||
const removePrefill =
|
const removePrefill =
|
||||||
doc?.Placeholders?.length > 0 && doc?.Placeholders?.filter(x => x?.Role !== 'prefill');
|
doc?.Placeholders?.length > 0 && doc?.Placeholders?.filter(x => x?.Role !== 'prefill');
|
||||||
@@ -142,7 +142,7 @@ async function sendNotifyMail(doc, signUser, mailProvider, publicUrl) {
|
|||||||
`<div>${logo}</div><div style='padding:2px;font-family:system-ui;background-color:#47a3ad'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document signed by ${signerName}</p>` +
|
`<div>${logo}</div><div style='padding:2px;font-family:system-ui;background-color:#47a3ad'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document signed by ${signerName}</p>` +
|
||||||
`</div><div style='padding:20px;font-family:system-ui;font-size:14px'><p>Dear ${creatorName},</p><p>${pdfName} has been signed by ${signerName} "${signerEmail}" successfully</p>` +
|
`</div><div style='padding:20px;font-family:system-ui;font-size:14px'><p>Dear ${creatorName},</p><p>${pdfName} has been signed by ${signerName} "${signerEmail}" successfully</p>` +
|
||||||
`<p><a href=${viewDocUrl} target=_blank>View Document</a></p></div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, ` +
|
`<p><a href=${viewDocUrl} target=_blank>View Document</a></p></div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, ` +
|
||||||
`please contact the sender ${creatorEmail} directly. If you think this email is inappropriate or spam, you may file a complaint with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
|
`please contact the sender ${creatorEmail} directly. If you think this email is inappropriate or spam, you may file a complaints with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
extUserId: sender.objectId,
|
extUserId: sender.objectId,
|
||||||
@@ -169,7 +169,7 @@ async function sendCompletedMail(obj) {
|
|||||||
const TenantAppName = appName;
|
const TenantAppName = appName;
|
||||||
const logo =
|
const logo =
|
||||||
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
|
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
|
||||||
const opurl = ` <a href=www.opensignlabs.com target=_blank>here</a>`;
|
const opurl = ` <a href='mailto:complaint@opensiglabs.com' target=_blank>here</a>`;
|
||||||
let signersMail;
|
let signersMail;
|
||||||
if (doc?.Signers?.length > 0) {
|
if (doc?.Signers?.length > 0) {
|
||||||
const isOwnerExistsinSigners = doc?.Signers?.find(x => x.Email === sender.Email);
|
const isOwnerExistsinSigners = doc?.Signers?.find(x => x.Email === sender.Email);
|
||||||
@@ -186,7 +186,7 @@ async function sendCompletedMail(obj) {
|
|||||||
`<div>${logo}</div><div style='padding:2px;font-family:system-ui;background-color:#47a3ad'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document signed successfully</p></div><div>` +
|
`<div>${logo}</div><div style='padding:2px;font-family:system-ui;background-color:#47a3ad'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document signed successfully</p></div><div>` +
|
||||||
`<p style='padding:20px;font-family:system-ui;font-size:14px'>All parties have successfully signed the document <b>"${pdfName}"</b>. Kindly download the document from the attachment.</p>` +
|
`<p style='padding:20px;font-family:system-ui;font-size:14px'>All parties have successfully signed the document <b>"${pdfName}"</b>. Kindly download the document from the attachment.</p>` +
|
||||||
`</div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, please contact the sender ${sender.Email} directly.` +
|
`</div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, please contact the sender ${sender.Email} directly.` +
|
||||||
`If you think this email is inappropriate or spam, you may file a complaint with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
|
`If you think this email is inappropriate or spam, you may file a complaints with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
|
||||||
|
|
||||||
if (obj?.isCustomMail) {
|
if (obj?.isCustomMail) {
|
||||||
const tenant = sender?.TenantId;
|
const tenant = sender?.TenantId;
|
||||||
|
|||||||
@@ -98,11 +98,6 @@ export default function reportJson(id, currentUserId) {
|
|||||||
IsCompleted: true,
|
IsCompleted: true,
|
||||||
IsDeclined: { $ne: true },
|
IsDeclined: { $ne: true },
|
||||||
IsArchive: { $ne: true },
|
IsArchive: { $ne: true },
|
||||||
// CreatedBy: {
|
|
||||||
// __type: 'Pointer',
|
|
||||||
// className: '_User',
|
|
||||||
// objectId: currentUserId,
|
|
||||||
// },
|
|
||||||
$or: [
|
$or: [
|
||||||
// Condition 1: If `CreatedBy` exists, no need for `Signers` filter
|
// Condition 1: If `CreatedBy` exists, no need for `Signers` filter
|
||||||
{ CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId } },
|
{ CreatedBy: { __type: 'Pointer', className: '_User', objectId: currentUserId } },
|
||||||
@@ -230,3 +225,36 @@ export default function reportJson(id, currentUserId) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Escape regex special characters. Copied from filterDocs.js
|
||||||
|
function escapeRegExp(str) {
|
||||||
|
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies searchTerm rules; combines existing access $or with search $or using $and.
|
||||||
|
*/
|
||||||
|
export function applySearch({ reportId, baseWhere, searchTerm }) {
|
||||||
|
if (!searchTerm) return baseWhere;
|
||||||
|
|
||||||
|
const escaped = escapeRegExp(searchTerm);
|
||||||
|
const nameMatch = { Name: { $regex: `.*${escaped}.*`, $options: 'i' } };
|
||||||
|
const emailMatch = { Email: { $regex: `.*${escaped}.*`, $options: 'i' } };
|
||||||
|
|
||||||
|
if (reportId === 'contacts') {
|
||||||
|
return { ...baseWhere, $or: [nameMatch, emailMatch] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchOr = [
|
||||||
|
nameMatch,
|
||||||
|
{ Signers: { $inQuery: { className: 'contracts_Contactbook', where: emailMatch } } },
|
||||||
|
];
|
||||||
|
|
||||||
|
// If baseWhere already has an access-control $or, combine using $and
|
||||||
|
if (baseWhere.$or) {
|
||||||
|
const { $or: accessOr, ...rest } = baseWhere;
|
||||||
|
return { ...rest, $and: [{ $or: accessOr }, { $or: searchOr }] };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...baseWhere, $or: searchOr };
|
||||||
|
}
|
||||||
|
|||||||
@@ -114,6 +114,9 @@ export default async function saveAsTemplate(request) {
|
|||||||
if (_docRes?.Bcc?.length > 0) {
|
if (_docRes?.Bcc?.length > 0) {
|
||||||
templateCls.set('Bcc', _docRes?.Bcc);
|
templateCls.set('Bcc', _docRes?.Bcc);
|
||||||
}
|
}
|
||||||
|
if (_docRes?.PenColors?.length > 0) {
|
||||||
|
templateCls.set('PenColors', _docRes?.PenColors);
|
||||||
|
}
|
||||||
const res = await templateCls.save(null, { useMasterKey: true });
|
const res = await templateCls.save(null, { useMasterKey: true });
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export default async function saveSignature(request) {
|
export default async function saveSignature(request) {
|
||||||
const { signature, userId, initials, id, title } = request.params;
|
const { signature, userId, initials, id, title, stamp } = request.params;
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Missing userId parameter.');
|
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Missing userId parameter.');
|
||||||
@@ -19,6 +19,9 @@ export default async function saveSignature(request) {
|
|||||||
if (signature) {
|
if (signature) {
|
||||||
signatureCls.set('ImageURL', signature);
|
signatureCls.set('ImageURL', signature);
|
||||||
}
|
}
|
||||||
|
if (stamp) {
|
||||||
|
signatureCls.set('Stamp', stamp);
|
||||||
|
}
|
||||||
if (title) {
|
if (title) {
|
||||||
signatureCls.set('SignatureName', title);
|
signatureCls.set('SignatureName', title);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,15 +58,20 @@ async function sendMailProvider(req, plan, monthchange) {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const httpsAgent = new https.Agent({ rejectUnauthorized: false }); // Disable SSL validation
|
const httpsAgent = new https.Agent({ rejectUnauthorized: false }); // Disable SSL validation
|
||||||
|
const localUrl = req.params.url;
|
||||||
|
const newlocalUrl = localUrl.replace(
|
||||||
|
'https://localhost:3001/api',
|
||||||
|
'http://localhost:8080'
|
||||||
|
);
|
||||||
axios
|
axios
|
||||||
.get(req.params.url, { responseType: 'stream', httpsAgent })
|
.get(newlocalUrl, { responseType: 'stream', httpsAgent: httpsAgent })
|
||||||
.then(response => {
|
.then(response => {
|
||||||
response.data.pipe(Pdf);
|
response.data.pipe(Pdf);
|
||||||
Pdf.on('finish', () => resolve('success'));
|
Pdf.on('finish', () => resolve('success'));
|
||||||
Pdf.on('error', () => resolve('error'));
|
Pdf.on('error', () => resolve('error'));
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
console.log('error', e.message);
|
console.log('error in localurl', e.message);
|
||||||
resolve('error');
|
resolve('error');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
export default async function setWidgetPreferences(request) {
|
||||||
|
if (!request?.user) {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||||
|
}
|
||||||
|
const dateWidgetParams = request?.params?.dateWidget;
|
||||||
|
if (!dateWidgetParams || Object.keys(dateWidgetParams).length === 0) {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide parameters.');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const orgQuery = new Parse.Query('contracts_Users');
|
||||||
|
orgQuery.equalTo('UserId', request.user);
|
||||||
|
const userObj = await orgQuery.first({ useMasterKey: true });
|
||||||
|
if (!userObj) {
|
||||||
|
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Permission denied.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const widgetPreferencesRaw = userObj?.get('WidgetPreferences');
|
||||||
|
const widgetPreferences = Array.isArray(widgetPreferencesRaw) ? widgetPreferencesRaw : [];
|
||||||
|
|
||||||
|
// Normalize booleans (simple + safe)
|
||||||
|
const dateWidget = {
|
||||||
|
type: 'date',
|
||||||
|
isSigningDate: !!dateWidgetParams.isSigningDate,
|
||||||
|
isReadOnly: !!dateWidgetParams.isReadOnly,
|
||||||
|
date: dateWidgetParams?.isSigningDate ? '' : dateWidgetParams?.date || '',
|
||||||
|
format: dateWidgetParams.format || 'MM/dd/yyyy',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Upsert: replace if exists, otherwise append
|
||||||
|
const updatedWidgetPreferences =
|
||||||
|
widgetPreferences?.length > 0
|
||||||
|
? widgetPreferences.map(w => (w.type === 'date' ? dateWidget : w))
|
||||||
|
: [...widgetPreferences, dateWidget];
|
||||||
|
|
||||||
|
userObj.set('WidgetPreferences', updatedWidgetPreferences);
|
||||||
|
const saved = await userObj.save(null, { useMasterKey: true });
|
||||||
|
if (saved) {
|
||||||
|
const response = typeof saved.toJSON === 'function' ? saved.toJSON() : saved;
|
||||||
|
return {
|
||||||
|
WidgetPreferences: response.WidgetPreferences,
|
||||||
|
updatedAt: response.updatedAt,
|
||||||
|
createdAt: response.createdAt,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('set widget preferences error:', err);
|
||||||
|
throw new Parse.Error(err?.code || 400, err?.message || 'Something went wrong.');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,8 @@ export default async function triggerEvent(request) {
|
|||||||
const contactId = request.params.contactId;
|
const contactId = request.params.contactId;
|
||||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||||
const appId = serverAppId;
|
const appId = serverAppId;
|
||||||
|
const sessiontoken = request.headers?.sessiontoken;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const docQuery = new Parse.Query('contracts_Document');
|
const docQuery = new Parse.Query('contracts_Document');
|
||||||
docQuery.select(['Name', 'IsEnableOTP', 'SignedUrl', 'AuditTrail']);
|
docQuery.select(['Name', 'IsEnableOTP', 'SignedUrl', 'AuditTrail']);
|
||||||
@@ -17,13 +19,16 @@ export default async function triggerEvent(request) {
|
|||||||
|
|
||||||
let userId;
|
let userId;
|
||||||
if (isEnableOTP) {
|
if (isEnableOTP) {
|
||||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
let userId;
|
||||||
headers: {
|
if (sessiontoken) {
|
||||||
'X-Parse-Application-Id': appId,
|
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
headers: {
|
||||||
},
|
'X-Parse-Application-Id': appId,
|
||||||
});
|
'X-Parse-Session-Token': sessiontoken,
|
||||||
userId = userRes.data && userRes.data.objectId;
|
},
|
||||||
|
});
|
||||||
|
userId = userRes.data && userRes.data.objectId;
|
||||||
|
}
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return { message: 'User not found!' };
|
return { message: 'User not found!' };
|
||||||
}
|
}
|
||||||
@@ -58,7 +63,10 @@ export default async function triggerEvent(request) {
|
|||||||
|
|
||||||
return { message: 'event called!' };
|
return { message: 'event called!' };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(`Err in triggerEvent: ${err}`);
|
console.log(
|
||||||
|
`triggerEvent error: `,
|
||||||
|
err?.response?.data?.error || err?.message || 'Something went wrong!'
|
||||||
|
);
|
||||||
return { message: 'Something went wrong!' };
|
return { message: 'Something went wrong!' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Parse} Parse
|
||||||
|
*/
|
||||||
|
exports.up = async Parse => {
|
||||||
|
const schema = new Parse.Schema('contracts_Signature');
|
||||||
|
schema.addString('Stamp');
|
||||||
|
return schema.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Parse} Parse
|
||||||
|
*/
|
||||||
|
exports.down = async Parse => {
|
||||||
|
const schema = new Parse.Schema('contracts_Signature');
|
||||||
|
schema.deleteField('Stamp');
|
||||||
|
return schema.update();
|
||||||
|
};
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Parse} Parse
|
||||||
|
*/
|
||||||
|
exports.up = async Parse => {
|
||||||
|
const docSchema = new Parse.Schema('contracts_Document');
|
||||||
|
docSchema.addArray('PenColors');
|
||||||
|
await docSchema.update();
|
||||||
|
|
||||||
|
const templateSchema = new Parse.Schema('contracts_Template');
|
||||||
|
templateSchema.addArray('PenColors');
|
||||||
|
await templateSchema.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Parse} Parse
|
||||||
|
*/
|
||||||
|
exports.down = async Parse => {
|
||||||
|
const docSchema = new Parse.Schema('contracts_Document');
|
||||||
|
docSchema.deleteField('PenColors');
|
||||||
|
await docSchema.update();
|
||||||
|
|
||||||
|
const templateSchema = new Parse.Schema('contracts_Template');
|
||||||
|
templateSchema.deleteField('PenColors');
|
||||||
|
await templateSchema.update();
|
||||||
|
};
|
||||||
Generated
+14803
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user