mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-05 01:07:39 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bce0e4971e | ||
|
|
4fb8aa9a16 | ||
|
|
8a2329dd60 | ||
|
|
75a40fbf43 |
+29
-26
@@ -1,58 +1,57 @@
|
|||||||
{
|
{
|
||||||
"name": "open_sign",
|
"name": "open_sign",
|
||||||
"version": "2.32.0",
|
"version": "2.34.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.10",
|
||||||
"@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.6.3",
|
"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.0.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.9.0",
|
"react-datepicker": "^9.0.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.6.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.9.6",
|
"react-router": "^7.10.1",
|
||||||
"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,31 +98,35 @@
|
|||||||
"@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.13",
|
"@vitest/ui": "^4.0.15",
|
||||||
"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.3.0",
|
||||||
"lint-staged": "^16.2.7",
|
"lint-staged": "^16.2.7",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"prettier": "^3.6.2",
|
"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",
|
||||||
"vite": "^7.2.4",
|
"tmp": "^0.2.5",
|
||||||
|
"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.1",
|
||||||
"vitest": "^4.0.13"
|
"vitest": "^4.0.15"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"tmp": "$tmp"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "18 || 20 || 22"
|
"node": "18 || 20 || 22"
|
||||||
|
|||||||
@@ -170,7 +170,8 @@
|
|||||||
"Kiosk Mode": "Kiosk Modus",
|
"Kiosk Mode": "Kiosk Modus",
|
||||||
"Reset password": "Passwort zurücksetzen",
|
"Reset password": "Passwort zurücksetzen",
|
||||||
"View formdata": "Formulardaten ansehen",
|
"View formdata": "Formulardaten ansehen",
|
||||||
"Download all formdata": "Alle Formulardaten herunterladen"
|
"Download all formdata": "Alle Formulardaten herunterladen",
|
||||||
|
"API credits": "API-Credits"
|
||||||
},
|
},
|
||||||
"report-heading": {
|
"report-heading": {
|
||||||
"Sr.No": "Nr.",
|
"Sr.No": "Nr.",
|
||||||
@@ -269,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",
|
||||||
@@ -587,7 +588,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!",
|
||||||
@@ -703,7 +704,7 @@
|
|||||||
"select-date-format": "Wählen Sie ein Datumsformat",
|
"select-date-format": "Wählen Sie ein Datumsformat",
|
||||||
"quantity-of-credits": "Anzahl der Premium-Credits",
|
"quantity-of-credits": "Anzahl der Premium-Credits",
|
||||||
"remaining-credits": "Verfügbare Premium-Credits:",
|
"remaining-credits": "Verfügbare Premium-Credits:",
|
||||||
"remaining-credits-help": "Verwenden Sie Premium-Credits für API-Dokumentensignaturen, Massenversand oder die Einbettung der OpenSign-Integration auf Ihrer Website. Sie haben {{allowedcredits}} enthaltene Credits und {{addoncredits}} zusätzlich gekaufte Credits übrig.",
|
"remaining-credits-help": "Verwenden Sie Premium-Credits für die API-Dokumentensignatur, den Massenversand oder die Einbettung der OpenSign-Integration auf Ihrer Website. Sie haben noch {{allowedcredits}} inkludierte Credits und {{addoncredits}} zusätzlich gekaufte Credits übrig. Wenn Sie einen Teams- oder Enterprise-Plan nutzen, können diese Credits von allen Benutzern in Ihrem Unternehmen gemeinsam verwendet werden, sofern der Kontoadministrator für Ihr Konto kein Limit festgelegt hat.",
|
||||||
"additional-credits": "Bitte kaufen Sie Premium-Credits hinzu",
|
"additional-credits": "Bitte kaufen Sie Premium-Credits hinzu",
|
||||||
"quota-err-quicksend": "Kontingent erreicht, Sie haben nicht genügend Credits.",
|
"quota-err-quicksend": "Kontingent erreicht, Sie haben nicht genügend Credits.",
|
||||||
"buy-credits": "Premium-Credits kaufen",
|
"buy-credits": "Premium-Credits kaufen",
|
||||||
@@ -1296,5 +1297,36 @@
|
|||||||
"view-formdata-paid-title-error": "Die Funktion 'Formulardaten anzeigen' ermöglicht es Ihnen, die von Unterzeichnern ausgefüllten Widget-Daten auszudrucken und herunterzuladen.",
|
"view-formdata-paid-title-error": "Die Funktion 'Formulardaten anzeigen' ermöglicht es Ihnen, die von Unterzeichnern ausgefüllten Widget-Daten auszudrucken und herunterzuladen.",
|
||||||
"view-formdata-paid-error": "Hinweis: Die Funktion 'Formulardaten anzeigen' ist nur für Dokumente verfügbar, die ab Version v2.32.0 erstellt wurden und keine doppelten Widget-Namen enthalten.",
|
"view-formdata-paid-error": "Hinweis: Die Funktion 'Formulardaten anzeigen' ist nur für Dokumente verfügbar, die ab Version v2.32.0 erstellt wurden und keine doppelten Widget-Namen enthalten.",
|
||||||
"download-all-formdata-paid-title-error": "Die Funktion 'Alle Formulardaten herunterladen' ermöglicht es Ihnen, die von Unterzeichnern ausgefüllten Widget-Daten für alle aus der Vorlage erstellten Dokumente herunterzuladen.",
|
"download-all-formdata-paid-title-error": "Die Funktion 'Alle Formulardaten herunterladen' ermöglicht es Ihnen, die von Unterzeichnern ausgefüllten Widget-Daten für alle aus der Vorlage erstellten Dokumente herunterzuladen.",
|
||||||
"download-all-formdata-paid-error": "Hinweis: Die Funktion 'Alle Formulardaten herunterladen' ist nur für Vorlagen verfügbar, die ab Version v2.32.0 erstellt wurden und keine doppelten Widget-Namen enthalten."
|
"download-all-formdata-paid-error": "Hinweis: Die Funktion 'Alle Formulardaten herunterladen' ist nur für Vorlagen verfügbar, die ab Version v2.32.0 erstellt wurden und keine doppelten Widget-Namen enthalten.",
|
||||||
|
"api-token-not-found": "API-Token nicht gefunden.",
|
||||||
|
"sub-head-api-credits": "Legen Sie die maximale Anzahl von API-Credits fest, die dieser Benutzer verbrauchen darf.",
|
||||||
|
"consumed-credits": "Verbrauchte Credits",
|
||||||
|
"allowed-api-credits": "Zulässige API-Credits",
|
||||||
|
"allowed-api-credits-help": "Die zulässigen Credits sollten größer oder gleich den verbrauchten Credits sein.",
|
||||||
|
"Enter-allowed-api-credits": "Zulässige API-Credits eingeben",
|
||||||
|
"login-to-sandbox": "Im Sandbox-Modus anmelden",
|
||||||
|
"your-credits-usage": "Ihr Kreditverbrauch",
|
||||||
|
"remaining": "verbleibend",
|
||||||
|
"used": "verwendet",
|
||||||
|
"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"
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,8 @@
|
|||||||
"Kiosk Mode": "Kiosk Mode",
|
"Kiosk Mode": "Kiosk Mode",
|
||||||
"Reset password": "Reset password",
|
"Reset password": "Reset password",
|
||||||
"View formdata": "View formdata",
|
"View formdata": "View formdata",
|
||||||
"Download all formdata": "Download all formdata"
|
"Download all formdata": "Download all formdata",
|
||||||
|
"API credits": "API credits"
|
||||||
},
|
},
|
||||||
"report-heading": {
|
"report-heading": {
|
||||||
"Sr.No": "Sr.No",
|
"Sr.No": "Sr.No",
|
||||||
@@ -269,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",
|
||||||
@@ -588,7 +589,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!",
|
||||||
@@ -704,7 +705,7 @@
|
|||||||
"select-date-format": "Select a date format",
|
"select-date-format": "Select a date format",
|
||||||
"quantity-of-credits": "Quantity of premium credits",
|
"quantity-of-credits": "Quantity of premium credits",
|
||||||
"remaining-credits": "Premium credits available:",
|
"remaining-credits": "Premium credits available:",
|
||||||
"remaining-credits-help": "Use premium credits for API document signing, bulk sending, or embedding OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining.",
|
"remaining-credits-help": "Use premium credits for API document signing, bulk sending, or embedding OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining. If you are on Teams or enterprise plan these are the credits that could be shared across all users in your company unless there is a limit set by the account admin for your account.",
|
||||||
"additional-credits": "Please purchase premium credits",
|
"additional-credits": "Please purchase premium credits",
|
||||||
"quota-err-quicksend": "Quota reached, you don't have enough credits.",
|
"quota-err-quicksend": "Quota reached, you don't have enough credits.",
|
||||||
"buy-credits": "Buy premium credits",
|
"buy-credits": "Buy premium credits",
|
||||||
@@ -1297,5 +1298,36 @@
|
|||||||
"view-formdata-paid-title-error": "The View Form Data feature lets you print and download the widget data filled in by signers while signing.",
|
"view-formdata-paid-title-error": "The View Form Data feature lets you print and download the widget data filled in by signers while signing.",
|
||||||
"view-formdata-paid-error": "Note: 'View Formdata' feature is only available for documents created on or after v2.32.0 that do not contain duplicate widget names.",
|
"view-formdata-paid-error": "Note: 'View Formdata' feature is only available for documents created on or after v2.32.0 that do not contain duplicate widget names.",
|
||||||
"download-all-formdata-paid-title-error": "The Download All Form Data feature lets you download widget data filled in by signers for all documents created from the template.",
|
"download-all-formdata-paid-title-error": "The Download All Form Data feature lets you download widget data filled in by signers for all documents created from the template.",
|
||||||
"download-all-formdata-paid-error": "Note: 'Download All Formdata' feature is only available for templates created on or after v2.32.0 that do not contain duplicate widget names."
|
"download-all-formdata-paid-error": "Note: 'Download All Formdata' feature is only available for templates created on or after v2.32.0 that do not contain duplicate widget names.",
|
||||||
|
"api-token-not-found": "API token not found.",
|
||||||
|
"sub-head-api-credits": " Define the maximum number of API credits this user is allowed to consume.",
|
||||||
|
"consumed-credits": "Consumed credits",
|
||||||
|
"allowed-api-credits": "Allowed API credits",
|
||||||
|
"allowed-api-credits-help": "The allowed credits should be greater than or equal to the consumed credits.",
|
||||||
|
"Enter-allowed-api-credits": "Enter allowed API credits",
|
||||||
|
"login-to-sandbox": "Login to sandbox",
|
||||||
|
"your-credits-usage": "Your credits usage",
|
||||||
|
"remaining": "remaining",
|
||||||
|
"used": "used",
|
||||||
|
"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"
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,8 @@
|
|||||||
"Kiosk Mode": "Modo Kiosco",
|
"Kiosk Mode": "Modo Kiosco",
|
||||||
"Reset password": "Restablecer contraseña",
|
"Reset password": "Restablecer contraseña",
|
||||||
"View formdata": "Ver datos del formulario",
|
"View formdata": "Ver datos del formulario",
|
||||||
"Download all formdata": "Descargar todos los datos del formulario"
|
"Download all formdata": "Descargar todos los datos del formulario",
|
||||||
|
"API credits": "Créditos de API"
|
||||||
},
|
},
|
||||||
"report-heading": {
|
"report-heading": {
|
||||||
"Sr.No": "Nº",
|
"Sr.No": "Nº",
|
||||||
@@ -269,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",
|
||||||
@@ -588,7 +589,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!",
|
||||||
@@ -704,7 +705,7 @@
|
|||||||
"select-date-format": "Selecciona un formato de fecha",
|
"select-date-format": "Selecciona un formato de fecha",
|
||||||
"quantity-of-credits": "Cantidad de créditos premium",
|
"quantity-of-credits": "Cantidad de créditos premium",
|
||||||
"remaining-credits": "Créditos premium disponibles:",
|
"remaining-credits": "Créditos premium disponibles:",
|
||||||
"remaining-credits-help": "Usa créditos premium para la API para la firma de documentos, envío en masa, o para incorporar la integración de OpenSign en tu página web. Te quedan {{allowedcredits}} créditos incluidos y {{addoncredits}} créditos comprados adicionalmente.",
|
"remaining-credits-help": "Utilice créditos premium para la firma de documentos mediante API, el envío masivo o para integrar OpenSign en su sitio web. Le quedan {{allowedcredits}} créditos incluidos y {{addoncredits}} créditos adicionales comprados. Si está en un plan Teams o Enterprise, estos créditos pueden compartirse entre todos los usuarios de su empresa, a menos que el administrador de la cuenta haya establecido un límite para su cuenta.",
|
||||||
"additional-credits": "Por favor, compra créditos premium",
|
"additional-credits": "Por favor, compra créditos premium",
|
||||||
"quota-err-quicksend": "Cuota alcanzada, no tienes créditos suficientes.",
|
"quota-err-quicksend": "Cuota alcanzada, no tienes créditos suficientes.",
|
||||||
"buy-credits": "Comprar créditos premium",
|
"buy-credits": "Comprar créditos premium",
|
||||||
@@ -1297,5 +1298,36 @@
|
|||||||
"view-formdata-paid-title-error": "La función 'Ver datos del formulario' le permite imprimir y descargar los datos de los widgets completados por los firmantes durante la firma.",
|
"view-formdata-paid-title-error": "La función 'Ver datos del formulario' le permite imprimir y descargar los datos de los widgets completados por los firmantes durante la firma.",
|
||||||
"view-formdata-paid-error": "Nota: La función 'Ver datos del formulario' solo está disponible para documentos creados en o después de la versión v2.32.0 que no contengan nombres de widgets duplicados.",
|
"view-formdata-paid-error": "Nota: La función 'Ver datos del formulario' solo está disponible para documentos creados en o después de la versión v2.32.0 que no contengan nombres de widgets duplicados.",
|
||||||
"download-all-formdata-paid-title-error": "La función 'Descargar todos los datos del formulario' le permite descargar los datos de los widgets completados por los firmantes para todos los documentos creados a partir de la plantilla.",
|
"download-all-formdata-paid-title-error": "La función 'Descargar todos los datos del formulario' le permite descargar los datos de los widgets completados por los firmantes para todos los documentos creados a partir de la plantilla.",
|
||||||
"download-all-formdata-paid-error": "Nota: La función 'Descargar todos los datos del formulario' solo está disponible para plantillas creadas en o después de la versión v2.32.0 que no contengan nombres de widgets duplicados."
|
"download-all-formdata-paid-error": "Nota: La función 'Descargar todos los datos del formulario' solo está disponible para plantillas creadas en o después de la versión v2.32.0 que no contengan nombres de widgets duplicados.",
|
||||||
|
"api-token-not-found": "Token de API no encontrado.",
|
||||||
|
"sub-head-api-credits": "Defina la cantidad máxima de créditos API que este usuario puede consumir.",
|
||||||
|
"consumed-credits": "Créditos consumidos",
|
||||||
|
"allowed-api-credits": "Créditos API permitidos",
|
||||||
|
"allowed-api-credits-help": "Los créditos permitidos deben ser mayores o iguales a los créditos consumidos.",
|
||||||
|
"Enter-allowed-api-credits": "Ingrese los créditos API permitidos",
|
||||||
|
"login-to-sandbox": "Iniciar sesión en sandbox",
|
||||||
|
"your-credits-usage": "Uso de sus créditos",
|
||||||
|
"remaining": "restantes",
|
||||||
|
"used": "usados",
|
||||||
|
"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"
|
||||||
}
|
}
|
||||||
@@ -206,7 +206,8 @@
|
|||||||
"Kiosk Mode": "Mode Kiosque",
|
"Kiosk Mode": "Mode Kiosque",
|
||||||
"Reset password": "Réinitialiser le mot de passe",
|
"Reset password": "Réinitialiser le mot de passe",
|
||||||
"View formdata": "Voir les données du formulaire",
|
"View formdata": "Voir les données du formulaire",
|
||||||
"Download all formdata": "Télécharger toutes les données du formulaire"
|
"Download all formdata": "Télécharger toutes les données du formulaire",
|
||||||
|
"API credits": "Crédits API"
|
||||||
},
|
},
|
||||||
"report-help": {
|
"report-help": {
|
||||||
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
|
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
|
||||||
@@ -269,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",
|
||||||
@@ -587,7 +588,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 ! ",
|
||||||
@@ -704,7 +705,7 @@
|
|||||||
"quantity-of-credits": "Quantité de crédits de prime",
|
"quantity-of-credits": "Quantité de crédits de prime",
|
||||||
"remaining-credits": "Crédits premium disponibles :",
|
"remaining-credits": "Crédits premium disponibles :",
|
||||||
"additional-credits": "Veuillez acheter des crédits premium",
|
"additional-credits": "Veuillez acheter des crédits premium",
|
||||||
"remaining-credits-help": "Utilisez des crédits premium pour la signature de documents API, l'envoi groupé ou l'intégration d'OpenSign sur votre site Web. Il vous reste {{allowedcredits}} crédits inclus et {{addoncredits}} crédits achetés supplémentaires.",
|
"remaining-credits-help": "Utilisez des crédits premium pour la signature de documents via l'API, l'envoi groupé ou l'intégration d'OpenSign sur votre site Web. Il vous reste {{allowedcredits}} crédits inclus et {{addoncredits}} crédits supplémentaires achetés. Si vous êtes sur un plan Teams ou Enterprise, ces crédits peuvent être partagés entre tous les utilisateurs de votre entreprise, sauf si l'administrateur du compte a défini une limite pour votre compte.",
|
||||||
"quota-err-quicksend": "Quota atteint, vous n'avez pas assez de crédits.",
|
"quota-err-quicksend": "Quota atteint, vous n'avez pas assez de crédits.",
|
||||||
"buy-credits": "Acheter des crédits premium",
|
"buy-credits": "Acheter des crédits premium",
|
||||||
"rotate-right": "Faire pivoter à droite",
|
"rotate-right": "Faire pivoter à droite",
|
||||||
@@ -1293,8 +1294,39 @@
|
|||||||
"duplicate-template-widget-error": "Vous ne pouvez pas dupliquer ce modèle car il contient des noms de widgets en double.",
|
"duplicate-template-widget-error": "Vous ne pouvez pas dupliquer ce modèle car il contient des noms de widgets en double.",
|
||||||
"credit-alert": "Alerte de crédit",
|
"credit-alert": "Alerte de crédit",
|
||||||
"document-form-data": "Données du formulaire du document",
|
"document-form-data": "Données du formulaire du document",
|
||||||
"view-formdata-paid-title-error": "La fonction 'Afficher les données du formulaire' vous permet d’imprimer et de télécharger les données des widgets remplies par les signataires lors de la signature.",
|
"view-formdata-paid-title-error": "La fonction 'Afficher les données du formulaire' vous permet d'imprimer et de télécharger les données des widgets remplies par les signataires lors de la signature.",
|
||||||
"view-formdata-paid-error": "Remarque : La fonction 'Afficher les données du formulaire' est uniquement disponible pour les documents créés à partir de la version v2.32.0 et ne contenant pas de noms de widgets en double.",
|
"view-formdata-paid-error": "Remarque : La fonction 'Afficher les données du formulaire' est uniquement disponible pour les documents créés à partir de la version v2.32.0 et ne contenant pas de noms de widgets en double.",
|
||||||
"download-all-formdata-paid-title-error": "La fonction 'Télécharger toutes les données du formulaire' vous permet de télécharger les données des widgets remplies par les signataires pour tous les documents créés à partir du modèle.",
|
"download-all-formdata-paid-title-error": "La fonction 'Télécharger toutes les données du formulaire' vous permet de télécharger les données des widgets remplies par les signataires pour tous les documents créés à partir du modèle.",
|
||||||
"download-all-formdata-paid-error": "Remarque : La fonction 'Télécharger toutes les données du formulaire' est uniquement disponible pour les modèles créés à partir de la version v2.32.0 et ne contenant pas de noms de widgets en double."
|
"download-all-formdata-paid-error": "Remarque : La fonction 'Télécharger toutes les données du formulaire' est uniquement disponible pour les modèles créés à partir de la version v2.32.0 et ne contenant pas de noms de widgets en double.",
|
||||||
|
"api-token-not-found": "Jeton API introuvable.",
|
||||||
|
"sub-head-api-credits": "Définissez le nombre maximal de crédits API que cet utilisateur est autorisé à consommer.",
|
||||||
|
"consumed-credits": "Crédits consommés",
|
||||||
|
"allowed-api-credits": "Crédits API autorisés",
|
||||||
|
"allowed-api-credits-help": "Les crédits autorisés doivent être supérieurs ou égaux aux crédits consommés.",
|
||||||
|
"Enter-allowed-api-credits": "Saisissez les crédits API autorisés",
|
||||||
|
"login-to-sandbox": "Se connecter au sandbox",
|
||||||
|
"your-credits-usage": "Votre utilisation des crédits",
|
||||||
|
"remaining": "restants",
|
||||||
|
"used": "utilisés",
|
||||||
|
"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"
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,8 @@
|
|||||||
"Kiosk Mode": "कियोस्क मोड",
|
"Kiosk Mode": "कियोस्क मोड",
|
||||||
"Reset password": "पासवर्ड रीसेट करें",
|
"Reset password": "पासवर्ड रीसेट करें",
|
||||||
"View formdata": "फॉर्म डेटा देखें",
|
"View formdata": "फॉर्म डेटा देखें",
|
||||||
"Download all formdata": "सभी फॉर्म डेटा डाउनलोड करें"
|
"Download all formdata": "सभी फॉर्म डेटा डाउनलोड करें",
|
||||||
|
"API credits": "API क्रेडिट्स"
|
||||||
},
|
},
|
||||||
"report-heading": {
|
"report-heading": {
|
||||||
"Sr.No": "क्रमांक",
|
"Sr.No": "क्रमांक",
|
||||||
@@ -269,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": "एपीआई टोकन",
|
||||||
@@ -587,7 +588,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": "त्रुटि: टेम्पलेट नहीं मिला!",
|
||||||
@@ -703,7 +704,7 @@
|
|||||||
"select-date-format": "एक दिनांक प्रारूप चुनें",
|
"select-date-format": "एक दिनांक प्रारूप चुनें",
|
||||||
"quantity-of-credits": "प्रीमियम क्रेडिट की मात्रा",
|
"quantity-of-credits": "प्रीमियम क्रेडिट की मात्रा",
|
||||||
"remaining-credits": "प्रीमियम क्रेडिट उपलब्ध:",
|
"remaining-credits": "प्रीमियम क्रेडिट उपलब्ध:",
|
||||||
"remaining-credits-help": "अपनी वेबसाइट पर एपीआई दस्तावेज़ हस्ताक्षर, थोक भेजने या OpenSign एकीकरण को एम्बेड करने के लिए प्रीमियम क्रेडिट का उपयोग करें। आपके पास {{allowedcredits}} शामिल क्रेडिट और {{addoncredits}} अतिरिक्त खरीदे गए क्रेडिट शेष हैं।",
|
"remaining-credits-help": "API दस्तावेज़ साइनिंग, बल्क सेंडिंग या अपनी वेबसाइट पर OpenSign इंटीग्रेशन एम्बेड करने के लिए प्रीमियम क्रेडिट का उपयोग करें। आपके पास {{allowedcredits}} शामिल क्रेडिट और {{addoncredits}} अतिरिक्त खरीदे हुए क्रेडिट शेष हैं। यदि आप Teams या Enterprise प्लान पर हैं, तो ये क्रेडिट आपकी कंपनी के सभी उपयोगकर्ताओं के बीच साझा किए जा सकते हैं, जब तक कि आपके खाते के लिए अकाउंट एडमिन ने कोई सीमा निर्धारित न की हो।",
|
||||||
"additional-credits": "कृपया प्रीमियम क्रेडिट खरीदें",
|
"additional-credits": "कृपया प्रीमियम क्रेडिट खरीदें",
|
||||||
"quota-err-quicksend": "कोटा पहुँच गया, आपके पास पर्याप्त क्रेडिट नहीं हैं।",
|
"quota-err-quicksend": "कोटा पहुँच गया, आपके पास पर्याप्त क्रेडिट नहीं हैं।",
|
||||||
"buy-credits": "प्रीमियम क्रेडिट खरीदें",
|
"buy-credits": "प्रीमियम क्रेडिट खरीदें",
|
||||||
@@ -1296,5 +1297,36 @@
|
|||||||
"view-formdata-paid-title-error": "'फ़ॉर्म डेटा देखें' सुविधा आपको हस्ताक्षर करते समय साइनरों द्वारा भरे गए विजेट डेटा को प्रिंट और डाउनलोड करने की सुविधा देती है.",
|
"view-formdata-paid-title-error": "'फ़ॉर्म डेटा देखें' सुविधा आपको हस्ताक्षर करते समय साइनरों द्वारा भरे गए विजेट डेटा को प्रिंट और डाउनलोड करने की सुविधा देती है.",
|
||||||
"view-formdata-paid-error": "नोट: 'फ़ॉर्म डेटा देखें' सुविधा केवल उन दस्तावेज़ों के लिए उपलब्ध है जो v2.32.0 या उसके बाद बनाए गए हों और जिनमें डुप्लिकेट विजेट नाम न हों.",
|
"view-formdata-paid-error": "नोट: 'फ़ॉर्म डेटा देखें' सुविधा केवल उन दस्तावेज़ों के लिए उपलब्ध है जो v2.32.0 या उसके बाद बनाए गए हों और जिनमें डुप्लिकेट विजेट नाम न हों.",
|
||||||
"download-all-formdata-paid-title-error": "'सभी फ़ॉर्म डेटा डाउनलोड करें' सुविधा आपको टेम्पलेट से बनाए गए सभी दस्तावेज़ों के लिए साइनरों द्वारा भरे गए विजेट डेटा को डाउनलोड करने देती है.",
|
"download-all-formdata-paid-title-error": "'सभी फ़ॉर्म डेटा डाउनलोड करें' सुविधा आपको टेम्पलेट से बनाए गए सभी दस्तावेज़ों के लिए साइनरों द्वारा भरे गए विजेट डेटा को डाउनलोड करने देती है.",
|
||||||
"download-all-formdata-paid-error": "नोट: 'सभी फ़ॉर्म डेटा डाउनलोड करें' सुविधा केवल उन टेम्पलेट्स के लिए उपलब्ध है जो v2.32.0 या उसके बाद बनाए गए हों और जिनमें डुप्लिकेट विजेट नाम न हों."
|
"download-all-formdata-paid-error": "नोट: 'सभी फ़ॉर्म डेटा डाउनलोड करें' सुविधा केवल उन टेम्पलेट्स के लिए उपलब्ध है जो v2.32.0 या उसके बाद बनाए गए हों और जिनमें डुप्लिकेट विजेट नाम न हों.",
|
||||||
|
"api-token-not-found": "API टोकन नहीं मिला।",
|
||||||
|
"sub-head-api-credits": "इस उपयोगकर्ता द्वारा उपभोग किए जाने वाले API क्रेडिट की अधिकतम संख्या निर्धारित करें।",
|
||||||
|
"consumed-credits": "उपयोग किए गए क्रेडिट",
|
||||||
|
"allowed-api-credits": "अनुमत API क्रेडिट",
|
||||||
|
"allowed-api-credits-help": "अनुमत क्रेडिट उपयोग किए गए क्रेडिट के बराबर या उससे अधिक होने चाहिए।",
|
||||||
|
"Enter-allowed-api-credits": "अनुमत API क्रेडिट दर्ज करें",
|
||||||
|
"login-to-sandbox": "सैंडबॉक्स में लॉगिन करें",
|
||||||
|
"your-credits-usage": "आपके क्रेडिट उपयोग",
|
||||||
|
"remaining": "शेष",
|
||||||
|
"used": "उपयोग किए गए",
|
||||||
|
"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": "पुनः जनरेट करें"
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,8 @@
|
|||||||
"Kiosk Mode": "Modalità Kiosk",
|
"Kiosk Mode": "Modalità Kiosk",
|
||||||
"Reset password": "Reimposta password",
|
"Reset password": "Reimposta password",
|
||||||
"View formdata": "Visualizza i dati del modulo",
|
"View formdata": "Visualizza i dati del modulo",
|
||||||
"Download all formdata": "Scarica tutti i dati del modulo"
|
"Download all formdata": "Scarica tutti i dati del modulo",
|
||||||
|
"API credits": "Crediti API"
|
||||||
},
|
},
|
||||||
"report-heading": {
|
"report-heading": {
|
||||||
"Sr.No": "Nr.",
|
"Sr.No": "Nr.",
|
||||||
@@ -269,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",
|
||||||
@@ -587,7 +588,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!",
|
||||||
@@ -703,7 +704,7 @@
|
|||||||
"select-date-format": "Seleziona un formato data",
|
"select-date-format": "Seleziona un formato data",
|
||||||
"quantity-of-credits": "Quantità di crediti premium",
|
"quantity-of-credits": "Quantità di crediti premium",
|
||||||
"remaining-credits": "Crediti premium disponibili:",
|
"remaining-credits": "Crediti premium disponibili:",
|
||||||
"remaining-credits-help": "Usa i crediti premium per firmare documenti API, invii in massa o per integrare OpenSign nel tuo sito web. Hai a disposizione {{allowedcredits}} crediti inclusi e {{addoncredits}} crediti acquistati aggiuntivi rimanenti.",
|
"remaining-credits-help": "Usa i crediti premium per la firma di documenti tramite API, l'invio massivo o per integrare OpenSign nel tuo sito web. Hai ancora {{allowedcredits}} crediti inclusi e {{addoncredits}} crediti aggiuntivi acquistati. Se sei in un piano Teams o Enterprise, questi crediti possono essere condivisi tra tutti gli utenti della tua azienda, a meno che l'amministratore dell'account non abbia impostato un limite specifico per il tuo account.",
|
||||||
"additional-credits": "Acquista crediti premium",
|
"additional-credits": "Acquista crediti premium",
|
||||||
"quota-err-quicksend": "Quota raggiunta, non hai abbastanza crediti.",
|
"quota-err-quicksend": "Quota raggiunta, non hai abbastanza crediti.",
|
||||||
"buy-credits": "Acquista Crediti Premium",
|
"buy-credits": "Acquista Crediti Premium",
|
||||||
@@ -1296,5 +1297,36 @@
|
|||||||
"view-formdata-paid-title-error": "La funzione 'Visualizza dati del modulo' consente di stampare e scaricare i dati dei widget compilati dai firmatari durante la firma.",
|
"view-formdata-paid-title-error": "La funzione 'Visualizza dati del modulo' consente di stampare e scaricare i dati dei widget compilati dai firmatari durante la firma.",
|
||||||
"view-formdata-paid-error": "Nota: La funzione 'Visualizza dati del modulo' è disponibile solo per documenti creati dalla versione v2.32.0 in poi che non contengono nomi di widget duplicati.",
|
"view-formdata-paid-error": "Nota: La funzione 'Visualizza dati del modulo' è disponibile solo per documenti creati dalla versione v2.32.0 in poi che non contengono nomi di widget duplicati.",
|
||||||
"download-all-formdata-paid-title-error": "La funzione 'Scarica tutti i dati del modulo' consente di scaricare i dati dei widget compilati dai firmatari per tutti i documenti creati dal modello.",
|
"download-all-formdata-paid-title-error": "La funzione 'Scarica tutti i dati del modulo' consente di scaricare i dati dei widget compilati dai firmatari per tutti i documenti creati dal modello.",
|
||||||
"download-all-formdata-paid-error": "Nota: La funzione 'Scarica tutti i dati del modulo' è disponibile solo per modelli creati dalla versione v2.32.0 in poi che non contengano nomi di widget duplicati."
|
"download-all-formdata-paid-error": "Nota: La funzione 'Scarica tutti i dati del modulo' è disponibile solo per modelli creati dalla versione v2.32.0 in poi che non contengano nomi di widget duplicati.",
|
||||||
|
"api-token-not-found": "Token API non trovato.",
|
||||||
|
"sub-head-api-credits": "Definisci il numero massimo di crediti API che questo utente può consumare.",
|
||||||
|
"consumed-credits": "Crediti consumati",
|
||||||
|
"allowed-api-credits": "Crediti API consentiti",
|
||||||
|
"allowed-api-credits-help": "I crediti consentiti devono essere maggiori o uguali ai crediti consumati.",
|
||||||
|
"Enter-allowed-api-credits": "Inserisci i crediti API consentiti",
|
||||||
|
"login-to-sandbox": "Accedi alla sandbox",
|
||||||
|
"your-credits-usage": "Utilizzo dei tuoi crediti",
|
||||||
|
"remaining": "rimanenti",
|
||||||
|
"used": "usati",
|
||||||
|
"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"
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ const Header = ({ isConsole, setIsLoggingOut }) => {
|
|||||||
setAppLogo(logo);
|
setAppLogo(logo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
setIsLoggingOut(true);
|
setIsLoggingOut(true);
|
||||||
@@ -198,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>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,9 +56,7 @@ function DriveBody(props) {
|
|||||||
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,7 +82,7 @@ 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")
|
||||||
@@ -160,9 +158,7 @@ function DriveBody(props) {
|
|||||||
const handleDeleteDocument = async (docData) => {
|
const handleDeleteDocument = 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,7 +180,7 @@ 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")
|
||||||
@@ -218,16 +214,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: {
|
||||||
@@ -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);
|
||||||
@@ -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")
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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")}
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ function Placeholder(props) {
|
|||||||
data?.format,
|
data?.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,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -216,16 +216,17 @@ function Placeholder(props) {
|
|||||||
//placeholder, template flow
|
//placeholder, template flow
|
||||||
else if (props.isPlaceholder && !props.isDragging) {
|
else if (props.isPlaceholder && !props.isDragging) {
|
||||||
props.setCurrWidgetsDetails && props.setCurrWidgetsDetails(props.pos);
|
props.setCurrWidgetsDetails && props.setCurrWidgetsDetails(props.pos);
|
||||||
if (
|
if (props?.data?.Role !== "prefill") {
|
||||||
props.pos.key === props?.currWidgetsDetails?.key &&
|
//this condition is used open signers attach modal but it should only open when widgets already selected
|
||||||
props?.data?.Role !== "prefill"
|
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.data.Id);
|
||||||
const checkIndex = props.xyPosition.findIndex(
|
const checkIndex = props.xyPosition.findIndex(
|
||||||
(data) => data.Id === props.data.Id
|
(data) => data.Id === props.data.Id
|
||||||
);
|
);
|
||||||
props.setIsSelectId(checkIndex || 0);
|
props.setIsSelectId(checkIndex || 0);
|
||||||
|
props?.setRoleName("");
|
||||||
} else if (props?.data?.Role === "prefill") {
|
} else if (props?.data?.Role === "prefill") {
|
||||||
dispatch(setIsShowModal({ [props.pos.key]: true }));
|
dispatch(setIsShowModal({ [props.pos.key]: true }));
|
||||||
props.setUniqueId(props?.data?.Id);
|
props.setUniqueId(props?.data?.Id);
|
||||||
@@ -619,12 +620,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";
|
||||||
@@ -654,10 +655,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 && props?.setRoleName("prefill");
|
||||||
|
props.setUniqueId && props.setUniqueId(props?.data?.Id);
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
fontFamily: "Arial, sans-serif",
|
fontFamily: "Arial, sans-serif",
|
||||||
@@ -668,13 +673,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}
|
||||||
@@ -734,7 +747,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);
|
||||||
@@ -935,7 +948,7 @@ function Placeholder(props) {
|
|||||||
<span>{t("set-date")} :</span>
|
<span>{t("set-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)]}
|
||||||
@@ -989,7 +1002,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"
|
||||||
@@ -1003,7 +1016,7 @@ 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>
|
||||||
|
|||||||
@@ -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,7 @@ import {
|
|||||||
months,
|
months,
|
||||||
years,
|
years,
|
||||||
selectCheckbox,
|
selectCheckbox,
|
||||||
checkRegularExpress,
|
isBase64
|
||||||
isBase64,
|
|
||||||
getSignerPages
|
|
||||||
} 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 +32,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 +47,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 +75,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 +136,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 +261,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"
|
||||||
@@ -530,20 +563,22 @@ 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"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -72,7 +72,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 +90,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>
|
||||||
@@ -120,16 +115,12 @@ function PrefillWidgetModal(props) {
|
|||||||
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(() => {
|
||||||
@@ -179,7 +170,7 @@ function PrefillWidgetModal(props) {
|
|||||||
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]);
|
||||||
@@ -271,7 +262,7 @@ function PrefillWidgetModal(props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSavePrefillImg = async (widgetDetails) => {
|
const handleSavePrefillImg = async (widgetDetails) => {
|
||||||
setImageLoaders((prev) => ({ ...prev, [widgetDetails?.key]: true }));
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const imageName = generatePdfName(16);
|
const imageName = generatePdfName(16);
|
||||||
const imageUrl = await convertBase64ToFile(
|
const imageUrl = await convertBase64ToFile(
|
||||||
@@ -419,9 +410,9 @@ 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) => {
|
const handleWidgetType = (position, id) => {
|
||||||
switch (position?.type) {
|
switch (position?.type) {
|
||||||
case "checkbox":
|
case "checkbox":
|
||||||
return (
|
return (
|
||||||
@@ -533,10 +524,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:
|
||||||
@@ -658,7 +649,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 +718,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)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ const WidgetNameModal = (props) => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen={props.isOpen}
|
isOpen={props.isOpen}
|
||||||
@@ -373,7 +374,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,21 @@
|
|||||||
|
import SignatureCanvas from "react-signature-canvas";
|
||||||
|
|
||||||
|
function Draw(props) {
|
||||||
|
return (
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<SignatureCanvas
|
||||||
|
ref={props?.canvasRef}
|
||||||
|
penColor={props?.penColor}
|
||||||
|
canvasProps={{
|
||||||
|
className: `${props?.currWidgetsDetails?.type === "initials" ? "intialSignatureCanvas" : "signatureCanvas"} border-[1.3px] border-gray-300 rounded-[4px]`
|
||||||
|
}}
|
||||||
|
onEnd={() =>
|
||||||
|
props?.handleSignatureChange(props?.canvasRef.current?.toDataURL())
|
||||||
|
}
|
||||||
|
dotSize={1}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Draw;
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
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?.(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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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}
|
||||||
>
|
>
|
||||||
|
|||||||
+234
-154
@@ -28,6 +28,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
|
||||||
@@ -849,6 +854,7 @@ export const signPdfFun = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createDocument = async (
|
export const createDocument = async (
|
||||||
template,
|
template,
|
||||||
placeholders,
|
placeholders,
|
||||||
@@ -900,6 +906,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 +930,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 +944,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 +954,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 +1046,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 +1097,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 +1157,15 @@ export const onChangeInput = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} else if (
|
||||||
|
currentPosition?.type === "text" &&
|
||||||
|
textWidgetHeight &&
|
||||||
|
!value
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
...positionData,
|
||||||
|
Height: textWidgetHeight
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
...positionData,
|
...positionData,
|
||||||
@@ -1605,7 +1634,9 @@ export function onSaveImage(
|
|||||||
isAutoSign,
|
isAutoSign,
|
||||||
widgetsType,
|
widgetsType,
|
||||||
isApplyAll,
|
isApplyAll,
|
||||||
imgUrl
|
imgUrl,
|
||||||
|
defaultStampImg,
|
||||||
|
defaultStampType
|
||||||
) {
|
) {
|
||||||
// let getIMGWH;
|
// let getIMGWH;
|
||||||
const isSignOrInitials =
|
const isSignOrInitials =
|
||||||
@@ -1616,12 +1647,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 +1674,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 +1824,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,
|
||||||
@@ -2080,41 +2132,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 +3092,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
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -3466,7 +3540,10 @@ export const updateDateWidgetsRes = (
|
|||||||
return placeHolders?.map((item) => {
|
return placeHolders?.map((item) => {
|
||||||
if (item?.signerObjId === signerId || item?.Id === signerId) {
|
if (item?.signerObjId === signerId || item?.Id === signerId) {
|
||||||
// Sort page number placeholders
|
// Sort page number placeholders
|
||||||
const sortedPlaceHolder = [...item.placeHolder]
|
const placeHolder = Array.isArray(item.placeHolder)
|
||||||
|
? [...item.placeHolder]
|
||||||
|
: [];
|
||||||
|
const sortedPlaceHolder = placeHolder
|
||||||
.sort((a, b) => a.pageNumber - b.pageNumber)
|
.sort((a, b) => a.pageNumber - b.pageNumber)
|
||||||
.map((ph) => ({
|
.map((ph) => ({
|
||||||
...ph,
|
...ph,
|
||||||
@@ -3924,51 +4001,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
|
||||||
@@ -3981,74 +4062,68 @@ export const getSignerEmail = (data, signers) => {
|
|||||||
|
|
||||||
//function is used to delete widgets
|
//function is used to delete widgets
|
||||||
export const handleDeleteWidget = (key, Id, pageNumber, signerPos) => {
|
export const handleDeleteWidget = (key, Id, pageNumber, signerPos) => {
|
||||||
const updateData = [];
|
// Find the signer by ID
|
||||||
|
const signer = signerPos.find((item) => item.Id === Id);
|
||||||
|
if (!signer || !signer.placeHolder) return signerPos;
|
||||||
|
|
||||||
const filterSignerPos = signerPos.filter((data) => data.Id === Id);
|
const placeHolder = signer.placeHolder;
|
||||||
|
|
||||||
if (filterSignerPos.length > 0) {
|
// Find the page inside placeHolder
|
||||||
const getPlaceHolder = filterSignerPos[0].placeHolder;
|
const currentPage = placeHolder.find((p) => p.pageNumber === pageNumber);
|
||||||
|
if (!currentPage) return signerPos;
|
||||||
|
|
||||||
const getPageNumer = getPlaceHolder.filter(
|
// Remove widget from the selected page
|
||||||
(data) => data.pageNumber === pageNumber
|
const updatedPos = currentPage.pos.filter((w) => w.key !== key);
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
// CASE A → After deletion, page still has widgets then keep that widgets
|
||||||
|
// -------------------------------------------------------
|
||||||
|
if (updatedPos.length > 0) {
|
||||||
|
const updatedPlaceHolder = placeHolder.map((p) =>
|
||||||
|
p.pageNumber === pageNumber ? { ...p, pos: updatedPos } : p
|
||||||
);
|
);
|
||||||
|
|
||||||
if (getPageNumer.length > 0) {
|
return signerPos.map((s) =>
|
||||||
const getXYdata = getPageNumer[0].pos.filter((data) => data.key !== key);
|
s.Id === Id ? { ...s, placeHolder: updatedPlaceHolder } : s
|
||||||
|
);
|
||||||
if (getXYdata.length > 0) {
|
|
||||||
updateData.push(getXYdata);
|
|
||||||
const newUpdatePos = getPlaceHolder.map((obj) => {
|
|
||||||
if (obj.pageNumber === pageNumber) {
|
|
||||||
return { ...obj, pos: updateData[0] };
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
});
|
|
||||||
|
|
||||||
const newUpdateSigner = signerPos.map((obj) => {
|
|
||||||
if (obj.Id === Id) {
|
|
||||||
return { ...obj, placeHolder: newUpdatePos };
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
});
|
|
||||||
return newUpdateSigner;
|
|
||||||
} else {
|
|
||||||
const getRemainPage = filterSignerPos[0].placeHolder.filter(
|
|
||||||
(data) => data.pageNumber !== pageNumber
|
|
||||||
);
|
|
||||||
//condition to check placeholder length is greater than 1 do not need to remove whole placeholder
|
|
||||||
//array only resove particular widgets
|
|
||||||
if (getRemainPage && getRemainPage.length > 0) {
|
|
||||||
const newUpdatePos = filterSignerPos.map((obj) => {
|
|
||||||
if (obj.Id === Id) {
|
|
||||||
return { ...obj, placeHolder: getRemainPage };
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
});
|
|
||||||
let signerupdate = [];
|
|
||||||
signerupdate = signerPos.filter((data) => data.Id !== Id);
|
|
||||||
signerupdate.push(newUpdatePos[0]);
|
|
||||||
|
|
||||||
return signerupdate;
|
|
||||||
} else {
|
|
||||||
const updatedData = signerPos
|
|
||||||
.map((item) => {
|
|
||||||
if (item.Id === Id && item?.Role === "prefill") {
|
|
||||||
return null; // mark this item to remove
|
|
||||||
}
|
|
||||||
if (item.Id === Id) {
|
|
||||||
const updatedItem = { ...item };
|
|
||||||
delete updatedItem.placeHolder;
|
|
||||||
return updatedItem;
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
})
|
|
||||||
.filter(Boolean); // remove nulls (deleted items)
|
|
||||||
|
|
||||||
return updatedData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
// CASE B → current page becomes empty → remove current page entirely and keep another pages which have widgets
|
||||||
|
// -------------------------------------------------------
|
||||||
|
const remainPages = placeHolder.filter((p) => p.pageNumber !== pageNumber);
|
||||||
|
|
||||||
|
//`remainPages` keep another pages's data which have widgets
|
||||||
|
if (remainPages.length > 0) {
|
||||||
|
const index = signerPos.findIndex((s) => s.Id === Id);
|
||||||
|
if (index === -1) return signerPos;
|
||||||
|
|
||||||
|
const newSignerPos = [...signerPos];
|
||||||
|
newSignerPos[index] = {
|
||||||
|
...newSignerPos[index],
|
||||||
|
placeHolder: remainPages
|
||||||
|
};
|
||||||
|
|
||||||
|
return newSignerPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
// CASE C → No pages have widgets after delete widgets
|
||||||
|
// Remove placeHolder field for particular signers, EXCEPT prefill role
|
||||||
|
// -------------------------------------------------------
|
||||||
|
const updatedData = signerPos
|
||||||
|
.map((s) => {
|
||||||
|
if (s.Id === Id && s.Role === "prefill") return null; // remove whole signer
|
||||||
|
if (s.Id === Id) {
|
||||||
|
const updated = { ...s };
|
||||||
|
delete updated.placeHolder;
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
})
|
||||||
|
.filter(Boolean); // remove nulls (deleted items)
|
||||||
|
|
||||||
|
return updatedData;
|
||||||
};
|
};
|
||||||
//function to convert formatted date to new Date() format
|
//function to convert formatted date to new Date() format
|
||||||
export const getDefaultDate = (dateStr, format) => {
|
export const getDefaultDate = (dateStr, format) => {
|
||||||
@@ -4083,3 +4158,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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -533,3 +533,23 @@ export default function reportJson(id) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const usersActions = [
|
||||||
|
{
|
||||||
|
btnId: "4741",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnColor: "op-btn-secondary",
|
||||||
|
btnIcon: "fa-light fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete",
|
||||||
|
restrictAdmin: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1910",
|
||||||
|
hoverLabel: "Reset password",
|
||||||
|
btnIcon: "fa-light fa-key",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "resetpassword",
|
||||||
|
restrictAdmin: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|||||||
@@ -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" },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -84,6 +84,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);
|
||||||
@@ -417,6 +419,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 +460,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
|
||||||
@@ -538,6 +543,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 +657,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 +1234,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>
|
||||||
|
|||||||
@@ -13,6 +13,14 @@ 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 } 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"));
|
||||||
@@ -171,11 +184,24 @@ 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
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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];
|
||||||
@@ -688,7 +688,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 +699,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 +749,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 +767,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 +815,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 +831,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
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ 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 [defaultBody, setDefaultBody] = useState("");
|
||||||
const [defaultSubject, setDefaultSubject] = useState("");
|
const [defaultSubject, setDefaultSubject] = useState("");
|
||||||
@@ -1152,14 +1151,14 @@ 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>
|
||||||
@@ -1372,7 +1371,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="recipientArea"]',
|
selector: '[data-tut="recipientArea"]',
|
||||||
@@ -1384,7 +1383,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="addRecipient"]',
|
selector: '[data-tut="addRecipient"]',
|
||||||
@@ -1396,7 +1395,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="addWidgets"]',
|
selector: '[data-tut="addWidgets"]',
|
||||||
@@ -1408,7 +1407,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="pdfArea"]',
|
selector: '[data-tut="pdfArea"]',
|
||||||
@@ -1420,7 +1419,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="pdftools"]',
|
selector: '[data-tut="pdftools"]',
|
||||||
@@ -1432,7 +1431,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="headerArea"]',
|
selector: '[data-tut="headerArea"]',
|
||||||
@@ -1444,7 +1443,7 @@ function PlaceHolderSign() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -1641,13 +1640,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 +1846,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 +1854,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 +1862,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 +1965,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 +1985,7 @@ function PlaceHolderSign() {
|
|||||||
: false,
|
: false,
|
||||||
TimeToCompleteDays:
|
TimeToCompleteDays:
|
||||||
parseInt(updateDocument?.[0]?.TimeToCompleteDays) || 15,
|
parseInt(updateDocument?.[0]?.TimeToCompleteDays) || 15,
|
||||||
|
...penColors,
|
||||||
...Bcc,
|
...Bcc,
|
||||||
...RedirectUrl
|
...RedirectUrl
|
||||||
};
|
};
|
||||||
@@ -2017,8 +2024,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)}
|
||||||
@@ -2489,6 +2494,7 @@ function PlaceHolderSign() {
|
|||||||
isSave={true}
|
isSave={true}
|
||||||
setUniqueId={setUniqueId}
|
setUniqueId={setUniqueId}
|
||||||
signatureTypes={signatureType}
|
signatureTypes={signatureType}
|
||||||
|
penColors={pdfDetails?.[0]?.PenColors}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ModalUi
|
<ModalUi
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ const Preferences = () => {
|
|||||||
const appName =
|
const appName =
|
||||||
"OpenSign™";
|
"OpenSign™";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const Extand_Class = localStorage.getItem("Extand_Class");
|
|
||||||
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
|
||||||
const [isalert, setIsAlert] = useState({ type: "success", msg: "" });
|
const [isalert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||||
const [isTopLoader, setIsTopLoader] = useState(false);
|
const [isTopLoader, setIsTopLoader] = useState(false);
|
||||||
const [isLoader, setIsLoader] = useState(false);
|
const [isLoader, setIsLoader] = useState(false);
|
||||||
@@ -44,7 +42,6 @@ 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({});
|
const [tenantInfo, setTenantInfo] = useState({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -87,7 +84,6 @@ const Preferences = () => {
|
|||||||
const getUser = extUser.data?.result;
|
const getUser = extUser.data?.result;
|
||||||
if (getUser) {
|
if (getUser) {
|
||||||
const _getUser = JSON.parse(JSON.stringify(getUser));
|
const _getUser = JSON.parse(JSON.stringify(getUser));
|
||||||
setUserInfo(_getUser);
|
|
||||||
setIsNotifyOnSignatures(
|
setIsNotifyOnSignatures(
|
||||||
_getUser?.NotifyOnSignatures !== undefined
|
_getUser?.NotifyOnSignatures !== undefined
|
||||||
? _getUser?.NotifyOnSignatures
|
? _getUser?.NotifyOnSignatures
|
||||||
|
|||||||
@@ -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 }));
|
||||||
}
|
}
|
||||||
@@ -892,7 +893,7 @@ function SignYourSelf() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="reactourSecond"]',
|
selector: '[data-tut="reactourSecond"]',
|
||||||
@@ -904,7 +905,7 @@ function SignYourSelf() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="pdftools"]',
|
selector: '[data-tut="pdftools"]',
|
||||||
@@ -916,7 +917,7 @@ function SignYourSelf() {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -1215,7 +1216,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";
|
||||||
@@ -71,7 +72,6 @@ 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);
|
||||||
@@ -629,7 +629,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,24 +958,16 @@ 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);
|
||||||
@@ -996,7 +988,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 +1017,7 @@ const TemplatePlaceholder = () => {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="reactourAddbtn"]',
|
selector: '[data-tut="reactourAddbtn"]',
|
||||||
@@ -1038,19 +1030,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 +1066,7 @@ const TemplatePlaceholder = () => {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: '[data-tut="headerArea"]',
|
selector: '[data-tut="headerArea"]',
|
||||||
@@ -1074,7 +1078,7 @@ const TemplatePlaceholder = () => {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
position: "top",
|
position: "top",
|
||||||
style: { fontSize: "13px" }
|
styles: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -1277,6 +1281,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 +1301,7 @@ const TemplatePlaceholder = () => {
|
|||||||
: false,
|
: false,
|
||||||
TimeToCompleteDays:
|
TimeToCompleteDays:
|
||||||
parseInt(updateTemplate?.[0]?.TimeToCompleteDays) || 15,
|
parseInt(updateTemplate?.[0]?.TimeToCompleteDays) || 15,
|
||||||
|
...penColors,
|
||||||
...Bcc,
|
...Bcc,
|
||||||
...RedirectUrl
|
...RedirectUrl
|
||||||
};
|
};
|
||||||
@@ -1507,13 +1516,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 +1633,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 +1645,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) => {
|
||||||
@@ -2150,6 +2162,7 @@ const TemplatePlaceholder = () => {
|
|||||||
isSave={true}
|
isSave={true}
|
||||||
setUniqueId={setUniqueId}
|
setUniqueId={setUniqueId}
|
||||||
signatureTypes={signatureType}
|
signatureTypes={signatureType}
|
||||||
|
penColors={pdfDetails?.[0]?.PenColors}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<RotateAlert
|
<RotateAlert
|
||||||
|
|||||||
@@ -13,26 +13,8 @@ import {
|
|||||||
import DeleteUserModal from "../primitives/DeleteUserModal";
|
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";
|
||||||
|
|
||||||
const actions = [
|
|
||||||
{
|
|
||||||
btnId: "4741",
|
|
||||||
hoverLabel: "Delete",
|
|
||||||
btnColor: "op-btn-secondary",
|
|
||||||
btnIcon: "fa-light fa-trash",
|
|
||||||
redirectUrl: "",
|
|
||||||
action: "delete",
|
|
||||||
restrictAdmin: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
btnId: "1910",
|
|
||||||
hoverLabel: "Reset password",
|
|
||||||
btnIcon: "fa-light fa-key",
|
|
||||||
redirectUrl: "",
|
|
||||||
action: "resetpassword",
|
|
||||||
restrictAdmin: true
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"];
|
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"];
|
||||||
const UserList = () => {
|
const UserList = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -342,7 +324,7 @@ const UserList = () => {
|
|||||||
{t(`report-heading.${item}`)}
|
{t(`report-heading.${item}`)}
|
||||||
</th>
|
</th>
|
||||||
))}
|
))}
|
||||||
{actions?.length > 0 && (
|
{usersActions?.length > 0 && (
|
||||||
<th className="p-2 text-transparent pointer-events-none">
|
<th className="p-2 text-transparent pointer-events-none">
|
||||||
{t("action")}
|
{t("action")}
|
||||||
</th>
|
</th>
|
||||||
@@ -429,8 +411,8 @@ const UserList = () => {
|
|||||||
{isAdmin && (
|
{isAdmin && (
|
||||||
<td className="px-3 py-2">
|
<td className="px-3 py-2">
|
||||||
<div className="text-base-content min-w-max flex flex-row gap-x-2 gap-y-1 justify-start items-center">
|
<div className="text-base-content min-w-max flex flex-row gap-x-2 gap-y-1 justify-start items-center">
|
||||||
{actions?.length > 0 &&
|
{usersActions?.length > 0 &&
|
||||||
actions.map((act, index) => (
|
usersActions?.map((act, index) => (
|
||||||
<React.Fragment key={index}>
|
<React.Fragment key={index}>
|
||||||
{handleBtnVisibility(act, item) && (
|
{handleBtnVisibility(act, item) && (
|
||||||
<div
|
<div
|
||||||
@@ -458,37 +440,29 @@ const UserList = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<DeleteUserModal
|
|
||||||
title={t("delete-account")}
|
|
||||||
deleting={deleting}
|
|
||||||
userEmail={item?.Email}
|
|
||||||
isOpen={
|
|
||||||
isActModal[
|
|
||||||
"delete_" + item.objectId
|
|
||||||
]
|
|
||||||
}
|
|
||||||
onConfirm={() =>
|
|
||||||
handleDeleteAccount(item)
|
|
||||||
}
|
|
||||||
deleteRes={deleteUserRes}
|
|
||||||
handleClose={handleCloseModal}
|
|
||||||
/>
|
|
||||||
<PasswordResetModal
|
|
||||||
isOpen={
|
|
||||||
isActModal[
|
|
||||||
"resetpassword_" + item.objectId
|
|
||||||
]
|
|
||||||
}
|
|
||||||
userId={item?.UserId?.objectId}
|
|
||||||
onClose={handleCloseModal}
|
|
||||||
onSubmit={submitPassword}
|
|
||||||
showAlert={showAlert}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
)}
|
)}
|
||||||
|
<DeleteUserModal
|
||||||
|
title={t("delete-account")}
|
||||||
|
deleting={deleting}
|
||||||
|
userEmail={item?.Email}
|
||||||
|
isOpen={isActModal["delete_" + item.objectId]}
|
||||||
|
onConfirm={() => handleDeleteAccount(item)}
|
||||||
|
deleteRes={deleteUserRes}
|
||||||
|
handleClose={handleCloseModal}
|
||||||
|
/>
|
||||||
|
<PasswordResetModal
|
||||||
|
isOpen={
|
||||||
|
isActModal["resetpassword_" + item.objectId]
|
||||||
|
}
|
||||||
|
userId={item?.UserId?.objectId}
|
||||||
|
onClose={handleCloseModal}
|
||||||
|
onSubmit={submitPassword}
|
||||||
|
showAlert={showAlert}
|
||||||
|
/>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ 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";
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ const SignerCell = ({ reportName, item, handleRemovePrefill }) => {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{item.Placeholders.map(
|
{item?.Placeholders?.map(
|
||||||
(x, i) =>
|
(x, i) =>
|
||||||
x.Role !== "prefill" && (
|
x.Role !== "prefill" && (
|
||||||
<tr key={i} className="text-sm font-medium">
|
<tr key={i} className="text-sm font-medium">
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -2,8 +2,12 @@ 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 { useDispatch } from "react-redux";
|
||||||
|
import { sessionStatus } from "../../redux/reducers/userReducer";
|
||||||
|
|
||||||
const EditContactForm = (props) => {
|
const EditContactForm = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
const [isLoader, setIsLoader] = useState(false);
|
const [isLoader, setIsLoader] = useState(false);
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
Name: "",
|
Name: "",
|
||||||
@@ -30,39 +34,49 @@ const EditContactForm = (props) => {
|
|||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (props.handleEditContact) {
|
try {
|
||||||
try {
|
const sessionToken = Parse.User?.current()?.getSessionToken();
|
||||||
setIsLoader(true);
|
if (localStorage.getItem("TenantId") && sessionToken) {
|
||||||
const params = {
|
if (props.handleEditContact) {
|
||||||
contactId: props.contact.objectId,
|
try {
|
||||||
name: formData.Name,
|
setIsLoader(true);
|
||||||
email: formData.Email,
|
const params = {
|
||||||
phone: formData?.Phone,
|
contactId: props.contact.objectId,
|
||||||
company: formData?.Company,
|
name: formData.Name,
|
||||||
jobTitle: formData?.JobTitle,
|
email: formData.Email,
|
||||||
tenantId: localStorage.getItem("TenantId")
|
phone: formData?.Phone,
|
||||||
};
|
company: formData?.Company,
|
||||||
const res = await Parse.Cloud.run("editcontact", params);
|
jobTitle: formData?.JobTitle,
|
||||||
const updateContact = {
|
tenantId: localStorage.getItem("TenantId")
|
||||||
...res,
|
};
|
||||||
Name: formData.Name,
|
const res = await Parse.Cloud.run("editcontact", params);
|
||||||
Email: formData.Email,
|
const updateContact = {
|
||||||
Phone: formData?.Phone,
|
...res,
|
||||||
Company: formData?.Company,
|
Name: formData.Name,
|
||||||
JobTitle: formData?.JobTitle
|
Email: formData.Email,
|
||||||
};
|
Phone: formData?.Phone,
|
||||||
props.handleEditContact(updateContact);
|
Company: formData?.Company,
|
||||||
} catch (err) {
|
JobTitle: formData?.JobTitle
|
||||||
console.log("err in edit contact ", err);
|
};
|
||||||
if (err.code === 137) {
|
props.handleEditContact(updateContact);
|
||||||
alert(t("contact-already-exists"));
|
} catch (err) {
|
||||||
} else {
|
console.log("err in edit contact ", err);
|
||||||
alert(t("something-went-wrong-mssg"));
|
if (err.code === 137) {
|
||||||
|
alert(t("contact-already-exists"));
|
||||||
|
} else {
|
||||||
|
alert(t("something-went-wrong-mssg"));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
setIsLoader(false);
|
||||||
|
props.handleClose && props.handleClose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} else {
|
||||||
setIsLoader(false);
|
dispatch(sessionStatus(false));
|
||||||
props.handleClose && props.handleClose();
|
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("invalid session or missing tenantId ", err);
|
||||||
|
dispatch(sessionStatus(false));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
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 { useDispatch } from "react-redux";
|
||||||
|
import { sessionStatus } from "../../redux/reducers/userReducer";
|
||||||
|
|
||||||
const ImportContact = ({ setLoader, onImport, showAlert }) => {
|
const ImportContact = ({ setLoader, onImport, showAlert }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
const [currentImportPage, setCurrentImportPage] = useState(1);
|
const [currentImportPage, setCurrentImportPage] = useState(1);
|
||||||
const [importedData, setImportedData] = useState([]);
|
const [importedData, setImportedData] = useState([]);
|
||||||
const [invalidRecords, setInvalidRecords] = useState(0);
|
const [invalidRecords, setInvalidRecords] = useState(0);
|
||||||
@@ -183,40 +186,50 @@ const ImportContact = ({ setLoader, onImport, showAlert }) => {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setLoader(true);
|
setLoader(true);
|
||||||
try {
|
try {
|
||||||
const filterdata = importedData.map((x) => ({
|
const sessionToken = Parse.User?.current()?.getSessionToken();
|
||||||
Name: x.Name,
|
if (localStorage.getItem("TenantId") && sessionToken) {
|
||||||
Email: x.Email,
|
try {
|
||||||
Phone: x.Phone,
|
const filterdata = importedData.map((x) => ({
|
||||||
Company: x.Company,
|
Name: x.Name,
|
||||||
JobTitle: x.JobTitle,
|
Email: x.Email,
|
||||||
TenantId: localStorage.getItem("TenantId")
|
Phone: x.Phone,
|
||||||
}));
|
Company: x.Company,
|
||||||
const contacts = JSON.stringify(filterdata);
|
JobTitle: x.JobTitle,
|
||||||
const res = await Parse.Cloud.run("createbatchcontact", { contacts });
|
TenantId: localStorage.getItem("TenantId")
|
||||||
if (res) {
|
}));
|
||||||
showAlert(
|
const contacts = JSON.stringify(filterdata);
|
||||||
"info",
|
const res = await Parse.Cloud.run("createbatchcontact", { contacts });
|
||||||
t("contact-imported", {
|
if (res) {
|
||||||
imported: res?.success || 0,
|
showAlert(
|
||||||
failed: res?.failed || 0
|
"info",
|
||||||
})
|
t("contact-imported", {
|
||||||
);
|
imported: res?.success || 0,
|
||||||
if (res?.success > 0) {
|
failed: res?.failed || 0
|
||||||
setTimeout(() => window.location.reload(), 1500);
|
})
|
||||||
|
);
|
||||||
|
if (res?.success > 0) {
|
||||||
|
setTimeout(() => window.location.reload(), 1500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err while creating batch contact", err);
|
||||||
|
showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
|
} finally {
|
||||||
|
onImport && onImport();
|
||||||
|
setImportedData([]);
|
||||||
|
setInvalidRecords(0);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
dispatch(sessionStatus(false));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err while creating batch contact", err);
|
console.error("invalid session or missing tenantId ", err);
|
||||||
showAlert("danger", t("something-went-wrong-mssg"));
|
dispatch(sessionStatus(false));
|
||||||
} finally {
|
|
||||||
onImport && onImport();
|
|
||||||
setImportedData([]);
|
|
||||||
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();
|
||||||
@@ -267,7 +265,7 @@ const DocumentsReport = (props) => {
|
|||||||
[templateRes || templateDeatils],
|
[templateRes || templateDeatils],
|
||||||
placeholder || xyPosition,
|
placeholder || xyPosition,
|
||||||
signer || signerList,
|
signer || signerList,
|
||||||
templateRes?.URL || templateDeatils?.URL
|
templateRes?.URL || templateDeatils?.URL,
|
||||||
);
|
);
|
||||||
if (res.status === "success") {
|
if (res.status === "success") {
|
||||||
navigate(`/placeHolderSign/${res.id}`, {
|
navigate(`/placeHolderSign/${res.id}`, {
|
||||||
@@ -944,12 +942,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") {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import {
|
|||||||
handleSignatureType,
|
handleSignatureType,
|
||||||
replaceMailVaribles,
|
replaceMailVaribles,
|
||||||
signatureTypes,
|
signatureTypes,
|
||||||
openInNewTab,
|
|
||||||
createDocument,
|
createDocument,
|
||||||
defaultMailBody,
|
defaultMailBody,
|
||||||
defaultMailSubject
|
defaultMailSubject
|
||||||
@@ -30,7 +29,9 @@ 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";
|
||||||
@@ -42,7 +43,6 @@ import CustomizeMail from "../../components/pdf/CustomizeMail";
|
|||||||
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 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 =
|
||||||
@@ -309,7 +309,7 @@ const TemplatesReport = (props) => {
|
|||||||
[templateRes || templateDetails],
|
[templateRes || templateDetails],
|
||||||
placeholder || xyPosition,
|
placeholder || xyPosition,
|
||||||
signer || signerList,
|
signer || signerList,
|
||||||
templateRes?.URL || templateDetails?.URL
|
templateRes?.URL || templateDetails?.URL,
|
||||||
);
|
);
|
||||||
if (res.status === "success") {
|
if (res.status === "success") {
|
||||||
navigate(`/placeHolderSign/${res.id}`, {
|
navigate(`/placeHolderSign/${res.id}`, {
|
||||||
@@ -351,9 +351,6 @@ const TemplatesReport = (props) => {
|
|||||||
setError(t("duplicate-template-widget-error"));
|
setError(t("duplicate-template-widget-error"));
|
||||||
setIsModal({ [`duplicate_${item.objectId}`]: true });
|
setIsModal({ [`duplicate_${item.objectId}`]: true });
|
||||||
} else {
|
} else {
|
||||||
const isPrefill =
|
|
||||||
item?.Placeholders?.some((p) => p?.Role === "prefill") ?? false;
|
|
||||||
setError(isPrefill ? t("duplicate-template-error") : "");
|
|
||||||
setIsModal({ [`duplicate_${item.objectId}`]: true });
|
setIsModal({ [`duplicate_${item.objectId}`]: true });
|
||||||
}
|
}
|
||||||
} else if (act.action === "rename") {
|
} else if (act.action === "rename") {
|
||||||
@@ -903,12 +900,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") {
|
||||||
|
|||||||
@@ -44,8 +44,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mysignatureCanvas {
|
.mysignatureCanvas {
|
||||||
width: 456px;
|
/* width: 456px;
|
||||||
height: 180px;
|
height: 180px; */
|
||||||
|
width: 370px;
|
||||||
|
height: 146px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mystampCanvas {
|
||||||
|
/* width: 446px;
|
||||||
|
height: 180px; */
|
||||||
|
width: 370px;
|
||||||
|
height: 146px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intialSignature {
|
||||||
|
border: 2px solid #888;
|
||||||
|
background-color: rgb(255, 255, 255);
|
||||||
|
/* width: 180px;
|
||||||
|
height: 180px; */
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="opensigndark"] .tabWidth {
|
[data-theme="opensigndark"] .tabWidth {
|
||||||
@@ -70,13 +88,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 +128,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 +457,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 +473,12 @@ option {
|
|||||||
height: 118px;
|
height: 118px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabWidth {
|
.mystampCanvas {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
height: 118px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.penContainerDefault {
|
.tabWidth {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,18 +506,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 +535,12 @@ option {
|
|||||||
width: 230px;
|
width: 230px;
|
||||||
height: 91px;
|
height: 91px;
|
||||||
}
|
}
|
||||||
|
.mystampCanvas {
|
||||||
.tabWidth {
|
|
||||||
width: 230px;
|
width: 230px;
|
||||||
|
height: 91px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.penContainerDefault {
|
.tabWidth {
|
||||||
width: 230px;
|
width: 230px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,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" };
|
||||||
|
|||||||
@@ -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,21 @@ 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()}`;
|
||||||
|
};
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -13,10 +13,13 @@ async function convertLibre(input, ext, opts) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// -------------------- Concurrency limiter (no dependency) --------------------
|
|
||||||
const MAX_CONCURRENCY = Number(process.env.DOCX2PDF_CONCURRENCY || 2); // 1 for tiny droplets
|
// -------------------- Concurrency limiter --------------------
|
||||||
|
// CRITICAL FIX: Reduced to 1 for CPU-intensive LibreOffice conversions
|
||||||
|
const MAX_CONCURRENCY = Number(process.env.DOCX2PDF_CONCURRENCY || 1);
|
||||||
let active = 0;
|
let active = 0;
|
||||||
const queue = [];
|
const queue = [];
|
||||||
|
|
||||||
function runWithLimit(task) {
|
function runWithLimit(task) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const run = () => {
|
const run = () => {
|
||||||
@@ -34,7 +37,7 @@ function runWithLimit(task) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------- Timeout helper (async version = no TS hint) --------------------
|
// -------------------- Timeout helper --------------------
|
||||||
/**
|
/**
|
||||||
* @template T
|
* @template T
|
||||||
* @param {Promise<T>} promise
|
* @param {Promise<T>} promise
|
||||||
@@ -58,6 +61,7 @@ export async function withTimeout(promise, ms, label = 'operation') {
|
|||||||
const storage = multer.memoryStorage();
|
const storage = multer.memoryStorage();
|
||||||
export const upload = multer({
|
export const upload = multer({
|
||||||
storage,
|
storage,
|
||||||
|
limits: { fileSize: 50 * 1024 * 1024 }, // 50MB hard limit at multer level
|
||||||
fileFilter: (req, file, cb) => {
|
fileFilter: (req, file, cb) => {
|
||||||
const okExt = /\.docx$/i.test(file.originalname || '');
|
const okExt = /\.docx$/i.test(file.originalname || '');
|
||||||
const okMime =
|
const okMime =
|
||||||
@@ -109,14 +113,30 @@ export default async function docxtopdf(req, res) {
|
|||||||
return res.status(403).json({ error: 'Tenant not found for user.' });
|
return res.status(403).json({ error: 'Tenant not found for user.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- DOCX -> PDF (buffer -> buffer), with concurrency + timeout ----
|
// ---- DOCX -> PDF conversion with concurrency control and timeout ----
|
||||||
const fileName = `${generatePdfName(16)}.pdf`;
|
const fileName = `${generatePdfName(16)}.pdf`;
|
||||||
|
|
||||||
const pdfBuffer = await runWithLimit(() =>
|
// FIX: Increased timeout to 90s for large files, added nice priority
|
||||||
withTimeout(convertLibre(req.file.buffer, '.pdf', undefined), 60_000, 'DOCX->PDF')
|
const pdfBuffer = await runWithLimit(async () => {
|
||||||
);
|
// Log for monitoring
|
||||||
|
console.log(`[DOCX2PDF] Starting conversion, active: ${active}, queued: ${queue.length}`);
|
||||||
|
|
||||||
// ---- Upload PDF (no disk IO) ----
|
const startTime = Date.now();
|
||||||
|
try {
|
||||||
|
const result = await withTimeout(
|
||||||
|
convertLibre(req.file.buffer, '.pdf', undefined),
|
||||||
|
90_000, // Increased from 60s to 90s
|
||||||
|
'DOCX->PDF'
|
||||||
|
);
|
||||||
|
console.log(`[DOCX2PDF] Completed in ${Date.now() - startTime}ms`);
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[DOCX2PDF] Failed after ${Date.now() - startTime}ms:`, error.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ---- Upload PDF ----
|
||||||
const activeFileAdapter = resUser.data.results[0]?.TenantId?.ActiveFileAdapter;
|
const activeFileAdapter = resUser.data.results[0]?.TenantId?.ActiveFileAdapter;
|
||||||
let fileUrl;
|
let fileUrl;
|
||||||
if (activeFileAdapter) {
|
if (activeFileAdapter) {
|
||||||
@@ -140,12 +160,23 @@ export default async function docxtopdf(req, res) {
|
|||||||
|
|
||||||
return res.status(200).json({ message: 'success.', url: fileUrl });
|
return res.status(200).json({ message: 'success.', url: fileUrl });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const msg =
|
// More specific error messages
|
||||||
|
let msg =
|
||||||
err?.response?.data?.error || err?.response?.data || err?.message || 'Something went wrong.';
|
err?.response?.data?.error || err?.response?.data || err?.message || 'Something went wrong.';
|
||||||
console.log(`Error in docxtopdf: ${msg}`);
|
|
||||||
// Friendly message to the client
|
// Friendly message to the client
|
||||||
const message =
|
const message =
|
||||||
'We are currently experiencing some issues with processing DOCX files. Please upload the PDF version or contact us on support@opensignlabs.com';
|
'We are currently experiencing some issues with processing DOCX files. Please upload the PDF version or contact us on support@opensignlabs.com';
|
||||||
|
|
||||||
|
if (msg.includes('timed out')) {
|
||||||
|
msg =
|
||||||
|
'Document conversion is taking too long. Please try a smaller file or contact support@opensignlabs.com';
|
||||||
|
} else if (msg.includes('too large') || msg.includes('size')) {
|
||||||
|
msg =
|
||||||
|
'File is too large to process. Please reduce the file size or contact support@opensignlabs.com';
|
||||||
|
} else {
|
||||||
|
msg = message;
|
||||||
|
}
|
||||||
|
console.error(`[DOCX2PDF] Error: ${msg}`);
|
||||||
return res.status(400).json({ error: message });
|
return res.status(400).json({ error: message });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,11 +101,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,10 +185,10 @@ async function batchQuery(userId, Documents, Ip, parseConfig, type, publicUrl) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
|
...(x?.PenColors?.length > 0 ? { PenColors: x?.PenColors } : {}),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
// console.log('requests ', requests);
|
|
||||||
if (requests?.length > 0) {
|
if (requests?.length > 0) {
|
||||||
const newrequests = [requests?.[0]];
|
const newrequests = [requests?.[0]];
|
||||||
const response = await axios.post('batch', { requests: newrequests }, parseConfig);
|
const response = await axios.post('batch', { requests: newrequests }, parseConfig);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
};
|
||||||
@@ -17,7 +17,7 @@ import { exec } from 'child_process';
|
|||||||
import { createTransport } from 'nodemailer';
|
import { createTransport } from 'nodemailer';
|
||||||
import { appName, cloudServerUrl, serverAppId, smtpenable, smtpsecure, useLocal } from './Utils.js';
|
import { appName, cloudServerUrl, serverAppId, smtpenable, smtpsecure, useLocal } from './Utils.js';
|
||||||
import { SSOAuth } from './auth/authadapter.js';
|
import { SSOAuth } from './auth/authadapter.js';
|
||||||
import createContactIndex from './migrationdb/createContactIndex.js';
|
import runDbMigrations from './migrationdb/index.js';
|
||||||
import { validateSignedLocalUrl } from './cloud/parsefunction/getSignedUrl.js';
|
import { validateSignedLocalUrl } from './cloud/parsefunction/getSignedUrl.js';
|
||||||
import maintenance_mode_message from 'aws-sdk/lib/maintenance_mode_message.js';
|
import maintenance_mode_message from 'aws-sdk/lib/maintenance_mode_message.js';
|
||||||
let fsAdapter;
|
let fsAdapter;
|
||||||
@@ -119,6 +119,7 @@ export const config = {
|
|||||||
allowClientClassCreation: false,
|
allowClientClassCreation: false,
|
||||||
allowExpiredAuthDataToken: false,
|
allowExpiredAuthDataToken: false,
|
||||||
enableInsecureAuthAdapters: false,
|
enableInsecureAuthAdapters: false,
|
||||||
|
databaseOptions: { allowPublicExplain: false },
|
||||||
encodeParseObjectInCloudFunction: true,
|
encodeParseObjectInCloudFunction: true,
|
||||||
...(isMailAdapter === true
|
...(isMailAdapter === true
|
||||||
? {
|
? {
|
||||||
@@ -240,7 +241,7 @@ if (!process.env.TESTING) {
|
|||||||
console.log('opensign-server running on port ' + port + '.');
|
console.log('opensign-server running on port ' + port + '.');
|
||||||
const isWindows = process.platform === 'win32';
|
const isWindows = process.platform === 'win32';
|
||||||
// console.log('isWindows', isWindows);
|
// console.log('isWindows', isWindows);
|
||||||
createContactIndex();
|
runDbMigrations();
|
||||||
const migrate = isWindows
|
const migrate = isWindows
|
||||||
? `set APPLICATION_ID=${serverAppId}&& set SERVER_URL=${cloudServerUrl}&& set MASTER_KEY=${process.env.MASTER_KEY}&& npx parse-dbtool migrate`
|
? `set APPLICATION_ID=${serverAppId}&& set SERVER_URL=${cloudServerUrl}&& set MASTER_KEY=${process.env.MASTER_KEY}&& npx parse-dbtool migrate`
|
||||||
: `APPLICATION_ID=${serverAppId} SERVER_URL=${cloudServerUrl} MASTER_KEY=${process.env.MASTER_KEY} npx parse-dbtool migrate`;
|
: `APPLICATION_ID=${serverAppId} SERVER_URL=${cloudServerUrl} MASTER_KEY=${process.env.MASTER_KEY} npx parse-dbtool migrate`;
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ export default async function createContactIndex() {
|
|||||||
const migrationExists = await migrationCollection.findOne({ name: migrationName });
|
const migrationExists = await migrationCollection.findOne({ name: migrationName });
|
||||||
|
|
||||||
if (migrationExists) {
|
if (migrationExists) {
|
||||||
console.log(' INFO No migrations were executed, database schema was already up to date.');
|
console.log(' INFO The unqiue index for contracts_Contactbook is already present.');
|
||||||
console.log(' SUCCESS Successfully ran indexed migrations directly on db.');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,10 +60,9 @@ export default async function createContactIndex() {
|
|||||||
|
|
||||||
// Insert the document
|
// Insert the document
|
||||||
await migrationdb.insertOne(schemaDocument);
|
await migrationdb.insertOne(schemaDocument);
|
||||||
console.log(' Unique index created successfully.');
|
console.log(' SUCCESS The unqiue index for contracts_Contactbook is already created.');
|
||||||
console.log(' SUCCESS Successfully ran indexed migrations directly on db.');
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(' ERROR running indexed migration:', error);
|
console.log(' ERROR Running unqiue index for contracts_Contactbook migration:', error);
|
||||||
} finally {
|
} finally {
|
||||||
await client.close();
|
await client.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import dotenv from 'dotenv';
|
||||||
|
import { MongoClient } from 'mongodb';
|
||||||
|
import { generateId } from '../Utils.js';
|
||||||
|
dotenv.config({ quiet: true });
|
||||||
|
|
||||||
|
export default async function createDocumentIndex() {
|
||||||
|
// Provide the complete MongoDB connection URL with the database name
|
||||||
|
const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/dev'; // Replace with your MongoDB URI
|
||||||
|
const client = new MongoClient(uri);
|
||||||
|
try {
|
||||||
|
await client.connect();
|
||||||
|
const database = client.db();
|
||||||
|
|
||||||
|
const migrationCollection = database.collection('Migrationdb');
|
||||||
|
const docMigration = 'documentIndex_1';
|
||||||
|
|
||||||
|
// Check if the migration has already been executed
|
||||||
|
const docMigrationExists = await migrationCollection.findOne({ name: docMigration });
|
||||||
|
|
||||||
|
if (docMigrationExists) {
|
||||||
|
console.log(' INFO The completed report index for contracts_document is already present.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const docCollection = database.collection('contracts_Document');
|
||||||
|
|
||||||
|
await docCollection.createIndex(
|
||||||
|
{ _p_CreatedBy: 1, _updated_at: -1 },
|
||||||
|
{
|
||||||
|
name: 'idx_docs_by_creator_recent_completed',
|
||||||
|
partialFilterExpression: { IsCompleted: true },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await docCollection.createIndex(
|
||||||
|
{ Signers: 1, _updated_at: -1 },
|
||||||
|
{
|
||||||
|
name: 'idx_docs_by_signer_recent_completed',
|
||||||
|
partialFilterExpression: { IsCompleted: true },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Save the migration record in the migrationdb collection
|
||||||
|
await migrationCollection.insertOne({
|
||||||
|
_id: generateId(10),
|
||||||
|
name: docMigration,
|
||||||
|
_created_at: new Date(),
|
||||||
|
_updated_at: new Date(),
|
||||||
|
executedAt: new Date(),
|
||||||
|
details: 'Created unique index on CreatedBy, IsImported, Email',
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(' SUCCESS The completed report index for contracts_document is created.');
|
||||||
|
} catch (error) {
|
||||||
|
console.log(' ERROR Running completed report index for contracts_document migration:', error);
|
||||||
|
} finally {
|
||||||
|
await client.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import createContactIndex from './createContactIndex.js';
|
||||||
|
import createDocumentIndex from './createDocumentIndex.js';
|
||||||
|
|
||||||
|
export default async function runDbMigrations() {
|
||||||
|
await createContactIndex();
|
||||||
|
await createDocumentIndex();
|
||||||
|
}
|
||||||
Generated
+14894
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "open_sign_server",
|
"name": "open_sign_server",
|
||||||
"version": "2.32.0",
|
"version": "2.34.0",
|
||||||
"description": "opensign server using the parse-server module",
|
"description": "opensign server using the parse-server module",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -18,41 +18,42 @@
|
|||||||
"watch": "nodemon index.js"
|
"watch": "nodemon index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.940.0",
|
"@aws-sdk/client-s3": "^3.952.0",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.940.0",
|
"@aws-sdk/s3-request-presigner": "^3.952.0",
|
||||||
"@parse/fs-files-adapter": "^3.0.0",
|
"@parse/fs-files-adapter": "^3.0.0",
|
||||||
"@parse/push-adapter": "^7.0.0",
|
"@parse/push-adapter": "^8.1.0",
|
||||||
"@parse/s3-files-adapter": "^4.2.0",
|
"@parse/s3-files-adapter": "^4.2.0",
|
||||||
"@pdf-lib/fontkit": "^1.1.1",
|
"@pdf-lib/fontkit": "^1.1.1",
|
||||||
"@signpdf/placeholder-pdf-lib": "^3.2.6",
|
"@signpdf/placeholder-pdf-lib": "^3.2.6",
|
||||||
"@signpdf/signer-p12": "^3.2.4",
|
"@signpdf/signer-p12": "^3.2.4",
|
||||||
"@signpdf/signpdf": "^3.2.5",
|
"@signpdf/signpdf": "^3.2.5",
|
||||||
"aws-sdk": "^2.1692.0",
|
"aws-sdk": "^2.1693.0",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"coherentpdf": "^2.5.5",
|
"coherentpdf": "^2.5.5",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"date-fns-tz": "^3.2.0",
|
"date-fns-tz": "^3.2.0",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"express": "^5.1.0",
|
"express": "^5.2.1",
|
||||||
"form-data": "^4.0.5",
|
"form-data": "^4.0.5",
|
||||||
"generate-api-key": "^1.0.2",
|
"generate-api-key": "^1.0.2",
|
||||||
"googleapis": "^166.0.0",
|
"googleapis": "^169.0.0",
|
||||||
"libreoffice-convert": "^1.7.0",
|
"libreoffice-convert": "^1.7.0",
|
||||||
"mailgun.js": "^12.2.0",
|
"mailgun.js": "^12.4.0",
|
||||||
"mongodb": "^5.9.2",
|
"moment": "^2.30.1",
|
||||||
|
"mongodb": "^7.0.0",
|
||||||
"multer": "^2.0.2",
|
"multer": "^2.0.2",
|
||||||
"multer-s3": "^3.0.1",
|
"multer-s3": "^3.0.1",
|
||||||
"node-forge": "^1.3.1",
|
"node-forge": "^1.3.3",
|
||||||
"nodemailer": "^7.0.11",
|
"nodemailer": "^7.0.11",
|
||||||
"p-limit": "^7.2.0",
|
"p-limit": "^7.2.0",
|
||||||
"parse": "^7.0.2",
|
"parse": "^8.0.0",
|
||||||
"parse-dbtool": "^1.2.0",
|
"parse-dbtool": "^1.2.0",
|
||||||
"parse-server": "^8.4.0",
|
"parse-server": "^8.6.2",
|
||||||
"parse-server-api-mail-adapter": "^5.0.2",
|
"parse-server-api-mail-adapter": "^5.0.2",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"posthog-node": "^5.14.0",
|
"posthog-node": "^5.17.2",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"rate-limiter-flexible": "^8.3.0",
|
"rate-limiter-flexible": "^9.0.1",
|
||||||
"sharp": "^0.34.5",
|
"sharp": "^0.34.5",
|
||||||
"speakeasy": "^2.0.0",
|
"speakeasy": "^2.0.0",
|
||||||
"ws": "^8.18.3"
|
"ws": "^8.18.3"
|
||||||
@@ -60,12 +61,12 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/eslint-parser": "^7.28.5",
|
"@babel/eslint-parser": "^7.28.5",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.2",
|
||||||
"jasmine": "^5.12.0",
|
"jasmine": "^5.12.0",
|
||||||
"mongodb-runner": "^5.11.1",
|
"mongodb-runner": "^6.4.0",
|
||||||
"nodemon": "^3.1.11",
|
"nodemon": "^3.1.11",
|
||||||
"nyc": "^17.1.0",
|
"nyc": "^17.1.0",
|
||||||
"prettier": "^3.6.2"
|
"prettier": "^3.7.4"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"ws": "$ws",
|
"ws": "$ws",
|
||||||
|
|||||||
Reference in New Issue
Block a user