Compare commits

...
16 Commits
Author SHA1 Message Date
prafull-opensignlabsandGitHub fca45ced38 Merge pull request #1663 from OpenSignLabs/updates-14122971328
v2.15.0
2025-03-28 11:37:55 +05:30
prafull-opensignlabs ac8ab70246 v2.15.0
v2.15.0
2025-03-28 06:02:14 +00:00
prafull-opensignlabsandGitHub 8373679f27 Merge pull request #1661 from OpenSignLabs/do_deploy
feat: update proxy file
2025-03-24 13:47:33 +05:30
prafull-opensignlabs 0a23aabbe4 feat: update proxy file 2025-03-24 13:45:45 +05:30
prafull-opensignlabsandGitHub 4a85599703 Merge pull request #1660 from OpenSignLabs/updates-14030275569
feat: changes to implement one click deployment
2025-03-24 13:42:41 +05:30
prafull-opensignlabs 3e9b84de72 feat: changes to implement one click deployment
feat: changes to implement one click deployment
2025-03-24 08:11:52 +00:00
prafull-opensignlabsandGitHub 4313d8d0e4 Merge pull request #1654 from OpenSignLabs/updates-14016837992
refactor: remove unnecessary code
2025-03-23 13:11:28 +05:30
prafull-opensignlabs 3088fdd163 Merge pull request #403 from OpenSignLabs/staging
refactor: remove unnecessary code
2025-03-23 07:40:01 +00:00
ZathielandGitHub 8c86fe27ec Merge pull request #1616 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/i18next-browser-languagedetector-8.0.4
build(deps): bump i18next-browser-languagedetector from 8.0.2 to 8.0.4 in /apps/OpenSign
2025-03-21 21:50:38 +01:00
ZathielandGitHub 01e09998e5 Merge pull request #1650 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/npm_and_yarn-1c007eb283
build(deps): bump axios from 1.8.3 to 1.8.4 in /apps/OpenSignServer in the npm_and_yarn group across 1 directory
2025-03-21 21:49:55 +01:00
ZathielandGitHub 55fdb52bf3 Merge pull request #1651 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/npm_and_yarn-1c007eb283
build(deps): bump axios from 1.8.3 to 1.8.4 in /apps/OpenSign in the npm_and_yarn group across 1 directory
2025-03-21 21:49:17 +01:00
dependabot[bot]andGitHub 08f46a393b build(deps): bump axios
Bumps the npm_and_yarn group with 1 update in the /apps/OpenSign directory: [axios](https://github.com/axios/axios).


Updates `axios` from 1.8.3 to 1.8.4
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.8.3...v1.8.4)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-21 14:41:30 +00:00
dependabot[bot]andGitHub 9345da543a build(deps): bump axios
Bumps the npm_and_yarn group with 1 update in the /apps/OpenSignServer directory: [axios](https://github.com/axios/axios).


Updates `axios` from 1.8.3 to 1.8.4
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.8.3...v1.8.4)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-21 14:41:20 +00:00
dependabot[bot]andGitHub 208891e10d build(deps): bump i18next-browser-languagedetector in /apps/OpenSign
Bumps [i18next-browser-languagedetector](https://github.com/i18next/i18next-browser-languageDetector) from 8.0.2 to 8.0.4.
- [Changelog](https://github.com/i18next/i18next-browser-languageDetector/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next-browser-languageDetector/compare/v8.0.2...v8.0.4)

---
updated-dependencies:
- dependency-name: i18next-browser-languagedetector
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-21 14:41:17 +00:00
prafull-opensignlabsandGitHub db0fa61b2b Merge pull request #1648 from OpenSignLabs/updates-13994222227
v2.14.0
2025-03-21 20:09:57 +05:30
prafull-opensignlabs 221f098de6 v2.14.0
v2.14.0
2025-03-21 14:38:32 +00:00
45 changed files with 4214 additions and 4240 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
{$HOST_URL} { {$HOST_URL} {
reverse_proxy client:3000 reverse_proxy client:3000
handle_path /app/* { handle_path /api/* {
reverse_proxy server:8080 reverse_proxy server:8080
rewrite * /app{uri} rewrite * {uri}
} }
} }
+407 -516
View File
File diff suppressed because it is too large Load Diff
+24 -23
View File
@@ -4,17 +4,18 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@formkit/auto-animate": "^0.8.2", "@formkit/auto-animate": "^0.8.2",
"@lottiefiles/dotlottie-react": "^0.13.0", "@lottiefiles/dotlottie-react": "^0.13.2",
"@pdf-lib/fontkit": "^1.1.1", "@pdf-lib/fontkit": "^1.1.1",
"@radix-ui/themes": "^3.1.6", "@radix-ui/themes": "^3.1.6",
"@react-pdf/renderer": "^4.1.6", "@react-pdf/renderer": "^4.3.0",
"@reduxjs/toolkit": "^2.5.1", "@reduxjs/toolkit": "^2.5.1",
"axios": "^1.7.9", "axios": "^1.8.4",
"css-minimizer-webpack-plugin": "^7.0.0", "css-minimizer-webpack-plugin": "^7.0.2",
"date-fns-tz": "^3.2.0",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"i18next": "^23.16.8", "i18next": "^23.16.8",
"i18next-browser-languagedetector": "^8.0.2", "i18next-browser-languagedetector": "^8.0.4",
"i18next-http-backend": "^3.0.1", "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",
@@ -25,7 +26,7 @@
"radix-ui": "^1.0.1", "radix-ui": "^1.0.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-bootstrap": "^2.10.9", "react-bootstrap": "^2.10.9",
"react-confetti": "^6.2.2", "react-confetti": "^6.4.0",
"react-cookie": "^7.2.2", "react-cookie": "^7.2.2",
"react-datepicker": "^7.6.0", "react-datepicker": "^7.6.0",
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
@@ -35,16 +36,16 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-gtm-module": "^2.0.11", "react-gtm-module": "^2.0.11",
"react-helmet": "^6.1.0", "react-helmet": "^6.1.0",
"react-i18next": "^15.4.0", "react-i18next": "^15.4.1",
"react-konva": "^18.2.10", "react-konva": "^18.2.10",
"react-pdf": "^9.2.1", "react-pdf": "^9.2.1",
"react-quill-new": "^3.3.3", "react-quill-new": "^3.4.6",
"react-redux": "^9.2.0", "react-redux": "^9.2.0",
"react-rnd": "^10.4.14", "react-rnd": "^10.5.2",
"react-router": "^7.1.5", "react-router": "^7.1.5",
"react-scripts": "^5.0.1", "react-scripts": "^5.0.1",
"react-scrollbars-custom": "^4.1.1", "react-scrollbars-custom": "^4.1.1",
"react-select": "^5.10.0", "react-select": "^5.10.1",
"react-signature-canvas": "^1.0.7", "react-signature-canvas": "^1.0.7",
"react-syntax-highlighter": "^15.6.1", "react-syntax-highlighter": "^15.6.1",
"react-timezone-select": "^3.2.8", "react-timezone-select": "^3.2.8",
@@ -53,11 +54,11 @@
"reactour": "^1.19.4", "reactour": "^1.19.4",
"redux": "^5.0.1", "redux": "^5.0.1",
"redux-thunk": "^3.1.0", "redux-thunk": "^3.1.0",
"regex-parser": "^2.3.0", "regex-parser": "^2.3.1",
"serve": "^14.2.4", "serve": "^14.2.4",
"styled-components": "^5.3.0", "styled-components": "^5.3.0",
"web-vitals": "^4.2.4", "web-vitals": "^4.2.4",
"ws": "^8.18.0", "ws": "^8.18.1",
"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"
}, },
"scripts": { "scripts": {
@@ -96,26 +97,26 @@
} }
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.26.9", "@babel/core": "^7.26.10",
"@babel/preset-env": "^7.26.9", "@babel/preset-env": "^7.26.9",
"@babel/preset-react": "^7.26.3", "@babel/preset-react": "^7.26.3",
"@babel/runtime-corejs2": "^7.26.9", "@babel/runtime-corejs2": "^7.27.0",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.21",
"babel-loader": "^9.2.1", "babel-loader": "^10.0.0",
"commitizen": "^4.3.1", "commitizen": "^4.3.1",
"concurrently": "^9.1.2", "concurrently": "^9.1.2",
"css-loader": "^7.1.2", "css-loader": "^7.1.2",
"daisyui": "^4.12.23", "daisyui": "^4.12.23",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"dotenv-webpack": "^8.1.0", "dotenv-webpack": "^8.1.0",
"eslint": "^9.20.0", "eslint": "^9.23.0",
"eslint-plugin-prettier": "^5.2.3", "eslint-plugin-prettier": "^5.2.5",
"eslint-plugin-react": "^7.37.4", "eslint-plugin-react": "^7.37.4",
"lint-staged": "^15.4.3", "lint-staged": "^15.5.0",
"mini-css-extract-plugin": "^2.9.2", "mini-css-extract-plugin": "^2.9.2",
"postcss": "^8.5.1", "postcss": "^8.5.3",
"prettier": "^3.5.0", "prettier": "^3.5.3",
"pretty-quick": "^4.0.0", "pretty-quick": "^4.1.1",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"terser-webpack-plugin": "^5.3.11", "terser-webpack-plugin": "^5.3.11",
"webpack-cli": "^5.1.4" "webpack-cli": "^5.1.4"
@@ -247,7 +247,7 @@
"generate-token-alert": "Sind Sie sicher, dass Sie das Token neu generieren möchten? Das alte Token wird ablaufen.", "generate-token-alert": "Sind Sie sicher, dass Sie das Token neu generieren möchten? Das alte Token wird ablaufen.",
"yes": "Ja", "yes": "Ja",
"copied": "Kopiert", "copied": "Kopiert",
"something-went-wrong-mssg": "Etwas ist schiefgelaufen. Bitte versuchen Sie es später erneut.", "something-went-wrong-mssg": "Etwas ist schiefgelaufen, Das Aktualisieren dieser Seite kann das Problem lösen.",
"token-generated": "Token erfolgreich generiert.", "token-generated": "Token erfolgreich generiert.",
"webhook": "Webhook", "webhook": "Webhook",
"update-webhook": "Webhook aktualisieren", "update-webhook": "Webhook aktualisieren",
@@ -458,6 +458,7 @@
"placeholder-alert-3": "Sind Sie sicher, dass Sie dieses Dokument zur Unterzeichnung senden möchten?", "placeholder-alert-3": "Sind Sie sicher, dass Sie dieses Dokument zur Unterzeichnung senden möchten?",
"placeholder-alert-4": "Sie haben erfolgreich E-Mails an alle Empfänger gesendet!", "placeholder-alert-4": "Sie haben erfolgreich E-Mails an alle Empfänger gesendet!",
"placeholder-mail-alert": "Sie haben erfolgreich eine E-Mail an {{name}} gesendet. Die nachfolgenden Unterzeichner erhalten eine E-Mail, sobald {{name}} das Dokument unterzeichnet.", "placeholder-mail-alert": "Sie haben erfolgreich eine E-Mail an {{name}} gesendet. Die nachfolgenden Unterzeichner erhalten eine E-Mail, sobald {{name}} das Dokument unterzeichnet.",
"placeholder-mail-alert-you": "Nachfolgende Unterzeichner erhalten E-Mails, sobald Sie das Dokument unterschreiben.",
"placeholder-alert-5": "Möchten Sie die Dokumente jetzt unterschreiben?", "placeholder-alert-5": "Möchten Sie die Dokumente jetzt unterschreiben?",
"placeholder-alert-6": "Bitte richten Sie den E-Mail-Adapter ein, um E-Mails zu senden!", "placeholder-alert-6": "Bitte richten Sie den E-Mail-Adapter ein, um E-Mails zu senden!",
"placeholder-alert-7": "Bitte wählen Sie einen Unterzeichner aus, um Platzhalter hinzuzufügen!", "placeholder-alert-7": "Bitte wählen Sie einen Unterzeichner aus, um Platzhalter hinzuzufügen!",
@@ -831,7 +832,7 @@
"initial-type": "Ihre Initialen", "initial-type": "Ihre Initialen",
"redirect-url": "Weiterleitungs-URL", "redirect-url": "Weiterleitungs-URL",
"bulk-send": "Massenversand", "bulk-send": "Massenversand",
"select-timezone": "Wählen Sie Ihre Zeitzone", "select-timezone": "Zeitzone",
"current-time": "Aktuelle Uhrzeit", "current-time": "Aktuelle Uhrzeit",
"email-help": "Aus Sicherheitsgründen dürfen Sie die E-Mail-Adresse nicht ändern. Bitte erstellen Sie ein weiteres kostenloses Konto mit der neuen E-Mail-Adresse.", "email-help": "Aus Sicherheitsgründen dürfen Sie die E-Mail-Adresse nicht ändern. Bitte erstellen Sie ein weiteres kostenloses Konto mit der neuen E-Mail-Adresse.",
"doc-sent": "Dokument erfolgreich gesendet.", "doc-sent": "Dokument erfolgreich gesendet.",
@@ -856,5 +857,11 @@
"enabled-signature-type-help": "Die Einstellung 'Aktivierte Signaturtypen' bestimmt, welche Signaturoptionen in Ihrer Organisation verfügbar sind. Wenn Sie beispielsweise die Option 'Zeichnen' deaktivieren, wird sie den Mitgliedern Ihrer Organisation im Signatur-Widget nicht angezeigt, während die anderen drei Optionen weiterhin zugänglich bleiben.", "enabled-signature-type-help": "Die Einstellung 'Aktivierte Signaturtypen' bestimmt, welche Signaturoptionen in Ihrer Organisation verfügbar sind. Wenn Sie beispielsweise die Option 'Zeichnen' deaktivieren, wird sie den Mitgliedern Ihrer Organisation im Signatur-Widget nicht angezeigt, während die anderen drei Optionen weiterhin zugänglich bleiben.",
"indexing-public-profile": "Erlaube die Indexierung des öffentlichen Profils durch Suchmaschinen", "indexing-public-profile": "Erlaube die Indexierung des öffentlichen Profils durch Suchmaschinen",
"user-created-successfully": "Benutzer erfolgreich erstellt.", "user-created-successfully": "Benutzer erfolgreich erstellt.",
"only-15-reminder-allowed": "Sie können bis zu 15 automatische Erinnerungen festlegen. Wenn zum Beispiel 'TimeToComplete' auf 15 Tage und 'RemindOnceInEvery' auf 1 Tag eingestellt ist, erreichen Sie das maximale Limit von 15 Erinnerungen. Passen Sie Ihre Einstellungen entsprechend an." "only-15-reminder-allowed": "Sie können bis zu 15 automatische Erinnerungen festlegen. Wenn zum Beispiel 'TimeToComplete' auf 15 Tage und 'RemindOnceInEvery' auf 1 Tag eingestellt ist, erreichen Sie das maximale Limit von 15 Erinnerungen. Passen Sie Ihre Einstellungen entsprechend an.",
"rate-your-experience": "👋 Bitte bewerten Sie Ihre Erfahrung mit Opensign",
"thanks-for-feedback": "Danke für Ihr Feedback 🙏",
"share-your-feedback": "Teilen Sie Ihr Feedback",
"share-your-review": "Teilen Sie Ihre Bewertung",
"date-format": "Datumsformat",
"document-deleted": "Das Dokument wurde gelöscht oder Sie haben keinen Zugriff. Bitte kontaktieren Sie den Absender."
} }
@@ -247,7 +247,7 @@
"generate-token-alert": "Are you sure you want to regenerate token it will expire old token?", "generate-token-alert": "Are you sure you want to regenerate token it will expire old token?",
"yes": "Yes", "yes": "Yes",
"copied": "Copied", "copied": "Copied",
"something-went-wrong-mssg": "Something went wrong, please try again later.", "something-went-wrong-mssg": "Something went wrong, refreshing this page may solve this issue.",
"token-generated": "Token generated successfully.", "token-generated": "Token generated successfully.",
"webhook": "Webhook", "webhook": "Webhook",
"update-webhook": "Update webhook", "update-webhook": "Update webhook",
@@ -458,6 +458,7 @@
"placeholder-alert-3": " Are you sure you want to send out this document for signatures?", "placeholder-alert-3": " Are you sure you want to send out this document for signatures?",
"placeholder-alert-4": "You have successfully sent mails to all recipients!", "placeholder-alert-4": "You have successfully sent mails to all recipients!",
"placeholder-mail-alert": "You have successfully sent email to {{name}}. Subsequent signers will get email(s) once {{name}} signs the document", "placeholder-mail-alert": "You have successfully sent email to {{name}}. Subsequent signers will get email(s) once {{name}} signs the document",
"placeholder-mail-alert-you": "Subsequent signers will get email(s) once you signs the document.",
"placeholder-alert-5": "Do you want to sign the document right now?", "placeholder-alert-5": "Do you want to sign the document right now?",
"placeholder-alert-6": "Please setup mail adapter to send mail!", "placeholder-alert-6": "Please setup mail adapter to send mail!",
"placeholder-alert-7": "Please select signer for add placeholder!", "placeholder-alert-7": "Please select signer for add placeholder!",
@@ -831,7 +832,7 @@
"initial-type": "Your initials", "initial-type": "Your initials",
"redirect-url": "Redirect url", "redirect-url": "Redirect url",
"bulk-send": "Bulk send", "bulk-send": "Bulk send",
"select-timezone": "Select your Timezone", "select-timezone": "Timezone",
"current-time": "Current time", "current-time": "Current time",
"email-help": "You are not allowed to change email address due to security reasons. Please create another free account using the new email address.", "email-help": "You are not allowed to change email address due to security reasons. Please create another free account using the new email address.",
"doc-sent": "Document sent successfully.", "doc-sent": "Document sent successfully.",
@@ -856,5 +857,11 @@
"enabled-signature-type-help": "The 'Enabled Signature Types' setting determines which signature options are available across your organization. For example, if you disable the 'Draw' option, members of your organization will not see it in the signature widget, while the other three options will remain accessible.", "enabled-signature-type-help": "The 'Enabled Signature Types' setting determines which signature options are available across your organization. For example, if you disable the 'Draw' option, members of your organization will not see it in the signature widget, while the other three options will remain accessible.",
"indexing-public-profile": "Allow indexing of public profile by search engines", "indexing-public-profile": "Allow indexing of public profile by search engines",
"user-created-successfully": "user created successfully.", "user-created-successfully": "user created successfully.",
"only-15-reminder-allowed": "You can set up to 15 automatic reminders. For example, if 'TimeToComplete' is 15 days and 'RemindOnceInEvery' is 1 day, you'll reach the maximum limit of 15 reminders. Adjust your settings accordingly." "only-15-reminder-allowed": "You can set up to 15 automatic reminders. For example, if 'TimeToComplete' is 15 days and 'RemindOnceInEvery' is 1 day, you'll reach the maximum limit of 15 reminders. Adjust your settings accordingly.",
"rate-your-experience": "👋 Please rate your experience with Opensign",
"thanks-for-feedback": "Thanks for your feedback 🙏",
"share-your-feedback": "Share your feedback",
"share-your-review": "Share your review",
"date-format": "Date format",
"document-deleted": "The document has been deleted or you don't have access. Please contact the sender."
} }
@@ -248,7 +248,7 @@
"generate-token-alert": "¿En definitiva quieres regenerar el token? Esto expirará el token antiguo.", "generate-token-alert": "¿En definitiva quieres regenerar el token? Esto expirará el token antiguo.",
"yes": "Sí", "yes": "Sí",
"copied": "Copiado", "copied": "Copiado",
"something-went-wrong-mssg": "Algo salió mal, por favor, intenta de nuevo más tarde.", "something-went-wrong-mssg": "Un problème est survenu, Actualiser cette page peut résoudre le problème.",
"token-generated": "Token generado exitosamente.", "token-generated": "Token generado exitosamente.",
"webhook": "Webhook", "webhook": "Webhook",
"update-webhook": "Actualizar webhook", "update-webhook": "Actualizar webhook",
@@ -458,6 +458,7 @@
"placeholder-alert-3": " ¿En definitiva quieres enviar este documento para ser firmado?", "placeholder-alert-3": " ¿En definitiva quieres enviar este documento para ser firmado?",
"placeholder-alert-4": "¡Has enviado exitosamente correos a todos los destinatarios!", "placeholder-alert-4": "¡Has enviado exitosamente correos a todos los destinatarios!",
"placeholder-mail-alert": "Has enviado un correo electrónico con éxito a {{name}}. Los siguientes firmantes recibirán un correo electrónico una vez que {{name}} firme el documento.", "placeholder-mail-alert": "Has enviado un correo electrónico con éxito a {{name}}. Los siguientes firmantes recibirán un correo electrónico una vez que {{name}} firme el documento.",
"placeholder-mail-alert-you": "Los firmantes posteriores recibirán correos electrónicos una vez que firme el documento.",
"placeholder-alert-5": "¿Quieres firmar documentos ahora mismo?", "placeholder-alert-5": "¿Quieres firmar documentos ahora mismo?",
"placeholder-alert-6": "¡Por favor, configura el adaptador de correo para enviar correos!", "placeholder-alert-6": "¡Por favor, configura el adaptador de correo para enviar correos!",
"placeholder-alert-7": "¡Por favor, selecciona un firmante para agregar un marcador de posición!", "placeholder-alert-7": "¡Por favor, selecciona un firmante para agregar un marcador de posición!",
@@ -831,7 +832,7 @@
"initial-type": "Tus iniciales", "initial-type": "Tus iniciales",
"redirect-url": "URL de redireccionamiento", "redirect-url": "URL de redireccionamiento",
"bulk-send": "envío masivo", "bulk-send": "envío masivo",
"select-timezone": "Seleccione su zona horaria", "select-timezone": "Zona horaria",
"current-time": "Hora actual", "current-time": "Hora actual",
"email-help": "No se permite cambiar la dirección de correo electrónico por razones de seguridad. Por favor, cree otra cuenta gratuita utilizando la nueva dirección de correo electrónico.", "email-help": "No se permite cambiar la dirección de correo electrónico por razones de seguridad. Por favor, cree otra cuenta gratuita utilizando la nueva dirección de correo electrónico.",
"doc-sent": "Documento enviado con éxito.", "doc-sent": "Documento enviado con éxito.",
@@ -856,5 +857,11 @@
"enabled-signature-type-help": "La configuración de 'Tipos de firma habilitados' determina qué opciones de firma están disponibles en su organización. Por ejemplo, si desactiva la opción 'Dibujar', los miembros de su organización no la verán en el widget de firma, mientras que las otras tres opciones seguirán siendo accesibles.", "enabled-signature-type-help": "La configuración de 'Tipos de firma habilitados' determina qué opciones de firma están disponibles en su organización. Por ejemplo, si desactiva la opción 'Dibujar', los miembros de su organización no la verán en el widget de firma, mientras que las otras tres opciones seguirán siendo accesibles.",
"indexing-public-profile": "Permitir la indexación del perfil público por los motores de búsqueda", "indexing-public-profile": "Permitir la indexación del perfil público por los motores de búsqueda",
"user-created-successfully": "Usuario creado con éxito.", "user-created-successfully": "Usuario creado con éxito.",
"only-15-reminder-allowed": "Puede configurar hasta 15 recordatorios automáticos. Por ejemplo, si 'TimeToComplete' es de 15 días y 'RemindOnceInEvery' es de 1 día, alcanzará el límite máximo de 15 recordatorios. Ajuste su configuración en consecuencia." "only-15-reminder-allowed": "Puede configurar hasta 15 recordatorios automáticos. Por ejemplo, si 'TimeToComplete' es de 15 días y 'RemindOnceInEvery' es de 1 día, alcanzará el límite máximo de 15 recordatorios. Ajuste su configuración en consecuencia.",
"rate-your-experience": "👋 Por favor, califique su experiencia con Opensign",
"thanks-for-feedback": "Gracias por su comentario 🙏",
"share-your-feedback": "Comparta sus comentarios",
"share-your-review": "Comparta su reseña",
"date-format": "Formato de fecha",
"document-deleted": "El documento ha sido eliminado o no tiene acceso. Por favor, contacte al remitente."
} }
@@ -458,6 +458,7 @@
"placeholder-alert-3": "Etes-vous sûr de vouloir envoyer ce document pour signature ? ", "placeholder-alert-3": "Etes-vous sûr de vouloir envoyer ce document pour signature ? ",
"placeholder-alert-4": "Vous avez envoyé avec succès des mails à tous les", "placeholder-alert-4": "Vous avez envoyé avec succès des mails à tous les",
"placeholder-mail-alert": "Vous avez envoyé un e-mail avec succès à {{name}}. Les signataires suivants recevront un e-mail une fois que {{name}} aura signé le document.", "placeholder-mail-alert": "Vous avez envoyé un e-mail avec succès à {{name}}. Les signataires suivants recevront un e-mail une fois que {{name}} aura signé le document.",
"placeholder-mail-alert-you": "Les signataires suivants recevront un e-mail dès que vous signez le document.",
"placeholder-alert-5": "Voulez-vous signer des documents maintenant ?", "placeholder-alert-5": "Voulez-vous signer des documents maintenant ?",
"placeholder-alert-6": "Veuillez configurer l'adaptateur de messagerie pour envoyer du courrier !", "placeholder-alert-6": "Veuillez configurer l'adaptateur de messagerie pour envoyer du courrier !",
"placeholder-alert-7": "Veuillez sélectionner le signataire pour ajouter un espace réservé !", "placeholder-alert-7": "Veuillez sélectionner le signataire pour ajouter un espace réservé !",
@@ -831,7 +832,7 @@
"initial-type": "Vos initiales", "initial-type": "Vos initiales",
"redirect-url": "URL de redirection", "redirect-url": "URL de redirection",
"bulk-send": "Envoi groupé", "bulk-send": "Envoi groupé",
"select-timezone": "Sélectionnez votre fuseau horaire", "select-timezone": "Fuseau horaire",
"current-time": "Heure actuelle", "current-time": "Heure actuelle",
"email-help": "Vous n'êtes pas autorisé à changer d'adresse e-mail pour des raisons de sécurité. Veuillez créer un autre compte gratuit en utilisant la nouvelle adresse e-mail.", "email-help": "Vous n'êtes pas autorisé à changer d'adresse e-mail pour des raisons de sécurité. Veuillez créer un autre compte gratuit en utilisant la nouvelle adresse e-mail.",
"doc-sent": "Document envoyé avec succès.", "doc-sent": "Document envoyé avec succès.",
@@ -856,5 +857,11 @@
"enabled-signature-type-help": "Le paramètre 'Types de signature activés' détermine quelles options de signature sont disponibles dans votre organisation. Par exemple, si vous désactivez l'option 'Dessiner', les membres de votre organisation ne la verront pas dans le widget de signature, tandis que les trois autres options resteront accessibles.", "enabled-signature-type-help": "Le paramètre 'Types de signature activés' détermine quelles options de signature sont disponibles dans votre organisation. Par exemple, si vous désactivez l'option 'Dessiner', les membres de votre organisation ne la verront pas dans le widget de signature, tandis que les trois autres options resteront accessibles.",
"indexing-public-profile": "Autoriser l'indexation du profil public par les moteurs de recherche", "indexing-public-profile": "Autoriser l'indexation du profil public par les moteurs de recherche",
"user-created-successfully": "Utilisateur créé avec succès.", "user-created-successfully": "Utilisateur créé avec succès.",
"only-15-reminder-allowed": "Vous pouvez définir jusqu'à 15 rappels automatiques. Par exemple, si 'TimeToComplete' est de 15 jours et 'RemindOnceInEvery' est de 1 jour, vous atteindrez la limite maximale de 15 rappels. Ajustez vos paramètres en conséquence." "only-15-reminder-allowed": "Vous pouvez définir jusqu'à 15 rappels automatiques. Par exemple, si 'TimeToComplete' est de 15 jours et 'RemindOnceInEvery' est de 1 jour, vous atteindrez la limite maximale de 15 rappels. Ajustez vos paramètres en conséquence.",
"rate-your-experience": "👋 Veuillez évaluer votre expérience avec Opensign",
"thanks-for-feedback": "Merci pour votre retour 🙏",
"share-your-feedback": "Partagez votre avis",
"share-your-review": "Partagez votre avis",
"date-format": "Format de date",
"document-deleted": "Le document a été supprimé ou vous n'y avez pas accès. Veuillez contacter l'expéditeur."
} }
@@ -247,7 +247,7 @@
"generate-token-alert": "Sei sicuro di voler rigenerare il token? Questo invaliderà il vecchio token.", "generate-token-alert": "Sei sicuro di voler rigenerare il token? Questo invaliderà il vecchio token.",
"yes": "Sì", "yes": "Sì",
"copied": "Copiato", "copied": "Copiato",
"something-went-wrong-mssg": "Qualcosa è andato storto, riprova più tardi.", "something-went-wrong-mssg": "Si è verificato un errore, L'aggiornamento della pagina potrebbe risolvere il problema.",
"token-generated": "Token generato con successo.", "token-generated": "Token generato con successo.",
"webhook": "Webhook", "webhook": "Webhook",
"update-webhook": "Aggiorna Webhook", "update-webhook": "Aggiorna Webhook",
@@ -458,6 +458,7 @@
"placeholder-alert-3": "Sei sicuro di voler inviare questo documento per le firme?", "placeholder-alert-3": "Sei sicuro di voler inviare questo documento per le firme?",
"placeholder-alert-4": "Hai inviato con successo le mail a tutti i destinatari!", "placeholder-alert-4": "Hai inviato con successo le mail a tutti i destinatari!",
"placeholder-mail-alert": "Hai inviato con successo un'e-mail a {{name}}. I firmatari successivi riceveranno un'e-mail una volta che {{name}} avrà firmato il documento.", "placeholder-mail-alert": "Hai inviato con successo un'e-mail a {{name}}. I firmatari successivi riceveranno un'e-mail una volta che {{name}} avrà firmato il documento.",
"placeholder-mail-alert-you": "I firmatari successivi riceveranno un'email non appena firmi il documento.",
"placeholder-alert-5": "Vuoi firmare i documenti ora?", "placeholder-alert-5": "Vuoi firmare i documenti ora?",
"placeholder-alert-6": "Configura l'adattatore email per inviare mail!", "placeholder-alert-6": "Configura l'adattatore email per inviare mail!",
"placeholder-alert-7": "Seleziona il firmatario per aggiungere un segnaposto!", "placeholder-alert-7": "Seleziona il firmatario per aggiungere un segnaposto!",
@@ -831,7 +832,7 @@
"initial-type": "Le tue iniziali", "initial-type": "Le tue iniziali",
"redirect-url": "URL di reindirizzamento", "redirect-url": "URL di reindirizzamento",
"bulk-send": "Invio in blocco", "bulk-send": "Invio in blocco",
"select-timezone": "Seleziona il tuo fuso orario", "select-timezone": "Fuso orario",
"current-time": "Ora corrente", "current-time": "Ora corrente",
"email-help": "Non ti è permesso cambiare l'indirizzo email per motivi di sicurezza. Ti preghiamo di creare un altro account gratuito utilizzando il nuovo indirizzo email.", "email-help": "Non ti è permesso cambiare l'indirizzo email per motivi di sicurezza. Ti preghiamo di creare un altro account gratuito utilizzando il nuovo indirizzo email.",
"doc-sent": "Documento inviato con successo.", "doc-sent": "Documento inviato con successo.",
@@ -856,5 +857,11 @@
"enabled-signature-type-help": "L'impostazione 'Tipi di firma abilitati' determina quali opzioni di firma sono disponibili nella tua organizzazione. Ad esempio, se disabiliti l'opzione 'Disegna', i membri della tua organizzazione non la vedranno nel widget della firma, mentre le altre tre opzioni resteranno accessibili.", "enabled-signature-type-help": "L'impostazione 'Tipi di firma abilitati' determina quali opzioni di firma sono disponibili nella tua organizzazione. Ad esempio, se disabiliti l'opzione 'Disegna', i membri della tua organizzazione non la vedranno nel widget della firma, mentre le altre tre opzioni resteranno accessibili.",
"indexing-public-profile": "Consenti l'indicizzazione del profilo pubblico dai motori di ricerca", "indexing-public-profile": "Consenti l'indicizzazione del profilo pubblico dai motori di ricerca",
"user-created-successfully": "Utente creato con successo.", "user-created-successfully": "Utente creato con successo.",
"only-15-reminder-allowed": "Puoi impostare fino a 15 promemoria automatici. Ad esempio, se 'TimeToComplete' è di 15 giorni e 'RemindOnceInEvery' è di 1 giorno, raggiungerai il limite massimo di 15 promemoria. Regola le tue impostazioni di conseguenza." "only-15-reminder-allowed": "Puoi impostare fino a 15 promemoria automatici. Ad esempio, se 'TimeToComplete' è di 15 giorni e 'RemindOnceInEvery' è di 1 giorno, raggiungerai il limite massimo di 15 promemoria. Regola le tue impostazioni di conseguenza.",
"rate-your-experience": "👋 Valuta la tua esperienza con Opensign",
"thanks-for-feedback": "Grazie per il tuo feedback 🙏",
"share-your-feedback": "Condividi il tuo feedback",
"share-your-review": "Condividi la tua recensione",
"date-format": "Formato data",
"document-deleted": "Il documento è stato eliminato o non hai accesso. Si prega di contattare il mittente."
} }
@@ -30,15 +30,19 @@ function DraftDocument() {
documentData === "Error: Something went wrong!" || documentData === "Error: Something went wrong!" ||
(documentData.result && documentData.result.error) (documentData.result && documentData.result.error)
) { ) {
setIsLoading({ if (documentData?.result?.error?.includes("deleted")) {
isLoader: false, setIsLoading({
message: "Error: Something went wrong!" isLoader: false,
}); message: t("document-deleted")
});
} else {
setIsLoading({
isLoader: false,
message: t("something-went-wrong-mssg")
});
}
} else { } else {
setIsLoading({ setIsLoading({ isLoader: false, message: t("no-data") });
isLoader: false,
message: "No data found!"
});
} }
}; };
@@ -188,7 +188,7 @@ const EditTemplate = ({ template, onSuccess }) => {
<Tooltip id="istourenabled-tooltip" className="z-50"> <Tooltip id="istourenabled-tooltip" className="z-50">
<div className="max-w-[200px] md:max-w-[450px]"> <div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">{t("enable-tour")}</p> <p className="font-bold">{t("enable-tour")}</p>
<p className="p-[5px]"> <div className="p-[5px]">
<ol className="list-disc"> <ol className="list-disc">
<li> <li>
<span className="font-bold">{t("yes")}: </span> <span className="font-bold">{t("yes")}: </span>
@@ -199,7 +199,7 @@ const EditTemplate = ({ template, onSuccess }) => {
<span>{t("istourenabled-help.p2")}</span> <span>{t("istourenabled-help.p2")}</span>
</li> </li>
</ol> </ol>
</p> </div>
<p>{t("istourenabled-help.p3", { appName: appName })}</p> <p>{t("istourenabled-help.p3", { appName: appName })}</p>
</div> </div>
</Tooltip> </Tooltip>
@@ -5,6 +5,7 @@ import Loader from "../../primitives/Loader";
import ModalUi from "../../primitives/ModalUi"; import ModalUi from "../../primitives/ModalUi";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Parse from "parse"; import Parse from "parse";
function EmailComponent({ function EmailComponent({
isEmail, isEmail,
setIsEmail, setIsEmail,
@@ -20,6 +21,7 @@ function EmailComponent({
const [emailErr, setEmailErr] = useState(false); const [emailErr, setEmailErr] = useState(false);
const [isDownloading, setIsDownloading] = useState(""); const [isDownloading, setIsDownloading] = useState("");
const isAndroid = /Android/i.test(navigator.userAgent); const isAndroid = /Android/i.test(navigator.userAgent);
//function for send email //function for send email
const sendEmail = async () => { const sendEmail = async () => {
setIsLoading(true); setIsLoading(true);
@@ -105,7 +107,7 @@ function EmailComponent({
</div> </div>
)} )}
<div className="flex justify-between items-center py-[10px] px-[20px] border-b-[1px] border-base-content"> <div className="flex justify-between items-center py-[10px] px-[20px] border-b-[1px] border-base-content">
<span className="text-base-content font-semibold"> <span className="text-base-content font-bold text-sm md:text-lg">
{t("successfully-signed")} {t("successfully-signed")}
</span> </span>
<div className="flex flex-row"> <div className="flex flex-row">
@@ -114,14 +116,14 @@ function EmailComponent({
onClick={(e) => onClick={(e) =>
handleToPrint(e, setIsDownloading, pdfDetails) handleToPrint(e, setIsDownloading, pdfDetails)
} }
className="op-btn op-btn-neutral op-btn-sm text-[15px]" className="op-btn op-btn-neutral op-btn-sm text-xs md:text-[15px]"
> >
<i className="fa-light fa-print" aria-hidden="true"></i> <i className="fa-light fa-print" aria-hidden="true"></i>
{t("print")} {t("print")}
</button> </button>
)} )}
<button <button
className="op-btn op-btn-primary op-btn-sm text-[15px] ml-2" className="op-btn op-btn-primary op-btn-sm text-xs md:text-[15px] ml-2"
onClick={() => { onClick={() => {
handleClose(); handleClose();
setIsDownloadModal(true); setIsDownloadModal(true);
@@ -137,12 +139,12 @@ function EmailComponent({
{t("email-mssg")} {t("email-mssg")}
</p> </p>
{emailList.length > 0 ? ( {emailList.length > 0 ? (
<div className="p-0 border-[1.5px] op-border-primary rounded w-full text-[15px]"> <div className="p-0 border-[1px] op-border-primary w-full rounded-md text-[15px] overflow-hidden">
<div className="flex flex-row flex-wrap"> <div className="flex flex-row flex-wrap">
{emailList.map((data, ind) => { {emailList.map((data, ind) => {
return ( return (
<div <div
className="flex flex-row items-center op-bg-primary m-[4px] rounded-md py-[5px] px-[10px]" className="flex flex-row items-center op-bg-primary mx-[2px] mt-[2px] rounded-md py-[5px] px-[10px]"
key={ind} key={ind}
> >
<span className="text-base-100 text-[13px]"> <span className="text-base-100 text-[13px]">
@@ -162,7 +164,7 @@ function EmailComponent({
<input <input
type="email" type="email"
value={emailValue} value={emailValue}
className="p-[10px] pb-[20px] rounded w-full text-[15px] bg-transparent outline-none" className="p-[10px] rounded-md w-full text-[15px] bg-transparent outline-none"
onChange={handleEmailValue} onChange={handleEmailValue}
onKeyDown={handleEnterPress} onKeyDown={handleEnterPress}
onBlur={() => emailValue && handleEnterPress("add")} onBlur={() => emailValue && handleEnterPress("add")}
@@ -179,7 +181,7 @@ function EmailComponent({
<input <input
type="email" type="email"
value={emailValue} value={emailValue}
className="p-[10px] pb-[20px] rounded w-full text-[15px] outline-none bg-transparent border-[1.5px] op-border-primary" className="p-[10px] pb-[20px] rounded-md w-full text-[15px] outline-none bg-transparent border-[1px] op-border-primary"
onChange={handleEmailValue} onChange={handleEmailValue}
onKeyDown={handleEnterPress} onKeyDown={handleEnterPress}
placeholder={t("enter-email-plaholder")} placeholder={t("enter-email-plaholder")}
@@ -197,7 +199,7 @@ function EmailComponent({
{t("email-error-1")} {t("email-error-1")}
</p> </p>
)} )}
<button {/* <button
className={`${ className={`${
emailValue ? "cursor-pointer" : "cursor-default" emailValue ? "cursor-pointer" : "cursor-default"
} op-btn op-btn-primary op-btn-sm m-2 shadow-md`} } op-btn op-btn-primary op-btn-sm m-2 shadow-md`}
@@ -205,26 +207,27 @@ function EmailComponent({
> >
<i className="fa-light fa-plus" aria-hidden="true"></i> <i className="fa-light fa-plus" aria-hidden="true"></i>
</button> </button>
<div className="bg-[#e3e2e1] mt-[10px] p-[5px] rounded"> <div className="bg-[#e3e2e1] mt-[10px] p-[5px] rounded">
<span className="font-bold">{t("report-heading.Note")}: </span> <span className="font-bold">{t("report-heading.Note")}: </span>
<span className="text-[15px]">{t("email-error-2")}</span> <span className="text-[15px]">{t("email-error-2")}</span>
</div> </div>
<hr className="w-full my-[15px] bg-base-content" /> <hr className="w-full my-[15px] bg-base-content" /> */}
<button <div className="mt-2">
type="button" <button
className="op-btn op-btn-secondary" type="button"
onClick={() => emailList.length > 0 && sendEmail()} className="op-btn op-btn-secondary"
> onClick={() => emailList.length > 0 && sendEmail()}
{t("send")} >
</button> {t("send")}
<button </button>
type="button" <button
className="op-btn op-btn-ghost ml-2" type="button"
onClick={() => handleClose()} className="op-btn op-btn-ghost ml-2"
> onClick={() => handleClose()}
{t("close")} >
</button> {t("close")}
</button>
</div>
</div> </div>
</ModalUi> </ModalUi>
)} )}
@@ -1,305 +0,0 @@
import React, { useState } from "react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { tomorrow } from "react-syntax-highlighter/dist/esm/styles/prism";
import { copytoData } from "../../constant/Utils";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router";
function EmbedTab(props) {
const { t } = useTranslation();
const navigate = useNavigate();
const tabName = [
{ title: "React/Next.js", icon: "fa-brands fa-react", color: "#61dafb" },
{ title: "JavaScript", icon: "fa-brands fa-js", color: "#ffd43b" },
{ title: "Angular", icon: "fa-brands fa-angular", color: "#ff5733" }
];
const [activeTab, setActiveTab] = useState(0);
// State to track if the code has been copied
const [isCopied, setIsCopied] = useState(false);
const reactCode = [
{
id: 0,
title: "Installation",
codeString: `npm install @opensign/react`
},
{
id: 1,
title: "Usage",
codeString: `
import React from "react";
import Opensign from "@opensign/react";
export default function App() {
return (
<div className="app">
<Opensign
onLoad={() => console.log("success")}
onLoadError={(error) => console.log(error)}
templateId= "${props.templateId ? props.templateId : "#templateId"}"
/>
</div>
);
}
`
}
];
const angularCode = [
{
id: 0,
title: "Installation",
codeString: `npm install @opensign/angular`
},
{
id: 1,
title: "Usage",
codeString: `
import { Component } from '@angular/core';
import { OpensignComponent } from "@opensign/angular"
@Component({
selector:'app-root',
standalone: true,
imports: [OpensignComponent],
template:\`<opensign templateId="${props.templateId ? props.templateId : "#templateId"}"
(onLoad)="handleLoad()"
(onLoadError)="handleError($event)"
></opensign>\`,
})
export class AppComponent {
handleLoad() {
console.log("success");
}
handleError(error: string) {
console.log(error);
}
}
`
}
];
const jsCodeString = `
<script
src= "${window.location.origin}/static/js/public-template.bundle.js"
id="opensign-script"
templateId=${props.templateId ? props.templateId : "#templateId"}
></script>
`;
const handleCopy = (code, ind) => {
copytoData(code);
setIsCopied({ ...isCopied, [ind]: true });
setTimeout(() => setIsCopied(false), 3000);
};
return (
<div className={`${props.templateId && "border-t-[1px] mt-4"}`}>
{props.templateId && (
<h3 className="text-base-content font-bold text-lg pt-[15px] pb-[5px]">
{t("embed-template")}
</h3>
)}
<div className="flex justify-center items-center mt-2">
<div role="tablist" className="op-tabs op-tabs-bordered">
{tabName.map((tabData, ind) => (
<div
onClick={() => setActiveTab(ind)}
key={ind}
role="tab"
className={`${
activeTab === ind ? "op-tab-active" : ""
} op-tab flex items-center pb-10 md:pb-0`}
>
<i
className={`${tabData.icon}`}
style={{ color: tabData.color }}
></i>
<span className="ml-1 text-[10px] font-medium md:font-normal md:text-[15px]">
{tabData.title}
</span>
</div>
))}
</div>
</div>
<div>
{activeTab === 0 ? (
<div className="mt-4">
{reactCode.map((data, ind) => {
return (
<div key={ind}>
<p className="font-medium text-[18px]">
{t(`${data.title}`)}
</p>
{ind === 0 && (
<p className="text-[15px] mt-2">
{t("public-template-mssg-1")}
</p>
)}
<div className="relative p-1">
<div
onClick={() => handleCopy(data.codeString, ind)}
className="absolute top-[20px] right-[20px] cursor-pointer"
>
<i className="fa-light fa-copy text-white mr-[2px]" />
<span className=" text-white">
{isCopied[ind] ? t("copied-code") : t("copy-code")}
</span>
</div>
<SyntaxHighlighter
customStyle={{
borderRadius: "15px"
}}
language="javascript"
style={tomorrow}
>
{data.codeString}
</SyntaxHighlighter>
</div>
</div>
);
})}
{props.isEmbedPage && (
<p className="text-[15px] my-2">
{t("js-snippet-msg-1")}
<span
className="text-blue-600 cursor-pointer px-1"
onClick={() => navigate("/report/6TeaPr321t")}
>
{t("js-snippet-msg-2")}
</span>
<span>{t("js-snippet-msg-3")}</span>
</p>
)}
<p className="font-medium mt-3 text-[15px]">
{t("public-template-mssg-3")}
</p>
<p className="my-[6px]">
{" "}
{t("public-template-mssg-4")}
<a
href="https://www.npmjs.com/package/@opensign/react"
target="_blank"
rel="noreferrer"
className="cursor-pointer text-blue-700 "
>
{" "}
OpenSign React package{" "}
</a>
{t("public-template-mssg-5")}
</p>
</div>
) : activeTab === 1 ? (
<div className="mt-4">
<div>
<p className="font-medium text-[18px]">{t(`Usage`)}</p>
<p className="text-[15px] my-2">{t("js-snippet-msg")}</p>
<div className="relative p-1">
<div
onClick={() => handleCopy(jsCodeString, 0)}
className="absolute top-[20px] right-[20px] cursor-pointer"
>
<i className="fa-light fa-copy text-white mr-[2px]" />
<span className=" text-white">
{isCopied[0] ? t("copied-code") : t("copy-code")}
</span>
</div>
<SyntaxHighlighter
customStyle={{
borderRadius: "15px"
}}
language="javascript"
style={tomorrow}
>
{jsCodeString}
</SyntaxHighlighter>
</div>
{props.isEmbedPage && (
<p className="text-[15px] my-2">
{t("js-snippet-msg-1")}
<span
className="text-blue-600 cursor-pointer px-1"
onClick={() => navigate("/report/6TeaPr321t")}
>
{t("js-snippet-msg-2")}
</span>
<span>{t("js-snippet-msg-3")}</span>
</p>
)}
</div>
</div>
) : (
activeTab === 2 && (
<div className="mt-4">
{angularCode.map((data, ind) => {
return (
<div key={ind}>
<p className="font-medium text-[18px]">
{t(`${data.title}`)}
</p>
{ind === 0 && (
<p className="text-[15px] mt-2">
{t("angular-npm-mssg-1")}
</p>
)}
<div className="relative p-1">
<div
onClick={() => handleCopy(data.codeString, ind)}
className="absolute top-[20px] right-[20px] cursor-pointer"
>
<i className="fa-light fa-copy text-white mr-[2px]" />
<span className=" text-white">
{isCopied[ind] ? t("copied-code") : t("copy-code")}
</span>
</div>
<SyntaxHighlighter
customStyle={{
borderRadius: "15px"
}}
language="javascript"
style={tomorrow}
>
{data.codeString}
</SyntaxHighlighter>
</div>
</div>
);
})}
{props.isEmbedPage && (
<p className="text-[15px] my-2">
{t("js-snippet-msg-1")}
<span
className="text-blue-600 cursor-pointer px-1"
onClick={() => navigate("/report/6TeaPr321t")}
>
{t("js-snippet-msg-2")}
</span>
<span>{t("js-snippet-msg-3")}</span>
</p>
)}
<p className="font-medium mt-3 text-[15px]">
{t("public-template-mssg-3")}
</p>
<p className="my-[6px]">
{" "}
{t("public-template-mssg-4")}
<a
href="https://www.npmjs.com/package/@opensign/angular"
target="_blank"
rel="noreferrer"
className="cursor-pointer text-blue-700 "
>
{" "}
OpenSign Angular package{" "}
</a>
{t("public-template-mssg-5")}
</p>
</div>
)
)}
</div>
</div>
);
}
export default EmbedTab;
@@ -25,6 +25,8 @@ const selectFormat = (data) => {
switch (data) { switch (data) {
case "L": case "L":
return "MM/dd/yyyy"; return "MM/dd/yyyy";
case "MM/DD/YYYY":
return "MM/dd/yyyy";
case "DD-MM-YYYY": case "DD-MM-YYYY":
return "dd-MM-yyyy"; return "dd-MM-yyyy";
case "DD/MM/YYYY": case "DD/MM/YYYY":
@@ -41,6 +43,8 @@ const selectFormat = (data) => {
return "MM.dd.yyyy"; return "MM.dd.yyyy";
case "MMM DD, YYYY": case "MMM DD, YYYY":
return "MMM dd, yyyy"; return "MMM dd, yyyy";
case "MMMM DD, YYYY":
return "MMMM dd, yyyy";
case "DD MMMM, YYYY": case "DD MMMM, YYYY":
return "dd MMMM, yyyy"; return "dd MMMM, yyyy";
default: default:
@@ -24,7 +24,7 @@ const widgetCls =
function PlaceholderType(props) { function PlaceholderType(props) {
const { t } = useTranslation(); const { t } = useTranslation();
const type = props?.pos?.type; const type = props?.pos?.type;
const widgetTypeTraslation = t(`widgets-name.${props?.pos?.type}`); const widgetTypeTranslation = t(`widgets-name.${props?.pos?.type}`);
const [selectOption, setSelectOption] = useState(""); const [selectOption, setSelectOption] = useState("");
const [validatePlaceholder, setValidatePlaceholder] = useState(""); const [validatePlaceholder, setValidatePlaceholder] = useState("");
const inputRef = useRef(null); const inputRef = useRef(null);
@@ -342,8 +342,8 @@ function PlaceholderType(props) {
className="font-medium" className="font-medium"
> >
{props.isNeedSign {props.isNeedSign
? props.pos?.options?.hint || widgetTypeTraslation ? props.pos?.options?.hint || widgetTypeTranslation
: widgetTypeTraslation} : widgetTypeTranslation}
</div> </div>
)} )}
</div> </div>
@@ -368,8 +368,8 @@ function PlaceholderType(props) {
className="font-medium" className="font-medium"
> >
{props.isNeedSign {props.isNeedSign
? props.pos?.options?.hint || widgetTypeTraslation ? props.pos?.options?.hint || widgetTypeTranslation
: widgetTypeTraslation} : widgetTypeTranslation}
</div> </div>
)} )}
</div> </div>
@@ -475,7 +475,7 @@ function PlaceholderType(props) {
/> />
) : ( ) : (
<div style={textWidgetStyle} className="select-none-cls"> <div style={textWidgetStyle} className="select-none-cls">
<span>{textValue || widgetTypeTraslation}</span> <span>{textValue || widgetTypeTranslation}</span>
</div> </div>
); );
case "dropdown": case "dropdown":
@@ -538,7 +538,7 @@ function PlaceholderType(props) {
> >
{props.pos?.options?.name {props.pos?.options?.name
? props.pos.options.name ? props.pos.options.name
: widgetTypeTraslation} : widgetTypeTranslation}
<i className="fa-light fa-circle-chevron-down mr-1 "></i> <i className="fa-light fa-circle-chevron-down mr-1 "></i>
</div> </div>
); );
@@ -562,8 +562,8 @@ function PlaceholderType(props) {
className="font-medium text-center" className="font-medium text-center"
> >
{props.isNeedSign {props.isNeedSign
? props.pos?.options?.hint || widgetTypeTraslation ? props.pos?.options?.hint || widgetTypeTranslation
: widgetTypeTraslation} : widgetTypeTranslation}
</div> </div>
)} )}
</div> </div>
@@ -574,7 +574,7 @@ function PlaceholderType(props) {
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? ( (props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
<textarea <textarea
ref={inputRef} ref={inputRef}
placeholder={hint} placeholder={hint || widgetTypeTranslation}
rows={1} rows={1}
onKeyDown={handleEnterPress} onKeyDown={handleEnterPress}
value={textValue} value={textValue}
@@ -597,7 +597,7 @@ function PlaceholderType(props) {
/> />
) : ( ) : (
<div className="flex h-full select-none-cls" style={textWidgetStyle}> <div className="flex h-full select-none-cls" style={textWidgetStyle}>
<span>{widgetTypeTraslation}</span> <span>{widgetTypeTranslation}</span>
</div> </div>
); );
case "company": case "company":
@@ -606,7 +606,7 @@ function PlaceholderType(props) {
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? ( (props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
<textarea <textarea
ref={inputRef} ref={inputRef}
placeholder={hint} placeholder={hint || widgetTypeTranslation}
rows={1} rows={1}
onKeyDown={handleEnterPress} onKeyDown={handleEnterPress}
value={textValue} value={textValue}
@@ -628,7 +628,7 @@ function PlaceholderType(props) {
/> />
) : ( ) : (
<div style={textWidgetStyle} className="select-none-cls"> <div style={textWidgetStyle} className="select-none-cls">
<span>{widgetTypeTraslation}</span> <span>{widgetTypeTranslation}</span>
</div> </div>
); );
case "job title": case "job title":
@@ -637,7 +637,7 @@ function PlaceholderType(props) {
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? ( (props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
<textarea <textarea
ref={inputRef} ref={inputRef}
placeholder={hint} placeholder={hint || widgetTypeTranslation}
rows={1} rows={1}
onKeyDown={handleEnterPress} onKeyDown={handleEnterPress}
value={textValue} value={textValue}
@@ -659,7 +659,7 @@ function PlaceholderType(props) {
/> />
) : ( ) : (
<div style={textWidgetStyle} className="select-none-cls"> <div style={textWidgetStyle} className="select-none-cls">
<span>{widgetTypeTraslation}</span> <span>{widgetTypeTranslation}</span>
</div> </div>
); );
case "date": case "date":
@@ -748,8 +748,8 @@ function PlaceholderType(props) {
className="font-medium text-center" className="font-medium text-center"
> >
{props.isNeedSign {props.isNeedSign
? props.pos?.options?.hint || widgetTypeTraslation ? props.pos?.options?.hint || widgetTypeTranslation
: widgetTypeTraslation} : widgetTypeTranslation}
</div> </div>
)} )}
</div> </div>
@@ -760,7 +760,7 @@ function PlaceholderType(props) {
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? ( (props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
<textarea <textarea
ref={inputRef} ref={inputRef}
placeholder={hint} placeholder={hint || widgetTypeTranslation}
rows={1} rows={1}
onKeyDown={(e) => { onKeyDown={(e) => {
// Prevent new line on Enter key press // Prevent new line on Enter key press
@@ -792,7 +792,7 @@ function PlaceholderType(props) {
/> />
) : ( ) : (
<div style={textWidgetStyle} className="select-none-cls"> <div style={textWidgetStyle} className="select-none-cls">
<span>{widgetTypeTraslation}</span> <span>{widgetTypeTranslation}</span>
</div> </div>
); );
case radioButtonWidget: case radioButtonWidget:
@@ -891,8 +891,8 @@ function PlaceholderType(props) {
className="font-medium" className="font-medium"
> >
{props.isNeedSign {props.isNeedSign
? props.pos?.options?.hint || widgetTypeTraslation ? props.pos?.options?.hint || widgetTypeTranslation
: widgetTypeTraslation} : widgetTypeTranslation}
</div> </div>
)} )}
</div> </div>
@@ -0,0 +1,79 @@
import React, { useState } from "react";
import { formatDateTime } from "../../../constant/Utils";
import { useTranslation } from "react-i18next";
const DateFormatSelector = (props) => {
const { t } = useTranslation();
const date = new Date();
const [selectedFormat, setSelectedFormat] = useState(props.dateFormat);
const [is12Hour, setIs12Hour] = useState(props?.is12HourTime);
const dateFormats = [
"MM/DD/YYYY",
"MMMM DD, YYYY",
"DD MMMM, YYYY",
"DD-MM-YYYY",
"DD MMM, YYYY",
"YYYY-MM-DD",
"MM-DD-YYYY",
"MM.DD.YYYY",
"MMM DD, YYYY"
];
// Handle format change
const handleFormatChange = (event) => {
setSelectedFormat(event.target.value);
props.setDateFormat && props.setDateFormat(event.target.value);
};
const handleHrInput = () => {
setIs12Hour(!is12Hour);
props.setIs12HourTime && props.setIs12HourTime(!is12Hour);
};
return (
<div className="max-w-[400px] pr-[20px]">
<label className="text-[14px] mb-[0.7rem] font-medium">
{t("date-format")}
</label>
<select
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full h-full text-[11px]"
value={selectedFormat}
onChange={handleFormatChange}
>
{dateFormats.map((format) => (
<option key={format} value={format}>
{format}
</option>
))}
</select>
<div className="flex flex-col md:flex-row md:gap-4 mt-[0.75rem] text-[12px]">
<div className="flex items-center gap-2 ml-2">
<input
type="radio"
value={true}
className="op-radio op-radio-xs"
checked={is12Hour}
onChange={handleHrInput}
/>
<div className="text-center">12 hr</div>
</div>
<div className="flex items-center gap-2 ml-2">
<input
type="radio"
value={false}
className="op-radio op-radio-xs"
checked={!is12Hour}
onChange={handleHrInput}
/>
<div className="text-center">24 hr</div>
</div>
</div>
<p className="mt-[12px] ml-[10px] text-[13px] font-medium">
<strong>
{formatDateTime(date, selectedFormat, props?.timezone, is12Hour)}
</strong>
</p>
</div>
);
};
export default DateFormatSelector;
@@ -1,10 +1,10 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import AsyncSelect from "react-select/async"; import AsyncSelect from "react-select/async";
import AddSigner from "../../AddSigner"; import AddContact from "../../../primitives/AddContact";
import Parse from "parse";
import Tooltip from "../../../primitives/Tooltip"; import Tooltip from "../../../primitives/Tooltip";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { findContact } from "../../../constant/Utils";
function arrayMove(array, from, to) { function arrayMove(array, from, to) {
array = array.slice(); array = array.slice();
array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]); array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]);
@@ -103,17 +103,21 @@ const SignersInput = (props) => {
// `handleNewDetails` is used to set just save from quick form to selected option in dropdown // `handleNewDetails` is used to set just save from quick form to selected option in dropdown
const handleNewDetails = (data) => { const handleNewDetails = (data) => {
setState([...state, data]); const user = {
value: data["objectId"],
label: data["Name"],
email: data?.Email
};
setState([...state, user]);
if (selected.length > 0) { if (selected.length > 0) {
setSelected([...selected, data]); setSelected([...selected, user]);
} else { } else {
setSelected([data]); setSelected([user]);
} }
}; };
const loadOptions = async (inputValue) => { const loadOptions = async (inputValue) => {
try { try {
const params = { search: inputValue }; const contactRes = await findContact(inputValue);
const contactRes = await Parse.Cloud.run("getsigners", params);
if (contactRes) { if (contactRes) {
const res = JSON.parse(JSON.stringify(contactRes)); const res = JSON.parse(JSON.stringify(contactRes));
//compareArrays is a function where compare between two array (total signersList and dcument signers list) //compareArrays is a function where compare between two array (total signersList and dcument signers list)
@@ -148,7 +152,9 @@ const SignersInput = (props) => {
{props.label ? props.label : t("signers")} {props.label ? props.label : t("signers")}
{props.required && <span className="text-red-500 text-[13px]">*</span>} {props.required && <span className="text-red-500 text-[13px]">*</span>}
<span <span
className={`z-[${props?.helptextZindex ? props.helptextZindex : 30}] absolute ml-1 text-xs`} className={`z-[${
props?.helptextZindex ? props.helptextZindex : 30
}] absolute ml-1 text-xs`}
> >
<Tooltip <Tooltip
id={`${props.label ? props.label : "signers"}-tooltip`} id={`${props.label ? props.label : "signers"}-tooltip`}
@@ -209,9 +215,8 @@ const SignersInput = (props) => {
</button> </button>
{isModal && ( {isModal && (
<AddSigner <AddContact
valueKey={"objectId"} isDisableTitle
displayKey={"Name"}
details={handleNewDetails} details={handleNewDetails}
closePopup={handleModalCloseClick} closePopup={handleModalCloseClick}
/> />
@@ -7,27 +7,10 @@ const TimezoneSelector = (props) => {
// Intl.DateTimeFormat().resolvedOptions().timeZone // Default to the user's local timezone // Intl.DateTimeFormat().resolvedOptions().timeZone // Default to the user's local timezone
const onChangeTimezone = (timezone) => { const onChangeTimezone = (timezone) => {
setSelectedTimezone(timezone); setSelectedTimezone(timezone?.value);
props.setTimezone && props.setTimezone(timezone?.value); props.setTimezone && props.setTimezone(timezone?.value);
}; };
// Format date and time for the selected timezone
const formatDate = (date, timezone) => {
return timezone
? new Intl.DateTimeFormat("en-US", {
weekday: "short",
year: "numeric",
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
timeZone: timezone,
hour12: false
}).format(date)
: new Date(date).toUTCString();
};
return ( return (
<> <>
<div className="max-w-[400px] pr-[20px]"> <div className="max-w-[400px] pr-[20px]">
@@ -54,11 +37,6 @@ const TimezoneSelector = (props) => {
}} }}
/> />
</div> </div>
<div className="mt-[12px] ml-[10px] text-[13px]">
<strong>
{formatDate(new Date(), selectedTimezone?.value || selectedTimezone)}
</strong>{" "}
</div>
</> </>
); );
}; };
+5 -4
View File
@@ -3,8 +3,7 @@ import { useTranslation } from "react-i18next";
import { NavLink } from "react-router"; import { NavLink } from "react-router";
const Menu = ({ item, isOpen, closeSidebar }) => { const Menu = ({ item, isOpen, closeSidebar }) => {
const appName = const appName = "OpenSign™";
"OpenSign™";
const drivename = appName === "OpenSign™" ? "OpenSign™" : ""; const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
@@ -18,13 +17,15 @@ const Menu = ({ item, isOpen, closeSidebar }) => {
className={({ isActive }) => className={({ isActive }) =>
`${ `${
isActive ? " bg-base-300 text-base-content" : "" isActive ? " bg-base-300 text-base-content" : ""
} flex items-center text-left p-3 lg:p-4 text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none` } flex items-center justify-start text-left p-3 lg:p-4 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}
tabIndex={isOpen ? 0 : -1} tabIndex={isOpen ? 0 : -1}
role="menuitem" role="menuitem"
> >
<i className={`${item.icon} text-[18px]`} aria-hidden="true"></i> <span className="w-[20px] h-[20px] flex justify-center">
<i className={`${item.icon} text-[18px]`} aria-hidden="true"></i>
</span>
<span className="ml-3 lg:ml-4"> <span className="ml-3 lg:ml-4">
{t(`sidebar.${item.title}`, { appName: drivename })} {t(`sidebar.${item.title}`, { appName: drivename })}
</span> </span>
+13 -10
View File
@@ -3,8 +3,7 @@ import { useTranslation } from "react-i18next";
import { NavLink } from "react-router"; import { NavLink } from "react-router";
const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => { const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
const appName = const appName = "OpenSign™";
"OpenSign™";
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;
@@ -12,14 +11,16 @@ const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
<li role="none" className="my-0.5"> <li role="none" className="my-0.5">
<button <button
onClick={() => toggleSubmenu(item.title)} onClick={() => toggleSubmenu(item.title)}
className="flex items-center text-left p-3 lg:p-4 text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none " className="flex items-center justify-start text-left p-3 lg:p-4 text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none "
aria-expanded={submenuOpen} aria-expanded={submenuOpen}
aria-haspopup="true" aria-haspopup="true"
aria-controls={`submenu-${title}`} aria-controls={`submenu-${title}`}
> >
<i className={`${icon} text-[18px]`}></i> <span className="w-[20px] h-[20px] flex justify-center">
<i className={`${icon} text-[18px]`}></i>
</span>
<div className="flex justify-between items-center w-full"> <div className="flex justify-between items-center w-full">
<span className="ml-3 lg:ml-4"> <span className="ml-3 lg:ml-4 text-start">
{t(`sidebar.${item.title}`, { appName })} {t(`sidebar.${item.title}`, { appName })}
</span> </span>
<i <i
@@ -45,16 +46,18 @@ const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
className={({ isActive }) => className={({ isActive }) =>
`${ `${
isActive ? "bg-base-300 text-base-content" : "" isActive ? "bg-base-300 text-base-content" : ""
} flex items-center text-left pl-6 md:pl-8 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` } flex items-center justify-start text-left pl-6 md:pl-8 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}
role="menuitem" role="menuitem"
tabIndex={submenuOpen ? 0 : -1} tabIndex={submenuOpen ? 0 : -1}
> >
<i <span className="w-[15px] h-[15px] flex justify-center">
className={`${childItem.icon} text-[18px]`} <i
aria-hidden="true" className={`${childItem.icon} text-[18px]`}
></i> aria-hidden="true"
></i>
</span>
<span className="ml-3 lg:ml-4"> <span className="ml-3 lg:ml-4">
{t(`sidebar.${item.title}-Children.${childItem.title}`, { {t(`sidebar.${item.title}-Children.${childItem.title}`, {
appName: drivename appName: drivename
+77 -48
View File
@@ -8,6 +8,7 @@ import { saveAs } from "file-saver";
import printModule from "print-js"; import printModule from "print-js";
import fontkit from "@pdf-lib/fontkit"; import fontkit from "@pdf-lib/fontkit";
import { themeColor } from "./const"; import { themeColor } from "./const";
import { format, toZonedTime } from "date-fns-tz";
export const fontsizeArr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]; export const fontsizeArr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28];
export const fontColorArr = ["red", "black", "blue", "yellow"]; export const fontColorArr = ["red", "black", "blue", "yellow"];
@@ -232,17 +233,47 @@ export const widgets = [
{ type: "email", icon: "fa-light fa-envelope", iconSize: "20px" } { type: "email", icon: "fa-light fa-envelope", iconSize: "20px" }
]; ];
export const getDate = () => { export const getDate = (dateformat) => {
const format = dateformat || "MM/DD/YYYY";
const date = new Date(); const date = new Date();
const milliseconds = date.getTime(); const milliseconds = date.getTime();
const newDate = moment(milliseconds).format("MM/DD/YYYY"); const newDate = moment(milliseconds).format(format);
return newDate; return newDate;
}; };
export const addWidgetOptions = (type) => {
const defaultOpt = { export const selectFormat = (data) => {
name: type, switch (data) {
status: "required" case "L":
}; return "MM/dd/yyyy";
case "MM/DD/YYYY":
return "MM/dd/yyyy";
case "DD-MM-YYYY":
return "dd-MM-yyyy";
case "DD/MM/YYYY":
return "dd/MM/yyyy";
case "LL":
return "MMMM dd, yyyy";
case "DD MMM, YYYY":
return "dd MMM, yyyy";
case "YYYY-MM-DD":
return "yyyy-MM-dd";
case "MM-DD-YYYY":
return "MM-dd-yyyy";
case "MM.DD.YYYY":
return "MM.dd.yyyy";
case "MMM DD, YYYY":
return "MMM dd, yyyy";
case "MMMM DD, YYYY":
return "MMMM dd, yyyy";
case "DD MMMM, YYYY":
return "dd MMMM, yyyy";
default:
return "MM/dd/yyyy";
}
};
export const addWidgetOptions = (type, signer) => {
const defaultOpt = { name: type, status: "required" };
switch (type) { switch (type) {
case "signature": case "signature":
return defaultOpt; return defaultOpt;
@@ -263,12 +294,16 @@ export const addWidgetOptions = (type) => {
return { ...defaultOpt }; return { ...defaultOpt };
case "job title": case "job title":
return { ...defaultOpt }; return { ...defaultOpt };
case "date": case "date": {
const dateFormat = signer?.DateFormat
? selectFormat(signer?.DateFormat)
: "MM/dd/yyyy";
return { return {
...defaultOpt, ...defaultOpt,
response: getDate(), response: getDate(signer?.DateFormat),
validation: { format: "MM/dd/yyyy", type: "date-format" } validation: { format: dateFormat, type: "date-format" }
}; };
}
case "image": case "image":
return defaultOpt; return defaultOpt;
case "email": case "email":
@@ -289,7 +324,7 @@ export const addWidgetOptions = (type) => {
} }
}; };
export const addWidgetSelfsignOptions = (type, getWidgetValue) => { export const addWidgetSelfsignOptions = (type, getWidgetValue, owner) => {
switch (type) { switch (type) {
case "signature": case "signature":
return { name: "signature" }; return { name: "signature" };
@@ -319,12 +354,16 @@ export const addWidgetSelfsignOptions = (type, getWidgetValue) => {
defaultValue: getWidgetValue(type), defaultValue: getWidgetValue(type),
validation: { type: "text", pattern: "" } validation: { type: "text", pattern: "" }
}; };
case "date": case "date": {
const dateFormat = owner?.DateFormat
? selectFormat(owner?.DateFormat)
: "MM/dd/yyyy";
return { return {
name: "date", name: "date",
response: getDate(), response: getDate(owner?.DateFormat),
validation: { format: "MM/dd/yyyy", type: "date-format" } validation: { format: dateFormat, type: "date-format" }
}; };
}
case "image": case "image":
return { name: "image" }; return { name: "image" };
case "email": case "email":
@@ -932,10 +971,7 @@ export const calculateInitialWidthHeight = (widgetData) => {
const height = span.offsetHeight; const height = span.offsetHeight;
document.body.removeChild(span); document.body.removeChild(span);
return { return { getWidth: width, getHeight: height };
getWidth: width,
getHeight: height
};
}; };
export const addInitialData = (signerPos, setXyPosition, value, userId) => { export const addInitialData = (signerPos, setXyPosition, value, userId) => {
function widgetDataValue(type) { function widgetDataValue(type) {
@@ -966,9 +1002,7 @@ export const addInitialData = (signerPos, setXyPosition, value, userId) => {
) )
}; };
} else { } else {
return { return item;
...item
};
} }
} else if (item.pos && item.pos.length > 0) { } else if (item.pos && item.pos.length > 0) {
// If there is no nested array, add the new field // If there is no nested array, add the new field
@@ -986,17 +1020,9 @@ export const addInitialData = (signerPos, setXyPosition, value, userId) => {
...item.options, ...item.options,
defaultValue: item?.options?.defaultValue || widgetData defaultValue: item?.options?.defaultValue || widgetData
} }
// Width:
// calculateInitialWidthHeight(item.type, widgetData).getWidth ||
// item?.Width,
// Height:
// calculateInitialWidthHeight(item.type, widgetData).getHeight ||
// item?.Height
}; };
} else { } else {
return { return item;
...item
};
} }
} }
}); });
@@ -2167,13 +2193,13 @@ export const fetchUrl = async (url, pdfName) => {
try { try {
const response = await fetch(url); const response = await fetch(url);
if (!response.ok) { if (!response.ok) {
alert("something went wrong, please try again later."); alert("something went wrong, refreshing this page may solve this issue.");
throw new Error("Network response was not ok"); throw new Error("Network response was not ok");
} }
const blob = await response.blob(); const blob = await response.blob();
saveAs(blob, `${sanitizeFileName(pdfName)}_signed_by_${appName}.pdf`); saveAs(blob, `${sanitizeFileName(pdfName)}_signed_by_${appName}.pdf`);
} catch (error) { } catch (error) {
alert("something went wrong, please try again later."); alert("something went wrong, refreshing this page may solve this issue.");
console.error("Error downloading the file:", error); console.error("Error downloading the file:", error);
} }
}; };
@@ -2244,7 +2270,7 @@ export const handleDownloadPdf = async (
} catch (err) { } catch (err) {
console.log("err in getsignedurl", err); console.log("err in getsignedurl", err);
setIsDownloading(""); setIsDownloading("");
alert("something went wrong, please try again later."); alert("something went wrong, refreshing this page may solve this issue.");
} }
} }
}; };
@@ -2302,7 +2328,7 @@ export const handleToPrint = async (event, setIsDownloading, pdfDetails) => {
} catch (err) { } catch (err) {
setIsDownloading(""); setIsDownloading("");
console.log("err in getsignedurl", err); console.log("err in getsignedurl", err);
alert("something went wrong, please try again later."); alert("something went wrong, refreshing this page may solve this issue.");
} }
}; };
@@ -2388,7 +2414,7 @@ export const handleDownloadCertificate = async (
} catch (err) { } catch (err) {
setIsDownloading("certificate_err"); setIsDownloading("certificate_err");
console.log("err in download in certificate", err); console.log("err in download in certificate", err);
alert("something went wrong, please try again later."); alert("something went wrong, refreshing this page may solve this issue.");
} }
} }
}; };
@@ -2845,20 +2871,11 @@ export function generatePdfName(length) {
// Format date and time for the selected timezone // Format date and time for the selected timezone
export const formatTimeInTimezone = (date, timezone) => { export const formatTimeInTimezone = (date, timezone) => {
return timezone const nyDate = timezone && toZonedTime(date, timezone);
? new Intl.DateTimeFormat("en-US", { const generatedDate = timezone
weekday: "short", ? format(nyDate, "EEE, dd MMM yyyy HH:mm:ss zzz", { timeZone: timezone })
year: "numeric",
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
timeZone: timezone,
timeZoneName: "short",
hour12: false
}).format(date)
: new Date(date).toUTCString(); : new Date(date).toUTCString();
return generatedDate;
}; };
// `usertimezone` is used to get timezone of current user // `usertimezone` is used to get timezone of current user
@@ -2957,3 +2974,15 @@ export const mailTemplate = (param) => {
return { subject, body }; return { subject, body };
}; };
export function formatDateTime(date, dateFormat, timeZone, is12Hour) {
const zonedDate = toZonedTime(date, timeZone); // Convert date to the given timezone
const timeFormat = is12Hour ? "hh:mm:ss a" : "HH:mm:ss";
return dateFormat
? format(
zonedDate,
`${selectFormat(dateFormat)}, ${timeFormat} 'GMT' XXX`,
{ timeZone }
)
: formatTimeInTimezone(date, timeZone);
}
+3 -5
View File
@@ -1,11 +1,9 @@
import logo from "../assets/images/logo.png"; import logo from "../assets/images/logo.png";
export function serverUrl_fn() { export function serverUrl_fn() {
let baseUrl; let baseUrl = process.env.REACT_APP_SERVERURL
baseUrl = process.env.REACT_APP_SERVERURL ? process.env.REACT_APP_SERVERURL
? process.env.REACT_APP_SERVERURL : window.location.origin + "/api/app";
: window.location.origin + "/app";
return baseUrl; return baseUrl;
} }
export const appInfo = { export const appInfo = {
-8
View File
@@ -14,7 +14,6 @@ import {
Preview Preview
} from "react-dnd-multi-backend"; } from "react-dnd-multi-backend";
import DragElement from "./components/pdf/DragElement"; import DragElement from "./components/pdf/DragElement";
import TagManager from "react-gtm-module";
import Parse from "parse"; import Parse from "parse";
import "./polyfills"; import "./polyfills";
import { serverUrl_fn } from "./constant/appinfo"; import { serverUrl_fn } from "./constant/appinfo";
@@ -56,13 +55,6 @@ const generatePreview = (props) => {
); );
}; };
if (process.env.REACT_APP_GTM) {
const tagManagerArgs = {
gtmId: process.env.REACT_APP_GTM
};
TagManager.initialize(tagManagerArgs);
}
const root = ReactDOM.createRoot(document.getElementById("root")); const root = ReactDOM.createRoot(document.getElementById("root"));
root.render( root.render(
<CookiesProvider defaultSetOptions={{ path: "/" }}> <CookiesProvider defaultSetOptions={{ path: "/" }}>
+6 -13
View File
@@ -187,13 +187,6 @@ const Forms = (props) => {
} }
} catch (err) { } catch (err) {
if (err?.message?.includes("is encrypted")) { if (err?.message?.includes("is encrypted")) {
try {
await Parse.Cloud.run("encryptedpdf", {
email: Parse.User.current().getEmail()
});
} catch (err) {
console.log("err in sending posthog encryptedpdf", err);
}
try { try {
setIsDecrypting(true); setIsDecrypting(true);
const size = files?.[0].size; const size = files?.[0].size;
@@ -859,7 +852,7 @@ const Forms = (props) => {
<div className="max-w-[200px] md:max-w-[450px]"> <div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">{t("send-in-order")}</p> <p className="font-bold">{t("send-in-order")}</p>
<p>{t("send-in-order-help.p1")}</p> <p>{t("send-in-order-help.p1")}</p>
<p className="p-[5px]"> <div className="p-[5px]">
<ol className="list-disc"> <ol className="list-disc">
<li> <li>
<span className="font-bold"> <span className="font-bold">
@@ -874,7 +867,7 @@ const Forms = (props) => {
<span>{t("send-in-order-help.p3")}</span> <span>{t("send-in-order-help.p3")}</span>
</li> </li>
</ol> </ol>
</p> </div>
<p>{t("send-in-order-help.p4")}</p> <p>{t("send-in-order-help.p4")}</p>
</div> </div>
</Tooltip> </Tooltip>
@@ -956,7 +949,7 @@ const Forms = (props) => {
{t("send-in-order")} {t("send-in-order")}
</p> </p>
<p>{t("send-in-order-help.p1")}</p> <p>{t("send-in-order-help.p1")}</p>
<p className="p-[5px]"> <div className="p-[5px]">
<ol className="list-disc"> <ol className="list-disc">
<li> <li>
<span className="font-bold"> <span className="font-bold">
@@ -975,7 +968,7 @@ const Forms = (props) => {
</span> </span>
</li> </li>
</ol> </ol>
</p> </div>
<p>{t("send-in-order-help.p4")}</p> <p>{t("send-in-order-help.p4")}</p>
</div> </div>
</Tooltip> </Tooltip>
@@ -1093,7 +1086,7 @@ const Forms = (props) => {
<Tooltip id="istourenabled-tooltip" className="z-[999]"> <Tooltip id="istourenabled-tooltip" className="z-[999]">
<div className="max-w-[200px] md:max-w-[450px]"> <div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">{t("enable-tour")}</p> <p className="font-bold">{t("enable-tour")}</p>
<p className="p-[5px]"> <div className="p-[5px]">
<ol className="list-disc"> <ol className="list-disc">
<li> <li>
<span className="font-bold"> <span className="font-bold">
@@ -1106,7 +1099,7 @@ const Forms = (props) => {
<span>{t("istourenabled-help.p2")}</span> <span>{t("istourenabled-help.p2")}</span>
</li> </li>
</ol> </ol>
</p> </div>
<p> <p>
{t("istourenabled-help.p3", { appName: appName })} {t("istourenabled-help.p3", { appName: appName })}
</p> </p>
+49 -59
View File
@@ -7,9 +7,7 @@ import { NavLink, useNavigate, useLocation } from "react-router";
import login_img from "../assets/images/login_img.svg"; import login_img from "../assets/images/login_img.svg";
import { useWindowSize } from "../hook/useWindowSize"; import { useWindowSize } from "../hook/useWindowSize";
import ModalUi from "../primitives/ModalUi"; import ModalUi from "../primitives/ModalUi";
import { import { emailRegex } from "../constant/const";
emailRegex,
} from "../constant/const";
import Alert from "../primitives/Alert"; import Alert from "../primitives/Alert";
import { appInfo } from "../constant/appinfo"; import { appInfo } from "../constant/appinfo";
import { fetchAppInfo } from "../redux/reducers/infoReducer"; import { fetchAppInfo } from "../redux/reducers/infoReducer";
@@ -24,8 +22,7 @@ import { useTranslation } from "react-i18next";
import SelectLanguage from "../components/pdf/SelectLanguage"; import SelectLanguage from "../components/pdf/SelectLanguage";
function Login() { function Login() {
const appName = const appName = "OpenSign™";
"OpenSign™";
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
@@ -43,7 +40,7 @@ function Login() {
baseUrl: localStorage.getItem("baseUrl"), baseUrl: localStorage.getItem("baseUrl"),
parseAppId: localStorage.getItem("parseAppId"), parseAppId: localStorage.getItem("parseAppId"),
loading: false, loading: false,
thirdpartyLoader: false, thirdpartyLoader: false
}); });
const [userDetails, setUserDetails] = useState({ const [userDetails, setUserDetails] = useState({
Company: "", Company: "",
@@ -61,9 +58,7 @@ function Login() {
const app = await getAppLogo(); const app = await getAppLogo();
if (app?.error === "invalid_json") { if (app?.error === "invalid_json") {
setErrMsg(t("server-down", { appName: appName })); setErrMsg(t("server-down", { appName: appName }));
} else if ( } else if (app?.user === "not_exist") {
app?.user === "not_exist"
) {
navigate("/addadmin"); navigate("/addadmin");
} }
if (app?.logo) { if (app?.logo) {
@@ -153,9 +148,9 @@ function Login() {
localStorage.setItem("PageLanding", menu.pageId); localStorage.setItem("PageLanding", menu.pageId);
localStorage.setItem("defaultmenuid", menu.menuId); localStorage.setItem("defaultmenuid", menu.menuId);
localStorage.setItem("pageType", menu.pageType); localStorage.setItem("pageType", menu.pageType);
setState({ ...state, loading: false }); setState({ ...state, loading: false });
// Redirect to the appropriate URL after successful login // Redirect to the appropriate URL after successful login
navigate(redirectUrl); navigate(redirectUrl);
} else { } else {
setState({ ...state, loading: false }); setState({ ...state, loading: false });
setIsModal(true); setIsModal(true);
@@ -171,14 +166,14 @@ function Login() {
logOutUser(); logOutUser();
} }
} else { } else {
setState({ ...state, loading: false }); setState({ ...state, loading: false });
setState({ setState({
...state, ...state,
loading: false, loading: false,
alertType: "danger", alertType: "danger",
alertMsg: "User not found." alertMsg: "User not found."
}); });
logOutUser(); logOutUser();
} }
}) })
.catch((error) => { .catch((error) => {
@@ -186,7 +181,7 @@ function Login() {
...state, ...state,
loading: false, loading: false,
alertType: "danger", alertType: "danger",
alertMsg: `Something went wrong.` alertMsg: t("something-went-wrong-mssg")
}); });
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000); setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
console.error("Error while fetching Follow", error); console.error("Error while fetching Follow", error);
@@ -282,7 +277,7 @@ function Login() {
localStorage.setItem("PageLanding", menu.pageId); localStorage.setItem("PageLanding", menu.pageId);
localStorage.setItem("defaultmenuid", menu.menuId); localStorage.setItem("defaultmenuid", menu.menuId);
localStorage.setItem("pageType", menu.pageType); localStorage.setItem("pageType", menu.pageType);
navigate(redirectUrl); navigate(redirectUrl);
} else { } else {
setState({ setState({
...state, ...state,
@@ -380,8 +375,8 @@ function Login() {
localStorage.setItem("PageLanding", menu.pageId); localStorage.setItem("PageLanding", menu.pageId);
localStorage.setItem("defaultmenuid", menu.menuId); localStorage.setItem("defaultmenuid", menu.menuId);
localStorage.setItem("pageType", menu.pageType); localStorage.setItem("pageType", menu.pageType);
// Redirect to the appropriate URL after successful login // Redirect to the appropriate URL after successful login
navigate(redirectUrl); navigate(redirectUrl);
} else { } else {
setState({ ...state, loading: false }); setState({ ...state, loading: false });
logOutUser(); logOutUser();
@@ -408,7 +403,7 @@ function Login() {
setState({ setState({
...state, ...state,
alertType: "danger", alertType: "danger",
alertMsg: "Something went wrong, please try again later." alertMsg: t("something-went-wrong-mssg")
}); });
console.log("err", error); console.log("err", error);
} finally { } finally {
@@ -501,7 +496,6 @@ function Login() {
localStorage.setItem("parseAppId", appid); localStorage.setItem("parseAppId", appid);
}; };
return errMsg ? ( return errMsg ? (
<div className="h-screen flex justify-center text-center items-center p-4 text-gray-500 text-base"> <div className="h-screen flex justify-center text-center items-center p-4 text-gray-500 text-base">
{errMsg} {errMsg}
@@ -561,39 +555,35 @@ function Login() {
onInput={(e) => e.target.setCustomValidity("")} onInput={(e) => e.target.setCustomValidity("")}
/> />
<hr className="my-1 border-none" /> <hr className="my-1 border-none" />
<label className="block text-xs" htmlFor="password"> <label className="block text-xs" htmlFor="password">
{t("password")} {t("password")}
</label> </label>
<div className="relative"> <div className="relative">
<input <input
id="password" id="password"
type={ type={state.passwordVisible ? "text" : "password"}
state.passwordVisible ? "text" : "password" className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
} name="password"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs" value={state.password}
name="password" autoComplete="current-password"
value={state.password} onChange={handleChange}
autoComplete="current-password" onInvalid={(e) =>
onChange={handleChange} e.target.setCustomValidity(t("input-required"))
onInvalid={(e) => }
e.target.setCustomValidity( onInput={(e) => e.target.setCustomValidity("")}
t("input-required") required
) />
} <span
onInput={(e) => e.target.setCustomValidity("")} className="absolute cursor-pointer top-[50%] right-[10px] -translate-y-[50%] text-base-content"
required onClick={togglePasswordVisibility}
/> >
<span {state.passwordVisible ? (
className="absolute cursor-pointer top-[50%] right-[10px] -translate-y-[50%] text-base-content" <i className="fa-light fa-eye-slash text-xs pb-1" /> // Close eye icon
onClick={togglePasswordVisibility} ) : (
> <i className="fa-light fa-eye text-xs pb-1 " /> // Open eye icon
{state.passwordVisible ? ( )}
<i className="fa-light fa-eye-slash text-xs pb-1" /> // Close eye icon </span>
) : ( </div>
<i className="fa-light fa-eye text-xs pb-1 " /> // Open eye icon
)}
</span>
</div>
<div className="relative mt-1"> <div className="relative mt-1">
<NavLink <NavLink
+11 -12
View File
@@ -1,11 +1,7 @@
import React, { useEffect, useState, useRef } from "react"; import React, { useEffect, useState, useRef } from "react";
import "../styles/opensigndrive.css"; import "../styles/opensigndrive.css";
import { import { iconColor } from "../constant/const";
iconColor, import { getDrive } from "../constant/Utils";
} from "../constant/const";
import {
getDrive
} from "../constant/Utils";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import Title from "../components/Title"; import Title from "../components/Title";
import Parse from "parse"; import Parse from "parse";
@@ -29,8 +25,7 @@ const AppLoader = () => {
); );
}; };
function Opensigndrive() { function Opensigndrive() {
const appName = const appName = "OpenSign™";
"OpenSign™";
const drivename = appName === "OpenSign™" ? "OpenSign™" : ""; const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
const { t } = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -130,7 +125,7 @@ function Opensigndrive() {
} }
]; ];
const getDetails = async () => { const getDetails = async () => {
getPdfDocumentList(); getPdfDocumentList();
}; };
//function for get all pdf document list //function for get all pdf document list
const getPdfDocumentList = async (disbaleLoading) => { const getPdfDocumentList = async (disbaleLoading) => {
@@ -144,7 +139,7 @@ function Opensigndrive() {
try { try {
const driveDetails = await getDrive(docId, skip, limit); const driveDetails = await getDrive(docId, skip, limit);
if (driveDetails && driveDetails === "Error: Something went wrong!") { if (driveDetails && driveDetails === "Error: Something went wrong!") {
setHandleError("Error: Something went wrong!"); setHandleError(t("something-went-wrong-mssg"));
} else if (driveDetails && driveDetails.length > 0) { } else if (driveDetails && driveDetails.length > 0) {
const addMoreTour = [ const addMoreTour = [
{ {
@@ -635,7 +630,9 @@ function Opensigndrive() {
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
<div <div
id="folder-menu" id="folder-menu"
className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} hidden md:block`} className={`${
isOptions ? "dropdown show dropDownStyle" : "dropdown"
} hidden md:block`}
onClick={() => setIsOptions(!isOptions)} onClick={() => setIsOptions(!isOptions)}
> >
<div className="sort" data-tut="reactourSecond"> <div className="sort" data-tut="reactourSecond">
@@ -773,7 +770,9 @@ function Opensigndrive() {
</div> </div>
<div <div
id="folder-menu" id="folder-menu"
className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} md:hidden`} className={`${
isOptions ? "dropdown show dropDownStyle" : "dropdown"
} md:hidden`}
onClick={() => setIsOptions(!isOptions)} onClick={() => setIsOptions(!isOptions)}
> >
<div <div
File diff suppressed because it is too large Load Diff
+15 -10
View File
@@ -150,7 +150,6 @@ function PlaceHolderSign() {
status: false, status: false,
message: "" message: ""
}); });
const [extUserId, setExtUserId] = useState("");
const [isCustomize, setIsCustomize] = useState(false); const [isCustomize, setIsCustomize] = useState(false);
const [zoomPercent, setZoomPercent] = useState(0); const [zoomPercent, setZoomPercent] = useState(0);
const [scale, setScale] = useState(1); const [scale, setScale] = useState(1);
@@ -164,13 +163,13 @@ function PlaceHolderSign() {
const [userList, setUserList] = useState([]); const [userList, setUserList] = useState([]);
const [isAttchSignerModal, setIsAttchSignerModal] = useState(false); const [isAttchSignerModal, setIsAttchSignerModal] = useState(false);
const [isNewContact, setIsNewContact] = useState({ status: false, id: "" }); const [isNewContact, setIsNewContact] = useState({ status: false, id: "" });
const [owner, setOwner] = useState({});
const isMobile = window.innerWidth < 767; const isMobile = window.innerWidth < 767;
const [, drop] = useDrop({ const [, drop] = useDrop({
accept: "BOX", accept: "BOX",
drop: (item, monitor) => addPositionOfSignature(item, monitor), drop: (item, monitor) => addPositionOfSignature(item, monitor),
collect: (monitor) => ({ isOver: !!monitor.isOver() }) collect: (monitor) => ({ isOver: !!monitor.isOver() })
}); });
const documentId = docId; const documentId = docId;
useEffect(() => { useEffect(() => {
if (documentId) { if (documentId) {
@@ -286,7 +285,7 @@ function PlaceHolderSign() {
setPdfArrayBuffer(arrayBuffer); setPdfArrayBuffer(arrayBuffer);
setPdfBase64Url(base64Pdf); setPdfBase64Url(base64Pdf);
} }
setExtUserId(documentData[0]?.ExtUserPtr?.objectId); setOwner(documentData?.[0]?.ExtUserPtr);
const alreadyPlaceholder = documentData[0]?.SignedUrl; const alreadyPlaceholder = documentData[0]?.SignedUrl;
// Check if document is sent for signing // Check if document is sent for signing
if (alreadyPlaceholder) { if (alreadyPlaceholder) {
@@ -457,7 +456,11 @@ function PlaceHolderSign() {
documentData === "Error: Something went wrong!" || documentData === "Error: Something went wrong!" ||
(documentData.result && documentData.result.error) (documentData.result && documentData.result.error)
) { ) {
setHandleError(t("something-went-wrong-mssg")); if (documentData?.result?.error?.includes("deleted")) {
setHandleError(t("document-deleted"));
} else {
setHandleError(t("something-went-wrong-mssg"));
}
setIsLoading({ isLoad: false }); setIsLoading({ isLoad: false });
} else { } else {
setHandleError(t("no-data-avaliable")); setHandleError(t("no-data-avaliable"));
@@ -525,7 +528,7 @@ function PlaceHolderSign() {
scale: containerScale, scale: containerScale,
zIndex: posZIndex, zIndex: posZIndex,
type: dragTypeValue, type: dragTypeValue,
options: addWidgetOptions(dragTypeValue), options: addWidgetOptions(dragTypeValue, owner),
Width: widgetWidth / (containerScale * scale), Width: widgetWidth / (containerScale * scale),
Height: widgetHeight / (containerScale * scale) Height: widgetHeight / (containerScale * scale)
}; };
@@ -556,7 +559,7 @@ function PlaceHolderSign() {
scale: containerScale, scale: containerScale,
zIndex: posZIndex, zIndex: posZIndex,
type: dragTypeValue, type: dragTypeValue,
options: addWidgetOptions(dragTypeValue), options: addWidgetOptions(dragTypeValue, owner),
Width: widgetWidth / (containerScale * scale), Width: widgetWidth / (containerScale * scale),
Height: widgetHeight / (containerScale * scale) Height: widgetHeight / (containerScale * scale)
}; };
@@ -1225,7 +1228,7 @@ function PlaceHolderSign() {
sigingUrl: signPdf sigingUrl: signPdf
}; };
let params = { let params = {
extUserId: extUserId, extUserId: owner?.objectId,
recipient: signerMail[i].Email, recipient: signerMail[i].Email,
subject: replaceVar?.subject subject: replaceVar?.subject
? replaceVar?.subject ? replaceVar?.subject
@@ -2093,9 +2096,11 @@ function PlaceHolderSign() {
<LottieWithLoader /> <LottieWithLoader />
{pdfDetails[0].SendinOrder ? ( {pdfDetails[0].SendinOrder ? (
<p> <p>
{t("placeholder-mail-alert", { {isCurrUser
name: signersdata[0]?.Name ? t("placeholder-mail-alert-you")
})} : t("placeholder-mail-alert", {
name: signersdata[0]?.Name
})}
</p> </p>
) : ( ) : (
<p>{t("placeholder-alert-4")}</p> <p>{t("placeholder-alert-4")}</p>
+37 -13
View File
@@ -20,6 +20,7 @@ import EditorToolbar, {
module2, module2,
formats formats
} from "../components/pdf/EditorToolbar"; } from "../components/pdf/EditorToolbar";
import DateFormatSelector from "../components/shared/fields/DateFormatSelector";
const Preferences = () => { const Preferences = () => {
const appName = "OpenSign™"; const appName = "OpenSign™";
@@ -47,6 +48,8 @@ const Preferences = () => {
const [tab, setTab] = useState([generaltab]); const [tab, setTab] = useState([generaltab]);
const [sendinOrder, setSendinOrder] = useState(true); const [sendinOrder, setSendinOrder] = useState(true);
const [isTourEnabled, setIsTourEnabled] = useState(false); const [isTourEnabled, setIsTourEnabled] = useState(false);
const [dateFormat, setDateFormat] = useState("MM/DD/YYYY");
const [is12HourTime, setIs12HourTime] = useState(false);
useEffect(() => { useEffect(() => {
fetchSignType(); fetchSignType();
@@ -99,10 +102,18 @@ const Preferences = () => {
? _getUser?.IsTourEnabled ? _getUser?.IsTourEnabled
: true; : true;
setIsTourEnabled(istourenabled); setIsTourEnabled(istourenabled);
const DateFormat =
_getUser?.DateFormat !== undefined
? _getUser?.DateFormat
: "MM/DD/YYYY";
setDateFormat(DateFormat);
const is12Hr =
_getUser?.Is12HourTime !== undefined ? _getUser?.Is12HourTime : false;
setIs12HourTime(is12Hr);
} }
} catch (err) { } catch (err) {
console.log("err while getting user details", err); console.log("err while getting user details", err);
setErrMsg("Something went wrong"); setErrMsg(t("something-went-wrong-mssg"));
} finally { } finally {
setIsTopLoader(false); setIsTopLoader(false);
} }
@@ -154,11 +165,13 @@ const Preferences = () => {
params = { params = {
...params, ...params,
SendinOrder: sendinOrder, SendinOrder: sendinOrder,
IsTourEnabled: isTourEnabled IsTourEnabled: isTourEnabled,
DateFormat: dateFormat,
Is12HourTime: is12HourTime
}; };
const updateRes = await Parse.Cloud.run("updatepreferences", params); const updateRes = await Parse.Cloud.run("updatepreferences", params);
if (updateRes) { if (updateRes) {
setIsAlert({ type: "success", msg: "Saved successfully." }); setIsAlert({ type: "success", msg: t("saved-successfully") });
let extUser = let extUser =
localStorage.getItem("Extand_Class") && localStorage.getItem("Extand_Class") &&
JSON.parse(localStorage.getItem("Extand_Class"))?.[0]; JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
@@ -166,6 +179,8 @@ const Preferences = () => {
extUser.NotifyOnSignatures = isNotifyOnSignatures; extUser.NotifyOnSignatures = isNotifyOnSignatures;
extUser.SendinOrder = sendinOrder; extUser.SendinOrder = sendinOrder;
extUser.IsTourEnabled = isTourEnabled; extUser.IsTourEnabled = isTourEnabled;
extUser.DateFormat = dateFormat;
extUser.Is12HourTime = is12HourTime;
const _extUser = JSON.parse(JSON.stringify(extUser)); const _extUser = JSON.parse(JSON.stringify(extUser));
localStorage.setItem("Extand_Class", JSON.stringify([_extUser])); localStorage.setItem("Extand_Class", JSON.stringify([_extUser]));
} }
@@ -238,12 +253,12 @@ const Preferences = () => {
const updateRes = JSON.parse(JSON.stringify(res)); const updateRes = JSON.parse(JSON.stringify(res));
SetCompletionBody(updateRes?.CompletionBody); SetCompletionBody(updateRes?.CompletionBody);
setCompletionSubject(updateRes?.CompletionSubject); setCompletionSubject(updateRes?.CompletionSubject);
setIsAlert({ type: "success", msg: "Saved successfully." }); setIsAlert({ type: "success", msg: t("saved-successfully") });
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500); setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
} }
} catch (err) { } catch (err) {
console.log("Err", err); console.log("Err", err);
setIsAlert({ type: "danger", msg: "Something went wrong." }); setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500); setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
} finally { } finally {
setIsLoader(false); setIsLoader(false);
@@ -265,12 +280,12 @@ const Preferences = () => {
const updateRes = JSON.parse(JSON.stringify(res)); const updateRes = JSON.parse(JSON.stringify(res));
setRequestBody(updateRes?.RequestBody); setRequestBody(updateRes?.RequestBody);
setRequestSubject(updateRes?.RequestSubject); setRequestSubject(updateRes?.RequestSubject);
setIsAlert({ type: "success", msg: "Saved successfully." }); setIsAlert({ type: "success", msg: t("saved-successfully") });
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500); setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
} }
} catch (err) { } catch (err) {
console.log("Err", err); console.log("Err", err);
setIsAlert({ type: "danger", msg: "Something went wrong." }); setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500); setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
} finally { } finally {
setIsLoader(false); setIsLoader(false);
@@ -376,7 +391,7 @@ const Preferences = () => {
{t("allowed-signature-types")} {t("allowed-signature-types")}
</p> </p>
<p>{t("allowed-signature-types-help.p1")}</p> <p>{t("allowed-signature-types-help.p1")}</p>
<p className="p-[5px] ml-2"> <div className="p-[5px] ml-2">
<ol className="list-disc"> <ol className="list-disc">
<li> <li>
<span className="font-bold">Draw: </span> <span className="font-bold">Draw: </span>
@@ -403,7 +418,7 @@ const Preferences = () => {
</span> </span>
</li> </li>
</ol> </ol>
</p> </div>
</div> </div>
</ReactTooltip> </ReactTooltip>
</label> </label>
@@ -481,6 +496,15 @@ const Preferences = () => {
setTimezone={setTimezone} setTimezone={setTimezone}
/> />
</div> </div>
<div className="mb-[0.75rem]">
<DateFormatSelector
timezone={timezone}
dateFormat={dateFormat}
is12HourTime={is12HourTime}
setIs12HourTime={setIs12HourTime}
setDateFormat={setDateFormat}
/>
</div>
<div className="mb-[0.75rem] text-[12px]"> <div className="mb-[0.75rem] text-[12px]">
<label className="block mb-[0.7rem]"> <label className="block mb-[0.7rem]">
<span className="text-[14px] font-medium"> <span className="text-[14px] font-medium">
@@ -501,7 +525,7 @@ const Preferences = () => {
<div className="max-w-[200px] md:max-w-[450px]"> <div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">{t("send-in-order")}</p> <p className="font-bold">{t("send-in-order")}</p>
<p>{t("send-in-order-help.p1")}</p> <p>{t("send-in-order-help.p1")}</p>
<p className="p-[5px]"> <div className="p-[5px]">
<ol className="list-disc"> <ol className="list-disc">
<li> <li>
<span className="font-bold"> <span className="font-bold">
@@ -514,7 +538,7 @@ const Preferences = () => {
<span>{t("send-in-order-help.p3")}</span> <span>{t("send-in-order-help.p3")}</span>
</li> </li>
</ol> </ol>
</p> </div>
<p>{t("send-in-order-help.p4")}</p> <p>{t("send-in-order-help.p4")}</p>
</div> </div>
</ReactTooltip> </ReactTooltip>
@@ -563,7 +587,7 @@ const Preferences = () => {
> >
<div className="max-w-[200px] md:max-w-[450px]"> <div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">{t("enable-tour")}</p> <p className="font-bold">{t("enable-tour")}</p>
<p className="p-[5px]"> <div className="p-[5px]">
<ol className="list-disc"> <ol className="list-disc">
<li> <li>
<span className="font-bold"> <span className="font-bold">
@@ -576,7 +600,7 @@ const Preferences = () => {
<span>{t("istourenabled-help.p2")}</span> <span>{t("istourenabled-help.p2")}</span>
</li> </li>
</ol> </ol>
</p> </div>
<p> <p>
{t("istourenabled-help.p3", { {t("istourenabled-help.p3", {
appName: appName appName: appName
+13 -54
View File
@@ -40,7 +40,8 @@ import {
convertBase64ToFile, convertBase64ToFile,
generatePdfName, generatePdfName,
handleRemoveWidgets, handleRemoveWidgets,
compressedFileSize compressedFileSize,
addWidgetSelfsignOptions
} from "../constant/Utils"; } from "../constant/Utils";
import { useParams } from "react-router"; import { useParams } from "react-router";
import Tour from "reactour"; import Tour from "reactour";
@@ -144,6 +145,7 @@ function SignYourSelf() {
isVisible: false, isVisible: false,
signId: "" signId: ""
}); });
const [owner, setOwner] = useState({});
const [, drop] = useDrop({ const [, drop] = useDrop({
accept: "BOX", accept: "BOX",
drop: (item, monitor) => addPositionOfSignature(item, monitor), drop: (item, monitor) => addPositionOfSignature(item, monitor),
@@ -204,6 +206,7 @@ function SignYourSelf() {
const documentData = await contractDocument(documentId); const documentData = await contractDocument(documentId);
if (documentData && documentData.length > 0) { if (documentData && documentData.length > 0) {
setOwner(documentData?.[0]?.ExtUserPtr);
setPdfDetails(documentData); setPdfDetails(documentData);
const placeholders = const placeholders =
documentData[0]?.Placeholders?.length > 0 documentData[0]?.Placeholders?.length > 0
@@ -249,7 +252,11 @@ function SignYourSelf() {
documentData === "Error: Something went wrong!" || documentData === "Error: Something went wrong!" ||
(documentData.result && documentData.result.error) (documentData.result && documentData.result.error)
) { ) {
setHandleError(t("something-went-wrong-mssg")); if (documentData?.result?.error?.includes("deleted")) {
setHandleError(t("document-deleted"));
} else {
setHandleError(t("something-went-wrong-mssg"));
}
setIsLoading({ isLoad: false }); setIsLoading({ isLoad: false });
} else { } else {
setHandleError(t("no-data-avaliable")); setHandleError(t("no-data-avaliable"));
@@ -321,7 +328,7 @@ function SignYourSelf() {
} }
} catch (err) { } catch (err) {
console.log("Error: error in getDocumentDetails", err); console.log("Error: error in getDocumentDetails", err);
setHandleError("Error: Something went wrong!"); setHandleError(t("something-went-wrong-mssg"));
setIsLoading({ isLoad: false }); setIsLoading({ isLoad: false });
} }
}; };
@@ -344,54 +351,6 @@ function SignYourSelf() {
} }
}; };
const addWidgetOptions = (type) => {
switch (type) {
case "signature":
return { name: "signature" };
case "stamp":
return { name: "stamp" };
case "checkbox":
return { name: "checkbox" };
case textWidget:
return { name: "text" };
case "initials":
return { name: "initials" };
case "name":
return {
name: "name",
defaultValue: getWidgetValue(type),
validation: { type: "text", pattern: "" }
};
case "company":
return {
name: "company",
defaultValue: getWidgetValue(type),
validation: { type: "text", pattern: "" }
};
case "job title":
return {
name: "job title",
defaultValue: getWidgetValue(type),
validation: { type: "text", pattern: "" }
};
case "date":
return {
name: "date",
response: getDate(),
validation: { format: "MM/dd/yyyy", type: "date-format" }
};
case "image":
return { name: "image" };
case "email":
return {
name: "email",
defaultValue: getWidgetValue(type),
validation: { type: "email", pattern: "" }
};
default:
return {};
}
};
//function for setting position after drop signature button over pdf //function for setting position after drop signature button over pdf
const addPositionOfSignature = (item, monitor) => { const addPositionOfSignature = (item, monitor) => {
setCurrWidgetsDetails({}); setCurrWidgetsDetails({});
@@ -416,7 +375,7 @@ function SignYourSelf() {
// `getBoundingClientRect()` is used to get accurate measurement height of the div // `getBoundingClientRect()` is used to get accurate measurement height of the div
const divHeight = divRef.current.getBoundingClientRect().height; const divHeight = divRef.current.getBoundingClientRect().height;
const getWidth = widgetTypeExist const getWidth = widgetTypeExist
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth ? calculateInitialWidthHeight(widgetValue).getWidth
: defaultWidthHeight(dragTypeValue).width; : defaultWidthHeight(dragTypeValue).width;
const getHeight = defaultWidthHeight(dragTypeValue).height; const getHeight = defaultWidthHeight(dragTypeValue).height;
@@ -430,7 +389,7 @@ function SignYourSelf() {
scale: containerScale, scale: containerScale,
Width: getWidth, Width: getWidth,
Height: getHeight, Height: getHeight,
options: addWidgetOptions(dragTypeValue) options: addWidgetSelfsignOptions(dragTypeValue, getWidgetValue, owner)
}; };
dropData.push(dropObj); dropData.push(dropObj);
} else { } else {
@@ -459,7 +418,7 @@ function SignYourSelf() {
type: dragTypeValue, type: dragTypeValue,
Width: getWidth / (containerScale * scale), Width: getWidth / (containerScale * scale),
Height: getHeight / (containerScale * scale), Height: getHeight / (containerScale * scale),
options: addWidgetOptions(dragTypeValue), options: addWidgetSelfsignOptions(dragTypeValue, getWidgetValue, owner),
scale: containerScale scale: containerScale
}; };
dropData.push(dropObj); dropData.push(dropObj);
@@ -139,6 +139,7 @@ const TemplatePlaceholder = () => {
const [updatedPdfUrl, setUpdatedPdfUrl] = useState(""); const [updatedPdfUrl, setUpdatedPdfUrl] = useState("");
const [tempSignerId, setTempSignerId] = useState(""); const [tempSignerId, setTempSignerId] = useState("");
const [unSignedWidgetId, setUnSignedWidgetId] = useState(""); const [unSignedWidgetId, setUnSignedWidgetId] = useState("");
const [owner, setOwner] = useState({});
useEffect(() => { useEffect(() => {
fetchTemplate(); fetchTemplate();
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -214,6 +215,7 @@ const TemplatePlaceholder = () => {
: []; : [];
if (documentData && documentData.length > 0) { if (documentData && documentData.length > 0) {
setOwner(documentData?.[0]?.ExtUserPtr);
const url = documentData[0] && documentData[0]?.URL; const url = documentData[0] && documentData[0]?.URL;
if (url) { if (url) {
const arrayBuffer = await convertPdfArrayBuffer(url); const arrayBuffer = await convertPdfArrayBuffer(url);
@@ -391,7 +393,7 @@ const TemplatePlaceholder = () => {
scale: containerScale, scale: containerScale,
zIndex: posZIndex, zIndex: posZIndex,
type: dragTypeValue, type: dragTypeValue,
options: addWidgetOptions(dragTypeValue), options: addWidgetOptions(dragTypeValue, owner),
Width: widgetWidth / (containerScale * scale), Width: widgetWidth / (containerScale * scale),
Height: widgetHeight / (containerScale * scale) Height: widgetHeight / (containerScale * scale)
}; };
@@ -421,7 +423,7 @@ const TemplatePlaceholder = () => {
// isMobile: isMobile, // isMobile: isMobile,
zIndex: posZIndex, zIndex: posZIndex,
type: item.text, type: item.text,
options: addWidgetOptions(dragTypeValue), options: addWidgetOptions(dragTypeValue, owner),
Width: widgetWidth / (containerScale * scale), Width: widgetWidth / (containerScale * scale),
Height: widgetHeight / (containerScale * scale) Height: widgetHeight / (containerScale * scale)
}; };
@@ -7,8 +7,7 @@ import Title from "../components/Title";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { emailRegex } from "../constant/const"; import { emailRegex } from "../constant/const";
const UpdateExistUserAdmin = () => { const UpdateExistUserAdmin = () => {
const appName = const appName = "OpenSign™";
"OpenSign™";
const { t } = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
const [formdata, setFormdata] = useState({ email: "", masterkey: "" }); const [formdata, setFormdata] = useState({ email: "", masterkey: "" });
@@ -30,7 +29,7 @@ const UpdateExistUserAdmin = () => {
} }
} catch (err) { } catch (err) {
console.log("Err in checkadminexist", err); console.log("Err in checkadminexist", err);
setErrMsg("Something went wrong."); setErrMsg(t("something-went-wrong-mssg"));
} finally { } finally {
setLoader(false); setLoader(false);
} }
+10 -10
View File
@@ -33,8 +33,9 @@ const AddContact = (props) => {
try { try {
const baseURL = localStorage.getItem("baseUrl"); const baseURL = localStorage.getItem("baseUrl");
const url = `${baseURL}functions/isuserincontactbook`; const url = `${baseURL}functions/isuserincontactbook`;
const token = const token = {
{ "X-Parse-Session-Token": localStorage.getItem("accesstoken") }; "X-Parse-Session-Token": localStorage.getItem("accesstoken")
};
const headers = { const headers = {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"), "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
@@ -63,18 +64,15 @@ const AddContact = (props) => {
) )
); );
const userId = user?.objectId || ""; const userId = user?.objectId || "";
const tenantDetails = await getTenantDetails( const tenantDetails = await getTenantDetails(userId);
userId,
);
const tenantId = tenantDetails?.objectId || ""; const tenantId = tenantDetails?.objectId || "";
if (tenantId) { if (tenantId) {
try { try {
const baseURL = localStorage.getItem("baseUrl"); const baseURL = localStorage.getItem("baseUrl");
const url = `${baseURL}functions/savecontact`; const url = `${baseURL}functions/savecontact`;
const token = const token = {
{ "X-Parse-Session-Token": localStorage.getItem("accesstoken")
"X-Parse-Session-Token": localStorage.getItem("accesstoken") };
};
const data = { name, email, phone, tenantId }; const data = { name, email, phone, tenantId };
const headers = { const headers = {
"Content-Type": "application/json", "Content-Type": "application/json",
@@ -137,7 +135,9 @@ const AddContact = (props) => {
</div> </div>
)} )}
<div className="w-full mx-auto p-[8px]"> <div className="w-full mx-auto p-[8px]">
<div className="text-[14px] font-[700]">{t("add-contact")}</div> {!props?.isDisableTitle && (
<div className="text-[14px] font-[700]">{t("add-contact")}</div>
)}
{isUserExist && ( {isUserExist && (
<div className="mb-[0.75rem] flex items-center mt-1"> <div className="mb-[0.75rem] flex items-center mt-1">
<input <input
@@ -14,7 +14,7 @@ import {
copytoData, copytoData,
fetchUrl, fetchUrl,
formatDate, formatDate,
formatTimeInTimezone, formatDateTime,
getSignedUrl, getSignedUrl,
getTenantDetails, getTenantDetails,
handleSignatureType, handleSignatureType,
@@ -1012,11 +1012,23 @@ const ReportTable = (props) => {
); );
if (matchSigner) { if (matchSigner) {
const timezone = extClass?.[0]?.Timezone || ""; const timezone = extClass?.[0]?.Timezone || "";
const DateFormat = extClass?.[0]?.DateFormat || "MM/DD/YYYY";
const Is12Hr = extClass?.[0]?.Is12HourTime || false;
const signedon = matchSigner?.SignedOn const signedon = matchSigner?.SignedOn
? formatTimeInTimezone(new Date(matchSigner?.SignedOn), timezone) ? formatDateTime(
new Date(matchSigner?.SignedOn),
DateFormat,
timezone,
Is12Hr
)
: "-"; : "-";
const viewedon = matchSigner?.ViewedOn const viewedon = matchSigner?.ViewedOn
? formatTimeInTimezone(new Date(matchSigner?.ViewedOn), timezone) ? formatDateTime(
new Date(matchSigner?.ViewedOn),
DateFormat,
timezone,
Is12Hr
)
: "-"; : "-";
return { return {
id: i, id: i,
+39 -4
View File
@@ -6,10 +6,6 @@ dotenv.config();
export const cloudServerUrl = 'http://localhost:8080/app'; export const cloudServerUrl = 'http://localhost:8080/app';
export const appName = 'OpenSign™'; export const appName = 'OpenSign™';
export function customAPIurl() {
const url = new URL(cloudServerUrl);
return url.pathname === '/api/app' ? url.origin + '/api' : url.origin;
}
export const color = [ export const color = [
'#93a3db', '#93a3db',
@@ -256,3 +252,42 @@ export const mailTemplate = param => {
return { subject, body }; return { subject, body };
}; };
export const selectFormat = data => {
switch (data) {
case 'L':
return 'MM/dd/yyyy';
case 'MM/DD/YYYY':
return 'MM/dd/yyyy';
case 'DD-MM-YYYY':
return 'dd-MM-yyyy';
case 'DD/MM/YYYY':
return 'dd/MM/yyyy';
case 'LL':
return 'MMMM dd, yyyy';
case 'DD MMM, YYYY':
return 'dd MMM, yyyy';
case 'YYYY-MM-DD':
return 'yyyy-MM-dd';
case 'MM-DD-YYYY':
return 'MM-dd-yyyy';
case 'MM.DD.YYYY':
return 'MM.dd.yyyy';
case 'MMM DD, YYYY':
return 'MMM dd, yyyy';
case 'MMMM DD, YYYY':
return 'MMMM dd, yyyy';
case 'DD MMMM, YYYY':
return 'dd MMMM, yyyy';
default:
return 'MM/dd/yyyy';
}
};
export function formatDateTime(date, dateFormat, timeZone, is12Hour) {
const zonedDate = toZonedTime(date, timeZone); // Convert date to the given timezone
const timeFormat = is12Hour ? 'hh:mm:ss a' : 'HH:mm:ss';
return dateFormat
? format(zonedDate, `${selectFormat(dateFormat)}, ${timeFormat} 'GMT' XXX`, { timeZone })
: formatTimeInTimezone(date, timeZone);
}
-2
View File
@@ -21,7 +21,6 @@ import UserAfterFind from './parsefunction/UserAfterFInd.js';
import SignatureAfterFind from './parsefunction/SignatureAfterFind.js'; import SignatureAfterFind from './parsefunction/SignatureAfterFind.js';
import TenantAterFind from './parsefunction/TenantAfterFind.js'; import TenantAterFind from './parsefunction/TenantAfterFind.js';
import VerifyEmail from './parsefunction/VerifyEmail.js'; import VerifyEmail from './parsefunction/VerifyEmail.js';
import encryptedpdf from './parsefunction/encryptedPdf.js';
import { getSignedUrl } from './parsefunction/getSignedUrl.js'; import { getSignedUrl } from './parsefunction/getSignedUrl.js';
import createBatchDocs from './parsefunction/createBatchDocs.js'; import createBatchDocs from './parsefunction/createBatchDocs.js';
import linkContactToDoc from './parsefunction/linkContactToDoc.js'; import linkContactToDoc from './parsefunction/linkContactToDoc.js';
@@ -83,7 +82,6 @@ Parse.Cloud.define('getReport', getReport);
Parse.Cloud.define('getTemplate', GetTemplate); Parse.Cloud.define('getTemplate', GetTemplate);
Parse.Cloud.define('callwebhook', callWebhook); Parse.Cloud.define('callwebhook', callWebhook);
Parse.Cloud.define('verifyemail', VerifyEmail); Parse.Cloud.define('verifyemail', VerifyEmail);
Parse.Cloud.define('encryptedpdf', encryptedpdf);
Parse.Cloud.define('getsignedurl', getSignedUrl); Parse.Cloud.define('getsignedurl', getSignedUrl);
Parse.Cloud.define('batchdocuments', createBatchDocs); Parse.Cloud.define('batchdocuments', createBatchDocs);
Parse.Cloud.define('linkcontacttodoc', linkContactToDoc); Parse.Cloud.define('linkcontacttodoc', linkContactToDoc);
@@ -1,14 +0,0 @@
import { PostHog } from 'posthog-node';
const ph_project_api_key = process.env.PH_PROJECT_API_KEY;
const client = ph_project_api_key ? new PostHog(ph_project_api_key) : '';
export default async function encryptedpdf(request) {
const email = request.params.email;
if (client) {
client?.capture({
distinctId: email,
event: 'encrypted_pdf_error',
properties: { response_code: 200 },
});
}
return { message: 'success' };
}
@@ -1,7 +1,5 @@
import axios from 'axios'; import axios from 'axios';
import { import { cloudServerUrl } from '../../Utils.js';
cloudServerUrl,
} from '../../Utils.js';
export default async function getDocument(request) { export default async function getDocument(request) {
const serverUrl = cloudServerUrl; //process.env.SERVER_URL; const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
const docId = request.params.docId; const docId = request.params.docId;
@@ -47,13 +45,12 @@ export default async function getDocument(request) {
console.log('err user in not authenticated', err); console.log('err user in not authenticated', err);
return { error: "You don't have access of this document!" }; return { error: "You don't have access of this document!" };
} }
} } else {
else {
return { error: "You don't have access of this document!" }; return { error: "You don't have access of this document!" };
} }
} }
} else { } else {
return { error: "You don't have access of this document!" }; return { error: "document deleted or you don't have access." };
} }
} catch (err) { } catch (err) {
console.log('err', err); console.log('err', err);
@@ -1,12 +1,12 @@
import { PDFDocument, rgb } from 'pdf-lib'; import { PDFDocument, rgb } from 'pdf-lib';
import fs from 'node:fs'; import fs from 'node:fs';
import fontkit from '@pdf-lib/fontkit'; import fontkit from '@pdf-lib/fontkit';
import { import { formatDateTime } from '../../../Utils.js';
formatTimeInTimezone,
} from '../../../Utils.js';
export default async function GenerateCertificate(docDetails) { export default async function GenerateCertificate(docDetails) {
const timezone = docDetails?.ExtUserPtr?.Timezone || ''; const timezone = docDetails?.ExtUserPtr?.Timezone || '';
const Is12Hr = docDetails?.ExtUserPtr?.Is12HourTime || false;
const DateFormat = docDetails?.ExtUserPtr?.DateFormat || 'MM/DD/YYYY';
const pdfDoc = await PDFDocument.create(); const pdfDoc = await PDFDocument.create();
// `fontBytes` is used to embed custom font in pdf // `fontBytes` is used to embed custom font in pdf
const fontBytes = fs.readFileSync('./font/times.ttf'); // const fontBytes = fs.readFileSync('./font/times.ttf'); //
@@ -22,23 +22,27 @@ export default async function GenerateCertificate(docDetails) {
const titleColor = rgb(0, 0.2, 0.4); //rgb(0, 0.53, 0.71); const titleColor = rgb(0, 0.2, 0.4); //rgb(0, 0.53, 0.71);
const titleUnderline = rgb(0, 0.2, 0.4); // rgb(0.12, 0.12, 0.12); const titleUnderline = rgb(0, 0.2, 0.4); // rgb(0.12, 0.12, 0.12);
const title = 25; const title = 25;
const subtitle = 20; const subtitle = 16;
const text = 14; const text = 13;
const signertext = 13;
const timeText = 11; const timeText = 11;
const textKeyColor = rgb(0.12, 0.12, 0.12); const textKeyColor = rgb(0.12, 0.12, 0.12);
const textValueColor = rgb(0.3, 0.3, 0.3); const textValueColor = rgb(0.3, 0.3, 0.3);
const completedAt = docDetails?.completedAt ? new Date(docDetails?.completedAt) : new Date(); const completedAt = docDetails?.completedAt ? new Date(docDetails?.completedAt) : new Date();
const completedAtperTimezone = formatTimeInTimezone(completedAt, timezone); const completedAtperTimezone = formatDateTime(completedAt, DateFormat, timezone, Is12Hr);
const completedUTCtime = completedAtperTimezone; const completedUTCtime = completedAtperTimezone;
const signersCount = docDetails?.Signers?.length || 1; const signersCount = docDetails?.Signers?.length || 1;
const generateAt = docDetails?.completedAt ? new Date(docDetails?.completedAt) : new Date(); const generateAt = docDetails?.completedAt ? new Date(docDetails?.completedAt) : new Date();
const generatedAtperTimezone = formatTimeInTimezone(generateAt, timezone); const generatedAtperTimezone = formatDateTime(generateAt, DateFormat, timezone, Is12Hr);
const generatedUTCTime = generatedAtperTimezone; const generatedUTCTime = generatedAtperTimezone;
const generatedOn = 'Generated On ' + generatedUTCTime; const generatedOn = 'Generated On ' + generatedUTCTime;
const textWidth = timesRomanFont.widthOfTextAtSize(generatedOn, 12);
const margin = 30;
const maxX = width - margin - textWidth; // Ensures text stays inside the border with 30px margin
const OriginIp = docDetails?.OriginIp || ''; const OriginIp = docDetails?.OriginIp || '';
const company = docDetails?.ExtUserPtr?.Company || ''; const company = docDetails?.ExtUserPtr?.Company || '';
const createdAt = docDetails?.DocSentAt?.iso || docDetails.createdAt; const createdAt = docDetails?.DocSentAt?.iso || docDetails.createdAt;
const createdAtperTimezone = formatTimeInTimezone(createdAt, timezone); const createdAtperTimezone = formatDateTime(createdAt, DateFormat, timezone, Is12Hr);
const IsEnableOTP = docDetails?.IsEnableOTP || false; const IsEnableOTP = docDetails?.IsEnableOTP || false;
const filteredaudit = docDetails?.AuditTrail?.filter(x => x?.UserPtr?.objectId); const filteredaudit = docDetails?.AuditTrail?.filter(x => x?.UserPtr?.objectId);
const auditTrail = const auditTrail =
@@ -75,15 +79,15 @@ export default async function GenerateCertificate(docDetails) {
borderColor: borderColor, borderColor: borderColor,
borderWidth: 1, borderWidth: 1,
}); });
page.drawImage(pngImage, { page.drawImage(pngImage, {
x: 30, x: 30,
y: 790, y: 790,
width: 100, width: 100,
height: 25, height: 25,
}); });
page.drawText(generatedOn, { page.drawText(generatedOn, {
x: 320, x: Math.max(startX, maxX), // Adjusts dynamically 320
y: 810, y: 810,
size: 12, size: 12,
font: timesRomanFont, font: timesRomanFont,
@@ -92,13 +96,13 @@ export default async function GenerateCertificate(docDetails) {
page.drawText('Certificate of Completion', { page.drawText('Certificate of Completion', {
x: 160, x: 160,
y: 750, y: 755,
size: title, size: title,
font: timesRomanFont, font: timesRomanFont,
color: titleColor, color: titleColor,
}); });
const underlineY = 740; const underlineY = 745;
page.drawLine({ page.drawLine({
start: { x: 30, y: underlineY }, start: { x: 30, y: underlineY },
end: { x: width - 30, y: underlineY }, end: { x: width - 30, y: underlineY },
@@ -108,7 +112,7 @@ export default async function GenerateCertificate(docDetails) {
page.drawText('Summary', { page.drawText('Summary', {
x: 30, x: 30,
y: 710, y: 727,
size: subtitle, size: subtitle,
font: timesRomanFont, font: timesRomanFont,
color: titleColor, color: titleColor,
@@ -116,15 +120,15 @@ export default async function GenerateCertificate(docDetails) {
page.drawText('Document Id :', { page.drawText('Document Id :', {
x: 30, x: 30,
y: 685, y: 710,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
page.drawText(docDetails.objectId, { page.drawText(docDetails.objectId, {
x: 115, x: 110,
y: 685, y: 710,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
@@ -132,15 +136,15 @@ export default async function GenerateCertificate(docDetails) {
page.drawText('Document Name :', { page.drawText('Document Name :', {
x: 30, x: 30,
y: 665, y: 690,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
page.drawText(docDetails?.Name, { page.drawText(docDetails?.Name, {
x: 140, x: 130,
y: 665, y: 690,
size: docDetails?.Name?.length >= 78 ? 12 : text, size: docDetails?.Name?.length >= 78 ? 12 : text,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
@@ -148,52 +152,52 @@ export default async function GenerateCertificate(docDetails) {
page.drawText('Organization :', { page.drawText('Organization :', {
x: 30, x: 30,
y: 645, y: 670,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
page.drawText(company, { page.drawText(company, {
x: 115, x: 110,
y: 645, y: 670,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
page.drawText('Created on :', { page.drawText('Created on :', {
x: 30, x: 30,
y: 625, y: 650,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
page.drawText(`${createdAtperTimezone}`, { page.drawText(`${createdAtperTimezone}`, {
x: 105, x: 97,
y: 625, y: 650,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
page.drawText('Completed on :', { page.drawText('Completed on :', {
x: 30, x: 30,
y: 605, y: 630,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
page.drawText(`${completedUTCtime}`, { page.drawText(`${completedUTCtime}`, {
x: 125, x: 115,
y: 605, y: 630,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
page.drawText('Signers :', { page.drawText('Signers :', {
x: 30, x: 30,
y: 585, y: 610,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
@@ -201,73 +205,76 @@ export default async function GenerateCertificate(docDetails) {
page.drawText(`${signersCount}`, { page.drawText(`${signersCount}`, {
x: 80, x: 80,
y: 585, y: 610,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
page.drawText('Document originator', { page.drawText('Document originator', {
x: 30, x: 30,
y: 565, y: 590,
size: 17, size: 17,
font: timesRomanFont, font: timesRomanFont,
color: titleColor, color: titleColor,
}); });
page.drawText('Name :', { page.drawText('Name :', {
x: 60, x: 60,
y: 545, y: 573,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
page.drawText(ownerName, { page.drawText(ownerName, {
x: 105, x: 105,
y: 545, y: 573,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
page.drawText('Email :', { page.drawText('Email :', {
x: 60, x: 60,
y: 525, y: 553,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
page.drawText(ownerEmail, { page.drawText(ownerEmail, {
x: 105, x: 105,
y: 525, y: 553,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
page.drawText('IP address :', { page.drawText('IP address :', {
x: 60, x: 60,
y: 505, y: 533,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
page.drawText(`${OriginIp}`, { page.drawText(`${OriginIp}`, {
x: 130, x: 125,
y: 505, y: 533,
size: text, size: text,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
page.drawLine({ page.drawLine({
start: { x: 30, y: 495 }, start: { x: 30, y: 527 },
end: { x: width - 30, y: 495 }, end: { x: width - 30, y: 527 },
color: rgb(0.12, 0.12, 0.12), color: rgb(0.12, 0.12, 0.12),
thickness: 0.5, thickness: 0.5,
}); });
let yPosition1 = 475; let yPosition1 = 512;
let yPosition2 = 455; let yPosition2 = 498;
let yPosition3 = 435; let yPosition3 = 478;
let yPosition4 = 415; let yPosition4 = 458;
let yPosition5 = 395; let yPosition5 = 438;
let yPosition6 = 360; let yPosition6 = 418;
let yPosition7 = 398;
let yPosition8 = 363;
auditTrail.slice(0, 3).forEach(async (x, i) => { auditTrail.slice(0, 3).forEach(async (x, i) => {
const embedPng = x.Signature ? await pdfDoc.embedPng(x.Signature) : ''; const embedPng = x.Signature ? await pdfDoc.embedPng(x.Signature) : '';
page.drawText(`Signer ${i + 1}`, { page.drawText(`Signer ${i + 1}`, {
@@ -280,7 +287,7 @@ export default async function GenerateCertificate(docDetails) {
page.drawText('Name :', { page.drawText('Name :', {
x: 30, x: 30,
y: yPosition2, y: yPosition2,
size: text, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
@@ -288,32 +295,32 @@ export default async function GenerateCertificate(docDetails) {
page.drawText(x?.Name, { page.drawText(x?.Name, {
x: 75, x: 75,
y: yPosition2, y: yPosition2,
size: text, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
page.drawText('Viewed on :', { if (IsEnableOTP) {
x: half + 45, page.drawText('Security level :', {
y: yPosition2, x: half + 120,
size: timeText, y: yPosition2,
font: timesRomanFont, size: timeText,
color: textKeyColor, font: timesRomanFont,
}); color: textKeyColor,
});
//new Date(x.ViewedOn).toUTCString() page.drawText('Email, OTP Auth', {
page.drawText(`${formatTimeInTimezone(x.ViewedOn, timezone)}`, { x: half + 190,
x: half + 102, y: yPosition2,
y: yPosition2, size: timeText,
size: timeText, font: timesRomanFont,
font: timesRomanFont, color: textValueColor,
color: textValueColor, });
}); }
page.drawText('Email :', { page.drawText('Email :', {
x: 30, x: 30,
y: yPosition3, y: yPosition3,
size: text, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
@@ -321,70 +328,70 @@ export default async function GenerateCertificate(docDetails) {
page.drawText(x?.Email, { page.drawText(x?.Email, {
x: 75, x: 75,
y: yPosition3, y: yPosition3,
size: text, size: signertext,
font: timesRomanFont,
color: textValueColor,
});
page.drawText('Viewed on :', {
x: 30,
y: yPosition4,
size: signertext,
font: timesRomanFont,
color: textKeyColor,
});
page.drawText(`${formatDateTime(x.ViewedOn, DateFormat, timezone, Is12Hr)}`, {
x: 97,
y: yPosition4,
size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
page.drawText('Signed on :', { page.drawText('Signed on :', {
x: half + 45, x: 30,
y: yPosition3 + 5, y: yPosition5,
size: timeText, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
// new Date(x.SignedOn).toUTCString() page.drawText(`${formatDateTime(x.SignedOn, DateFormat, timezone, Is12Hr)}`, {
page.drawText(`${formatTimeInTimezone(x.SignedOn, timezone)}`, { x: 95,
x: half + 98, y: yPosition5,
y: yPosition3 + 5, size: signertext,
size: timeText,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
page.drawText('IP address :', { page.drawText('IP address :', {
x: 30, x: 30,
y: yPosition4, y: yPosition6,
size: text, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
page.drawText(x?.ipAddress, { page.drawText(x?.ipAddress, {
x: 100, x: 95,
y: yPosition4, y: yPosition6,
size: 13, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
if (IsEnableOTP) {
page.drawText('Security level :', {
x: half + 45,
y: yPosition4 + 10,
size: timeText,
font: timesRomanFont,
color: textKeyColor,
});
page.drawText('Email, OTP Auth', {
x: half + 115,
y: yPosition4 + 10,
size: timeText,
font: timesRomanFont,
color: textValueColor,
});
}
page.drawText('Signature :', { page.drawText('Signature :', {
x: 30, x: 30,
y: yPosition5, y: yPosition7,
size: text, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
page.drawRectangle({ page.drawRectangle({
x: 98, x: 98,
y: yPosition5 - 30, y: yPosition7 - 30,
width: 104, width: 104,
height: 44, height: 44,
borderColor: rgb(0.22, 0.18, 0.47), borderColor: rgb(0.22, 0.18, 0.47),
@@ -393,24 +400,26 @@ export default async function GenerateCertificate(docDetails) {
if (embedPng) { if (embedPng) {
page.drawImage(embedPng, { page.drawImage(embedPng, {
x: 100, x: 100,
y: yPosition5 - 27, y: yPosition7 - 27,
width: 100, width: 100,
height: 40, height: 40,
}); });
} }
page.drawLine({ page.drawLine({
start: { x: 30, y: yPosition6 }, start: { x: 30, y: yPosition8 },
end: { x: width - 30, y: yPosition6 }, end: { x: width - 30, y: yPosition8 },
color: rgb(0.12, 0.12, 0.12), color: rgb(0.12, 0.12, 0.12),
thickness: 0.5, thickness: 0.5,
}); });
yPosition1 = yPosition6 - 20; yPosition1 = yPosition8 - 20;
yPosition2 = yPosition1 - 20; yPosition2 = yPosition1 - 20;
yPosition3 = yPosition2 - 20; yPosition3 = yPosition2 - 20;
yPosition4 = yPosition3 - 20; yPosition4 = yPosition3 - 20;
yPosition5 = yPosition4 - 20; yPosition5 = yPosition4 - 20;
yPosition6 = yPosition6 - 140; yPosition6 = yPosition5 - 20;
yPosition7 = yPosition6 - 20;
yPosition8 = yPosition8 - 174;
}); });
if (auditTrail.length > 3) { if (auditTrail.length > 3) {
@@ -420,7 +429,7 @@ export default async function GenerateCertificate(docDetails) {
const embedPng = x.Signature ? await pdfDoc.embedPng(x.Signature) : ''; const embedPng = x.Signature ? await pdfDoc.embedPng(x.Signature) : '';
// Calculate remaining space on current page // Calculate remaining space on current page
const remainingSpace = yPosition6; const remainingSpace = yPosition8;
// If there's not enough space for the next entry, create a new page // If there's not enough space for the next entry, create a new page
if (remainingSpace < 90) { if (remainingSpace < 90) {
@@ -440,7 +449,10 @@ export default async function GenerateCertificate(docDetails) {
yPosition3 = yPosition2 - 20; yPosition3 = yPosition2 - 20;
yPosition4 = yPosition3 - 20; yPosition4 = yPosition3 - 20;
yPosition5 = yPosition4 - 20; yPosition5 = yPosition4 - 20;
yPosition6 = currentPage.getHeight() - 160; yPosition5 = yPosition4 - 20;
yPosition6 = yPosition5 - 20;
yPosition7 = yPosition6 - 20;
yPosition8 = currentPage.getHeight() - 190;
} }
currentPage.drawText(`Signer ${4 + i}`, { currentPage.drawText(`Signer ${4 + i}`, {
@@ -453,7 +465,7 @@ export default async function GenerateCertificate(docDetails) {
currentPage.drawText('Name :', { currentPage.drawText('Name :', {
x: 30, x: 30,
y: yPosition2, y: yPosition2,
size: text, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
@@ -461,32 +473,32 @@ export default async function GenerateCertificate(docDetails) {
currentPage.drawText(x?.Name, { currentPage.drawText(x?.Name, {
x: 75, x: 75,
y: yPosition2, y: yPosition2,
size: text, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
currentPage.drawText('Viewed on :', { if (IsEnableOTP) {
x: half + 45, currentPage.drawText('Security level :', {
y: yPosition2, x: half + 120,
size: timeText, y: yPosition2,
font: timesRomanFont, size: timeText,
color: textKeyColor, font: timesRomanFont,
}); color: textKeyColor,
});
// new Date(x.ViewedOn).toUTCString() currentPage.drawText(`Email, OTP Auth`, {
currentPage.drawText(`${formatTimeInTimezone(x.ViewedOn, timezone)}`, { x: half + 190,
x: half + 102, y: yPosition2,
y: yPosition2, size: timeText,
size: timeText, font: timesRomanFont,
font: timesRomanFont, color: textValueColor,
color: textValueColor, });
}); }
currentPage.drawText('Email :', { currentPage.drawText('Email :', {
x: 30, x: 30,
y: yPosition3, y: yPosition3,
size: text, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
@@ -494,70 +506,68 @@ export default async function GenerateCertificate(docDetails) {
currentPage.drawText(x?.Email, { currentPage.drawText(x?.Email, {
x: 75, x: 75,
y: yPosition3, y: yPosition3,
size: text, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
currentPage.drawText('Signed on :', { currentPage.drawText('Viewed on :', {
x: half + 45, x: 30,
y: yPosition3 + 5, y: yPosition4,
size: timeText, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
// new Date(x.SignedOn).toUTCString() currentPage.drawText(`${formatDateTime(x.ViewedOn, DateFormat, timezone, Is12Hr)}`, {
currentPage.drawText(`${formatTimeInTimezone(x.SignedOn, timezone)}`, { x: 97,
x: half + 98, y: yPosition4,
y: yPosition3 + 5, size: signertext,
size: timeText, font: timesRomanFont,
color: textValueColor,
});
currentPage.drawText('Signed on :', {
x: 30,
y: yPosition5,
size: signertext,
font: timesRomanFont,
color: textKeyColor,
});
currentPage.drawText(`${formatDateTime(x.SignedOn, DateFormat, timezone, Is12Hr)}`, {
x: 95,
y: yPosition5,
size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
currentPage.drawText('IP address :', { currentPage.drawText('IP address :', {
x: 30, x: 30,
y: yPosition4, y: yPosition6,
size: text, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
currentPage.drawText(x?.ipAddress, { currentPage.drawText(x?.ipAddress, {
x: 100, x: 100,
y: yPosition4, y: yPosition6,
size: text, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textValueColor, color: textValueColor,
}); });
if (IsEnableOTP) {
currentPage.drawText('Security level :', {
x: half + 45,
y: yPosition4 + 10,
size: timeText,
font: timesRomanFont,
color: textKeyColor,
});
currentPage.drawText(`Email, OTP Auth`, {
x: half + 115,
y: yPosition4 + 10,
size: timeText,
font: timesRomanFont,
color: textValueColor,
});
}
currentPage.drawText('Signature :', { currentPage.drawText('Signature :', {
x: 30, x: 30,
y: yPosition5, y: yPosition7,
size: text, size: signertext,
font: timesRomanFont, font: timesRomanFont,
color: textKeyColor, color: textKeyColor,
}); });
currentPage.drawRectangle({ currentPage.drawRectangle({
x: 98, x: 98,
y: yPosition5 - 27, y: yPosition7 - 27,
width: 104, width: 104,
height: 44, height: 44,
borderColor: rgb(0.22, 0.18, 0.47), borderColor: rgb(0.22, 0.18, 0.47),
@@ -566,26 +576,28 @@ export default async function GenerateCertificate(docDetails) {
if (embedPng) { if (embedPng) {
currentPage.drawImage(embedPng, { currentPage.drawImage(embedPng, {
x: 100, x: 100,
y: yPosition5 - 25, y: yPosition7 - 25,
width: 100, width: 100,
height: 40, height: 40,
}); });
} }
currentPage.drawLine({ currentPage.drawLine({
start: { x: 30, y: yPosition6 }, start: { x: 30, y: yPosition8 },
end: { x: width - 30, y: yPosition6 }, end: { x: width - 30, y: yPosition8 },
color: rgb(0.12, 0.12, 0.12), color: rgb(0.12, 0.12, 0.12),
thickness: 0.5, thickness: 0.5,
}); });
// Update y positions for the next entry // Update y positions for the next entry
yPosition1 = yPosition6 - 20; yPosition1 = yPosition8 - 20;
yPosition2 = yPosition1 - 20; yPosition2 = yPosition1 - 20;
yPosition3 = yPosition2 - 20; yPosition3 = yPosition2 - 20;
yPosition4 = yPosition3 - 20; yPosition4 = yPosition3 - 20;
yPosition5 = yPosition4 - 20; yPosition5 = yPosition4 - 20;
yPosition6 = yPosition6 - 140; yPosition6 = yPosition5 - 20;
yPosition7 = yPosition6 - 20;
yPosition8 = yPosition8 - 174;
}); });
} }
@@ -209,7 +209,8 @@ async function sendCompletedMail(obj) {
subject = replaceVar.subject; subject = replaceVar.subject;
body = replaceVar.body; body = replaceVar.body;
} }
const Bcc = doc?.Bcc?.length > 0 ? doc.Bcc.map(x => x.Email) : ''; const Bcc = doc?.Bcc?.length > 0 ? doc.Bcc.map(x => x.Email) : [];
const updatedBcc = doc?.SenderMail ? [...Bcc, doc?.SenderMail] : Bcc;
const params = { const params = {
extUserId: sender.objectId, extUserId: sender.objectId,
url: url, url: url,
@@ -220,7 +221,7 @@ async function sendCompletedMail(obj) {
pdfName: pdfName, pdfName: pdfName,
html: body, html: body,
mailProvider: obj.mailProvider, mailProvider: obj.mailProvider,
bcc: Bcc, bcc: updatedBcc?.length > 0 ? updatedBcc : '',
certificatePath: `./exports/signed_certificate_${doc.objectId}.pdf`, certificatePath: `./exports/signed_certificate_${doc.objectId}.pdf`,
filename: obj?.filename, filename: obj?.filename,
}; };
@@ -31,120 +31,97 @@ async function sendMailProvider(req, plan, monthchange) {
if (req.params.url) { if (req.params.url) {
const randomNumber = Math.floor(Math.random() * 5000); const randomNumber = Math.floor(Math.random() * 5000);
const testPdf = `test_${randomNumber}.pdf`; const testPdf = `test_${randomNumber}.pdf`;
let Pdf = fs.createWriteStream(testPdf); try {
const writeToLocalDisk = () => { let Pdf = fs.createWriteStream(testPdf);
return new Promise((resolve, reject) => { const writeToLocalDisk = () => {
const isSecure =
new URL(req.params.url)?.protocol === 'https:' &&
new URL(req.params.url)?.hostname !== 'localhost';
if (isSecure) {
https
.get(req.params.url, async function (response) {
response.pipe(Pdf);
response.on('end', () => resolve('success'));
})
.on('error', e => {
console.error(`error: ${e.message}`);
resolve('error');
});
} else {
const httpsAgent = new https.Agent({ rejectUnauthorized: false }); // Disable SSL validation
axios
.get(req.params.url, { responseType: 'stream', httpsAgent })
.then(response => {
response.data.pipe(Pdf);
Pdf.on('finish', () => resolve('success'));
Pdf.on('error', () => resolve('error'));
})
.catch(e => {
console.log('error', e.message);
resolve('error');
});
}
});
};
// `writeToLocalDisk` is used to create pdf file from doc url
const ress = await writeToLocalDisk();
if (ress) {
function readTolocal() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
setTimeout(() => { const isSecure =
let PdfBuffer = fs.readFileSync(Pdf.path); new URL(req.params.url)?.protocol === 'https:' &&
resolve(PdfBuffer); new URL(req.params.url)?.hostname !== 'localhost';
}, 100); if (isSecure) {
https
.get(req.params.url, async function (response) {
response.pipe(Pdf);
response.on('end', () => resolve('success'));
})
.on('error', e => {
console.error(`error: ${e.message}`);
resolve('error');
});
} else {
const httpsAgent = new https.Agent({ rejectUnauthorized: false }); // Disable SSL validation
axios
.get(req.params.url, { responseType: 'stream', httpsAgent })
.then(response => {
response.data.pipe(Pdf);
Pdf.on('finish', () => resolve('success'));
Pdf.on('error', () => resolve('error'));
})
.catch(e => {
console.log('error', e.message);
resolve('error');
});
}
}); });
}
// `PdfBuffer` used to create buffer from pdf file
let PdfBuffer = await readTolocal();
const pdfName = req.params.pdfName && `${req.params.pdfName}.pdf`;
const filename = req.params.filename;
const file = {
filename: filename || pdfName || 'exported.pdf',
content: smtpenable ? PdfBuffer : undefined,
data: smtpenable ? undefined : PdfBuffer,
}; };
// `writeToLocalDisk` is used to create pdf file from doc url
const ress = await writeToLocalDisk();
if (ress) {
function readTolocal() {
return new Promise((resolve, reject) => {
setTimeout(() => {
let PdfBuffer = fs.readFileSync(Pdf.path);
resolve(PdfBuffer);
}, 100);
});
}
// `PdfBuffer` used to create buffer from pdf file
let PdfBuffer = await readTolocal();
const pdfName = req.params.pdfName && `${req.params.pdfName}.pdf`;
const filename = req.params.filename;
const file = {
filename: filename || pdfName || 'exported.pdf',
content: smtpenable ? PdfBuffer : undefined,
data: smtpenable ? undefined : PdfBuffer,
};
let attachment; let attachment;
const certificatePath = req.params.certificatePath || `./exports/certificate.pdf`; const certificatePath = req.params.certificatePath || `./exports/certificate.pdf`;
if (fs.existsSync(certificatePath)) { if (fs.existsSync(certificatePath)) {
try { try {
// `certificateBuffer` used to create buffer from pdf file // `certificateBuffer` used to create buffer from pdf file
const certificateBuffer = fs.readFileSync(certificatePath); const certificateBuffer = fs.readFileSync(certificatePath);
const certificate = { const certificate = {
filename: 'certificate.pdf', filename: 'certificate.pdf',
content: smtpenable ? certificateBuffer : undefined, //fs.readFileSync('./exports/exported_file_1223.pdf'), content: smtpenable ? certificateBuffer : undefined, //fs.readFileSync('./exports/exported_file_1223.pdf'),
data: smtpenable ? undefined : certificateBuffer, data: smtpenable ? undefined : certificateBuffer,
}; };
attachment = [file, certificate]; attachment = [file, certificate];
} catch (err) { } catch (err) {
attachment = [file];
console.log('Err in read certificate sendmailv3', err);
}
} else {
attachment = [file]; attachment = [file];
console.log('Err in read certificate sendmailv3', err);
} }
} else { const from = req.params.from || '';
attachment = [file]; const mailsender = smtpenable ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER;
} const replyto = req.params?.replyto || '';
const from = req.params.from || ''; const messageParams = {
const mailsender = smtpenable ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER; from: from + ' <' + mailsender + '>',
const replyto = req.params?.replyto || ''; to: req.params.recipient,
const messageParams = { subject: req.params.subject,
from: from + ' <' + mailsender + '>', text: req.params.text || 'mail',
to: req.params.recipient, html: req.params.html || '',
subject: req.params.subject, attachments: smtpenable ? attachment : undefined,
text: req.params.text || 'mail', attachment: smtpenable ? undefined : attachment,
html: req.params.html || '', bcc: req.params.bcc ? req.params.bcc : undefined,
attachments: smtpenable ? attachment : undefined, replyTo: replyto ? replyto : undefined,
attachment: smtpenable ? undefined : attachment, };
bcc: req.params.bcc ? req.params.bcc : undefined, if (transporterSMTP) {
replyTo: replyto ? replyto : undefined, const res = await transporterSMTP.sendMail(messageParams);
}; console.log('smtp transporter res: ', res?.response);
if (transporterSMTP) { if (!res.err) {
const res = await transporterSMTP.sendMail(messageParams);
console.log('smtp transporter res: ', res?.response);
if (!res.err) {
if (req.params?.extUserId) {
await updateMailCount(req.params.extUserId, plan, monthchange);
}
if (fs.existsSync(certificatePath)) {
try {
fs.unlinkSync(certificatePath);
} catch (err) {
console.log('Err in unlink certificate sendmailv3');
}
}
if (fs.existsSync(testPdf)) {
try {
fs.unlinkSync(testPdf);
} catch (err) {
console.log('Err in unlink pdf sendmailv3');
}
}
return { status: 'success' };
}
} else {
if (mailgunApiKey) {
const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
console.log('mailgun res: ', res?.status);
if (res.status === 200) {
if (req.params?.extUserId) { if (req.params?.extUserId) {
await updateMailCount(req.params.extUserId, plan, monthchange); await updateMailCount(req.params.extUserId, plan, monthchange);
} }
@@ -165,23 +142,60 @@ async function sendMailProvider(req, plan, monthchange) {
return { status: 'success' }; return { status: 'success' };
} }
} else { } else {
if (fs.existsSync(certificatePath)) { if (mailgunApiKey) {
try { const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
fs.unlinkSync(certificatePath); console.log('mailgun res: ', res?.status);
} catch (err) { if (res.status === 200) {
console.log('Err in unlink certificate sendmailv3'); if (req.params?.extUserId) {
await updateMailCount(req.params.extUserId, plan, monthchange);
}
if (fs.existsSync(certificatePath)) {
try {
fs.unlinkSync(certificatePath);
} catch (err) {
console.log('Err in unlink certificate sendmailv3');
}
}
if (fs.existsSync(testPdf)) {
try {
fs.unlinkSync(testPdf);
} catch (err) {
console.log('Err in unlink pdf sendmailv3');
}
}
return { status: 'success' };
} }
} } else {
if (fs.existsSync(testPdf)) { if (fs.existsSync(certificatePath)) {
try { try {
fs.unlinkSync(testPdf); fs.unlinkSync(certificatePath);
} catch (err) { } catch (err) {
console.log('Err in unlink pdf sendmailv3'); console.log('Err in unlink certificate sendmailv3');
}
} }
if (fs.existsSync(testPdf)) {
try {
fs.unlinkSync(testPdf);
} catch (err) {
console.log('Err in unlink pdf sendmailv3');
}
}
return { status: 'error' };
} }
return { status: 'error' };
} }
} }
} catch (err) {
console.log('err in sendmailv3', err);
if (fs.existsSync(testPdf)) {
try {
fs.unlinkSync(testPdf);
} catch (err) {
console.log('Err in unlink pdf sendmailv3');
}
}
if (err) {
return { status: 'error' };
}
} }
} else { } else {
const from = req.params.from || ''; const from = req.params.from || '';
@@ -230,8 +244,8 @@ async function sendMailProvider(req, plan, monthchange) {
} }
async function sendmailv3(req) { async function sendmailv3(req) {
const nonCustomMail = await sendMailProvider(req); const nonCustomMail = await sendMailProvider(req);
return nonCustomMail; return nonCustomMail;
} }
export default sendmailv3; export default sendmailv3;
@@ -48,6 +48,12 @@ export default async function updatePreferences(request) {
if (request.params.IsTourEnabled !== undefined) { if (request.params.IsTourEnabled !== undefined) {
newOrg.set('IsTourEnabled', request.params.IsTourEnabled); newOrg.set('IsTourEnabled', request.params.IsTourEnabled);
} }
if (request.params.DateFormat) {
newOrg.set('DateFormat', request.params.DateFormat);
}
if (request.params.Is12HourTime !== undefined) {
newOrg.set('Is12HourTime', request.params.Is12HourTime);
}
const updateUserRes = await newOrg.save(null, { useMasterKey: true }); const updateUserRes = await newOrg.save(null, { useMasterKey: true });
if (updateUserRes) { if (updateUserRes) {
const _updateUserRes = JSON.parse(JSON.stringify(updateUserRes)); const _updateUserRes = JSON.parse(JSON.stringify(updateUserRes));
-12
View File
@@ -15,7 +15,6 @@ import AWS from 'aws-sdk';
import { app as customRoute } from './cloud/customRoute/customApp.js'; import { app as customRoute } from './cloud/customRoute/customApp.js';
import { exec } from 'child_process'; import { exec } from 'child_process';
import { createTransport } from 'nodemailer'; import { createTransport } from 'nodemailer';
import { PostHog } from 'posthog-node';
import { appName, cloudServerUrl, smtpenable, smtpsecure, useLocal } from './Utils.js'; import { appName, cloudServerUrl, 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 createContactIndex from './migrationdb/createContactIndex.js';
@@ -175,16 +174,6 @@ function getUserIP(request) {
return request.socket.remoteAddress; return request.socket.remoteAddress;
} }
} }
app.use(function (req, res, next) {
const ph_project_api_key = process.env.PH_PROJECT_API_KEY;
try {
req.posthog = new PostHog(ph_project_api_key);
} catch (err) {
// console.log('Err', err);
req.posthog = '';
}
next();
});
app.use(async function (req, res, next) { app.use(async function (req, res, next) {
const isFilePath = req.path.includes('files') || false; const isFilePath = req.path.includes('files') || false;
@@ -225,7 +214,6 @@ if (!process.env.TESTING) {
// Mount your custom express app // Mount your custom express app
app.use('/', customRoute); app.use('/', customRoute);
// Parse Server plays nicely with the rest of your web routes // Parse Server plays nicely with the rest of your web routes
app.get('/', function (req, res) { app.get('/', function (req, res) {
res.status(200).send('opensign-server is running !!!'); res.status(200).send('opensign-server is running !!!');
+2352 -2099
View File
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -18,26 +18,26 @@
"watch": "nodemon index.js" "watch": "nodemon index.js"
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.741.0", "@aws-sdk/client-s3": "^3.775.0",
"@aws-sdk/s3-request-presigner": "^3.741.0", "@aws-sdk/s3-request-presigner": "^3.775.0",
"@parse/fs-files-adapter": "^3.0.0", "@parse/fs-files-adapter": "^3.0.0",
"@parse/s3-files-adapter": "^4.1.0", "@parse/s3-files-adapter": "^4.1.0",
"@pdf-lib/fontkit": "^1.1.1", "@pdf-lib/fontkit": "^1.1.1",
"@signpdf/placeholder-pdf-lib": "^3.2.4", "@signpdf/placeholder-pdf-lib": "^3.2.4",
"@signpdf/signer-p12": "^3.2.4", "@signpdf/signer-p12": "^3.2.4",
"@signpdf/signpdf": "^3.2.4", "@signpdf/signpdf": "^3.2.5",
"aws-sdk": "^2.1692.0", "aws-sdk": "^2.1692.0",
"axios": "^1.7.9", "axios": "^1.8.4",
"cors": "^2.8.5", "cors": "^2.8.5",
"date-fns-tz": "^3.2.0", "date-fns-tz": "^3.2.0",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"express": "^4.21.1", "express": "^4.21.1",
"form-data": "^4.0.1", "form-data": "^4.0.2",
"generate-api-key": "^1.0.2", "generate-api-key": "^1.0.2",
"googleapis": "^144.0.0", "googleapis": "^148.0.0",
"mailgun.js": "^11.1.0", "mailgun.js": "^11.1.0",
"mongodb": "^6.13.0", "mongodb": "^6.15.0",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.2",
"multer-s3": "^3.0.1", "multer-s3": "^3.0.1",
"node-forge": "^1.3.1", "node-forge": "^1.3.1",
"nodemailer": "^6.10.0", "nodemailer": "^6.10.0",
@@ -46,18 +46,18 @@
"parse-server": "^7.4.0", "parse-server": "^7.4.0",
"parse-server-api-mail-adapter": "^4.1.0", "parse-server-api-mail-adapter": "^4.1.0",
"pdf-lib": "^1.17.1", "pdf-lib": "^1.17.1",
"posthog-node": "^4.5.0", "posthog-node": "^4.10.2",
"ws": "^8.18.0" "ws": "^8.18.1"
}, },
"type": "module", "type": "module",
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.26.5", "@babel/eslint-parser": "^7.27.0",
"eslint": "^9.20.0", "eslint": "^9.23.0",
"jasmine": "^5.6.0", "jasmine": "^5.6.0",
"mongodb-runner": "^5.7.1", "mongodb-runner": "^5.8.0",
"nodemon": "^3.1.9", "nodemon": "^3.1.9",
"nyc": "^17.1.0", "nyc": "^17.1.0",
"prettier": "^3.5.0" "prettier": "^3.5.3"
}, },
"overrides": { "overrides": {
"ws": "$ws", "ws": "$ws",
+2 -1
View File
@@ -11,7 +11,8 @@ services:
env_file: .env.prod env_file: .env.prod
environment: environment:
- NODE_ENV=production - NODE_ENV=production
- SERVER_URL=${HOST_URL:-https://localhost:3001}/app - SERVER_URL=${HOST_URL:-https://localhost:3001}/api/app
- PUBLIC_URL=${HOST_URL:-https://localhost:3001}
networks: networks:
- app-network - app-network
mongo: mongo: