mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-04 00:38:57 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8af0010f55 | ||
|
|
d7b7ad6285 | ||
|
|
fca45ced38 | ||
|
|
ac8ab70246 | ||
|
|
8373679f27 | ||
|
|
0a23aabbe4 | ||
|
|
4a85599703 | ||
|
|
3e9b84de72 | ||
|
|
4313d8d0e4 | ||
|
|
3088fdd163 | ||
|
|
8c86fe27ec | ||
|
|
01e09998e5 | ||
|
|
55fdb52bf3 | ||
|
|
08f46a393b | ||
|
|
9345da543a | ||
|
|
208891e10d | ||
|
|
db0fa61b2b | ||
|
|
221f098de6 |
@@ -1,7 +1,7 @@
|
||||
{$HOST_URL} {
|
||||
reverse_proxy client:3000
|
||||
handle_path /app/* {
|
||||
handle_path /api/* {
|
||||
reverse_proxy server:8080
|
||||
rewrite * /app{uri}
|
||||
rewrite * {uri}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+269
-789
File diff suppressed because it is too large
Load Diff
+23
-23
@@ -4,17 +4,17 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@formkit/auto-animate": "^0.8.2",
|
||||
"@lottiefiles/dotlottie-react": "^0.13.0",
|
||||
"@lottiefiles/dotlottie-react": "^0.13.2",
|
||||
"@pdf-lib/fontkit": "^1.1.1",
|
||||
"@radix-ui/themes": "^3.1.6",
|
||||
"@react-pdf/renderer": "^4.1.6",
|
||||
"@reduxjs/toolkit": "^2.5.1",
|
||||
"axios": "^1.7.9",
|
||||
"css-minimizer-webpack-plugin": "^7.0.0",
|
||||
"axios": "^1.8.4",
|
||||
"css-minimizer-webpack-plugin": "^7.0.2",
|
||||
"date-fns-tz": "^3.2.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"i18next": "^23.16.8",
|
||||
"i18next-browser-languagedetector": "^8.0.2",
|
||||
"i18next-http-backend": "^3.0.1",
|
||||
"i18next-browser-languagedetector": "^8.0.4",
|
||||
"i18next-http-backend": "^3.0.2",
|
||||
"jszip": "^3.10.1",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"moment": "^2.30.1",
|
||||
@@ -25,7 +25,7 @@
|
||||
"radix-ui": "^1.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.10.9",
|
||||
"react-confetti": "^6.2.2",
|
||||
"react-confetti": "^6.4.0",
|
||||
"react-cookie": "^7.2.2",
|
||||
"react-datepicker": "^7.6.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
@@ -35,16 +35,16 @@
|
||||
"react-dom": "^18.2.0",
|
||||
"react-gtm-module": "^2.0.11",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-i18next": "^15.4.0",
|
||||
"react-i18next": "^15.4.1",
|
||||
"react-konva": "^18.2.10",
|
||||
"react-pdf": "^9.2.1",
|
||||
"react-quill-new": "^3.3.3",
|
||||
"react-quill-new": "^3.4.6",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-rnd": "^10.4.14",
|
||||
"react-rnd": "^10.5.2",
|
||||
"react-router": "^7.1.5",
|
||||
"react-scripts": "^5.0.1",
|
||||
"react-scrollbars-custom": "^4.1.1",
|
||||
"react-select": "^5.10.0",
|
||||
"react-select": "^5.10.1",
|
||||
"react-signature-canvas": "^1.0.7",
|
||||
"react-syntax-highlighter": "^15.6.1",
|
||||
"react-timezone-select": "^3.2.8",
|
||||
@@ -53,11 +53,11 @@
|
||||
"reactour": "^1.19.4",
|
||||
"redux": "^5.0.1",
|
||||
"redux-thunk": "^3.1.0",
|
||||
"regex-parser": "^2.3.0",
|
||||
"regex-parser": "^2.3.1",
|
||||
"serve": "^14.2.4",
|
||||
"styled-components": "^5.3.0",
|
||||
"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"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -96,26 +96,26 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.26.9",
|
||||
"@babel/core": "^7.26.10",
|
||||
"@babel/preset-env": "^7.26.9",
|
||||
"@babel/preset-react": "^7.26.3",
|
||||
"@babel/runtime-corejs2": "^7.26.9",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"babel-loader": "^9.2.1",
|
||||
"@babel/runtime-corejs2": "^7.27.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"babel-loader": "^10.0.0",
|
||||
"commitizen": "^4.3.1",
|
||||
"concurrently": "^9.1.2",
|
||||
"css-loader": "^7.1.2",
|
||||
"daisyui": "^4.12.23",
|
||||
"dotenv": "^16.4.7",
|
||||
"dotenv-webpack": "^8.1.0",
|
||||
"eslint": "^9.20.0",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"eslint": "^9.23.0",
|
||||
"eslint-plugin-prettier": "^5.2.5",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"lint-staged": "^15.4.3",
|
||||
"lint-staged": "^15.5.0",
|
||||
"mini-css-extract-plugin": "^2.9.2",
|
||||
"postcss": "^8.5.1",
|
||||
"prettier": "^3.5.0",
|
||||
"pretty-quick": "^4.0.0",
|
||||
"postcss": "^8.5.3",
|
||||
"prettier": "^3.5.3",
|
||||
"pretty-quick": "^4.1.1",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"terser-webpack-plugin": "^5.3.11",
|
||||
"webpack-cli": "^5.1.4"
|
||||
|
||||
@@ -151,7 +151,8 @@
|
||||
"extend-expiry-date": "Ablaufdatum verlängern",
|
||||
"Duplicate Template": "Vorlage duplizieren",
|
||||
"Duplicate": "Duplikat",
|
||||
"daily-mail-quota": "Tägliches E-Mail-Kontingent"
|
||||
"daily-mail-quota": "Tägliches E-Mail-Kontingent",
|
||||
"Save as template": "Als Vorlage speichern"
|
||||
},
|
||||
"report-heading": {
|
||||
"Sr.No": "Nr.",
|
||||
@@ -247,7 +248,7 @@
|
||||
"generate-token-alert": "Sind Sie sicher, dass Sie das Token neu generieren möchten? Das alte Token wird ablaufen.",
|
||||
"yes": "Ja",
|
||||
"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.",
|
||||
"webhook": "Webhook",
|
||||
"update-webhook": "Webhook aktualisieren",
|
||||
@@ -308,7 +309,7 @@
|
||||
"revoke-document": "Dokument widerrufen",
|
||||
"revoke-document-alert": "Sind Sie sicher, dass Sie dieses Dokument widerrufen möchten?",
|
||||
"resend-mail": "E-Mail erneut senden",
|
||||
"resend-mail-help": "Sie können folgende Variablen verwenden, die durch ihre tatsächlichen Werte ersetzt werden: {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}.",
|
||||
"resend-mail-help": "Sie können folgende Variablen verwenden, die durch ihre tatsächlichen Werte ersetzt werden: {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}, {{note}}.",
|
||||
"subject": "Betreff",
|
||||
"body": "Inhalt",
|
||||
"add-contact": "Kontakt hinzufügen",
|
||||
@@ -458,6 +459,7 @@
|
||||
"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-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-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!",
|
||||
@@ -521,7 +523,7 @@
|
||||
"correct-password": "Bitte korrektes Passwort angeben",
|
||||
"decrypting-pdf": "PDF wird entschlüsselt, bitte warten...",
|
||||
"invalid-otp": "Ungültiger OTP",
|
||||
"user-not-found": "Benutzer nicht gefunden!",
|
||||
"user-not-found": "Benutzer nicht gefunden",
|
||||
"enter-otp-alert": "Bitte OTP eingeben!",
|
||||
"get-verification-code": "Verifizierungscode erhalten",
|
||||
"get-verification-code-2": "Sie erhalten einen Verifizierungscode per E-Mail",
|
||||
@@ -831,7 +833,7 @@
|
||||
"initial-type": "Ihre Initialen",
|
||||
"redirect-url": "Weiterleitungs-URL",
|
||||
"bulk-send": "Massenversand",
|
||||
"select-timezone": "Wählen Sie Ihre Zeitzone",
|
||||
"select-timezone": "Zeitzone",
|
||||
"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.",
|
||||
"doc-sent": "Dokument erfolgreich gesendet.",
|
||||
@@ -856,5 +858,20 @@
|
||||
"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",
|
||||
"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": "Wie war Ihre Erfahrung mit {{appName}}?",
|
||||
"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.",
|
||||
"save-as-template-?": "Sind Sie sicher, dass Sie dieses Dokument als Vorlage speichern möchten?",
|
||||
"go-to-manage-templates": "Zu 'Vorlagen verwalten' gehen",
|
||||
"template-created": "Vorlage erstellt",
|
||||
"how-would-you-like-to-proceed?": "Wie möchten Sie fortfahren?",
|
||||
"failed-to-load-refresh-page": "Fehler beim Laden des Dokuments. Bitte versuchen Sie, diese Seite zu aktualisieren.",
|
||||
"document-has-been-signed": "Das Dokument wurde erfolgreich unterschrieben!",
|
||||
"document-has-been-signed-by-you": "Das Dokument wurde erfolgreich von Ihnen unterschrieben!",
|
||||
"participant-completed-signing": "Alle Teilnehmer haben den Signaturprozess abgeschlossen.",
|
||||
"you-will-receive-email-shortly": "✅ Das war's! Sie erhalten in Kürze eine Bestätigungs-E-Mail."
|
||||
}
|
||||
|
||||
@@ -151,7 +151,8 @@
|
||||
"extend-expiry-date": "Extend expiry date",
|
||||
"Duplicate Template": "Duplicate template",
|
||||
"Duplicate": "Duplicate",
|
||||
"daily-mail-quota": "Daily Email Quota"
|
||||
"daily-mail-quota": "Daily Email Quota",
|
||||
"Save as template": "Save as template"
|
||||
},
|
||||
"report-heading": {
|
||||
"Sr.No": "Sr.No",
|
||||
@@ -247,7 +248,7 @@
|
||||
"generate-token-alert": "Are you sure you want to regenerate token it will expire old token?",
|
||||
"yes": "Yes",
|
||||
"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.",
|
||||
"webhook": "Webhook",
|
||||
"update-webhook": "Update webhook",
|
||||
@@ -308,7 +309,7 @@
|
||||
"revoke-document": "Revoke document",
|
||||
"revoke-document-alert": "Are you sure you want to revoke this document?",
|
||||
"resend-mail": "Resend mail",
|
||||
"resend-mail-help": "You can use following variables which will get replaced with their actual values:- {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}.",
|
||||
"resend-mail-help": "You can use following variables which will get replaced with their actual values:- {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}, {{note}}.",
|
||||
"subject": "Subject",
|
||||
"body": "Body",
|
||||
"add-contact": "Add contact",
|
||||
@@ -458,6 +459,7 @@
|
||||
"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-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-6": "Please setup mail adapter to send mail!",
|
||||
"placeholder-alert-7": "Please select signer for add placeholder!",
|
||||
@@ -521,7 +523,7 @@
|
||||
"correct-password": "Please provide correct password",
|
||||
"decrypting-pdf": " Decrypting pdf please wait...",
|
||||
"invalid-otp": "Invalid otp",
|
||||
"user-not-found": "User not found!",
|
||||
"user-not-found": "User not found",
|
||||
"enter-otp-alert": "Please enter OTP!",
|
||||
"get-verification-code": "Get verification code",
|
||||
"get-verification-code-2": "You will get a verification code via Email",
|
||||
@@ -831,7 +833,7 @@
|
||||
"initial-type": "Your initials",
|
||||
"redirect-url": "Redirect url",
|
||||
"bulk-send": "Bulk send",
|
||||
"select-timezone": "Select your Timezone",
|
||||
"select-timezone": "Timezone",
|
||||
"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.",
|
||||
"doc-sent": "Document sent successfully.",
|
||||
@@ -856,5 +858,20 @@
|
||||
"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",
|
||||
"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": "How was your experience with {{appName}}?",
|
||||
"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.",
|
||||
"save-as-template-?": "Are you sure you want to save this document as template?",
|
||||
"go-to-manage-templates": "go to 'Manage templates'",
|
||||
"template-created": "Template Created",
|
||||
"how-would-you-like-to-proceed?": "How would you like to proceed?",
|
||||
"failed-to-load-refresh-page": "Failed to load the document. Please try refreshing this page.",
|
||||
"document-has-been-signed": "The document has been signed successfully!",
|
||||
"document-has-been-signed-by-you": "The document has been successfully signed by you!",
|
||||
"participant-completed-signing": "All participants have completed the signing process.",
|
||||
"you-will-receive-email-shortly": "✅ That's it! You'll receive a confirmation email shortly."
|
||||
}
|
||||
|
||||
@@ -151,7 +151,8 @@
|
||||
"extend-expiry-date": "Date d'expiration",
|
||||
"Duplicate Template": "Plantilla duplicada",
|
||||
"Duplicate": "Duplicada",
|
||||
"daily-mail-quota": "Cuota diaria de correos electrónicos"
|
||||
"daily-mail-quota": "Cuota diaria de correos electrónicos",
|
||||
"Save as template": "Guardar como plantilla"
|
||||
},
|
||||
"report-heading": {
|
||||
"Sr.No": "Nº",
|
||||
@@ -248,7 +249,7 @@
|
||||
"generate-token-alert": "¿En definitiva quieres regenerar el token? Esto expirará el token antiguo.",
|
||||
"yes": "Sí",
|
||||
"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.",
|
||||
"webhook": "Webhook",
|
||||
"update-webhook": "Actualizar webhook",
|
||||
@@ -309,7 +310,7 @@
|
||||
"revoke-document": "Revocar documento",
|
||||
"revoke-document-alert": "¿En definitiva quieres revocar este documento?",
|
||||
"resend-mail": "Reenviar correo",
|
||||
"resend-mail-help": "Puedes usar las siguientes variables que serán reemplazadas por sus valores reales:- {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}.",
|
||||
"resend-mail-help": "Puedes usar las siguientes variables que serán reemplazadas por sus valores reales:- {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}, {{note}}.",
|
||||
"subject": "Asunto",
|
||||
"body": "Cuerpo",
|
||||
"add-contact": "Agregar contacto",
|
||||
@@ -458,6 +459,7 @@
|
||||
"placeholder-alert-3": " ¿En definitiva quieres enviar este documento para ser firmado?",
|
||||
"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-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-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!",
|
||||
@@ -521,7 +523,7 @@
|
||||
"correct-password": "Por favor, proporciona la contraseña correcta",
|
||||
"decrypting-pdf": " Desencriptando PDF, por favor, espera...",
|
||||
"invalid-otp": "OTP inválido",
|
||||
"user-not-found": "¡Usuario no encontrado!",
|
||||
"user-not-found": "Usuario no encontrado",
|
||||
"enter-otp-alert": "¡Por favor, ingresa el OTP!",
|
||||
"get-verification-code": "Obtener código de verificación",
|
||||
"get-verification-code-2": "Obtendrás un código de verificación por correo",
|
||||
@@ -831,7 +833,7 @@
|
||||
"initial-type": "Tus iniciales",
|
||||
"redirect-url": "URL de redireccionamiento",
|
||||
"bulk-send": "envío masivo",
|
||||
"select-timezone": "Seleccione su zona horaria",
|
||||
"select-timezone": "Zona horaria",
|
||||
"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.",
|
||||
"doc-sent": "Documento enviado con éxito.",
|
||||
@@ -856,5 +858,20 @@
|
||||
"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",
|
||||
"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": "¿Cómo fue su experiencia con {{appName}}?",
|
||||
"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.",
|
||||
"save-as-template-?": "¿Está seguro de que desea guardar este documento como plantilla?",
|
||||
"go-to-manage-templates": "Ir a 'Gestionar plantillas'",
|
||||
"template-created": "Plantilla creada",
|
||||
"how-would-you-like-to-proceed?": "¿Cómo le gustaría proceder?",
|
||||
"failed-to-load-refresh-page": "Error al cargar el documento. Intente actualizar esta página.",
|
||||
"document-has-been-signed": "¡El documento ha sido firmado con éxito!",
|
||||
"document-has-been-signed-by-you": "¡El documento ha sido firmado con éxito por usted!",
|
||||
"participant-completed-signing": "Todos los participantes han completado el proceso de firma.",
|
||||
"you-will-receive-email-shortly": "✅ ¡Eso es todo! Recibirá un correo de confirmación en breve."
|
||||
}
|
||||
|
||||
@@ -172,7 +172,8 @@
|
||||
"extend-expiry-date": "Prolonger la date d'expiration",
|
||||
"Duplicate Template": "dupliquer le modèle",
|
||||
"Duplicate": "Double",
|
||||
"daily-mail-quota": "Quota d'e-mails quotidien"
|
||||
"daily-mail-quota": "Quota d'e-mails quotidien",
|
||||
"Save as template": "Enregistrer comme modèle"
|
||||
},
|
||||
"report-help": {
|
||||
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
|
||||
@@ -308,7 +309,7 @@
|
||||
"revoke-document": "Révoquer le document",
|
||||
"revoke-document-alert": "Êtes-vous sûr de vouloir révoquer ce document ?",
|
||||
"resend-mail": "Renvoyer le courrier",
|
||||
"resend-mail-help": "Vous pouvez utiliser les variables suivantes qui seront remplacées par leurs valeurs réelles : - {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email} }, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}.",
|
||||
"resend-mail-help": "Vous pouvez utiliser les variables suivantes qui seront remplacées par leurs valeurs réelles : - {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email} }, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}, {{note}}.",
|
||||
"subject": "Sujet",
|
||||
"body": "Corps",
|
||||
"add-contact": "Ajouter le contact",
|
||||
@@ -458,6 +459,7 @@
|
||||
"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-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-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é !",
|
||||
@@ -521,7 +523,7 @@
|
||||
"correct-password": "Veuillez fournir un mot de passe correct",
|
||||
"decrypting-pdf": "Décryptage du pdf, veuillez patienter...",
|
||||
"invalid-otp": "OTP invalide",
|
||||
"user-not-found": "Utilisateur non trouvé!",
|
||||
"user-not-found": "Utilisateur non trouvé",
|
||||
"enter-otp-alert": "Veuillez saisir OTP !",
|
||||
"get-verification-code": "Obtenir le code de vérification",
|
||||
"get-verification-code-2": "Vous recevrez un code de vérification par e-mail",
|
||||
@@ -831,7 +833,7 @@
|
||||
"initial-type": "Vos initiales",
|
||||
"redirect-url": "URL de redirection",
|
||||
"bulk-send": "Envoi groupé",
|
||||
"select-timezone": "Sélectionnez votre fuseau horaire",
|
||||
"select-timezone": "Fuseau horaire",
|
||||
"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.",
|
||||
"doc-sent": "Document envoyé avec succès.",
|
||||
@@ -856,5 +858,20 @@
|
||||
"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",
|
||||
"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": "Comment s'est passée votre expérience avec {{appName}} ?",
|
||||
"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.",
|
||||
"save-as-template-?": "Êtes-vous sûr de vouloir enregistrer ce document comme modèle ?",
|
||||
"go-to-manage-templates": "Aller à 'Gérer les modèles'",
|
||||
"template-created": "Modèle créé",
|
||||
"how-would-you-like-to-proceed?": "Comment souhaitez-vous procéder ?",
|
||||
"failed-to-load-refresh-page": "Échec du chargement du document. Veuillez essayer d'actualiser cette page.",
|
||||
"document-has-been-signed": "Le document a été signé avec succès !",
|
||||
"document-has-been-signed-by-you": "Le document a été signé avec succès par vous !",
|
||||
"participant-completed-signing": "Tous les participants ont terminé le processus de signature.",
|
||||
"you-will-receive-email-shortly": "✅ Voilà, c'est fait ! Vous recevrez un e-mail de confirmation sous peu."
|
||||
}
|
||||
|
||||
@@ -151,7 +151,8 @@
|
||||
"extend-expiry-date": "Estendi data di scadenza",
|
||||
"Duplicate Template": "Duplica modello",
|
||||
"Duplicate": "Duplica",
|
||||
"daily-mail-quota": "Quota e-mail giornaliera"
|
||||
"daily-mail-quota": "Quota e-mail giornaliera",
|
||||
"Save as template": "Salva come modello"
|
||||
},
|
||||
"report-heading": {
|
||||
"Sr.No": "Nr.",
|
||||
@@ -247,7 +248,7 @@
|
||||
"generate-token-alert": "Sei sicuro di voler rigenerare il token? Questo invaliderà il vecchio token.",
|
||||
"yes": "Sì",
|
||||
"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.",
|
||||
"webhook": "Webhook",
|
||||
"update-webhook": "Aggiorna Webhook",
|
||||
@@ -308,7 +309,7 @@
|
||||
"revoke-document": "Revoca documento",
|
||||
"revoke-document-alert": "Sei sicuro di voler revocare questo documento?",
|
||||
"resend-mail": "Reinvia email",
|
||||
"resend-mail-help": "Puoi usare le seguenti variabili che verranno sostituite con i loro valori effettivi: {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}.",
|
||||
"resend-mail-help": "Puoi usare le seguenti variabili che verranno sostituite con i loro valori effettivi: {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email}}, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}, {{note}}.",
|
||||
"subject": "Oggetto",
|
||||
"body": "Corpo del messaggio",
|
||||
"add-contact": "Aggiungi contatto",
|
||||
@@ -458,6 +459,7 @@
|
||||
"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-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-6": "Configura l'adattatore email per inviare mail!",
|
||||
"placeholder-alert-7": "Seleziona il firmatario per aggiungere un segnaposto!",
|
||||
@@ -521,7 +523,7 @@
|
||||
"correct-password": "Fornisci la password corretta",
|
||||
"decrypting-pdf": "Decrittazione PDF, attendi...",
|
||||
"invalid-otp": "OTP non valido",
|
||||
"user-not-found": "Utente non trovato!",
|
||||
"user-not-found": "Utente non trovato",
|
||||
"enter-otp-alert": "Inserisci l'OTP!",
|
||||
"get-verification-code": "Ottieni codice di verifica",
|
||||
"get-verification-code-2": "Riceverai un codice di verifica tramite Email",
|
||||
@@ -831,7 +833,7 @@
|
||||
"initial-type": "Le tue iniziali",
|
||||
"redirect-url": "URL di reindirizzamento",
|
||||
"bulk-send": "Invio in blocco",
|
||||
"select-timezone": "Seleziona il tuo fuso orario",
|
||||
"select-timezone": "Fuso orario",
|
||||
"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.",
|
||||
"doc-sent": "Documento inviato con successo.",
|
||||
@@ -856,5 +858,20 @@
|
||||
"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",
|
||||
"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": "Com'è stata la sua esperienza con {{appName}}?",
|
||||
"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.",
|
||||
"save-as-template-?": "Sei sicuro di voler salvare questo documento come modello?",
|
||||
"go-to-manage-templates": "Vai a 'Gestisci modelli'",
|
||||
"template-created": "Modello creato",
|
||||
"how-would-you-like-to-proceed?": "Come desideri procedere?",
|
||||
"failed-to-load-refresh-page": "Impossibile caricare il documento. Prova ad aggiornare questa pagina.",
|
||||
"document-has-been-signed": "Il documento è stato firmato con successo!",
|
||||
"document-has-been-signed-by-you": "Il documento è stato firmato con successo da lei!",
|
||||
"participant-completed-signing": "Tutti i partecipanti hanno completato il processo di firma.",
|
||||
"you-will-receive-email-shortly": "✅ È tutto! Riceverà a breve un'e-mail di conferma."
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React from "react";
|
||||
import { Document, Page } from "react-pdf";
|
||||
import { Stage, Layer, Rect, Text } from "react-konva";
|
||||
import { useTranslation } from "react-i18next";
|
||||
const RenderDebugPdf = (props) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div>
|
||||
<div className="sticky top-0 p-[10px] z-10 bg-white border-[1px] border-[gray] my-[5px]">
|
||||
@@ -12,10 +14,9 @@ const RenderDebugPdf = (props) => {
|
||||
onMouseMove={props.handleMouseMoveDiv}
|
||||
>
|
||||
<Document
|
||||
onLoadError={() => {
|
||||
props.setPdfLoadFail(false);
|
||||
}}
|
||||
loading={"Loading Document.."}
|
||||
onLoadError={() => props.setPdfLoadFail(false)}
|
||||
loading={t("loading-doc")}
|
||||
error={<p className="mx-2">{t("failed-to-load-refresh-page")}</p>}
|
||||
onLoadSuccess={props.pageDetails}
|
||||
ref={props.pdfRef}
|
||||
file={props.pdfUrl}
|
||||
|
||||
@@ -17,8 +17,8 @@ const AddRoleModal = (props) => {
|
||||
onChange={(e) => props.setRoleName(e.target.value)}
|
||||
placeholder={
|
||||
props.signersdata.length > 0
|
||||
? "User " + (props.signersdata.length + 1)
|
||||
: "User 1"
|
||||
? "Role " + (props.signersdata.length + 1)
|
||||
: "Role 1"
|
||||
}
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs mt-1"
|
||||
/>
|
||||
|
||||
@@ -1,276 +0,0 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import opensignLogo from "../../assets/images/logo.png";
|
||||
import {
|
||||
Page,
|
||||
Text,
|
||||
View,
|
||||
Document,
|
||||
StyleSheet,
|
||||
Image
|
||||
} from "@react-pdf/renderer";
|
||||
|
||||
function Certificate({ pdfData }) {
|
||||
const [isMultiSigners, setIsMultiSigners] = useState();
|
||||
const [multiSigner, setMultiSigners] = useState([]);
|
||||
const [isLoad, setIsLoad] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
handleSignerData();
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
const handleSignerData = () => {
|
||||
const checkSigners = pdfData.filter((data) => data.Signers);
|
||||
if (checkSigners && checkSigners.length > 0) {
|
||||
setIsMultiSigners(true);
|
||||
|
||||
const checkSignSigners =
|
||||
pdfData[0].AuditTrail &&
|
||||
pdfData[0].AuditTrail.length > 0 &&
|
||||
pdfData[0].AuditTrail.filter((data) => data.Activity === "Signed");
|
||||
|
||||
setMultiSigners(checkSignSigners);
|
||||
} else {
|
||||
setIsMultiSigners(false);
|
||||
}
|
||||
setIsLoad(true);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
page: {
|
||||
borderRadius: "5px",
|
||||
padding: "10px",
|
||||
backgroundColor: "white"
|
||||
},
|
||||
section1: {
|
||||
border: "1px solid rgb(177, 174, 174)",
|
||||
padding: "20px"
|
||||
},
|
||||
textStyle: {
|
||||
fontWeight: "bold",
|
||||
fontSize: "11px",
|
||||
marginBottom: "10px"
|
||||
},
|
||||
textStyle2: {
|
||||
fontWeight: "600",
|
||||
fontSize: "11px",
|
||||
marginBottom: "10px",
|
||||
color: "gray"
|
||||
},
|
||||
image: {
|
||||
width: "71px",
|
||||
height: "17px"
|
||||
}
|
||||
});
|
||||
|
||||
const generatedDate = () => {
|
||||
const newDate = new Date();
|
||||
const utcTime = newDate.toUTCString();
|
||||
|
||||
return (
|
||||
<Text
|
||||
style={{
|
||||
color: "gray",
|
||||
fontSize: "10px"
|
||||
}}
|
||||
>
|
||||
Generated On {utcTime}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
const changeCompletedDate = () => {
|
||||
const completedOn = pdfData[0].updatedAt;
|
||||
const newDate = new Date(completedOn);
|
||||
const utcTime = newDate.toUTCString();
|
||||
|
||||
return <Text style={styles.textStyle2}>{utcTime}</Text>;
|
||||
};
|
||||
|
||||
const signerName = (data) => {
|
||||
const getSignerName = pdfData[0].Signers.filter(
|
||||
(sign) => sign.objectId === data.UserPtr.objectId
|
||||
);
|
||||
|
||||
return (
|
||||
getSignerName[0] &&
|
||||
getSignerName.length > 0 && (
|
||||
<>
|
||||
<Text style={styles.textStyle}>
|
||||
Name :
|
||||
<Text style={styles.textStyle2}>{getSignerName[0].Name}</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Email :
|
||||
<Text style={styles.textStyle2}>{getSignerName[0].Email}</Text>
|
||||
</Text>
|
||||
</>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
isLoad && (
|
||||
<Document>
|
||||
{/** Page defines a single page of content. */}
|
||||
<Page size="A4" style={styles.page}>
|
||||
<View style={styles.section1}>
|
||||
<View
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: "30px"
|
||||
}}
|
||||
>
|
||||
<Image src={opensignLogo} style={styles.image} />
|
||||
{generatedDate()}
|
||||
</View>
|
||||
|
||||
<View style={{ justifyContent: "center" }}>
|
||||
<Text
|
||||
style={{
|
||||
textAlign: "center",
|
||||
fontSize: "20px",
|
||||
fontWeight: "bold",
|
||||
color: "#31bceb",
|
||||
marginBottom: "10px"
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
Certificate of Completion
|
||||
</Text>
|
||||
<View style={{ border: "1px solid #bdbbbb" }}></View>
|
||||
<View>
|
||||
<View>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: "16px",
|
||||
fontWeight: "bold",
|
||||
color: "#31bceb",
|
||||
margin: "10px 0px 10px 0px"
|
||||
}}
|
||||
>
|
||||
Summary
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ display: "flex", flexDirection: "column" }}>
|
||||
<Text style={styles.textStyle}>
|
||||
Document ID :
|
||||
<Text style={styles.textStyle2}>{pdfData[0].objectId}</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Document Name :
|
||||
<Text style={styles.textStyle2}>{pdfData[0].Name}</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Organization :
|
||||
<Text style={styles.textStyle2}>
|
||||
{pdfData[0].ExtUserPtr.Company}
|
||||
</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Completed on : {changeCompletedDate()}
|
||||
</Text>
|
||||
{multiSigner && multiSigner.length > 0 && (
|
||||
<Text style={styles.textStyle}>
|
||||
Signers :
|
||||
<Text style={styles.textStyle2}>
|
||||
{multiSigner.length}
|
||||
</Text>
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
{isMultiSigners ? (
|
||||
<View style={{ display: "flex", flexDirection: "column" }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: "16px",
|
||||
fontWeight: "bold",
|
||||
color: "#31bceb",
|
||||
margin: "10px 0px 10px 0px"
|
||||
}}
|
||||
>
|
||||
Recipients
|
||||
</Text>
|
||||
|
||||
<View>
|
||||
{multiSigner &&
|
||||
multiSigner.map((data, ind) => {
|
||||
return (
|
||||
<View
|
||||
key={ind}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
border: "0.4px solid #bdbbbb",
|
||||
marginBottom: "10px"
|
||||
}}
|
||||
></View>
|
||||
{signerName(data)}
|
||||
|
||||
<Text style={styles.textStyle}>
|
||||
Accessed from :
|
||||
<Text style={styles.textStyle2}>
|
||||
{data.ipAddress}
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</View>
|
||||
) : (
|
||||
<View style={{ display: "flex", flexDirection: "column" }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: "16px",
|
||||
fontWeight: "bold",
|
||||
color: "#31bceb",
|
||||
margin: "10px 0px 10px 0px"
|
||||
}}
|
||||
>
|
||||
Recipients
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Signers : <Text style={styles.textStyle2}>1</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Name :
|
||||
<Text style={styles.textStyle2}>
|
||||
{pdfData[0].ExtUserPtr.Name}
|
||||
</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Email :
|
||||
<Text style={styles.textStyle2}>
|
||||
{pdfData[0].ExtUserPtr.Email}
|
||||
</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Accessed from :
|
||||
<Text style={styles.textStyle2}>
|
||||
{pdfData[0].AuditTrail &&
|
||||
pdfData[0].AuditTrail[0].ipAddress}
|
||||
</Text>
|
||||
</Text>
|
||||
|
||||
<Text style={styles.textStyle}>
|
||||
Signed on : {changeCompletedDate()}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Page>
|
||||
</Document>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default Certificate;
|
||||
@@ -30,15 +30,19 @@ function DraftDocument() {
|
||||
documentData === "Error: Something went wrong!" ||
|
||||
(documentData.result && documentData.result.error)
|
||||
) {
|
||||
setIsLoading({
|
||||
isLoader: false,
|
||||
message: "Error: Something went wrong!"
|
||||
});
|
||||
if (documentData?.result?.error?.includes("deleted")) {
|
||||
setIsLoading({
|
||||
isLoader: false,
|
||||
message: t("document-deleted")
|
||||
});
|
||||
} else {
|
||||
setIsLoading({
|
||||
isLoader: false,
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
}
|
||||
} else {
|
||||
setIsLoading({
|
||||
isLoader: false,
|
||||
message: "No data found!"
|
||||
});
|
||||
setIsLoading({ isLoader: false, message: t("no-data") });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ const EditTemplate = ({ template, onSuccess }) => {
|
||||
<Tooltip id="istourenabled-tooltip" className="z-50">
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">{t("enable-tour")}</p>
|
||||
<p className="p-[5px]">
|
||||
<div className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">{t("yes")}: </span>
|
||||
@@ -199,7 +199,7 @@ const EditTemplate = ({ template, onSuccess }) => {
|
||||
<span>{t("istourenabled-help.p2")}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
<p>{t("istourenabled-help.p3", { appName: appName })}</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
@@ -5,6 +5,7 @@ import Loader from "../../primitives/Loader";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Parse from "parse";
|
||||
|
||||
function EmailComponent({
|
||||
isEmail,
|
||||
setIsEmail,
|
||||
@@ -20,6 +21,7 @@ function EmailComponent({
|
||||
const [emailErr, setEmailErr] = useState(false);
|
||||
const [isDownloading, setIsDownloading] = useState("");
|
||||
const isAndroid = /Android/i.test(navigator.userAgent);
|
||||
|
||||
//function for send email
|
||||
const sendEmail = async () => {
|
||||
setIsLoading(true);
|
||||
@@ -105,7 +107,7 @@ function EmailComponent({
|
||||
</div>
|
||||
)}
|
||||
<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")}
|
||||
</span>
|
||||
<div className="flex flex-row">
|
||||
@@ -114,14 +116,14 @@ function EmailComponent({
|
||||
onClick={(e) =>
|
||||
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>
|
||||
{t("print")}
|
||||
</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={() => {
|
||||
handleClose();
|
||||
setIsDownloadModal(true);
|
||||
@@ -137,12 +139,12 @@ function EmailComponent({
|
||||
{t("email-mssg")}
|
||||
</p>
|
||||
{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">
|
||||
{emailList.map((data, ind) => {
|
||||
return (
|
||||
<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}
|
||||
>
|
||||
<span className="text-base-100 text-[13px]">
|
||||
@@ -162,7 +164,7 @@ function EmailComponent({
|
||||
<input
|
||||
type="email"
|
||||
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}
|
||||
onKeyDown={handleEnterPress}
|
||||
onBlur={() => emailValue && handleEnterPress("add")}
|
||||
@@ -179,7 +181,7 @@ function EmailComponent({
|
||||
<input
|
||||
type="email"
|
||||
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}
|
||||
onKeyDown={handleEnterPress}
|
||||
placeholder={t("enter-email-plaholder")}
|
||||
@@ -197,7 +199,7 @@ function EmailComponent({
|
||||
{t("email-error-1")}
|
||||
</p>
|
||||
)}
|
||||
<button
|
||||
{/* <button
|
||||
className={`${
|
||||
emailValue ? "cursor-pointer" : "cursor-default"
|
||||
} 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>
|
||||
</button>
|
||||
|
||||
<div className="bg-[#e3e2e1] mt-[10px] p-[5px] rounded">
|
||||
<span className="font-bold">{t("report-heading.Note")}: </span>
|
||||
<span className="text-[15px]">{t("email-error-2")}</span>
|
||||
</div>
|
||||
<hr className="w-full my-[15px] bg-base-content" />
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-secondary"
|
||||
onClick={() => emailList.length > 0 && sendEmail()}
|
||||
>
|
||||
{t("send")}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-ghost ml-2"
|
||||
onClick={() => handleClose()}
|
||||
>
|
||||
{t("close")}
|
||||
</button>
|
||||
<hr className="w-full my-[15px] bg-base-content" /> */}
|
||||
<div className="mt-2">
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-secondary"
|
||||
onClick={() => emailList.length > 0 && sendEmail()}
|
||||
>
|
||||
{t("send")}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-ghost ml-2"
|
||||
onClick={() => handleClose()}
|
||||
>
|
||||
{t("close")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</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;
|
||||
@@ -14,6 +14,7 @@ import ModalUi from "../../primitives/ModalUi";
|
||||
import Loader from "../../primitives/Loader";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
import { maxFileSize } from "../../constant/const";
|
||||
|
||||
function Header(props) {
|
||||
const { t } = useTranslation();
|
||||
@@ -50,6 +51,13 @@ function Header(props) {
|
||||
}
|
||||
};
|
||||
|
||||
// `removeFile` is used to remove file if exists
|
||||
const removeFile = (e) => {
|
||||
if (e) {
|
||||
e.target.value = "";
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileUpload = async (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (!file) {
|
||||
@@ -60,6 +68,13 @@ function Header(props) {
|
||||
alert("Only PDF files are allowed.");
|
||||
return;
|
||||
}
|
||||
|
||||
const mb = Math.round(file?.size / Math.pow(1024, 2));
|
||||
if (mb > maxFileSize) {
|
||||
alert(`${t("file-alert-1")} ${maxFileSize} MB`);
|
||||
removeFile(e);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const uploadedPdfBytes = await file.arrayBuffer();
|
||||
const uploadedPdfDoc = await PDFDocument.load(uploadedPdfBytes, {
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from "../../constant/Utils";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
import { maxFileSize } from "../../constant/const";
|
||||
|
||||
function PdfZoom(props) {
|
||||
const { t } = useTranslation();
|
||||
@@ -41,6 +42,14 @@ function PdfZoom(props) {
|
||||
console.log("error in delete pdf page", e);
|
||||
}
|
||||
};
|
||||
|
||||
// `removeFile` is used to remove file if exists
|
||||
const removeFile = (e) => {
|
||||
if (e) {
|
||||
e.target.value = "";
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileUpload = async (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (!file) {
|
||||
@@ -51,6 +60,12 @@ function PdfZoom(props) {
|
||||
alert("Only PDF files are allowed.");
|
||||
return;
|
||||
}
|
||||
const mb = Math.round(file?.size / Math.pow(1024, 2));
|
||||
if (mb > maxFileSize) {
|
||||
alert(`${t("file-alert-1")} ${maxFileSize} MB`);
|
||||
removeFile(e);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const uploadedPdfBytes = await file.arrayBuffer();
|
||||
const uploadedPdfDoc = await PDFDocument.load(uploadedPdfBytes, {
|
||||
|
||||
@@ -25,6 +25,8 @@ 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":
|
||||
@@ -41,6 +43,8 @@ const selectFormat = (data) => {
|
||||
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:
|
||||
|
||||
@@ -24,7 +24,7 @@ const widgetCls =
|
||||
function PlaceholderType(props) {
|
||||
const { t } = useTranslation();
|
||||
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 [validatePlaceholder, setValidatePlaceholder] = useState("");
|
||||
const inputRef = useRef(null);
|
||||
@@ -342,8 +342,8 @@ function PlaceholderType(props) {
|
||||
className="font-medium"
|
||||
>
|
||||
{props.isNeedSign
|
||||
? props.pos?.options?.hint || widgetTypeTraslation
|
||||
: widgetTypeTraslation}
|
||||
? props.pos?.options?.hint || widgetTypeTranslation
|
||||
: widgetTypeTranslation}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -368,8 +368,8 @@ function PlaceholderType(props) {
|
||||
className="font-medium"
|
||||
>
|
||||
{props.isNeedSign
|
||||
? props.pos?.options?.hint || widgetTypeTraslation
|
||||
: widgetTypeTraslation}
|
||||
? props.pos?.options?.hint || widgetTypeTranslation
|
||||
: widgetTypeTranslation}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -475,7 +475,7 @@ function PlaceholderType(props) {
|
||||
/>
|
||||
) : (
|
||||
<div style={textWidgetStyle} className="select-none-cls">
|
||||
<span>{textValue || widgetTypeTraslation}</span>
|
||||
<span>{textValue || widgetTypeTranslation}</span>
|
||||
</div>
|
||||
);
|
||||
case "dropdown":
|
||||
@@ -538,7 +538,7 @@ function PlaceholderType(props) {
|
||||
>
|
||||
{props.pos?.options?.name
|
||||
? props.pos.options.name
|
||||
: widgetTypeTraslation}
|
||||
: widgetTypeTranslation}
|
||||
<i className="fa-light fa-circle-chevron-down mr-1 "></i>
|
||||
</div>
|
||||
);
|
||||
@@ -562,8 +562,8 @@ function PlaceholderType(props) {
|
||||
className="font-medium text-center"
|
||||
>
|
||||
{props.isNeedSign
|
||||
? props.pos?.options?.hint || widgetTypeTraslation
|
||||
: widgetTypeTraslation}
|
||||
? props.pos?.options?.hint || widgetTypeTranslation
|
||||
: widgetTypeTranslation}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -574,7 +574,7 @@ function PlaceholderType(props) {
|
||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||
<textarea
|
||||
ref={inputRef}
|
||||
placeholder={hint}
|
||||
placeholder={hint || widgetTypeTranslation}
|
||||
rows={1}
|
||||
onKeyDown={handleEnterPress}
|
||||
value={textValue}
|
||||
@@ -597,7 +597,7 @@ function PlaceholderType(props) {
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-full select-none-cls" style={textWidgetStyle}>
|
||||
<span>{widgetTypeTraslation}</span>
|
||||
<span>{widgetTypeTranslation}</span>
|
||||
</div>
|
||||
);
|
||||
case "company":
|
||||
@@ -606,7 +606,7 @@ function PlaceholderType(props) {
|
||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||
<textarea
|
||||
ref={inputRef}
|
||||
placeholder={hint}
|
||||
placeholder={hint || widgetTypeTranslation}
|
||||
rows={1}
|
||||
onKeyDown={handleEnterPress}
|
||||
value={textValue}
|
||||
@@ -628,7 +628,7 @@ function PlaceholderType(props) {
|
||||
/>
|
||||
) : (
|
||||
<div style={textWidgetStyle} className="select-none-cls">
|
||||
<span>{widgetTypeTraslation}</span>
|
||||
<span>{widgetTypeTranslation}</span>
|
||||
</div>
|
||||
);
|
||||
case "job title":
|
||||
@@ -637,7 +637,7 @@ function PlaceholderType(props) {
|
||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||
<textarea
|
||||
ref={inputRef}
|
||||
placeholder={hint}
|
||||
placeholder={hint || widgetTypeTranslation}
|
||||
rows={1}
|
||||
onKeyDown={handleEnterPress}
|
||||
value={textValue}
|
||||
@@ -659,7 +659,7 @@ function PlaceholderType(props) {
|
||||
/>
|
||||
) : (
|
||||
<div style={textWidgetStyle} className="select-none-cls">
|
||||
<span>{widgetTypeTraslation}</span>
|
||||
<span>{widgetTypeTranslation}</span>
|
||||
</div>
|
||||
);
|
||||
case "date":
|
||||
@@ -748,8 +748,8 @@ function PlaceholderType(props) {
|
||||
className="font-medium text-center"
|
||||
>
|
||||
{props.isNeedSign
|
||||
? props.pos?.options?.hint || widgetTypeTraslation
|
||||
: widgetTypeTraslation}
|
||||
? props.pos?.options?.hint || widgetTypeTranslation
|
||||
: widgetTypeTranslation}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -760,7 +760,7 @@ function PlaceholderType(props) {
|
||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||
<textarea
|
||||
ref={inputRef}
|
||||
placeholder={hint}
|
||||
placeholder={hint || widgetTypeTranslation}
|
||||
rows={1}
|
||||
onKeyDown={(e) => {
|
||||
// Prevent new line on Enter key press
|
||||
@@ -792,7 +792,7 @@ function PlaceholderType(props) {
|
||||
/>
|
||||
) : (
|
||||
<div style={textWidgetStyle} className="select-none-cls">
|
||||
<span>{widgetTypeTraslation}</span>
|
||||
<span>{widgetTypeTranslation}</span>
|
||||
</div>
|
||||
);
|
||||
case radioButtonWidget:
|
||||
@@ -891,8 +891,8 @@ function PlaceholderType(props) {
|
||||
className="font-medium"
|
||||
>
|
||||
{props.isNeedSign
|
||||
? props.pos?.options?.hint || widgetTypeTraslation
|
||||
: widgetTypeTraslation}
|
||||
? props.pos?.options?.hint || widgetTypeTranslation
|
||||
: widgetTypeTranslation}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Document, Page } from "react-pdf";
|
||||
import { useSelector } from "react-redux";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
import { base64ToArrayBuffer } from "../../constant/Utils";
|
||||
import { maxFileSize } from "../../constant/const";
|
||||
|
||||
function RenderAllPdfPage(props) {
|
||||
const { t } = useTranslation();
|
||||
@@ -62,6 +63,12 @@ function RenderAllPdfPage(props) {
|
||||
};
|
||||
const pdfDataBase64 = `data:application/pdf;base64,${props?.pdfBase64Url}`;
|
||||
|
||||
// `removeFile` is used to remove file if exists
|
||||
const removeFile = (e) => {
|
||||
if (e) {
|
||||
e.target.value = "";
|
||||
}
|
||||
};
|
||||
// `handleFileUpload` is trigger when user click on add pages btn and is used to merge multiple pdf
|
||||
const handleFileUpload = async (e) => {
|
||||
const file = e.target.files[0];
|
||||
@@ -73,6 +80,12 @@ function RenderAllPdfPage(props) {
|
||||
alert("Only PDF files are allowed.");
|
||||
return;
|
||||
}
|
||||
const mb = Math.round(file?.size / Math.pow(1024, 2));
|
||||
if (mb > maxFileSize) {
|
||||
alert(`${t("file-alert-1")} ${maxFileSize} MB`);
|
||||
removeFile(e);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const uploadedPdfBytes = await file.arrayBuffer();
|
||||
const uploadedPdfDoc = await PDFDocument.load(uploadedPdfBytes, {
|
||||
@@ -110,6 +123,7 @@ function RenderAllPdfPage(props) {
|
||||
autoSignScroll hide-scrollbar max-h-[100vh] `}
|
||||
>
|
||||
<Document
|
||||
error=""
|
||||
loading={t("loading-doc")}
|
||||
onLoadSuccess={onDocumentLoad}
|
||||
file={pdfDataBase64}
|
||||
|
||||
@@ -381,17 +381,15 @@ function RenderPdf(props) {
|
||||
</React.Fragment>
|
||||
);
|
||||
}))}
|
||||
|
||||
{/* Mobile */}
|
||||
<Document
|
||||
error={<p className="mx-2">{t("failed-to-load-refresh-page")}</p>}
|
||||
onLoadError={() => props.setPdfLoad(false)}
|
||||
loading={t("loading-doc")}
|
||||
onLoadSuccess={props.pageDetails}
|
||||
// ref={pdfRef}'
|
||||
onClick={() => {
|
||||
if (props.setSelectWidgetId) {
|
||||
props.setSelectWidgetId("");
|
||||
}
|
||||
}}
|
||||
onClick={() =>
|
||||
props.setSelectWidgetId && props.setSelectWidgetId("")
|
||||
}
|
||||
file={pdfDataBase64}
|
||||
>
|
||||
<Page
|
||||
@@ -601,17 +599,16 @@ function RenderPdf(props) {
|
||||
</React.Fragment>
|
||||
);
|
||||
}))}
|
||||
|
||||
{/* large device */}
|
||||
{/* this component for render pdf document is in middle of the component */}
|
||||
<Document
|
||||
error={<p className="mx-2">{t("failed-to-load-refresh-page")}</p>}
|
||||
onLoadError={() => props.setPdfLoad(false)}
|
||||
loading={t("loading-doc")}
|
||||
onLoadSuccess={props.pageDetails}
|
||||
onClick={() => {
|
||||
if (props.setSelectWidgetId) {
|
||||
props.setSelectWidgetId("");
|
||||
}
|
||||
}}
|
||||
onClick={() =>
|
||||
props.setSelectWidgetId && props.setSelectWidgetId("")
|
||||
}
|
||||
file={pdfDataBase64}
|
||||
>
|
||||
<Page
|
||||
|
||||
@@ -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 AsyncSelect from "react-select/async";
|
||||
import AddSigner from "../../AddSigner";
|
||||
import Parse from "parse";
|
||||
import AddContact from "../../../primitives/AddContact";
|
||||
import Tooltip from "../../../primitives/Tooltip";
|
||||
import { createPortal } from "react-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { findContact } from "../../../constant/Utils";
|
||||
function arrayMove(array, from, to) {
|
||||
array = array.slice();
|
||||
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
|
||||
const handleNewDetails = (data) => {
|
||||
setState([...state, data]);
|
||||
const user = {
|
||||
value: data["objectId"],
|
||||
label: data["Name"],
|
||||
email: data?.Email
|
||||
};
|
||||
setState([...state, user]);
|
||||
if (selected.length > 0) {
|
||||
setSelected([...selected, data]);
|
||||
setSelected([...selected, user]);
|
||||
} else {
|
||||
setSelected([data]);
|
||||
setSelected([user]);
|
||||
}
|
||||
};
|
||||
const loadOptions = async (inputValue) => {
|
||||
try {
|
||||
const params = { search: inputValue };
|
||||
const contactRes = await Parse.Cloud.run("getsigners", params);
|
||||
const contactRes = await findContact(inputValue);
|
||||
if (contactRes) {
|
||||
const res = JSON.parse(JSON.stringify(contactRes));
|
||||
//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.required && <span className="text-red-500 text-[13px]">*</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
|
||||
id={`${props.label ? props.label : "signers"}-tooltip`}
|
||||
@@ -209,9 +215,8 @@ const SignersInput = (props) => {
|
||||
✕
|
||||
</button>
|
||||
{isModal && (
|
||||
<AddSigner
|
||||
valueKey={"objectId"}
|
||||
displayKey={"Name"}
|
||||
<AddContact
|
||||
isDisableTitle
|
||||
details={handleNewDetails}
|
||||
closePopup={handleModalCloseClick}
|
||||
/>
|
||||
|
||||
@@ -7,27 +7,10 @@ const TimezoneSelector = (props) => {
|
||||
// Intl.DateTimeFormat().resolvedOptions().timeZone // Default to the user's local timezone
|
||||
|
||||
const onChangeTimezone = (timezone) => {
|
||||
setSelectedTimezone(timezone);
|
||||
setSelectedTimezone(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 (
|
||||
<>
|
||||
<div className="max-w-[400px] pr-[20px]">
|
||||
@@ -54,11 +37,6 @@ const TimezoneSelector = (props) => {
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-[12px] ml-[10px] text-[13px]">
|
||||
<strong>
|
||||
{formatDate(new Date(), selectedTimezone?.value || selectedTimezone)}
|
||||
</strong>{" "}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,8 +3,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { NavLink } from "react-router";
|
||||
|
||||
const Menu = ({ item, isOpen, closeSidebar }) => {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
@@ -18,13 +17,15 @@ const Menu = ({ item, isOpen, closeSidebar }) => {
|
||||
className={({ isActive }) =>
|
||||
`${
|
||||
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}
|
||||
tabIndex={isOpen ? 0 : -1}
|
||||
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">
|
||||
{t(`sidebar.${item.title}`, { appName: drivename })}
|
||||
</span>
|
||||
|
||||
@@ -3,8 +3,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { NavLink } from "react-router";
|
||||
|
||||
const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||
const { t } = useTranslation();
|
||||
const { title, icon, children } = item;
|
||||
@@ -12,14 +11,16 @@ const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
|
||||
<li role="none" className="my-0.5">
|
||||
<button
|
||||
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-haspopup="true"
|
||||
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">
|
||||
<span className="ml-3 lg:ml-4">
|
||||
<span className="ml-3 lg:ml-4 text-start">
|
||||
{t(`sidebar.${item.title}`, { appName })}
|
||||
</span>
|
||||
<i
|
||||
@@ -45,16 +46,18 @@ const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
|
||||
className={({ isActive }) =>
|
||||
`${
|
||||
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}
|
||||
role="menuitem"
|
||||
tabIndex={submenuOpen ? 0 : -1}
|
||||
>
|
||||
<i
|
||||
className={`${childItem.icon} text-[18px]`}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span className="w-[15px] h-[15px] flex justify-center">
|
||||
<i
|
||||
className={`${childItem.icon} text-[18px]`}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</span>
|
||||
<span className="ml-3 lg:ml-4">
|
||||
{t(`sidebar.${item.title}-Children.${childItem.title}`, {
|
||||
appName: drivename
|
||||
|
||||
@@ -8,6 +8,7 @@ import { saveAs } from "file-saver";
|
||||
import printModule from "print-js";
|
||||
import fontkit from "@pdf-lib/fontkit";
|
||||
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 fontColorArr = ["red", "black", "blue", "yellow"];
|
||||
@@ -232,17 +233,47 @@ export const widgets = [
|
||||
{ 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 milliseconds = date.getTime();
|
||||
const newDate = moment(milliseconds).format("MM/DD/YYYY");
|
||||
const newDate = moment(milliseconds).format(format);
|
||||
return newDate;
|
||||
};
|
||||
export const addWidgetOptions = (type) => {
|
||||
const defaultOpt = {
|
||||
name: type,
|
||||
status: "required"
|
||||
};
|
||||
|
||||
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 const addWidgetOptions = (type, signer) => {
|
||||
const defaultOpt = { name: type, status: "required" };
|
||||
switch (type) {
|
||||
case "signature":
|
||||
return defaultOpt;
|
||||
@@ -263,12 +294,16 @@ export const addWidgetOptions = (type) => {
|
||||
return { ...defaultOpt };
|
||||
case "job title":
|
||||
return { ...defaultOpt };
|
||||
case "date":
|
||||
case "date": {
|
||||
const dateFormat = signer?.DateFormat
|
||||
? selectFormat(signer?.DateFormat)
|
||||
: "MM/dd/yyyy";
|
||||
return {
|
||||
...defaultOpt,
|
||||
response: getDate(),
|
||||
validation: { format: "MM/dd/yyyy", type: "date-format" }
|
||||
response: getDate(signer?.DateFormat),
|
||||
validation: { format: dateFormat, type: "date-format" }
|
||||
};
|
||||
}
|
||||
case "image":
|
||||
return defaultOpt;
|
||||
case "email":
|
||||
@@ -289,7 +324,7 @@ export const addWidgetOptions = (type) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const addWidgetSelfsignOptions = (type, getWidgetValue) => {
|
||||
export const addWidgetSelfsignOptions = (type, getWidgetValue, owner) => {
|
||||
switch (type) {
|
||||
case "signature":
|
||||
return { name: "signature" };
|
||||
@@ -319,12 +354,16 @@ export const addWidgetSelfsignOptions = (type, getWidgetValue) => {
|
||||
defaultValue: getWidgetValue(type),
|
||||
validation: { type: "text", pattern: "" }
|
||||
};
|
||||
case "date":
|
||||
case "date": {
|
||||
const dateFormat = owner?.DateFormat
|
||||
? selectFormat(owner?.DateFormat)
|
||||
: "MM/dd/yyyy";
|
||||
return {
|
||||
name: "date",
|
||||
response: getDate(),
|
||||
validation: { format: "MM/dd/yyyy", type: "date-format" }
|
||||
response: getDate(owner?.DateFormat),
|
||||
validation: { format: dateFormat, type: "date-format" }
|
||||
};
|
||||
}
|
||||
case "image":
|
||||
return { name: "image" };
|
||||
case "email":
|
||||
@@ -932,10 +971,7 @@ export const calculateInitialWidthHeight = (widgetData) => {
|
||||
const height = span.offsetHeight;
|
||||
|
||||
document.body.removeChild(span);
|
||||
return {
|
||||
getWidth: width,
|
||||
getHeight: height
|
||||
};
|
||||
return { getWidth: width, getHeight: height };
|
||||
};
|
||||
export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
||||
function widgetDataValue(type) {
|
||||
@@ -966,9 +1002,7 @@ export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
||||
)
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
...item
|
||||
};
|
||||
return item;
|
||||
}
|
||||
} else if (item.pos && item.pos.length > 0) {
|
||||
// If there is no nested array, add the new field
|
||||
@@ -986,17 +1020,9 @@ export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
||||
...item.options,
|
||||
defaultValue: item?.options?.defaultValue || widgetData
|
||||
}
|
||||
// Width:
|
||||
// calculateInitialWidthHeight(item.type, widgetData).getWidth ||
|
||||
// item?.Width,
|
||||
// Height:
|
||||
// calculateInitialWidthHeight(item.type, widgetData).getHeight ||
|
||||
// item?.Height
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
...item
|
||||
};
|
||||
return item;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -2156,7 +2182,9 @@ export const handleSendOTP = async (email) => {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
|
||||
};
|
||||
const body = { email: email };
|
||||
const body = {
|
||||
email: email
|
||||
};
|
||||
await axios.post(url, body, { headers: headers });
|
||||
} catch (error) {
|
||||
alert(error.message);
|
||||
@@ -2167,13 +2195,13 @@ export const fetchUrl = async (url, pdfName) => {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
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");
|
||||
}
|
||||
const blob = await response.blob();
|
||||
saveAs(blob, `${sanitizeFileName(pdfName)}_signed_by_${appName}.pdf`);
|
||||
} 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);
|
||||
}
|
||||
};
|
||||
@@ -2244,7 +2272,7 @@ export const handleDownloadPdf = async (
|
||||
} catch (err) {
|
||||
console.log("err in getsignedurl", err);
|
||||
setIsDownloading("");
|
||||
alert("something went wrong, please try again later.");
|
||||
alert("something went wrong, refreshing this page may solve this issue.");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2302,7 +2330,7 @@ export const handleToPrint = async (event, setIsDownloading, pdfDetails) => {
|
||||
} catch (err) {
|
||||
setIsDownloading("");
|
||||
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 +2416,7 @@ export const handleDownloadCertificate = async (
|
||||
} catch (err) {
|
||||
setIsDownloading("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 +2873,11 @@ export function generatePdfName(length) {
|
||||
|
||||
// Format date and time for the selected timezone
|
||||
export const formatTimeInTimezone = (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,
|
||||
timeZoneName: "short",
|
||||
hour12: false
|
||||
}).format(date)
|
||||
const nyDate = timezone && toZonedTime(date, timezone);
|
||||
const generatedDate = timezone
|
||||
? format(nyDate, "EEE, dd MMM yyyy HH:mm:ss zzz", { timeZone: timezone })
|
||||
: new Date(date).toUTCString();
|
||||
return generatedDate;
|
||||
};
|
||||
|
||||
// `usertimezone` is used to get timezone of current user
|
||||
@@ -2943,8 +2962,10 @@ export const mailTemplate = (param) => {
|
||||
param.senderMail +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td><td></td><td style='color:#626363;font-weight:bold'> " +
|
||||
param.organization +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expire on</td><td></td><td style='color:#626363;font-weight:bold'>" +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td></td><td style='color:#626363;font-weight:bold'>" +
|
||||
param.localExpireDate +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Note</td><td></td><td style='color:#626363;font-weight:bold'>" +
|
||||
param.note +
|
||||
"</td></tr><tr><td></td><td></td></tr></table></div> <div style='margin-left:70px'><a target=_blank href=" +
|
||||
param.sigingUrl +
|
||||
"><button style='padding:12px;background-color:#d46b0f;color:white;border:0px;font-weight:bold;margin-top:30px'>Sign here</button></a></div><div style='display:flex;justify-content:center;margin-top:10px'></div></div></div><div><p> This is an automated email from " +
|
||||
@@ -2957,3 +2978,15 @@ export const mailTemplate = (param) => {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import logo from "../assets/images/logo.png";
|
||||
|
||||
export function serverUrl_fn() {
|
||||
let baseUrl;
|
||||
baseUrl = process.env.REACT_APP_SERVERURL
|
||||
? process.env.REACT_APP_SERVERURL
|
||||
: window.location.origin + "/app";
|
||||
|
||||
let baseUrl = process.env.REACT_APP_SERVERURL
|
||||
? process.env.REACT_APP_SERVERURL
|
||||
: window.location.origin + "/api/app";
|
||||
return baseUrl;
|
||||
}
|
||||
export const appInfo = {
|
||||
|
||||
@@ -4,3 +4,4 @@ export const documentCls = "contracts_Document";
|
||||
export const themeColor = "#47a3ad";
|
||||
export const iconColor = "#686968";
|
||||
export const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
export const maxFileSize = 10; // 10MB
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
Preview
|
||||
} from "react-dnd-multi-backend";
|
||||
import DragElement from "./components/pdf/DragElement";
|
||||
import TagManager from "react-gtm-module";
|
||||
import Parse from "parse";
|
||||
import "./polyfills";
|
||||
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"));
|
||||
root.render(
|
||||
<CookiesProvider defaultSetOptions={{ path: "/" }}>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
export default function reportJson(id) {
|
||||
// console.log("json ", json);
|
||||
const head = ["Title", "Note", "Folder", "File", "Owner", "Signers"];
|
||||
@@ -29,6 +28,25 @@ export default function reportJson(id) {
|
||||
btnIcon: "fa-light fa-trash",
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
},
|
||||
{
|
||||
btnId: "22534",
|
||||
hoverLabel: "option",
|
||||
btnColor: "",
|
||||
restrictBtn: true,
|
||||
textColor: "black",
|
||||
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
|
||||
action: "option",
|
||||
subaction: [
|
||||
{
|
||||
btnId: "1630",
|
||||
btnLabel: "Save as template",
|
||||
hoverLabel: "Save as template",
|
||||
btnIcon: "fa-light fa-envelope",
|
||||
redirectUrl: "",
|
||||
action: "saveastemplate"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
helpMsg:
|
||||
@@ -107,6 +125,14 @@ export default function reportJson(id) {
|
||||
redirectUrl: "",
|
||||
action: "revoke"
|
||||
},
|
||||
{
|
||||
btnId: "0630",
|
||||
btnLabel: "Save as template",
|
||||
hoverLabel: "Save as template",
|
||||
btnIcon: "fa-light fa-envelope",
|
||||
redirectUrl: "",
|
||||
action: "saveastemplate"
|
||||
},
|
||||
{
|
||||
btnId: "1488",
|
||||
btnLabel: "Delete",
|
||||
@@ -143,6 +169,25 @@ export default function reportJson(id) {
|
||||
restrictBtn: true,
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
},
|
||||
{
|
||||
btnId: "33534",
|
||||
hoverLabel: "option",
|
||||
btnColor: "",
|
||||
restrictBtn: true,
|
||||
textColor: "black",
|
||||
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
|
||||
action: "option",
|
||||
subaction: [
|
||||
{
|
||||
btnId: "0930",
|
||||
btnLabel: "Save as template",
|
||||
hoverLabel: "Save as template",
|
||||
btnIcon: "fa-light fa-envelope",
|
||||
redirectUrl: "",
|
||||
action: "saveastemplate"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
helpMsg:
|
||||
@@ -169,6 +214,25 @@ export default function reportJson(id) {
|
||||
btnIcon: "fa-light fa-trash",
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
},
|
||||
{
|
||||
btnId: "44534",
|
||||
hoverLabel: "option",
|
||||
btnColor: "",
|
||||
restrictBtn: true,
|
||||
textColor: "black",
|
||||
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
|
||||
action: "option",
|
||||
subaction: [
|
||||
{
|
||||
btnId: "0940",
|
||||
btnLabel: "Save as template",
|
||||
hoverLabel: "Save as template",
|
||||
btnIcon: "fa-light fa-envelope",
|
||||
redirectUrl: "",
|
||||
action: "saveastemplate"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
helpMsg:
|
||||
@@ -212,6 +276,14 @@ export default function reportJson(id) {
|
||||
btnIcon: "fa-light fa-hourglass-end",
|
||||
redirectUrl: "",
|
||||
action: "extendexpiry"
|
||||
},
|
||||
{
|
||||
btnId: "5530",
|
||||
btnLabel: "Save as template",
|
||||
hoverLabel: "Save as template",
|
||||
btnIcon: "fa-light fa-envelope",
|
||||
redirectUrl: "",
|
||||
action: "saveastemplate"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -273,6 +345,14 @@ export default function reportJson(id) {
|
||||
redirectUrl: "",
|
||||
action: "revoke"
|
||||
},
|
||||
{
|
||||
btnId: "7730",
|
||||
btnLabel: "Save as template",
|
||||
hoverLabel: "Save as template",
|
||||
btnIcon: "fa-light fa-envelope",
|
||||
redirectUrl: "",
|
||||
action: "saveastemplate"
|
||||
},
|
||||
{
|
||||
btnId: "2000",
|
||||
btnLabel: "Delete",
|
||||
@@ -323,6 +403,25 @@ export default function reportJson(id) {
|
||||
btnIcon: "fa-light fa-trash",
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
},
|
||||
{
|
||||
btnId: "55534",
|
||||
hoverLabel: "option",
|
||||
btnColor: "",
|
||||
restrictBtn: true,
|
||||
textColor: "black",
|
||||
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
|
||||
action: "option",
|
||||
subaction: [
|
||||
{
|
||||
btnId: "6630",
|
||||
btnLabel: "Save as template",
|
||||
hoverLabel: "Save as template",
|
||||
btnIcon: "fa-light fa-envelope",
|
||||
redirectUrl: "",
|
||||
action: "saveastemplate"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -15,8 +15,7 @@ import { showHeader } from "../redux/reducers/showHeader";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const HomeLayout = () => {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const { t, i18n } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
@@ -54,8 +53,8 @@ const HomeLayout = () => {
|
||||
});
|
||||
if (user) {
|
||||
localStorage.setItem("profileImg", user.get("ProfilePic") || "");
|
||||
setIsUserValid(true);
|
||||
setIsLoader(false);
|
||||
setIsUserValid(true);
|
||||
setIsLoader(false);
|
||||
} else {
|
||||
setIsUserValid(false);
|
||||
}
|
||||
@@ -72,7 +71,7 @@ const HomeLayout = () => {
|
||||
//function to use save data in cookies storage
|
||||
const saveCookies = () => {
|
||||
const main_Domain = window.location.origin;
|
||||
const domainName = window.location.hostname; //app.opensignlabs.com
|
||||
const domainName = window.location.hostname;
|
||||
// Find the index of the first dot in the string
|
||||
const indexOfFirstDot = domainName.indexOf(".");
|
||||
// Remove the first dot and get the substring starting from the next character
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Confetti from "react-confetti"; // Import the confetti library
|
||||
import {
|
||||
getBase64FromUrl,
|
||||
handleDownloadCertificate,
|
||||
@@ -10,19 +11,25 @@ import ModalUi from "../primitives/ModalUi";
|
||||
import Loader from "../primitives/Loader";
|
||||
import DownloadPdfZip from "../primitives/DownloadPdfZip";
|
||||
import Title from "../components/Title";
|
||||
import CheckCircle from "../primitives/CheckCircle";
|
||||
|
||||
const DocSuccessPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const signed = window.location?.search?.includes("docid");
|
||||
const sent = window.location?.search?.includes("message");
|
||||
const [isDownloading, setIsDownloading] = useState(false);
|
||||
const [isDownloadModal, setIsDownloadModal] = useState(false);
|
||||
const [pdfDetails, setPdfDetails] = useState([]);
|
||||
const [pdfBase64Url, setPdfBase64Url] = useState("");
|
||||
const { t } = useTranslation();
|
||||
const [showConfetti, setShowConfetti] = useState(true); // State to control confetti
|
||||
|
||||
useEffect(() => {
|
||||
initialsetup();
|
||||
// Stop confetti after 5 seconds
|
||||
const timer = setTimeout(() => setShowConfetti(false), 5000);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
const initialsetup = async () => {
|
||||
const search = window.location.search.split("?")[1];
|
||||
if (search) {
|
||||
@@ -44,6 +51,7 @@ const DocSuccessPage = () => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleDownload = () => {
|
||||
if (pdfDetails?.[0]?.IsCompleted) {
|
||||
setIsDownloadModal(true);
|
||||
@@ -51,50 +59,79 @@ const DocSuccessPage = () => {
|
||||
handleDownloadPdf(pdfDetails, setIsDownloading, pdfBase64Url);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-screen justify-center items-center text-sm md:text-base">
|
||||
<>
|
||||
<Title title="Success" />
|
||||
{/* Confetti Effect */}
|
||||
{showConfetti && (
|
||||
<Confetti width={window.innerWidth} height={window.innerHeight} />
|
||||
)}
|
||||
{sent ? (
|
||||
<div>{t("doc-sent")}</div>
|
||||
<div className="min-h-screen flex flex-col items-center justify-center p-3 md:p-8 text-center">
|
||||
<div className="max-w-lg md:max-w-2xl bg-white rounded-lg shadow-lg p-3 md:p-10">
|
||||
{t("doc-sent")}
|
||||
</div>
|
||||
</div>
|
||||
) : signed ? (
|
||||
<div className="text-center">
|
||||
<p>
|
||||
{pdfDetails?.[0]?.IsCompleted
|
||||
? t("document-signed-alert-4")
|
||||
: t("document-signed-alert")}
|
||||
</p>
|
||||
<div className="m-2">
|
||||
<button
|
||||
onClick={(e) => handleToPrint(e, setIsDownloading, pdfDetails)}
|
||||
type="button"
|
||||
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-neutral"
|
||||
>
|
||||
<i className="fa-light fa-print" aria-hidden="true"></i>
|
||||
<span className="hidden lg:block">{t("print")}</span>
|
||||
</button>
|
||||
{pdfDetails?.[0]?.IsCompleted && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
handleDownloadCertificate(pdfDetails, setIsDownloading)
|
||||
}
|
||||
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-secondary"
|
||||
>
|
||||
<i
|
||||
className="fa-light fa-award mx-[3px] lg:mx-0"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span className="hidden lg:block">{t("certificate")}</span>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-primary"
|
||||
onClick={() => handleDownload()}
|
||||
>
|
||||
<i className="fa-light fa-download" aria-hidden="true"></i>
|
||||
<span className="hidden lg:block">{t("download")}</span>
|
||||
</button>
|
||||
<>
|
||||
<div className="min-h-screen flex flex-col items-center justify-center p-3 md:p-8 text-center">
|
||||
<div className="max-w-lg md:max-w-2xl bg-white rounded-lg shadow-lg p-3 md:p-10">
|
||||
<div className="flex flex-col items-center space-y-4 ">
|
||||
<CheckCircle className="text-green-500 w-12 h-12 md:w-14 md:h-14" />
|
||||
<h1 className="text-xl md:text-2xl font-semibold text-gray-800">
|
||||
{pdfDetails?.[0]?.IsCompleted
|
||||
? t("document-has-been-signed")
|
||||
: t("document-has-been-signed-by-you")}
|
||||
</h1>
|
||||
{pdfDetails?.[0]?.IsCompleted && (
|
||||
<p className="text-sm md:text-base text-gray-600">
|
||||
{t("participant-completed-signing")}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{/* Action Buttons */}
|
||||
<div className="mt-6 flex flex-wrap justify-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
className="font-medium text-sm md:text-[13px] md:px-4 py-2 op-btn op-btn-primary"
|
||||
onClick={() => handleDownload()}
|
||||
>
|
||||
<i className="fa-light fa-download" aria-hidden="true"></i>
|
||||
<span>{t("download")}</span>
|
||||
</button>
|
||||
|
||||
{pdfDetails?.[0]?.IsCompleted && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
handleDownloadCertificate(pdfDetails, setIsDownloading)
|
||||
}
|
||||
className="font-medium text-sm md:text-[13px] md:px-4 py-2 op-btn op-btn-secondary"
|
||||
>
|
||||
<i
|
||||
className="fa-light fa-award mx-[3px] md:mx-0"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span>{t("certificate")}</span>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={(e) =>
|
||||
handleToPrint(e, setIsDownloading, pdfDetails)
|
||||
}
|
||||
type="button"
|
||||
className="font-medium text-sm md:text-[13px] px-4 py-2 op-btn op-btn-neutral"
|
||||
>
|
||||
<i className="fa-light fa-print" aria-hidden="true"></i>
|
||||
<span>{t("print")}</span>
|
||||
</button>
|
||||
</div>
|
||||
{/* Footer Message */}
|
||||
<p className="mt-4 md:mt-6 text-xs md:text-sm text-gray-500">
|
||||
{t("you-will-receive-email-shortly")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{isDownloading === "pdf" && (
|
||||
<div className="fixed z-[1000] inset-0 flex justify-center items-center bg-black bg-opacity-30">
|
||||
@@ -114,7 +151,7 @@ const DocSuccessPage = () => {
|
||||
}
|
||||
handleClose={() => setIsDownloading("")}
|
||||
>
|
||||
<div className="p-3 md:p-5 text-[13px] md:text-base text-center text-base-content">
|
||||
<div className="p-3 md:p-5 text-sm md:text-base text-center text-base-content">
|
||||
{isDownloading === "certificate" ? (
|
||||
<p>{t("generate-certificate-alert")}</p>
|
||||
) : (
|
||||
@@ -129,11 +166,11 @@ const DocSuccessPage = () => {
|
||||
isDocId={true}
|
||||
pdfBase64={pdfBase64Url}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
} from "../constant/Utils";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
import axios from "axios";
|
||||
import { maxFileSize } from "../constant/const";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
import Loader from "../primitives/Loader";
|
||||
@@ -38,7 +39,6 @@ function Form() {
|
||||
const Forms = (props) => {
|
||||
const appName = "OpenSign™";
|
||||
const { t } = useTranslation();
|
||||
const maxFileSize = 20;
|
||||
const abortController = new AbortController();
|
||||
const inputFileRef = useRef(null);
|
||||
const navigate = useNavigate();
|
||||
@@ -187,13 +187,6 @@ const Forms = (props) => {
|
||||
}
|
||||
} catch (err) {
|
||||
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 {
|
||||
setIsDecrypting(true);
|
||||
const size = files?.[0].size;
|
||||
@@ -859,7 +852,7 @@ const Forms = (props) => {
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">{t("send-in-order")}</p>
|
||||
<p>{t("send-in-order-help.p1")}</p>
|
||||
<p className="p-[5px]">
|
||||
<div className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
@@ -874,7 +867,7 @@ const Forms = (props) => {
|
||||
<span>{t("send-in-order-help.p3")}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
<p>{t("send-in-order-help.p4")}</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
@@ -956,7 +949,7 @@ const Forms = (props) => {
|
||||
{t("send-in-order")}
|
||||
</p>
|
||||
<p>{t("send-in-order-help.p1")}</p>
|
||||
<p className="p-[5px]">
|
||||
<div className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
@@ -975,7 +968,7 @@ const Forms = (props) => {
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
<p>{t("send-in-order-help.p4")}</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
@@ -1093,7 +1086,7 @@ const Forms = (props) => {
|
||||
<Tooltip id="istourenabled-tooltip" className="z-[999]">
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">{t("enable-tour")}</p>
|
||||
<p className="p-[5px]">
|
||||
<div className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
@@ -1106,7 +1099,7 @@ const Forms = (props) => {
|
||||
<span>{t("istourenabled-help.p2")}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
{t("istourenabled-help.p3", { appName: appName })}
|
||||
</p>
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useNavigate, useParams } from "react-router";
|
||||
import axios from "axios";
|
||||
import {
|
||||
emailRegex,
|
||||
} from "../constant/const";
|
||||
import {
|
||||
contractUsers,
|
||||
saveLanguageInLocal
|
||||
} from "../constant/Utils";
|
||||
import { emailRegex } from "../constant/const";
|
||||
import { contractUsers, saveLanguageInLocal } from "../constant/Utils";
|
||||
import logo from "../assets/images/logo.png";
|
||||
import { appInfo } from "../constant/appinfo";
|
||||
import Parse from "parse";
|
||||
@@ -63,13 +58,10 @@ function GuestLogin() {
|
||||
|
||||
//function generate serverUrl and parseAppId from url and save it in local storage
|
||||
const handleServerUrl = async () => {
|
||||
setAppLogo(logo);
|
||||
setAppLogo(logo);
|
||||
|
||||
localStorage.clear(); // Clears everything
|
||||
localStorage.setItem(
|
||||
"appname",
|
||||
"OpenSign™"
|
||||
);
|
||||
localStorage.setItem("appname", "OpenSign™");
|
||||
//save isGuestSigner true in local to handle login flow header in mobile view
|
||||
localStorage.setItem("isGuestSigner", true);
|
||||
saveLanguageInLocal(i18n);
|
||||
@@ -113,7 +105,10 @@ function GuestLogin() {
|
||||
setLoading(true);
|
||||
setEmail(email);
|
||||
try {
|
||||
const params = { email: email.toString(), docId: documentId };
|
||||
const params = {
|
||||
email: email.toString(),
|
||||
docId: documentId
|
||||
};
|
||||
const Otp = await Parse.Cloud.run("SendOTPMailV1", params);
|
||||
if (Otp) {
|
||||
setLoading(false);
|
||||
@@ -216,7 +211,14 @@ function GuestLogin() {
|
||||
}
|
||||
};
|
||||
const handleInputChange = (e) => {
|
||||
setContact((prev) => ({ ...prev, [e.target.name]: e.target.value }));
|
||||
if (e.target.name === "email") {
|
||||
setContact((prev) => ({
|
||||
...prev,
|
||||
[e.target.name]: e.target.value?.toLowerCase()?.replace(/\s/g, "")
|
||||
}));
|
||||
} else {
|
||||
setContact((prev) => ({ ...prev, [e.target.name]: e.target.value }));
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -7,9 +7,7 @@ import { NavLink, useNavigate, useLocation } from "react-router";
|
||||
import login_img from "../assets/images/login_img.svg";
|
||||
import { useWindowSize } from "../hook/useWindowSize";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import {
|
||||
emailRegex,
|
||||
} from "../constant/const";
|
||||
import { emailRegex } from "../constant/const";
|
||||
import Alert from "../primitives/Alert";
|
||||
import { appInfo } from "../constant/appinfo";
|
||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||
@@ -24,8 +22,7 @@ import { useTranslation } from "react-i18next";
|
||||
import SelectLanguage from "../components/pdf/SelectLanguage";
|
||||
|
||||
function Login() {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const { t, i18n } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
@@ -43,7 +40,7 @@ function Login() {
|
||||
baseUrl: localStorage.getItem("baseUrl"),
|
||||
parseAppId: localStorage.getItem("parseAppId"),
|
||||
loading: false,
|
||||
thirdpartyLoader: false,
|
||||
thirdpartyLoader: false
|
||||
});
|
||||
const [userDetails, setUserDetails] = useState({
|
||||
Company: "",
|
||||
@@ -57,13 +54,15 @@ function Login() {
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
const showToast = (type, msg) => {
|
||||
setState({ ...state, loading: false, alertType: type, alertMsg: msg });
|
||||
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
|
||||
};
|
||||
const checkUserExt = async () => {
|
||||
const app = await getAppLogo();
|
||||
if (app?.error === "invalid_json") {
|
||||
setErrMsg(t("server-down", { appName: appName }));
|
||||
} else if (
|
||||
app?.user === "not_exist"
|
||||
) {
|
||||
} else if (app?.user === "not_exist") {
|
||||
navigate("/addadmin");
|
||||
}
|
||||
if (app?.logo) {
|
||||
@@ -153,68 +152,33 @@ function Login() {
|
||||
localStorage.setItem("PageLanding", menu.pageId);
|
||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||
localStorage.setItem("pageType", menu.pageType);
|
||||
setState({ ...state, loading: false });
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
setState({ ...state, loading: false });
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
setState({ ...state, loading: false });
|
||||
setIsModal(true);
|
||||
}
|
||||
} else {
|
||||
setState({
|
||||
...state,
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg:
|
||||
"You don't have access, please contact the admin."
|
||||
});
|
||||
showToast("danger", t("do-not-access-contact-admin"));
|
||||
logOutUser();
|
||||
}
|
||||
} else {
|
||||
setState({ ...state, loading: false });
|
||||
setState({
|
||||
...state,
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: "User not found."
|
||||
});
|
||||
logOutUser();
|
||||
showToast("danger", t("user-not-found"));
|
||||
logOutUser();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
setState({
|
||||
...state,
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: `Something went wrong.`
|
||||
});
|
||||
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
|
||||
showToast("danger", t("something-went-wrong-mssg"));
|
||||
console.error("Error while fetching Follow", error);
|
||||
});
|
||||
} catch (error) {
|
||||
setState({
|
||||
...state,
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: `${error.message}`
|
||||
});
|
||||
console.log(error);
|
||||
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
|
||||
showToast("danger", `${error.message}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
setState({
|
||||
...state,
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: "Invalid username/password or region"
|
||||
});
|
||||
console.error("Error while logging in user", error);
|
||||
} finally {
|
||||
setTimeout(
|
||||
() => setState((prev) => ({ ...prev, alertMsg: "" })),
|
||||
2000
|
||||
);
|
||||
showToast("danger", "Invalid username/password or region");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -282,55 +246,31 @@ function Login() {
|
||||
localStorage.setItem("PageLanding", menu.pageId);
|
||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||
localStorage.setItem("pageType", menu.pageType);
|
||||
navigate(redirectUrl);
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
setState({
|
||||
...state,
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: "Role not found."
|
||||
});
|
||||
showToast("danger", t("role-not-found"));
|
||||
logOutUser();
|
||||
}
|
||||
} else {
|
||||
setState({
|
||||
...state,
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: "You don't have access, please contact the admin."
|
||||
});
|
||||
showToast("danger", t("do-not-access-contact-admin"));
|
||||
logOutUser();
|
||||
}
|
||||
} else {
|
||||
setState({
|
||||
...state,
|
||||
alertType: "danger",
|
||||
alertMsg: "User not found."
|
||||
});
|
||||
showToast("danger", t("user-not-found"));
|
||||
logOutUser();
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("err in fetching extUser", err);
|
||||
setState({
|
||||
...state,
|
||||
alertType: "danger",
|
||||
alertMsg: `${err.message}`
|
||||
});
|
||||
showToast("danger", `${err.message}`);
|
||||
const payload = { sessionToken: sessionToken };
|
||||
handleSubmitbtn(payload);
|
||||
});
|
||||
} catch (error) {
|
||||
setState({
|
||||
...state,
|
||||
alertType: "danger",
|
||||
alertMsg: `${error.message}`
|
||||
});
|
||||
showToast("danger", `${error.message}`);
|
||||
console.log(error);
|
||||
} finally {
|
||||
setThirdpartyLoader(false);
|
||||
setState({ ...state, loading: false });
|
||||
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -380,40 +320,24 @@ function Login() {
|
||||
localStorage.setItem("PageLanding", menu.pageId);
|
||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||
localStorage.setItem("pageType", menu.pageType);
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
setState({ ...state, loading: false });
|
||||
logOutUser();
|
||||
}
|
||||
} else {
|
||||
setState({
|
||||
...state,
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: "You don't have access, please contact the admin."
|
||||
});
|
||||
showToast("danger", t("do-not-access-contact-admin"));
|
||||
logOutUser();
|
||||
}
|
||||
} else {
|
||||
setState({
|
||||
...state,
|
||||
alertType: "danger",
|
||||
alertMsg: "User not found."
|
||||
});
|
||||
showToast("danger", t("user-not-found"));
|
||||
logOutUser();
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
setState({
|
||||
...state,
|
||||
alertType: "danger",
|
||||
alertMsg: "Something went wrong, please try again later."
|
||||
});
|
||||
showToast("danger", t("something-went-wrong-mssg"));
|
||||
console.log("err", error);
|
||||
} finally {
|
||||
setState({ ...state, loading: false });
|
||||
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -425,8 +349,6 @@ function Login() {
|
||||
e.preventDefault();
|
||||
if (userDetails.Destination && userDetails.Company) {
|
||||
setThirdpartyLoader(true);
|
||||
// console.log("handelSubmit", userDetails);
|
||||
// const payload = await Parse.User.logIn(state.email, state.password);
|
||||
const payload = { sessionToken: localStorage.getItem("accesstoken") };
|
||||
const userInformation = JSON.parse(
|
||||
localStorage.getItem("UserInformation")
|
||||
@@ -466,13 +388,7 @@ function Login() {
|
||||
alert(t("server-error"));
|
||||
}
|
||||
} else {
|
||||
setState({
|
||||
...state,
|
||||
loading: false,
|
||||
alertType: "warning",
|
||||
alertMsg: "Please fill required details."
|
||||
});
|
||||
setTimeout(() => setState((prev) => ({ ...prev, alertMsg: "" })), 2000);
|
||||
showToast("warning", t("fill-required-details!"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -501,7 +417,6 @@ function Login() {
|
||||
localStorage.setItem("parseAppId", appid);
|
||||
};
|
||||
|
||||
|
||||
return errMsg ? (
|
||||
<div className="h-screen flex justify-center text-center items-center p-4 text-gray-500 text-base">
|
||||
{errMsg}
|
||||
@@ -522,7 +437,7 @@ function Login() {
|
||||
<div
|
||||
aria-labelledby="loginHeading"
|
||||
role="region"
|
||||
className="pb-1 md:pb-4 pt-10 md:px-10 lg:px-16"
|
||||
className="pb-1 md:pb-4 pt-10 md:px-10 lg:px-16 h-screen"
|
||||
>
|
||||
<div className="md:p-4 lg:p-10 p-4 bg-base-100 text-base-content op-card">
|
||||
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
||||
@@ -561,39 +476,35 @@ function Login() {
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
/>
|
||||
<hr className="my-1 border-none" />
|
||||
<label className="block text-xs" htmlFor="password">
|
||||
{t("password")}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
id="password"
|
||||
type={
|
||||
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"
|
||||
value={state.password}
|
||||
autoComplete="current-password"
|
||||
onChange={handleChange}
|
||||
onInvalid={(e) =>
|
||||
e.target.setCustomValidity(
|
||||
t("input-required")
|
||||
)
|
||||
}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
required
|
||||
/>
|
||||
<span
|
||||
className="absolute cursor-pointer top-[50%] right-[10px] -translate-y-[50%] text-base-content"
|
||||
onClick={togglePasswordVisibility}
|
||||
>
|
||||
{state.passwordVisible ? (
|
||||
<i className="fa-light fa-eye-slash text-xs pb-1" /> // Close eye icon
|
||||
) : (
|
||||
<i className="fa-light fa-eye text-xs pb-1 " /> // Open eye icon
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<label className="block text-xs" htmlFor="password">
|
||||
{t("password")}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
id="password"
|
||||
type={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"
|
||||
value={state.password}
|
||||
autoComplete="current-password"
|
||||
onChange={handleChange}
|
||||
onInvalid={(e) =>
|
||||
e.target.setCustomValidity(t("input-required"))
|
||||
}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
required
|
||||
/>
|
||||
<span
|
||||
className="absolute cursor-pointer top-[50%] right-[10px] -translate-y-[50%] text-base-content"
|
||||
onClick={togglePasswordVisibility}
|
||||
>
|
||||
{state.passwordVisible ? (
|
||||
<i className="fa-light fa-eye-slash text-xs pb-1" /> // Close eye icon
|
||||
) : (
|
||||
<i className="fa-light fa-eye text-xs pb-1 " /> // Open eye icon
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="relative mt-1">
|
||||
<NavLink
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import "../styles/opensigndrive.css";
|
||||
import {
|
||||
iconColor,
|
||||
} from "../constant/const";
|
||||
import {
|
||||
getDrive
|
||||
} from "../constant/Utils";
|
||||
import { iconColor } from "../constant/const";
|
||||
import { getDrive } from "../constant/Utils";
|
||||
import { useNavigate } from "react-router";
|
||||
import Title from "../components/Title";
|
||||
import Parse from "parse";
|
||||
@@ -29,8 +25,7 @@ const AppLoader = () => {
|
||||
);
|
||||
};
|
||||
function Opensigndrive() {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
@@ -130,7 +125,7 @@ function Opensigndrive() {
|
||||
}
|
||||
];
|
||||
const getDetails = async () => {
|
||||
getPdfDocumentList();
|
||||
getPdfDocumentList();
|
||||
};
|
||||
//function for get all pdf document list
|
||||
const getPdfDocumentList = async (disbaleLoading) => {
|
||||
@@ -144,7 +139,7 @@ function Opensigndrive() {
|
||||
try {
|
||||
const driveDetails = await getDrive(docId, skip, limit);
|
||||
if (driveDetails && driveDetails === "Error: Something went wrong!") {
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
} else if (driveDetails && driveDetails.length > 0) {
|
||||
const addMoreTour = [
|
||||
{
|
||||
@@ -635,7 +630,9 @@ function Opensigndrive() {
|
||||
<div className="flex flex-row items-center">
|
||||
<div
|
||||
id="folder-menu"
|
||||
className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} hidden md:block`}
|
||||
className={`${
|
||||
isOptions ? "dropdown show dropDownStyle" : "dropdown"
|
||||
} hidden md:block`}
|
||||
onClick={() => setIsOptions(!isOptions)}
|
||||
>
|
||||
<div className="sort" data-tut="reactourSecond">
|
||||
@@ -773,7 +770,9 @@ function Opensigndrive() {
|
||||
</div>
|
||||
<div
|
||||
id="folder-menu"
|
||||
className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} md:hidden`}
|
||||
className={`${
|
||||
isOptions ? "dropdown show dropDownStyle" : "dropdown"
|
||||
} md:hidden`}
|
||||
onClick={() => setIsOptions(!isOptions)}
|
||||
>
|
||||
<div
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -150,7 +150,6 @@ function PlaceHolderSign() {
|
||||
status: false,
|
||||
message: ""
|
||||
});
|
||||
const [extUserId, setExtUserId] = useState("");
|
||||
const [isCustomize, setIsCustomize] = useState(false);
|
||||
const [zoomPercent, setZoomPercent] = useState(0);
|
||||
const [scale, setScale] = useState(1);
|
||||
@@ -164,13 +163,13 @@ function PlaceHolderSign() {
|
||||
const [userList, setUserList] = useState([]);
|
||||
const [isAttchSignerModal, setIsAttchSignerModal] = useState(false);
|
||||
const [isNewContact, setIsNewContact] = useState({ status: false, id: "" });
|
||||
const [owner, setOwner] = useState({});
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const [, drop] = useDrop({
|
||||
accept: "BOX",
|
||||
drop: (item, monitor) => addPositionOfSignature(item, monitor),
|
||||
collect: (monitor) => ({ isOver: !!monitor.isOver() })
|
||||
});
|
||||
|
||||
const documentId = docId;
|
||||
useEffect(() => {
|
||||
if (documentId) {
|
||||
@@ -286,7 +285,7 @@ function PlaceHolderSign() {
|
||||
setPdfArrayBuffer(arrayBuffer);
|
||||
setPdfBase64Url(base64Pdf);
|
||||
}
|
||||
setExtUserId(documentData[0]?.ExtUserPtr?.objectId);
|
||||
setOwner(documentData?.[0]?.ExtUserPtr);
|
||||
const alreadyPlaceholder = documentData[0]?.SignedUrl;
|
||||
// Check if document is sent for signing
|
||||
if (alreadyPlaceholder) {
|
||||
@@ -457,7 +456,11 @@ function PlaceHolderSign() {
|
||||
documentData === "Error: Something went wrong!" ||
|
||||
(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 });
|
||||
} else {
|
||||
setHandleError(t("no-data-avaliable"));
|
||||
@@ -525,7 +528,7 @@ function PlaceHolderSign() {
|
||||
scale: containerScale,
|
||||
zIndex: posZIndex,
|
||||
type: dragTypeValue,
|
||||
options: addWidgetOptions(dragTypeValue),
|
||||
options: addWidgetOptions(dragTypeValue, owner),
|
||||
Width: widgetWidth / (containerScale * scale),
|
||||
Height: widgetHeight / (containerScale * scale)
|
||||
};
|
||||
@@ -556,7 +559,7 @@ function PlaceHolderSign() {
|
||||
scale: containerScale,
|
||||
zIndex: posZIndex,
|
||||
type: dragTypeValue,
|
||||
options: addWidgetOptions(dragTypeValue),
|
||||
options: addWidgetOptions(dragTypeValue, owner),
|
||||
Width: widgetWidth / (containerScale * scale),
|
||||
Height: widgetHeight / (containerScale * scale)
|
||||
};
|
||||
@@ -1179,6 +1182,7 @@ function PlaceHolderSign() {
|
||||
|
||||
const variables = {
|
||||
document_title: documentName,
|
||||
note: pdfDetails?.[0]?.Note,
|
||||
sender_name: senderName,
|
||||
sender_mail: senderEmail,
|
||||
sender_phone: senderPhone || "",
|
||||
@@ -1204,6 +1208,7 @@ function PlaceHolderSign() {
|
||||
"</body> </html>";
|
||||
const variables = {
|
||||
document_title: documentName,
|
||||
note: pdfDetails?.[0]?.Note,
|
||||
sender_name: senderName,
|
||||
sender_mail: senderEmail,
|
||||
sender_phone: senderPhone || "",
|
||||
@@ -1218,6 +1223,7 @@ function PlaceHolderSign() {
|
||||
}
|
||||
const mailparam = {
|
||||
senderName: senderName,
|
||||
note: pdfDetails?.[0]?.Note || "",
|
||||
senderMail: senderEmail,
|
||||
title: documentName,
|
||||
organization: orgName,
|
||||
@@ -1225,7 +1231,7 @@ function PlaceHolderSign() {
|
||||
sigingUrl: signPdf
|
||||
};
|
||||
let params = {
|
||||
extUserId: extUserId,
|
||||
extUserId: owner?.objectId,
|
||||
recipient: signerMail[i].Email,
|
||||
subject: replaceVar?.subject
|
||||
? replaceVar?.subject
|
||||
@@ -2093,9 +2099,11 @@ function PlaceHolderSign() {
|
||||
<LottieWithLoader />
|
||||
{pdfDetails[0].SendinOrder ? (
|
||||
<p>
|
||||
{t("placeholder-mail-alert", {
|
||||
name: signersdata[0]?.Name
|
||||
})}
|
||||
{isCurrUser
|
||||
? t("placeholder-mail-alert-you")
|
||||
: t("placeholder-mail-alert", {
|
||||
name: signersdata[0]?.Name
|
||||
})}
|
||||
</p>
|
||||
) : (
|
||||
<p>{t("placeholder-alert-4")}</p>
|
||||
|
||||
@@ -20,6 +20,7 @@ import EditorToolbar, {
|
||||
module2,
|
||||
formats
|
||||
} from "../components/pdf/EditorToolbar";
|
||||
import DateFormatSelector from "../components/shared/fields/DateFormatSelector";
|
||||
|
||||
const Preferences = () => {
|
||||
const appName = "OpenSign™";
|
||||
@@ -47,6 +48,8 @@ const Preferences = () => {
|
||||
const [tab, setTab] = useState([generaltab]);
|
||||
const [sendinOrder, setSendinOrder] = useState(true);
|
||||
const [isTourEnabled, setIsTourEnabled] = useState(false);
|
||||
const [dateFormat, setDateFormat] = useState("MM/DD/YYYY");
|
||||
const [is12HourTime, setIs12HourTime] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetchSignType();
|
||||
@@ -99,10 +102,18 @@ const Preferences = () => {
|
||||
? _getUser?.IsTourEnabled
|
||||
: true;
|
||||
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) {
|
||||
console.log("err while getting user details", err);
|
||||
setErrMsg("Something went wrong");
|
||||
setErrMsg(t("something-went-wrong-mssg"));
|
||||
} finally {
|
||||
setIsTopLoader(false);
|
||||
}
|
||||
@@ -154,11 +165,13 @@ const Preferences = () => {
|
||||
params = {
|
||||
...params,
|
||||
SendinOrder: sendinOrder,
|
||||
IsTourEnabled: isTourEnabled
|
||||
IsTourEnabled: isTourEnabled,
|
||||
DateFormat: dateFormat,
|
||||
Is12HourTime: is12HourTime
|
||||
};
|
||||
const updateRes = await Parse.Cloud.run("updatepreferences", params);
|
||||
if (updateRes) {
|
||||
setIsAlert({ type: "success", msg: "Saved successfully." });
|
||||
setIsAlert({ type: "success", msg: t("saved-successfully") });
|
||||
let extUser =
|
||||
localStorage.getItem("Extand_Class") &&
|
||||
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||
@@ -166,6 +179,8 @@ const Preferences = () => {
|
||||
extUser.NotifyOnSignatures = isNotifyOnSignatures;
|
||||
extUser.SendinOrder = sendinOrder;
|
||||
extUser.IsTourEnabled = isTourEnabled;
|
||||
extUser.DateFormat = dateFormat;
|
||||
extUser.Is12HourTime = is12HourTime;
|
||||
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||
localStorage.setItem("Extand_Class", JSON.stringify([_extUser]));
|
||||
}
|
||||
@@ -229,21 +244,23 @@ const Preferences = () => {
|
||||
setIsLoader(true);
|
||||
const replacedHtmlBody = completionBody.replace(/"/g, "'");
|
||||
const htmlBody = `<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>${replacedHtmlBody}</body></html>`;
|
||||
const tenantQuery = new Parse.Query("partners_Tenant");
|
||||
const updateTenantObj = await tenantQuery.get(tenantId);
|
||||
updateTenantObj.set("CompletionBody", htmlBody);
|
||||
updateTenantObj.set("CompletionSubject", completionsubject);
|
||||
const res = await updateTenantObj.save();
|
||||
if (res) {
|
||||
const updateRes = JSON.parse(JSON.stringify(res));
|
||||
const updateTenant = await Parse.Cloud.run("updatetenant", {
|
||||
tenantId: tenantId,
|
||||
details: {
|
||||
CompletionBody: htmlBody,
|
||||
CompletionSubject: completionsubject
|
||||
}
|
||||
});
|
||||
if (updateTenant) {
|
||||
const updateRes = JSON.parse(JSON.stringify(updateTenant));
|
||||
SetCompletionBody(updateRes?.CompletionBody);
|
||||
setCompletionSubject(updateRes?.CompletionSubject);
|
||||
setIsAlert({ type: "success", msg: "Saved successfully." });
|
||||
setIsAlert({ type: "success", msg: t("saved-successfully") });
|
||||
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
|
||||
}
|
||||
} catch (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);
|
||||
} finally {
|
||||
setIsLoader(false);
|
||||
@@ -256,21 +273,23 @@ const Preferences = () => {
|
||||
setIsLoader(true);
|
||||
const replacedHtmlBody = requestBody.replace(/"/g, "'");
|
||||
const htmlBody = `<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>${replacedHtmlBody}</body></html>`;
|
||||
const tenantQuery = new Parse.Query("partners_Tenant");
|
||||
const updateTenantObj = await tenantQuery.get(tenantId);
|
||||
updateTenantObj.set("RequestBody", htmlBody);
|
||||
updateTenantObj.set("RequestSubject", requestSubject);
|
||||
const res = await updateTenantObj.save();
|
||||
if (res) {
|
||||
const updateRes = JSON.parse(JSON.stringify(res));
|
||||
const updateTenant = await Parse.Cloud.run("updatetenant", {
|
||||
tenantId: tenantId,
|
||||
details: {
|
||||
RequestBody: htmlBody,
|
||||
RequestSubject: requestSubject
|
||||
}
|
||||
});
|
||||
if (updateTenant) {
|
||||
const updateRes = JSON.parse(JSON.stringify(updateTenant));
|
||||
setRequestBody(updateRes?.RequestBody);
|
||||
setRequestSubject(updateRes?.RequestSubject);
|
||||
setIsAlert({ type: "success", msg: "Saved successfully." });
|
||||
setIsAlert({ type: "success", msg: t("saved-successfully") });
|
||||
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
|
||||
}
|
||||
} catch (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);
|
||||
} finally {
|
||||
setIsLoader(false);
|
||||
@@ -376,7 +395,7 @@ const Preferences = () => {
|
||||
{t("allowed-signature-types")}
|
||||
</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">
|
||||
<li>
|
||||
<span className="font-bold">Draw: </span>
|
||||
@@ -403,7 +422,7 @@ const Preferences = () => {
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</ReactTooltip>
|
||||
</label>
|
||||
@@ -481,6 +500,15 @@ const Preferences = () => {
|
||||
setTimezone={setTimezone}
|
||||
/>
|
||||
</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]">
|
||||
<label className="block mb-[0.7rem]">
|
||||
<span className="text-[14px] font-medium">
|
||||
@@ -501,7 +529,7 @@ const Preferences = () => {
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">{t("send-in-order")}</p>
|
||||
<p>{t("send-in-order-help.p1")}</p>
|
||||
<p className="p-[5px]">
|
||||
<div className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
@@ -514,7 +542,7 @@ const Preferences = () => {
|
||||
<span>{t("send-in-order-help.p3")}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
<p>{t("send-in-order-help.p4")}</p>
|
||||
</div>
|
||||
</ReactTooltip>
|
||||
@@ -563,7 +591,7 @@ const Preferences = () => {
|
||||
>
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">{t("enable-tour")}</p>
|
||||
<p className="p-[5px]">
|
||||
<div className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
@@ -576,7 +604,7 @@ const Preferences = () => {
|
||||
<span>{t("istourenabled-help.p2")}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
{t("istourenabled-help.p3", {
|
||||
appName: appName
|
||||
|
||||
@@ -40,7 +40,8 @@ import {
|
||||
convertBase64ToFile,
|
||||
generatePdfName,
|
||||
handleRemoveWidgets,
|
||||
compressedFileSize
|
||||
compressedFileSize,
|
||||
addWidgetSelfsignOptions
|
||||
} from "../constant/Utils";
|
||||
import { useParams } from "react-router";
|
||||
import Tour from "reactour";
|
||||
@@ -144,6 +145,7 @@ function SignYourSelf() {
|
||||
isVisible: false,
|
||||
signId: ""
|
||||
});
|
||||
const [owner, setOwner] = useState({});
|
||||
const [, drop] = useDrop({
|
||||
accept: "BOX",
|
||||
drop: (item, monitor) => addPositionOfSignature(item, monitor),
|
||||
@@ -204,6 +206,7 @@ function SignYourSelf() {
|
||||
const documentData = await contractDocument(documentId);
|
||||
|
||||
if (documentData && documentData.length > 0) {
|
||||
setOwner(documentData?.[0]?.ExtUserPtr);
|
||||
setPdfDetails(documentData);
|
||||
const placeholders =
|
||||
documentData[0]?.Placeholders?.length > 0
|
||||
@@ -249,7 +252,11 @@ function SignYourSelf() {
|
||||
documentData === "Error: Something went wrong!" ||
|
||||
(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 });
|
||||
} else {
|
||||
setHandleError(t("no-data-avaliable"));
|
||||
@@ -321,7 +328,7 @@ function SignYourSelf() {
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Error: error in getDocumentDetails", err);
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
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
|
||||
const addPositionOfSignature = (item, monitor) => {
|
||||
setCurrWidgetsDetails({});
|
||||
@@ -416,7 +375,7 @@ function SignYourSelf() {
|
||||
// `getBoundingClientRect()` is used to get accurate measurement height of the div
|
||||
const divHeight = divRef.current.getBoundingClientRect().height;
|
||||
const getWidth = widgetTypeExist
|
||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
|
||||
? calculateInitialWidthHeight(widgetValue).getWidth
|
||||
: defaultWidthHeight(dragTypeValue).width;
|
||||
const getHeight = defaultWidthHeight(dragTypeValue).height;
|
||||
|
||||
@@ -430,7 +389,7 @@ function SignYourSelf() {
|
||||
scale: containerScale,
|
||||
Width: getWidth,
|
||||
Height: getHeight,
|
||||
options: addWidgetOptions(dragTypeValue)
|
||||
options: addWidgetSelfsignOptions(dragTypeValue, getWidgetValue, owner)
|
||||
};
|
||||
dropData.push(dropObj);
|
||||
} else {
|
||||
@@ -459,7 +418,7 @@ function SignYourSelf() {
|
||||
type: dragTypeValue,
|
||||
Width: getWidth / (containerScale * scale),
|
||||
Height: getHeight / (containerScale * scale),
|
||||
options: addWidgetOptions(dragTypeValue),
|
||||
options: addWidgetSelfsignOptions(dragTypeValue, getWidgetValue, owner),
|
||||
scale: containerScale
|
||||
};
|
||||
dropData.push(dropObj);
|
||||
@@ -1253,7 +1212,7 @@ function SignYourSelf() {
|
||||
setPdfBase64Url={setPdfBase64Url}
|
||||
setIsUploadPdf={setIsUploadPdf}
|
||||
pdfArrayBuffer={pdfArrayBuffer}
|
||||
isMergePdfBtn={true}
|
||||
isMergePdfBtn={!pdfDetails?.[0]?.IsCompleted}
|
||||
/>
|
||||
<div className=" w-full md:w-[57%] flex mr-4">
|
||||
<PdfZoom
|
||||
|
||||
@@ -139,6 +139,7 @@ const TemplatePlaceholder = () => {
|
||||
const [updatedPdfUrl, setUpdatedPdfUrl] = useState("");
|
||||
const [tempSignerId, setTempSignerId] = useState("");
|
||||
const [unSignedWidgetId, setUnSignedWidgetId] = useState("");
|
||||
const [owner, setOwner] = useState({});
|
||||
useEffect(() => {
|
||||
fetchTemplate();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@@ -214,6 +215,7 @@ const TemplatePlaceholder = () => {
|
||||
: [];
|
||||
|
||||
if (documentData && documentData.length > 0) {
|
||||
setOwner(documentData?.[0]?.ExtUserPtr);
|
||||
const url = documentData[0] && documentData[0]?.URL;
|
||||
if (url) {
|
||||
const arrayBuffer = await convertPdfArrayBuffer(url);
|
||||
@@ -282,14 +284,14 @@ const TemplatePlaceholder = () => {
|
||||
const updatedSigners = documentData[0].Signers.map((x, index) => ({
|
||||
...x,
|
||||
Id: randomId(),
|
||||
Role: "User " + (index + 1)
|
||||
Role: "Role " + (index + 1)
|
||||
}));
|
||||
setSignersData(updatedSigners);
|
||||
setUniqueId(updatedSigners[0].Id);
|
||||
setBlockColor(updatedSigners[0].blockColor);
|
||||
}
|
||||
} else {
|
||||
setRoleName("User 1");
|
||||
setRoleName("Role 1");
|
||||
if (
|
||||
documentData[0].Placeholders &&
|
||||
documentData[0].Placeholders.length > 0
|
||||
@@ -391,7 +393,7 @@ const TemplatePlaceholder = () => {
|
||||
scale: containerScale,
|
||||
zIndex: posZIndex,
|
||||
type: dragTypeValue,
|
||||
options: addWidgetOptions(dragTypeValue),
|
||||
options: addWidgetOptions(dragTypeValue, owner),
|
||||
Width: widgetWidth / (containerScale * scale),
|
||||
Height: widgetHeight / (containerScale * scale)
|
||||
};
|
||||
@@ -421,7 +423,7 @@ const TemplatePlaceholder = () => {
|
||||
// isMobile: isMobile,
|
||||
zIndex: posZIndex,
|
||||
type: item.text,
|
||||
options: addWidgetOptions(dragTypeValue),
|
||||
options: addWidgetOptions(dragTypeValue, owner),
|
||||
Width: widgetWidth / (containerScale * scale),
|
||||
Height: widgetHeight / (containerScale * scale)
|
||||
};
|
||||
@@ -1099,7 +1101,7 @@ const TemplatePlaceholder = () => {
|
||||
const Id = randomId();
|
||||
const index = signersdata.length;
|
||||
const obj = {
|
||||
Role: roleName || "User " + count,
|
||||
Role: roleName || "Role " + count,
|
||||
Id: Id,
|
||||
blockColor: color[index]
|
||||
};
|
||||
@@ -1108,7 +1110,7 @@ const TemplatePlaceholder = () => {
|
||||
signerPtr: {},
|
||||
signerObjId: "",
|
||||
blockColor: color[index],
|
||||
Role: roleName || "User " + count,
|
||||
Role: roleName || "Role " + count,
|
||||
Id: Id
|
||||
};
|
||||
|
||||
|
||||
@@ -7,8 +7,7 @@ import Title from "../components/Title";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { emailRegex } from "../constant/const";
|
||||
const UpdateExistUserAdmin = () => {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const [formdata, setFormdata] = useState({ email: "", masterkey: "" });
|
||||
@@ -30,7 +29,7 @@ const UpdateExistUserAdmin = () => {
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err in checkadminexist", err);
|
||||
setErrMsg("Something went wrong.");
|
||||
setErrMsg(t("something-went-wrong-mssg"));
|
||||
} finally {
|
||||
setLoader(false);
|
||||
}
|
||||
|
||||
@@ -33,8 +33,9 @@ const AddContact = (props) => {
|
||||
try {
|
||||
const baseURL = localStorage.getItem("baseUrl");
|
||||
const url = `${baseURL}functions/isuserincontactbook`;
|
||||
const token =
|
||||
{ "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
|
||||
const token = {
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
};
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
@@ -63,18 +64,15 @@ const AddContact = (props) => {
|
||||
)
|
||||
);
|
||||
const userId = user?.objectId || "";
|
||||
const tenantDetails = await getTenantDetails(
|
||||
userId,
|
||||
);
|
||||
const tenantDetails = await getTenantDetails(userId);
|
||||
const tenantId = tenantDetails?.objectId || "";
|
||||
if (tenantId) {
|
||||
try {
|
||||
const baseURL = localStorage.getItem("baseUrl");
|
||||
const url = `${baseURL}functions/savecontact`;
|
||||
const token =
|
||||
{
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
};
|
||||
const token = {
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
};
|
||||
const data = { name, email, phone, tenantId };
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
@@ -137,7 +135,9 @@ const AddContact = (props) => {
|
||||
</div>
|
||||
)}
|
||||
<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 && (
|
||||
<div className="mb-[0.75rem] flex items-center mt-1">
|
||||
<input
|
||||
|
||||
@@ -11,7 +11,7 @@ const Alert = ({ children, type, className }) => {
|
||||
case "danger":
|
||||
return "op-alert-error";
|
||||
case "warning":
|
||||
return "op-alert-warning";
|
||||
return "op-alert-warning text-black";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import React from "react";
|
||||
|
||||
const CheckCircle = ({ size = 56, color = "text-green-500" }) => {
|
||||
return (
|
||||
<div className={`flex items-center justify-center ${color}`}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={`w-${size / 4} h-${size / 4}`}
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
>
|
||||
<circle
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M9 12l2 2l4-4"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CheckCircle;
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import pad from "../assets/images/pad.svg";
|
||||
import { useLocation, useNavigate } from "react-router";
|
||||
import { Link, useLocation, useNavigate } from "react-router";
|
||||
import axios from "axios";
|
||||
import ModalUi from "./ModalUi";
|
||||
import AddSigner from "../components/AddSigner";
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
copytoData,
|
||||
fetchUrl,
|
||||
formatDate,
|
||||
formatTimeInTimezone,
|
||||
formatDateTime,
|
||||
getSignedUrl,
|
||||
getTenantDetails,
|
||||
handleSignatureType,
|
||||
@@ -46,7 +46,6 @@ const ReportTable = (props) => {
|
||||
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [actLoader, setActLoader] = useState({});
|
||||
const [isAlert, setIsAlert] = useState(false);
|
||||
const [isContactform, setIsContactform] = useState(false);
|
||||
const [isDeleteModal, setIsDeleteModal] = useState({});
|
||||
const [isRevoke, setIsRevoke] = useState({});
|
||||
@@ -81,6 +80,8 @@ const ReportTable = (props) => {
|
||||
const [invalidRecords, setInvalidRecords] = useState(0);
|
||||
const [renameDoc, setRenameDoc] = useState("");
|
||||
const [contact, setContact] = useState({ Name: "", Email: "", Phone: "" });
|
||||
const [isSuccess, setIsSuccess] = useState({});
|
||||
const [templateId, setTemplateId] = useState("");
|
||||
const recordsPerPage = 5;
|
||||
const startIndex = (currentPage - 1) * props.docPerPage;
|
||||
const { isMoreDocs, setIsNextRecord } = props;
|
||||
@@ -136,6 +137,10 @@ const ReportTable = (props) => {
|
||||
|
||||
return pages;
|
||||
};
|
||||
const showAlert = (type, message, time = 1500) => {
|
||||
setAlertMsg({ type: type, message: message });
|
||||
setTimeout(() => setAlertMsg({ type: "", message: "" }), time);
|
||||
};
|
||||
const pageNumbers = getPaginationRange();
|
||||
// below useEffect reset currenpage to 1 if user change route
|
||||
useEffect(() => {
|
||||
@@ -225,164 +230,143 @@ const ReportTable = (props) => {
|
||||
navigate(`/${act.redirectUrl}/${item.objectId}`);
|
||||
} else {
|
||||
setActLoader({ [`${item.objectId}_${act.btnId}`]: true });
|
||||
try {
|
||||
const params = { templateId: item.objectId };
|
||||
const templateDeatils = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}functions/getTemplate`,
|
||||
params,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
);
|
||||
const templateData =
|
||||
templateDeatils.data && templateDeatils.data.result;
|
||||
if (!templateData.error) {
|
||||
const Doc = templateData;
|
||||
|
||||
let signers = [];
|
||||
if (Doc.Signers?.length > 0) {
|
||||
Doc.Signers?.forEach((x) => {
|
||||
if (x.objectId) {
|
||||
const obj = {
|
||||
__type: "Pointer",
|
||||
className: "contracts_Contactbook",
|
||||
objectId: x.objectId
|
||||
};
|
||||
signers.push(obj);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let extUserId = Doc.ExtUserPtr.objectId;
|
||||
let creatorId = Doc.CreatedBy.objectId;
|
||||
if (extClass && extClass.length > 0) {
|
||||
if (Doc.ExtUserPtr?.objectId !== extClass[0].objectId) {
|
||||
const Extand_Class = localStorage.getItem("Extand_Class");
|
||||
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
||||
if (extClass && extClass.length > 0) {
|
||||
extUserId = extClass[0].objectId;
|
||||
creatorId = extClass[0]?.UserId.objectId;
|
||||
}
|
||||
}
|
||||
}
|
||||
const tenantSignTypes = await fetchTenantDetails();
|
||||
const docSignTypes = Doc?.SignatureType || signatureTypes;
|
||||
const updatedSignatureType = await handleSignatureType(
|
||||
tenantSignTypes,
|
||||
docSignTypes
|
||||
);
|
||||
const SignatureType =
|
||||
updatedSignatureType.length > 0
|
||||
? { SignatureType: updatedSignatureType }
|
||||
: {};
|
||||
const NotifyOnSignatures =
|
||||
Doc?.NotifyOnSignatures !== undefined
|
||||
? { NotifyOnSignatures: Doc.NotifyOnSignatures }
|
||||
: {};
|
||||
const Bcc = Doc?.Bcc?.length > 0 ? { Bcc: Doc?.Bcc } : {};
|
||||
const RedirectUrl = Doc?.RedirectUrl
|
||||
? { RedirectUrl: Doc?.RedirectUrl }
|
||||
: {};
|
||||
let placeholdersArr = [];
|
||||
if (Doc.Placeholders?.length > 0) {
|
||||
placeholdersArr = Doc.Placeholders;
|
||||
const data = {
|
||||
Name: Doc.Name,
|
||||
URL: Doc.URL,
|
||||
SignedUrl: Doc.SignedUrl,
|
||||
SentToOthers: Doc?.SentToOthers || false,
|
||||
Description: Doc.Description,
|
||||
Note: Doc.Note,
|
||||
Placeholders: placeholdersArr,
|
||||
ExtUserPtr: {
|
||||
__type: "Pointer",
|
||||
className: "contracts_Users",
|
||||
objectId: extUserId
|
||||
},
|
||||
CreatedBy: {
|
||||
__type: "Pointer",
|
||||
className: "_User",
|
||||
objectId: creatorId
|
||||
},
|
||||
Signers: signers,
|
||||
SendinOrder: Doc?.SendinOrder || false,
|
||||
AutomaticReminders: Doc?.AutomaticReminders || false,
|
||||
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5,
|
||||
IsEnableOTP: Doc?.IsEnableOTP || false,
|
||||
TimeToCompleteDays: parseInt(Doc?.TimeToCompleteDays) || 15,
|
||||
AllowModifications: Doc?.AllowModifications || false,
|
||||
...SignatureType,
|
||||
...NotifyOnSignatures,
|
||||
...Bcc,
|
||||
...RedirectUrl
|
||||
};
|
||||
try {
|
||||
const res = await axios.post(
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/contracts_Document`,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id":
|
||||
localStorage.getItem("parseAppId"),
|
||||
"X-Parse-Session-Token":
|
||||
localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (res.data && res.data.objectId) {
|
||||
setActLoader({});
|
||||
setIsAlert(true);
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
navigate(`/${act.redirectUrl}/${res.data.objectId}`, {
|
||||
state: { title: "Use Template" }
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err", err);
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
setActLoader({});
|
||||
}
|
||||
} else {
|
||||
setActLoader({});
|
||||
}
|
||||
} else {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
setActLoader({});
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err", err);
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
setActLoader({});
|
||||
}
|
||||
handleUseTemplate(item.objectId, act.redirectUrl);
|
||||
}
|
||||
} else {
|
||||
navigate(`/${act.redirectUrl}?docId=${item?.objectId}`);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUseTemplate = async (templateId, redirectUrl) => {
|
||||
try {
|
||||
const params = { templateId: templateId };
|
||||
const templateDeatils = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}functions/getTemplate`,
|
||||
params,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
);
|
||||
const templateData = templateDeatils.data && templateDeatils.data.result;
|
||||
if (!templateData.error) {
|
||||
const Doc = templateData;
|
||||
|
||||
let signers = [];
|
||||
if (Doc.Signers?.length > 0) {
|
||||
Doc.Signers?.forEach((x) => {
|
||||
if (x.objectId) {
|
||||
signers.push({
|
||||
__type: "Pointer",
|
||||
className: "contracts_Contactbook",
|
||||
objectId: x.objectId
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let extUserId = Doc.ExtUserPtr.objectId;
|
||||
let creatorId = Doc.CreatedBy.objectId;
|
||||
if (extClass && extClass.length > 0) {
|
||||
if (Doc.ExtUserPtr?.objectId !== extClass[0].objectId) {
|
||||
const Extand_Class = localStorage.getItem("Extand_Class");
|
||||
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
||||
if (extClass && extClass.length > 0) {
|
||||
extUserId = extClass[0].objectId;
|
||||
creatorId = extClass[0]?.UserId.objectId;
|
||||
}
|
||||
}
|
||||
}
|
||||
const tenantSignTypes = await fetchTenantDetails();
|
||||
const docSignTypes = Doc?.SignatureType || signatureTypes;
|
||||
const updatedSignatureType = await handleSignatureType(
|
||||
tenantSignTypes,
|
||||
docSignTypes
|
||||
);
|
||||
const SignatureType =
|
||||
updatedSignatureType.length > 0
|
||||
? { SignatureType: updatedSignatureType }
|
||||
: {};
|
||||
const NotifyOnSignatures =
|
||||
Doc?.NotifyOnSignatures !== undefined
|
||||
? { NotifyOnSignatures: Doc.NotifyOnSignatures }
|
||||
: {};
|
||||
const Bcc = Doc?.Bcc?.length > 0 ? { Bcc: Doc?.Bcc } : {};
|
||||
const RedirectUrl = Doc?.RedirectUrl
|
||||
? { RedirectUrl: Doc?.RedirectUrl }
|
||||
: {};
|
||||
let placeholdersArr = [];
|
||||
if (Doc.Placeholders?.length > 0) {
|
||||
placeholdersArr = Doc.Placeholders;
|
||||
const data = {
|
||||
Name: Doc.Name,
|
||||
URL: Doc.URL,
|
||||
SignedUrl: Doc.SignedUrl,
|
||||
SentToOthers: Doc?.SentToOthers || false,
|
||||
Description: Doc.Description,
|
||||
Note: Doc.Note,
|
||||
Placeholders: placeholdersArr,
|
||||
ExtUserPtr: {
|
||||
__type: "Pointer",
|
||||
className: "contracts_Users",
|
||||
objectId: extUserId
|
||||
},
|
||||
CreatedBy: {
|
||||
__type: "Pointer",
|
||||
className: "_User",
|
||||
objectId: creatorId
|
||||
},
|
||||
Signers: signers,
|
||||
SendinOrder: Doc?.SendinOrder || false,
|
||||
AutomaticReminders: Doc?.AutomaticReminders || false,
|
||||
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5,
|
||||
IsEnableOTP: Doc?.IsEnableOTP || false,
|
||||
TimeToCompleteDays: parseInt(Doc?.TimeToCompleteDays) || 15,
|
||||
AllowModifications: Doc?.AllowModifications || false,
|
||||
...SignatureType,
|
||||
...NotifyOnSignatures,
|
||||
...Bcc,
|
||||
...RedirectUrl
|
||||
};
|
||||
try {
|
||||
const res = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}classes/contracts_Document`,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
);
|
||||
if (res.data && res.data.objectId) {
|
||||
setActLoader({});
|
||||
navigate(`/${redirectUrl}/${res.data.objectId}`, {
|
||||
state: { title: "Use Template" }
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err", err);
|
||||
showAlert("danger", t("something-went-wrong-mssg"));
|
||||
setActLoader({});
|
||||
}
|
||||
} else {
|
||||
setActLoader({});
|
||||
}
|
||||
} else {
|
||||
showAlert("danger", t("something-went-wrong-mssg"));
|
||||
setActLoader({});
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err", err);
|
||||
showAlert("danger", t("something-went-wrong-mssg"));
|
||||
setActLoader({});
|
||||
}
|
||||
};
|
||||
const handleActionBtn = async (act, item) => {
|
||||
if (act.action === "redirect") {
|
||||
handleURL(item, act);
|
||||
@@ -415,6 +399,8 @@ const ReportTable = (props) => {
|
||||
} else if (act.action === "edit") {
|
||||
setContact(item);
|
||||
setIsModal({ [`edit_${item.objectId}`]: true });
|
||||
} else if (act.action === "saveastemplate") {
|
||||
setIsModal({ [`saveastemplate_${item.objectId}`]: true });
|
||||
} else if (act.action) {
|
||||
setIsModal({ [`extendexpiry_${item.objectId}`]: true });
|
||||
}
|
||||
@@ -470,12 +456,7 @@ const ReportTable = (props) => {
|
||||
});
|
||||
if (res.data && res.data.updatedAt) {
|
||||
setActLoader({});
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "success",
|
||||
message: t("record-delete-alert")
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
showAlert("success", t("record-delete-alert"));
|
||||
const upldatedList = props.List.filter(
|
||||
(x) => x.objectId !== item.objectId
|
||||
);
|
||||
@@ -483,12 +464,7 @@ const ReportTable = (props) => {
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err", err);
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
showAlert("danger", t("something-went-wrong-mssg"));
|
||||
setActLoader({});
|
||||
}
|
||||
};
|
||||
@@ -563,12 +539,7 @@ const ReportTable = (props) => {
|
||||
const res = result.data;
|
||||
if (res) {
|
||||
setActLoader({});
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "success",
|
||||
message: t("record-revoke-alert")
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
showAlert("success", t("record-revoke-alert"));
|
||||
const upldatedList = props.List.filter(
|
||||
(x) => x.objectId !== item.objectId
|
||||
);
|
||||
@@ -579,12 +550,7 @@ const ReportTable = (props) => {
|
||||
.catch((err) => {
|
||||
console.log("err", err);
|
||||
setReason("");
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
showAlert("danger", t("something-went-wrong-mssg"));
|
||||
setActLoader({});
|
||||
});
|
||||
};
|
||||
@@ -678,6 +644,7 @@ const ReportTable = (props) => {
|
||||
const signPdf = `${window.location.origin}/login/${encodeBase64}`;
|
||||
const variables = {
|
||||
document_title: doc.Name,
|
||||
note: doc?.Note || "",
|
||||
sender_name: doc.ExtUserPtr.Name,
|
||||
sender_mail: doc.ExtUserPtr.Email,
|
||||
sender_phone: doc.ExtUserPtr?.Phone || "",
|
||||
@@ -707,6 +674,7 @@ const ReportTable = (props) => {
|
||||
const signPdf = `${window.location.origin}/login/${encodeBase64}`;
|
||||
const variables = {
|
||||
document_title: doc.Name,
|
||||
note: doc?.Note || "",
|
||||
sender_name: doc.ExtUserPtr.Name,
|
||||
sender_mail: doc.ExtUserPtr.Email,
|
||||
sender_phone: doc.ExtUserPtr?.Phone || "",
|
||||
@@ -748,6 +716,7 @@ const ReportTable = (props) => {
|
||||
const signPdf = `${window.location.origin}/login/${encodeBase64}`;
|
||||
const variables = {
|
||||
document_title: doc.Name,
|
||||
note: doc?.Note || "",
|
||||
sender_name: doc.ExtUserPtr.Name,
|
||||
sender_mail: doc.ExtUserPtr.Email,
|
||||
sender_phone: doc.ExtUserPtr?.Phone || "",
|
||||
@@ -789,25 +758,15 @@ const ReportTable = (props) => {
|
||||
try {
|
||||
const res = await axios.post(url, params, { headers: headers });
|
||||
if (res?.data?.result?.status === "success") {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({ type: "success", message: t("mail-sent-alert") });
|
||||
showAlert("success", t("mail-sent-alert"));
|
||||
setIsResendMail({});
|
||||
} else {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
showAlert("danger", t("something-went-wrong-mssg"));
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err in sendmail", err);
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
showAlert("danger", t("something-went-wrong-mssg"));
|
||||
} finally {
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
setIsNextStep({});
|
||||
setUserDetails({});
|
||||
setActLoader({});
|
||||
@@ -840,27 +799,10 @@ const ReportTable = (props) => {
|
||||
// `handleQuickSendClose` is trigger when bulk send component trigger close event
|
||||
const handleQuickSendClose = (status, count) => {
|
||||
setIsBulkSend({});
|
||||
setIsAlert(true);
|
||||
if (status === "success") {
|
||||
if (count > 1) {
|
||||
setAlertMsg({
|
||||
type: "success",
|
||||
message: count + " " + t("document-sent-alert")
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
} else {
|
||||
setAlertMsg({
|
||||
type: "success",
|
||||
message: count + " " + t("document-sent-alert")
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
}
|
||||
showAlert("success", count + " " + t("document-sent-alert"));
|
||||
} else {
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
showAlert("danger", t("something-went-wrong-mssg"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -899,9 +841,7 @@ const ReportTable = (props) => {
|
||||
} catch (err) {
|
||||
console.log("err in fetch template in bulk modal", err);
|
||||
setIsBulkSend({});
|
||||
setIsAlert(true);
|
||||
setAlertMsg({ type: "danger", message: t("something-went-wrong-mssg") });
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
showAlert("danger", t("something-went-wrong-mssg"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -925,21 +865,12 @@ const ReportTable = (props) => {
|
||||
templateCls.set("SharedWith", teamArr);
|
||||
const res = await templateCls.save();
|
||||
if (res) {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "success",
|
||||
message: t("template-share-alert")
|
||||
});
|
||||
showAlert("success", t("template-share-alert"));
|
||||
}
|
||||
} catch (err) {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
showAlert("danger", t("something-went-wrong-mssg"));
|
||||
} finally {
|
||||
setActLoader({});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -966,13 +897,13 @@ const ReportTable = (props) => {
|
||||
}
|
||||
});
|
||||
if (res.data && res.data.updatedAt) {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "success",
|
||||
message: t("expiry-date-updated", {
|
||||
showAlert(
|
||||
"success",
|
||||
t("expiry-date-updated", {
|
||||
newexpirydate: new Date(expiryDate)?.toLocaleDateString()
|
||||
})
|
||||
});
|
||||
}),
|
||||
2000
|
||||
);
|
||||
if (props.ReportName === "Expired Documents") {
|
||||
const upldatedList = props.List.filter(
|
||||
(x) => x.objectId !== item.objectId
|
||||
@@ -982,58 +913,39 @@ const ReportTable = (props) => {
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err", err);
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
showAlert("danger", t("something-went-wrong-mssg"), 2000);
|
||||
} finally {
|
||||
setActLoader({});
|
||||
setExpiryDate();
|
||||
setTimeout(() => setIsAlert(false), 2000);
|
||||
setIsModal({});
|
||||
}
|
||||
} else {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({ type: "danger", message: t("expiry-date-error") });
|
||||
setTimeout(() => setIsAlert(false), 2000);
|
||||
showAlert("danger", t("expiry-date-error"), 2000);
|
||||
}
|
||||
} else {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({ type: "danger", message: t("expiry-date-error") });
|
||||
setTimeout(() => setIsAlert(false), 2000);
|
||||
showAlert("danger", t("expiry-date-error"), 2000);
|
||||
}
|
||||
};
|
||||
// `formatStatusRow` is used to format status row
|
||||
const formatStatusRow = (item) => {
|
||||
const timezone = extClass?.[0]?.Timezone || "";
|
||||
const DateFormat = extClass?.[0]?.DateFormat || "MM/DD/YYYY";
|
||||
const Is12Hr = extClass?.[0]?.Is12HourTime || false;
|
||||
const signers = item?.Placeholders?.map((x, i) => {
|
||||
const matchSigner = item?.AuditTrail?.find(
|
||||
const audit = item?.AuditTrail?.find(
|
||||
(audit) => audit?.UserPtr?.objectId === x.signerObjId
|
||||
);
|
||||
if (matchSigner) {
|
||||
const timezone = extClass?.[0]?.Timezone || "";
|
||||
const signedon = matchSigner?.SignedOn
|
||||
? formatTimeInTimezone(new Date(matchSigner?.SignedOn), timezone)
|
||||
const format = (date) =>
|
||||
date
|
||||
? formatDateTime(new Date(date), DateFormat, timezone, Is12Hr)
|
||||
: "-";
|
||||
const viewedon = matchSigner?.ViewedOn
|
||||
? formatTimeInTimezone(new Date(matchSigner?.ViewedOn), timezone)
|
||||
: "-";
|
||||
return {
|
||||
id: i,
|
||||
Email: matchSigner.UserPtr.Email,
|
||||
Activity: matchSigner?.Activity?.toUpperCase() || "-",
|
||||
SignedOn: signedon,
|
||||
ViewedOn: viewedon
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
id: i,
|
||||
Email: x?.signerPtr?.Email || x?.email,
|
||||
Activity: "SENT",
|
||||
SignedOn: "-",
|
||||
ViewedOn: "-"
|
||||
};
|
||||
}
|
||||
return {
|
||||
id: i,
|
||||
Email: x?.signerPtr?.Email || x?.email,
|
||||
Activity: audit?.Activity?.toUpperCase() || "SENT",
|
||||
SignedOn: format(audit?.SignedOn),
|
||||
ViewedOn: format(audit?.ViewedOn)
|
||||
};
|
||||
});
|
||||
// Decide how many signers to display based on `showAllSignes` state
|
||||
const displaySigners = isShowAllSigners[item.objectId]
|
||||
@@ -1063,7 +975,7 @@ const ReportTable = (props) => {
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={t("document-logs")}
|
||||
handleClose={() => setIsModal({})}
|
||||
handleClose={handleCloseModal}
|
||||
>
|
||||
<div className="pl-3 first:mt-2 border-t-[1px] border-gray-600 text-[12px] py-2">
|
||||
<p className="font-bold"> {x?.Email}</p>
|
||||
@@ -1277,28 +1189,25 @@ const ReportTable = (props) => {
|
||||
const contacts = JSON.stringify(filterdata);
|
||||
const res = await Parse.Cloud.run("createbatchcontact", { contacts });
|
||||
if (res) {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "info",
|
||||
message: t("contact-imported", {
|
||||
showAlert(
|
||||
"info",
|
||||
t("contact-imported", {
|
||||
imported: res?.success || 0,
|
||||
failed: res?.failed || 0
|
||||
})
|
||||
});
|
||||
);
|
||||
if (res?.success > 0) {
|
||||
setTimeout(() => window.location.reload(), 2000);
|
||||
setTimeout(() => window.location.reload(), 1500);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err while creating batch contact", err);
|
||||
setIsAlert(true);
|
||||
setAlertMsg({ type: "danger", message: t("something-went-wrong-mssg") });
|
||||
showAlert("danger", t("something-went-wrong-mssg"));
|
||||
} finally {
|
||||
setActLoader({});
|
||||
setIsModal({});
|
||||
setImportedData([]);
|
||||
setInvalidRecords(0);
|
||||
setTimeout(() => setIsAlert(false), 2000);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1313,22 +1222,13 @@ const ReportTable = (props) => {
|
||||
if (duplicateRes) {
|
||||
const newTemplate = JSON.parse(JSON.stringify(duplicateRes));
|
||||
props.setList((prevData) => [newTemplate, ...prevData]);
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "success",
|
||||
message: t("duplicate-template-created")
|
||||
});
|
||||
showAlert("success", t("duplicate-template-created"));
|
||||
}
|
||||
} catch (err) {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
showAlert("danger", t("something-went-wrong-mssg"));
|
||||
console.log("Err while create duplicate template", err);
|
||||
} finally {
|
||||
setActLoader({});
|
||||
setTimeout(() => setIsAlert(false), 2000);
|
||||
}
|
||||
};
|
||||
// `handleRenameDoc` is used to update document name
|
||||
@@ -1349,21 +1249,11 @@ const ReportTable = (props) => {
|
||||
x.objectId === item.objectId ? { ...x, Name: renameDoc } : x
|
||||
);
|
||||
props.setList(updateList);
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "success",
|
||||
message: "Document updated"
|
||||
});
|
||||
setActLoader({});
|
||||
setTimeout(() => setIsAlert(false), 2000);
|
||||
showAlert("success", "Document updated", 2000);
|
||||
} catch (err) {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
showAlert("danger", t("something-went-wrong-mssg"), 2000);
|
||||
setActLoader({});
|
||||
setTimeout(() => setIsAlert(false), 2000);
|
||||
}
|
||||
};
|
||||
const handleBtnVisibility = (act, item) => {
|
||||
@@ -1387,6 +1277,65 @@ const ReportTable = (props) => {
|
||||
const handleCloseModal = () => {
|
||||
setIsModal({});
|
||||
};
|
||||
const handleSaveAsTemplate = async (doc) => {
|
||||
try {
|
||||
const params = { docId: doc?.objectId };
|
||||
const templateRes = await Parse.Cloud.run("saveastemplate", params);
|
||||
// console.log("templateRes ", templateRes);
|
||||
setTemplateId(templateRes?.id);
|
||||
setIsSuccess({ [doc.objectId]: true });
|
||||
} catch (err) {
|
||||
console.log("Err in saveastemplate", err);
|
||||
} finally {
|
||||
setActLoader({});
|
||||
}
|
||||
};
|
||||
const handleCloseTemplate = () => {
|
||||
setTemplateId("");
|
||||
setIsSuccess({});
|
||||
handleCloseModal();
|
||||
setActLoader({});
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// `handleBulkSend` is used to open modal as well as fetch template
|
||||
// and show Ui on the basis template response
|
||||
const handleBulkSendTemplate = async (templateId, docId) => {
|
||||
setIsBulkSend({ [docId]: true });
|
||||
setIsLoader({ [docId]: true });
|
||||
try {
|
||||
const params = {
|
||||
templateId: templateId,
|
||||
include: ["Placeholders.signerPtr"]
|
||||
};
|
||||
const axiosRes = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}functions/getTemplate`,
|
||||
params,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
);
|
||||
const templateRes = axiosRes.data && axiosRes.data.result;
|
||||
const tenantSignTypes = await fetchTenantDetails();
|
||||
const docSignTypes = templateRes?.SignatureType || signatureTypes;
|
||||
const updatedSignatureType = await handleSignatureType(
|
||||
tenantSignTypes,
|
||||
docSignTypes
|
||||
);
|
||||
setSignatureType(updatedSignatureType);
|
||||
setPlaceholders(templateRes?.Placeholders);
|
||||
setTemplateDetails(templateRes);
|
||||
setIsLoader({});
|
||||
} catch (err) {
|
||||
console.log("err in fetch template in bulk modal", err);
|
||||
setIsBulkSend({});
|
||||
showAlert("danger", t("something-went-wrong-mssg"));
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="relative">
|
||||
{Object.keys(actLoader)?.length > 0 && (
|
||||
@@ -1395,7 +1344,9 @@ const ReportTable = (props) => {
|
||||
</div>
|
||||
)}
|
||||
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
|
||||
{isAlert && <Alert type={alertMsg.type}>{alertMsg.message}</Alert>}
|
||||
{alertMsg.message && (
|
||||
<Alert type={alertMsg.type}>{alertMsg.message}</Alert>
|
||||
)}
|
||||
{props.tourData && props.ReportName === "Templates" && (
|
||||
<>
|
||||
<Tour
|
||||
@@ -1769,7 +1720,7 @@ const ReportTable = (props) => {
|
||||
isOpen={
|
||||
isModal["duplicate_" + item.objectId]
|
||||
}
|
||||
handleClose={() => setIsModal({})}
|
||||
handleClose={handleCloseModal}
|
||||
>
|
||||
<div className=" flex flex-col px-4 pb-3 pt-2 ">
|
||||
<p className="text-base">
|
||||
@@ -1786,7 +1737,7 @@ const ReportTable = (props) => {
|
||||
</button>
|
||||
<button
|
||||
className="w-[100px] op-btn op-btn-secondary op-btn-md"
|
||||
onClick={() => setIsModal({})}
|
||||
onClick={handleCloseModal}
|
||||
>
|
||||
{t("no")}
|
||||
</button>
|
||||
@@ -1857,12 +1808,93 @@ const ReportTable = (props) => {
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
{isModal["saveastemplate_" + item.objectId] && (
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={
|
||||
isSuccess[item.objectId]
|
||||
? t("template-created")
|
||||
: t("btnLabel.Save as template")
|
||||
}
|
||||
handleClose={handleCloseTemplate}
|
||||
>
|
||||
{isSuccess[item.objectId] ? (
|
||||
<div className="mx-[10px] my-[15px]">
|
||||
<p className="text-base text-center">
|
||||
{t("how-would-you-like-to-proceed?")}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1 items-center justify-center mt-2">
|
||||
<button
|
||||
className="op-btn-primary op-btn op-btn-sm focus:outline-none text-sm relative"
|
||||
onClick={() =>
|
||||
handleUseTemplate(
|
||||
templateId,
|
||||
"placeHolderSign"
|
||||
)
|
||||
}
|
||||
>
|
||||
<i className="fa-light fa-plus"></i>{" "}
|
||||
{t("btnLabel.Use")}
|
||||
</button>
|
||||
<button
|
||||
className="op-btn-secondary op-btn op-btn-sm focus:outline-none text-sm relative"
|
||||
onClick={() =>
|
||||
handleBulkSendTemplate(
|
||||
templateId,
|
||||
item.objectId
|
||||
)
|
||||
}
|
||||
>
|
||||
<i className="fa-light fa-plus"></i>{" "}
|
||||
{`${t(`btnLabel.Quick send`)}`}
|
||||
</button>
|
||||
<button
|
||||
className="op-btn-secondary op-btn op-btn-sm focus:outline-none text-sm relative"
|
||||
onClick={() =>
|
||||
navigate(`/template/${templateId}`)
|
||||
}
|
||||
>
|
||||
<i className="fa-light fa-pen"></i>{" "}
|
||||
{t(`btnLabel.Edit`)}
|
||||
</button>
|
||||
</div>
|
||||
<Link
|
||||
to="/report/6TeaPr321t"
|
||||
className="cursor-pointer underline text-sm w-full flex justify-center mt-2"
|
||||
>
|
||||
{t("go-to-manage-templates")}
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
<div className="m-[20px]">
|
||||
<div className="text-lg font-normal text-black">
|
||||
{t("save-as-template-?")}
|
||||
</div>
|
||||
<hr className="bg-[#ccc] mt-3" />
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<button
|
||||
onClick={() => handleSaveAsTemplate(item)}
|
||||
className="op-btn op-btn-primary w-[100px]"
|
||||
>
|
||||
{t("yes")}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleCloseTemplate}
|
||||
className="op-btn op-btn-secondary w-[100px]"
|
||||
>
|
||||
{t("no")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</ModalUi>
|
||||
)}
|
||||
{isModal["extendexpiry_" + item.objectId] && (
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={t("btnLabel.extend-expiry-date")}
|
||||
reduceWidth={"md:max-w-[450px]"}
|
||||
handleClose={() => setIsModal({})}
|
||||
handleClose={handleCloseModal}
|
||||
>
|
||||
<form
|
||||
className="px-4 py-2 flex flex-col"
|
||||
@@ -2221,7 +2253,7 @@ const ReportTable = (props) => {
|
||||
<ModalUi
|
||||
title={t("btnLabel.Rename")}
|
||||
isOpen={isModal["rename_" + item.objectId]}
|
||||
handleClose={() => setIsModal({})}
|
||||
handleClose={handleCloseModal}
|
||||
>
|
||||
<div className=" flex flex-col px-4 pb-3 pt-2 ">
|
||||
<div className="flex flex-col gap-2">
|
||||
@@ -2243,7 +2275,7 @@ const ReportTable = (props) => {
|
||||
</button>
|
||||
<button
|
||||
className="w-[100px] op-btn op-btn-secondary op-btn-md"
|
||||
onClick={() => setIsModal({})}
|
||||
onClick={handleCloseModal}
|
||||
>
|
||||
{t("cancel")}
|
||||
</button>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
function sanitizeFileName(fileName) {
|
||||
// Remove spaces and invalid characters
|
||||
const file = fileName.replace(/[^a-zA-Z0-9._-]/g, "");
|
||||
const removedot = file.replace(/\.(?=.*\.)/g, "");
|
||||
return removedot.replace(/[^a-zA-Z0-9._-]/g, "");
|
||||
const file = fileName?.replace(/[^a-zA-Z0-9._-]/g, "");
|
||||
const removedot = file?.replace(/\.(?=.*\.)/g, "");
|
||||
return removedot?.replace(/[^a-zA-Z0-9._-]/g, "");
|
||||
}
|
||||
export default sanitizeFileName;
|
||||
|
||||
@@ -6,10 +6,6 @@ dotenv.config();
|
||||
|
||||
export const cloudServerUrl = 'http://localhost:8080/app';
|
||||
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 = [
|
||||
'#93a3db',
|
||||
@@ -53,7 +49,7 @@ export const saveFileUsage = async (size, fileUrl, userId) => {
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
const tenant = await tenantQuery.first();
|
||||
const tenant = await tenantQuery.first({ useMasterKey: true });
|
||||
if (tenant) {
|
||||
const tenantPtr = { __type: 'Pointer', className: 'partners_Tenant', objectId: tenant.id };
|
||||
try {
|
||||
@@ -229,6 +225,7 @@ export const flattenPdf = async pdfFile => {
|
||||
export const mailTemplate = param => {
|
||||
const themeColor = '#47a3ad';
|
||||
const subject = `${param.senderName} has requested you to sign "${param.title}"`;
|
||||
const AppName = appName;
|
||||
const logo = `<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' />`;
|
||||
|
||||
const opurl = ` <a href='www.opensignlabs.com' target=_blank>here</a>`;
|
||||
@@ -244,15 +241,56 @@ export const mailTemplate = param => {
|
||||
param.senderMail +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td><td></td><td style='color:#626363;font-weight:bold'> " +
|
||||
param.organization +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expire on</td><td></td><td style='color:#626363;font-weight:bold'>" +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td></td><td style='color:#626363;font-weight:bold'>" +
|
||||
param.localExpireDate +
|
||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Note</td><td></td><td style='color:#626363;font-weight:bold'>" +
|
||||
param.note +
|
||||
"</td></tr><tr><td></td><td></td></tr></table></div> <div style='margin-left:70px'><a target=_blank href=" +
|
||||
param.sigingUrl +
|
||||
"><button style='padding:12px;background-color:#d46b0f;color:white;border:0px;font-weight:bold;margin-top:30px'>Sign here</button></a></div><div style='display:flex;justify-content:center;margin-top:10px'></div></div></div><div><p> This is an automated email from " +
|
||||
appName +
|
||||
AppName +
|
||||
'. For any queries regarding this email, please contact the sender ' +
|
||||
param.senderMail +
|
||||
` directly. If you think this email is inappropriate or spam, you may file a complaint with ${appName}${opurl}.</p></div></div></body></html>`;
|
||||
` directly. If you think this email is inappropriate or spam, you may file a complaint with ${AppName}${opurl}.</p></div></div></body></html>`;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import getDrive from './parsefunction/getDrive.js';
|
||||
import getReport from './parsefunction/getReport.js';
|
||||
import TemplateAfterSave from './parsefunction/TemplateAfterSave.js';
|
||||
import GetTemplate from './parsefunction/GetTemplate.js';
|
||||
import callWebhook from './parsefunction/callWebhook.js';
|
||||
import DocumentBeforesave from './parsefunction/DocumentBeforesave.js';
|
||||
import TemplateBeforeSave from './parsefunction/TemplateBeforesave.js';
|
||||
import DocumentBeforeFind from './parsefunction/DocumentAfterFind.js';
|
||||
@@ -21,7 +20,6 @@ import UserAfterFind from './parsefunction/UserAfterFInd.js';
|
||||
import SignatureAfterFind from './parsefunction/SignatureAfterFind.js';
|
||||
import TenantAterFind from './parsefunction/TenantAfterFind.js';
|
||||
import VerifyEmail from './parsefunction/VerifyEmail.js';
|
||||
import encryptedpdf from './parsefunction/encryptedPdf.js';
|
||||
import { getSignedUrl } from './parsefunction/getSignedUrl.js';
|
||||
import createBatchDocs from './parsefunction/createBatchDocs.js';
|
||||
import linkContactToDoc from './parsefunction/linkContactToDoc.js';
|
||||
@@ -51,6 +49,8 @@ import fileUpload from './parsefunction/fileUpload.js';
|
||||
import getUserListByOrg from './parsefunction/getUserListByOrg.js';
|
||||
import editContact from './parsefunction/editContact.js';
|
||||
import forwardDoc from './parsefunction/ForwardDoc.js';
|
||||
import saveAsTemplate from './parsefunction/saveAsTemplate.js';
|
||||
import updateTenant from './parsefunction/updateTenant.js';
|
||||
|
||||
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
|
||||
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
|
||||
@@ -81,9 +81,7 @@ Parse.Cloud.define('getDocument', getDocument);
|
||||
Parse.Cloud.define('getDrive', getDrive);
|
||||
Parse.Cloud.define('getReport', getReport);
|
||||
Parse.Cloud.define('getTemplate', GetTemplate);
|
||||
Parse.Cloud.define('callwebhook', callWebhook);
|
||||
Parse.Cloud.define('verifyemail', VerifyEmail);
|
||||
Parse.Cloud.define('encryptedpdf', encryptedpdf);
|
||||
Parse.Cloud.define('getsignedurl', getSignedUrl);
|
||||
Parse.Cloud.define('batchdocuments', createBatchDocs);
|
||||
Parse.Cloud.define('linkcontacttodoc', linkContactToDoc);
|
||||
@@ -112,3 +110,5 @@ Parse.Cloud.define('fileupload', fileUpload);
|
||||
Parse.Cloud.define('getuserlistbyorg', getUserListByOrg);
|
||||
Parse.Cloud.define('editcontact', editContact);
|
||||
Parse.Cloud.define('forwarddoc', forwardDoc);
|
||||
Parse.Cloud.define('saveastemplate', saveAsTemplate);
|
||||
Parse.Cloud.define('updatetenant', updateTenant);
|
||||
|
||||
@@ -61,7 +61,7 @@ async function addTeamAndOrg(extUser) {
|
||||
|
||||
async function saveUser(userDetails) {
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
userQuery.equalTo('username', userDetails.email);
|
||||
userQuery.equalTo('username', userDetails.email?.toLowerCase()?.replace(/\s/g, ''));
|
||||
const userRes = await userQuery.first({ useMasterKey: true });
|
||||
|
||||
if (userRes) {
|
||||
@@ -83,9 +83,9 @@ async function saveUser(userDetails) {
|
||||
return { id: login.objectId, sessionToken: login.sessionToken };
|
||||
} else {
|
||||
const user = new Parse.User();
|
||||
user.set('username', userDetails.email);
|
||||
user.set('username', userDetails.email?.toLowerCase()?.replace(/\s/g, ''));
|
||||
user.set('password', userDetails.password);
|
||||
user.set('email', userDetails.email);
|
||||
user.set('email', userDetails.email?.toLowerCase()?.replace(/\s/g, ''));
|
||||
if (userDetails?.phone) {
|
||||
user.set('phone', userDetails.phone);
|
||||
}
|
||||
@@ -111,7 +111,6 @@ export default async function AddAdmin(request) {
|
||||
if (extUser) {
|
||||
return { message: 'User already exist' };
|
||||
} else {
|
||||
// console.log("role ", role);
|
||||
const partnerQuery = new Parse.Object('partners_Tenant');
|
||||
partnerQuery.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
@@ -123,7 +122,7 @@ export default async function AddAdmin(request) {
|
||||
partnerQuery.set('ContactNumber', userDetails.phone);
|
||||
}
|
||||
partnerQuery.set('TenantName', userDetails.company);
|
||||
partnerQuery.set('EmailAddress', userDetails.email);
|
||||
partnerQuery.set('EmailAddress', userDetails.email?.toLowerCase()?.replace(/\s/g, ''));
|
||||
partnerQuery.set('IsActive', true);
|
||||
partnerQuery.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
@@ -154,7 +153,7 @@ export default async function AddAdmin(request) {
|
||||
objectId: user.id,
|
||||
});
|
||||
newObj.set('UserRole', userDetails.role);
|
||||
newObj.set('Email', userDetails.email);
|
||||
newObj.set('Email', userDetails.email?.toLowerCase()?.replace(/\s/g, ''));
|
||||
newObj.set('Name', userDetails.name);
|
||||
if (userDetails?.phone) {
|
||||
newObj.set('Phone', userDetails?.phone);
|
||||
@@ -177,7 +176,7 @@ export default async function AddAdmin(request) {
|
||||
const extUser = {
|
||||
objectId: extRes.id,
|
||||
Name: userDetails.name,
|
||||
Email: userDetails.email,
|
||||
Email: userDetails.email?.toLowerCase()?.replace(/\s/g, ''),
|
||||
Phone: userDetails?.phone ? userDetails.phone : '',
|
||||
TenantId: { objectId: tenantRes.id },
|
||||
UserId: { objectId: user.id },
|
||||
|
||||
@@ -28,6 +28,7 @@ export default async function forwardDoc(request) {
|
||||
const docName = _docRes.Name;
|
||||
const fileAdapterId = _docRes?.FileAdapterId || '';
|
||||
const extUserId = _docRes?.ExtUserPtr?.objectId;
|
||||
const TenantAppName = appName;
|
||||
const from = _docRes?.ExtUserPtr?.Email;
|
||||
const replyTo = _docRes?.ExtUserPtr?.Email;
|
||||
const senderName = _docRes?.ExtUserPtr?.Name;
|
||||
@@ -51,8 +52,8 @@ export default async function forwardDoc(request) {
|
||||
`<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background-color:white'><div>` +
|
||||
`${logo}</div><div style='padding:2px;font-family:system-ui;background-color:${themeColor}'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document Copy</p></div><div>` +
|
||||
`<p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document <strong>${docName}</strong> is attached to this email. Kindly download the document from the attachment.</p>` +
|
||||
`</div></div><div><p>This is an automated email from ${appName}. For any queries regarding this email, please contact the sender ${replyTo} directly. ` +
|
||||
`If you think this email is inappropriate or spam, you may file a complaint with ${appName}${opurl}.</p></div></div></body></html>`,
|
||||
`</div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, please contact the sender ${replyTo} directly. ` +
|
||||
`If you think this email is inappropriate or spam, you may file a complaint with ${TenantAppName}${opurl}.</p></div></div></body></html>`,
|
||||
};
|
||||
mailRes = await axios.post(`${cloudServerUrl}/functions/sendmailv3`, params, {
|
||||
headers: {
|
||||
|
||||
@@ -6,13 +6,17 @@ export default async function GetLogoByDomain(request) {
|
||||
try {
|
||||
const tenantCreditsQuery = new Parse.Query('partners_Tenant');
|
||||
tenantCreditsQuery.equalTo('Domain', domain);
|
||||
const res = await tenantCreditsQuery.first();
|
||||
const res = await tenantCreditsQuery.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
const updateRes = JSON.parse(JSON.stringify(res));
|
||||
return { logo: updateRes?.Logo, appname: appName, user: 'exist' };
|
||||
return {
|
||||
logo: updateRes?.Logo,
|
||||
appname: appName,
|
||||
user: 'exist',
|
||||
};
|
||||
} else {
|
||||
const tenantCreditsQuery = new Parse.Query('partners_Tenant');
|
||||
const tenantRes = await tenantCreditsQuery.first();
|
||||
const tenantRes = await tenantCreditsQuery.first({ useMasterKey: true });
|
||||
if (tenantRes) {
|
||||
return { logo: '', appname: appName, user: 'exist' };
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import axios from 'axios';
|
||||
export default async function Newsletter(request) {
|
||||
const name = request.params.name;
|
||||
const email = request.params.email;
|
||||
const email = request.params?.email?.toLowerCase()?.replace(/\s/g, '');
|
||||
const domain = request.params.domain;
|
||||
try {
|
||||
const envAppId = process.env.REACT_APP_APPID || 'opensign';
|
||||
|
||||
@@ -22,19 +22,20 @@ async function sendMailOTPv1(request) {
|
||||
//--for elearning app side
|
||||
let code = Math.floor(1000 + Math.random() * 9000);
|
||||
let email = request.params.email;
|
||||
var TenantId = request.params.TenantId ? request.params.TenantId : undefined;
|
||||
let TenantId = request.params.TenantId ? request.params.TenantId : undefined;
|
||||
const AppName = appName;
|
||||
|
||||
if (email) {
|
||||
const recipient = request.params.email;
|
||||
const mailsender = smtpenable ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER;
|
||||
try {
|
||||
await Parse.Cloud.sendEmail({
|
||||
from: appName + ' <' + mailsender + '>',
|
||||
from: AppName + ' <' + mailsender + '>',
|
||||
recipient: recipient,
|
||||
subject: `Your ${appName} OTP`,
|
||||
subject: `Your ${AppName} OTP`,
|
||||
text: 'This email is a test.',
|
||||
html:
|
||||
`<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'><div style='background-color:red;padding:2px;font-family:system-ui; background-color:#47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',>OTP Verification</p></div><div style='padding:20px'><p style='font-family:system-ui;font-size:14px'>Your OTP for ${appName} verification is:</p><p style=' text-decoration: none; font-weight: bolder; color:blue;font-size:45px;margin:20px'>` +
|
||||
`<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'><div style='background-color:red;padding:2px;font-family:system-ui; background-color:#47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',>OTP Verification</p></div><div style='padding:20px'><p style='font-family:system-ui;font-size:14px'>Your OTP for ${AppName} verification is:</p><p style=' text-decoration: none; font-weight: bolder; color:blue;font-size:45px;margin:20px'>` +
|
||||
code +
|
||||
'</p></div> </div> </div></body></html>',
|
||||
});
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
import axios from 'axios';
|
||||
import { cloudServerUrl } from '../../Utils.js';
|
||||
export default async function callWebhook(request) {
|
||||
const event = request.params.event;
|
||||
const body = request.params.body;
|
||||
const docId = body.objectId;
|
||||
const contactId = request.params.contactId;
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const appId = process.env.APP_ID;
|
||||
try {
|
||||
const docQuery = new Parse.Query('contracts_Document');
|
||||
docQuery.include('ExtUserPtr.TenantId');
|
||||
const docRes = await docQuery.get(docId, { useMasterKey: true });
|
||||
const isEnableOTP = docRes?.get('IsEnableOTP') || false;
|
||||
let userId;
|
||||
if (isEnableOTP) {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
userId = userRes.data && userRes.data.objectId;
|
||||
}
|
||||
if (!isEnableOTP || userId) {
|
||||
if (event === 'viewed' && contactId) {
|
||||
if (docRes) {
|
||||
const _docRes = docRes.toJSON();
|
||||
const userPtr = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: contactId,
|
||||
};
|
||||
const date = new Date().toISOString();
|
||||
const obj = {
|
||||
UserPtr: userPtr,
|
||||
SignedUrl: _docRes.SignedUrl,
|
||||
Activity: 'Viewed',
|
||||
ipAddress: request.headers['x-real-ip'],
|
||||
ViewedOn: date,
|
||||
};
|
||||
const isUserExist = _docRes?.AuditTrail?.some(
|
||||
x => x.UserPtr.objectId === contactId && x?.ViewedOn
|
||||
);
|
||||
if (!isUserExist) {
|
||||
const updateDoc = new Parse.Object('contracts_Document');
|
||||
updateDoc.id = docRes.id;
|
||||
if (_docRes?.AuditTrail && _docRes?.AuditTrail?.length > 0) {
|
||||
updateDoc.set('AuditTrail', [..._docRes?.AuditTrail, obj]);
|
||||
} else {
|
||||
updateDoc.set('AuditTrail', [obj]);
|
||||
}
|
||||
await updateDoc.save(null, { useMasterKey: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
const extendcls = new Parse.Query('contracts_Users');
|
||||
extendcls.equalTo('objectId', docRes.get('ExtUserPtr')?.id);
|
||||
// extendcls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
|
||||
const resExt = await extendcls.first({ useMasterKey: true });
|
||||
if (resExt) {
|
||||
const extUser = JSON.parse(JSON.stringify(resExt));
|
||||
if (extUser?.Webhook) {
|
||||
const params = { event: event, ...body };
|
||||
await axios
|
||||
.post(extUser?.Webhook, params, {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
.then(res => {
|
||||
try {
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', res?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err.message);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('Err send data to webhook', err.message);
|
||||
try {
|
||||
const webhook = new Parse.Object('contracts_Webhook');
|
||||
webhook.set('Log', err?.status);
|
||||
webhook.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
webhook.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err save in contracts_Webhook', err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
return { message: 'webhook called!' };
|
||||
}
|
||||
} else {
|
||||
return { message: 'User not found!' };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in callwebhook', err);
|
||||
return { message: 'Something went wrong!' };
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ export default async function createBatchContact(req) {
|
||||
TenantId: { __type: 'Pointer', className: 'partners_Tenant', objectId: x.TenantId },
|
||||
CreatedBy: { __type: 'Pointer', className: '_User', objectId: req.user.id },
|
||||
Name: x.Name,
|
||||
Email: x.Email,
|
||||
Email: x.Email?.toLowerCase()?.replace(/\s/g, ''),
|
||||
IsDeleted: false,
|
||||
IsImported: true,
|
||||
...(x?.Phone ? { Phone: `${x?.Phone}` } : {}),
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
import axios from 'axios';
|
||||
import {
|
||||
cloudServerUrl,
|
||||
replaceMailVaribles,
|
||||
} from '../../Utils.js';
|
||||
import { cloudServerUrl, replaceMailVaribles } from '../../Utils.js';
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const appId = process.env.APP_ID;
|
||||
async function deductcount(
|
||||
docsCount,
|
||||
extUserId,
|
||||
) {
|
||||
async function deductcount(docsCount, extUserId) {
|
||||
try {
|
||||
const extCls = new Parse.Object('contracts_Users');
|
||||
extCls.id = extUserId;
|
||||
@@ -18,9 +12,9 @@ async function deductcount(
|
||||
console.log('Err in deduct in quick send', err);
|
||||
}
|
||||
}
|
||||
async function sendMail(document) {
|
||||
async function sendMail(document, publicUrl) {
|
||||
//sessionToken
|
||||
const baseUrl = new URL(process.env.PUBLIC_URL);
|
||||
const baseUrl = new URL(publicUrl); //process.env.PUBLIC_URL
|
||||
|
||||
// console.log("pdfDetails", pdfDetails);
|
||||
const timeToCompleteDays = document?.TimeToCompleteDays || 15;
|
||||
@@ -33,10 +27,8 @@ async function sendMail(document) {
|
||||
year: 'numeric',
|
||||
});
|
||||
let signerMail = document.Placeholders;
|
||||
const senderName =
|
||||
document.ExtUserPtr.Name;
|
||||
const senderEmail =
|
||||
document.ExtUserPtr.Email;
|
||||
const senderName = document.ExtUserPtr.Name;
|
||||
const senderEmail = document.ExtUserPtr.Email;
|
||||
|
||||
if (document.SendinOrder) {
|
||||
signerMail = signerMail.slice();
|
||||
@@ -70,6 +62,7 @@ async function sendMail(document) {
|
||||
'</body></html>';
|
||||
const variables = {
|
||||
document_title: document?.Name,
|
||||
note: document?.Note || '',
|
||||
sender_name: senderName,
|
||||
sender_mail: senderEmail,
|
||||
sender_phone: senderObj?.Phone || '',
|
||||
@@ -83,6 +76,7 @@ async function sendMail(document) {
|
||||
replaceVar = replaceMailVaribles(mailSubject, htmlReqBody, variables);
|
||||
}
|
||||
const mailparam = {
|
||||
note: document?.Note || '',
|
||||
senderName: senderName,
|
||||
senderMail: senderEmail,
|
||||
title: document.Name,
|
||||
@@ -94,8 +88,7 @@ async function sendMail(document) {
|
||||
extUserId: document.ExtUserPtr.objectId,
|
||||
recipient: objectId ? existSigner?.Email : signerMail[i].email,
|
||||
subject: replaceVar?.subject ? replaceVar?.subject : mailTemplate(mailparam).subject,
|
||||
from:
|
||||
document.ExtUserPtr.Email,
|
||||
from: document.ExtUserPtr.Email,
|
||||
replyto: senderEmail || '',
|
||||
html: replaceVar?.body ? replaceVar?.body : mailTemplate(mailparam).body,
|
||||
};
|
||||
@@ -108,13 +101,7 @@ async function sendMail(document) {
|
||||
}
|
||||
}
|
||||
}
|
||||
async function batchQuery(
|
||||
userId,
|
||||
Documents,
|
||||
Ip,
|
||||
parseConfig,
|
||||
type
|
||||
) {
|
||||
async function batchQuery(userId, Documents, Ip, parseConfig, type, publicUrl) {
|
||||
const extCls = new Parse.Query('contracts_Users');
|
||||
extCls.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
@@ -199,22 +186,22 @@ async function batchQuery(
|
||||
};
|
||||
});
|
||||
// console.log('requests ', requests);
|
||||
if (requests?.length > 0) {
|
||||
const newrequests = [requests?.[0]];
|
||||
const response = await axios.post('batch', { requests: newrequests }, parseConfig);
|
||||
// Handle the batch query response
|
||||
// console.log('Batch query response:', response.data);
|
||||
if (response.data && response.data.length > 0) {
|
||||
const document = Documents?.[0];
|
||||
const updateDocuments = {
|
||||
...document,
|
||||
objectId: response.data[0]?.success?.objectId,
|
||||
createdAt: response.data[0]?.success?.createdAt,
|
||||
};
|
||||
deductcount(response.data.length, resExt.id);
|
||||
sendMail(updateDocuments); //sessionToken
|
||||
return 'success';
|
||||
}
|
||||
if (requests?.length > 0) {
|
||||
const newrequests = [requests?.[0]];
|
||||
const response = await axios.post('batch', { requests: newrequests }, parseConfig);
|
||||
// Handle the batch query response
|
||||
// console.log('Batch query response:', response.data);
|
||||
if (response.data && response.data.length > 0) {
|
||||
const document = Documents?.[0];
|
||||
const updateDocuments = {
|
||||
...document,
|
||||
objectId: response.data[0]?.success?.objectId,
|
||||
createdAt: response.data[0]?.success?.createdAt,
|
||||
};
|
||||
deductcount(response.data.length, resExt.id);
|
||||
sendMail(updateDocuments, publicUrl); //sessionToken
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
const code = error?.response?.data?.code || error?.response?.status || error?.code || 400;
|
||||
@@ -236,6 +223,8 @@ export default async function createBatchDocs(request) {
|
||||
const type = request.headers?.type || 'quicksend';
|
||||
const Documents = JSON.parse(strDocuments);
|
||||
const Ip = request?.headers?.['x-real-ip'] || '';
|
||||
// Access the host from the headers
|
||||
const publicUrl = request.headers.public_url;
|
||||
const parseConfig = {
|
||||
baseURL: serverUrl,
|
||||
headers: {
|
||||
@@ -246,9 +235,8 @@ export default async function createBatchDocs(request) {
|
||||
};
|
||||
try {
|
||||
if (request?.user) {
|
||||
return await batchQuery(request.user.id, Documents, Ip, parseConfig, '', type);
|
||||
}
|
||||
else {
|
||||
return await batchQuery(request.user.id, Documents, Ip, parseConfig, '', type, publicUrl);
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@@ -15,7 +15,7 @@ export default async function editContact(request) {
|
||||
const query = new Parse.Query('contracts_Contactbook');
|
||||
query.equalTo('CreatedBy', createdBy);
|
||||
query.notEqualTo('IsDeleted', true);
|
||||
query.equalTo('Email', email);
|
||||
query.equalTo('Email', email?.toLowerCase()?.replace(/\s/g, ''));
|
||||
const isContactExist = await query.first({ useMasterKey: true });
|
||||
if (isContactExist) {
|
||||
throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Contact already exists.');
|
||||
@@ -25,7 +25,7 @@ export default async function editContact(request) {
|
||||
if (phone) {
|
||||
contactQuery.set('Phone', phone);
|
||||
}
|
||||
contactQuery.set('Email', email);
|
||||
contactQuery.set('Email', email?.toLowerCase()?.replace(/\s/g, ''));
|
||||
contactQuery.set('UserRole', 'contracts_Guest');
|
||||
contactQuery.set('IsDeleted', false);
|
||||
contactQuery.set('TenantId', {
|
||||
@@ -37,9 +37,9 @@ export default async function editContact(request) {
|
||||
const _users = Parse.Object.extend('User');
|
||||
const _user = new _users();
|
||||
_user.set('name', name);
|
||||
_user.set('username', email);
|
||||
_user.set('email', email);
|
||||
_user.set('password', email);
|
||||
_user.set('username', email?.toLowerCase()?.replace(/\s/g, ''));
|
||||
_user.set('email', email?.toLowerCase()?.replace(/\s/g, ''));
|
||||
_user.set('password', email?.toLowerCase()?.replace(/\s/g, ''));
|
||||
if (phone) {
|
||||
_user.set('phone', phone);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
cloudServerUrl,
|
||||
} from '../../Utils.js';
|
||||
import { cloudServerUrl } from '../../Utils.js';
|
||||
export default async function getDocument(request) {
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const docId = request.params.docId;
|
||||
@@ -47,13 +45,12 @@ export default async function getDocument(request) {
|
||||
console.log('err user in not authenticated', err);
|
||||
return { error: "You don't have access of this document!" };
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return { error: "You don't have access of this document!" };
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return { error: "You don't have access of this document!" };
|
||||
return { error: "document deleted or you don't have access." };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err', err);
|
||||
|
||||
@@ -52,7 +52,8 @@ const saveRoleContact = async contact => {
|
||||
// `linkContactToDoc` cloud function is used to create contact, add this contact in contracts_Guest role and
|
||||
// save contact pointer in placeholder, signers and ACL of Document
|
||||
export default async function linkContactToDoc(req) {
|
||||
const email = req.params.email;
|
||||
const requestemail = req.params?.email;
|
||||
const email = requestemail?.toLowerCase()?.replace(/\s/g, '');
|
||||
const docId = req.params.docId;
|
||||
const name = req.params.name;
|
||||
const phone = req.params.phone;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { PDFDocument, rgb } from 'pdf-lib';
|
||||
import fs from 'node:fs';
|
||||
import fontkit from '@pdf-lib/fontkit';
|
||||
import {
|
||||
formatTimeInTimezone,
|
||||
} from '../../../Utils.js';
|
||||
import { formatDateTime } from '../../../Utils.js';
|
||||
|
||||
export default async function GenerateCertificate(docDetails) {
|
||||
const timezone = docDetails?.ExtUserPtr?.Timezone || '';
|
||||
const Is12Hr = docDetails?.ExtUserPtr?.Is12HourTime || false;
|
||||
const DateFormat = docDetails?.ExtUserPtr?.DateFormat || 'MM/DD/YYYY';
|
||||
const pdfDoc = await PDFDocument.create();
|
||||
// `fontBytes` is used to embed custom font in pdf
|
||||
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 titleUnderline = rgb(0, 0.2, 0.4); // rgb(0.12, 0.12, 0.12);
|
||||
const title = 25;
|
||||
const subtitle = 20;
|
||||
const text = 14;
|
||||
const subtitle = 16;
|
||||
const text = 13;
|
||||
const signertext = 13;
|
||||
const timeText = 11;
|
||||
const textKeyColor = rgb(0.12, 0.12, 0.12);
|
||||
const textValueColor = rgb(0.3, 0.3, 0.3);
|
||||
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 signersCount = docDetails?.Signers?.length || 1;
|
||||
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 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 company = docDetails?.ExtUserPtr?.Company || '';
|
||||
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 filteredaudit = docDetails?.AuditTrail?.filter(x => x?.UserPtr?.objectId);
|
||||
const auditTrail =
|
||||
@@ -75,15 +79,15 @@ export default async function GenerateCertificate(docDetails) {
|
||||
borderColor: borderColor,
|
||||
borderWidth: 1,
|
||||
});
|
||||
page.drawImage(pngImage, {
|
||||
x: 30,
|
||||
y: 790,
|
||||
width: 100,
|
||||
height: 25,
|
||||
});
|
||||
page.drawImage(pngImage, {
|
||||
x: 30,
|
||||
y: 790,
|
||||
width: 100,
|
||||
height: 25,
|
||||
});
|
||||
|
||||
page.drawText(generatedOn, {
|
||||
x: 320,
|
||||
x: Math.max(startX, maxX), // Adjusts dynamically 320
|
||||
y: 810,
|
||||
size: 12,
|
||||
font: timesRomanFont,
|
||||
@@ -92,13 +96,13 @@ export default async function GenerateCertificate(docDetails) {
|
||||
|
||||
page.drawText('Certificate of Completion', {
|
||||
x: 160,
|
||||
y: 750,
|
||||
y: 755,
|
||||
size: title,
|
||||
font: timesRomanFont,
|
||||
color: titleColor,
|
||||
});
|
||||
|
||||
const underlineY = 740;
|
||||
const underlineY = 745;
|
||||
page.drawLine({
|
||||
start: { x: 30, y: underlineY },
|
||||
end: { x: width - 30, y: underlineY },
|
||||
@@ -108,7 +112,7 @@ export default async function GenerateCertificate(docDetails) {
|
||||
|
||||
page.drawText('Summary', {
|
||||
x: 30,
|
||||
y: 710,
|
||||
y: 727,
|
||||
size: subtitle,
|
||||
font: timesRomanFont,
|
||||
color: titleColor,
|
||||
@@ -116,15 +120,15 @@ export default async function GenerateCertificate(docDetails) {
|
||||
|
||||
page.drawText('Document Id :', {
|
||||
x: 30,
|
||||
y: 685,
|
||||
y: 710,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
page.drawText(docDetails.objectId, {
|
||||
x: 115,
|
||||
y: 685,
|
||||
x: 110,
|
||||
y: 710,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
@@ -132,15 +136,15 @@ export default async function GenerateCertificate(docDetails) {
|
||||
|
||||
page.drawText('Document Name :', {
|
||||
x: 30,
|
||||
y: 665,
|
||||
y: 690,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
page.drawText(docDetails?.Name, {
|
||||
x: 140,
|
||||
y: 665,
|
||||
x: 130,
|
||||
y: 690,
|
||||
size: docDetails?.Name?.length >= 78 ? 12 : text,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
@@ -148,52 +152,52 @@ export default async function GenerateCertificate(docDetails) {
|
||||
|
||||
page.drawText('Organization :', {
|
||||
x: 30,
|
||||
y: 645,
|
||||
y: 670,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
page.drawText(company, {
|
||||
x: 115,
|
||||
y: 645,
|
||||
x: 110,
|
||||
y: 670,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
page.drawText('Created on :', {
|
||||
x: 30,
|
||||
y: 625,
|
||||
y: 650,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
page.drawText(`${createdAtperTimezone}`, {
|
||||
x: 105,
|
||||
y: 625,
|
||||
x: 97,
|
||||
y: 650,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
page.drawText('Completed on :', {
|
||||
x: 30,
|
||||
y: 605,
|
||||
y: 630,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
page.drawText(`${completedUTCtime}`, {
|
||||
x: 125,
|
||||
y: 605,
|
||||
x: 115,
|
||||
y: 630,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
page.drawText('Signers :', {
|
||||
x: 30,
|
||||
y: 585,
|
||||
y: 610,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
@@ -201,73 +205,76 @@ export default async function GenerateCertificate(docDetails) {
|
||||
|
||||
page.drawText(`${signersCount}`, {
|
||||
x: 80,
|
||||
y: 585,
|
||||
y: 610,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
page.drawText('Document originator', {
|
||||
x: 30,
|
||||
y: 565,
|
||||
y: 590,
|
||||
size: 17,
|
||||
font: timesRomanFont,
|
||||
color: titleColor,
|
||||
});
|
||||
page.drawText('Name :', {
|
||||
x: 60,
|
||||
y: 545,
|
||||
y: 573,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
page.drawText(ownerName, {
|
||||
x: 105,
|
||||
y: 545,
|
||||
y: 573,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
page.drawText('Email :', {
|
||||
x: 60,
|
||||
y: 525,
|
||||
y: 553,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
page.drawText(ownerEmail, {
|
||||
x: 105,
|
||||
y: 525,
|
||||
y: 553,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
page.drawText('IP address :', {
|
||||
x: 60,
|
||||
y: 505,
|
||||
y: 533,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
page.drawText(`${OriginIp}`, {
|
||||
x: 130,
|
||||
y: 505,
|
||||
x: 125,
|
||||
y: 533,
|
||||
size: text,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
|
||||
page.drawLine({
|
||||
start: { x: 30, y: 495 },
|
||||
end: { x: width - 30, y: 495 },
|
||||
start: { x: 30, y: 527 },
|
||||
end: { x: width - 30, y: 527 },
|
||||
color: rgb(0.12, 0.12, 0.12),
|
||||
thickness: 0.5,
|
||||
});
|
||||
let yPosition1 = 475;
|
||||
let yPosition2 = 455;
|
||||
let yPosition3 = 435;
|
||||
let yPosition4 = 415;
|
||||
let yPosition5 = 395;
|
||||
let yPosition6 = 360;
|
||||
let yPosition1 = 512;
|
||||
let yPosition2 = 498;
|
||||
let yPosition3 = 478;
|
||||
let yPosition4 = 458;
|
||||
let yPosition5 = 438;
|
||||
let yPosition6 = 418;
|
||||
let yPosition7 = 398;
|
||||
let yPosition8 = 363;
|
||||
|
||||
auditTrail.slice(0, 3).forEach(async (x, i) => {
|
||||
const embedPng = x.Signature ? await pdfDoc.embedPng(x.Signature) : '';
|
||||
page.drawText(`Signer ${i + 1}`, {
|
||||
@@ -280,7 +287,7 @@ export default async function GenerateCertificate(docDetails) {
|
||||
page.drawText('Name :', {
|
||||
x: 30,
|
||||
y: yPosition2,
|
||||
size: text,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
@@ -288,32 +295,32 @@ export default async function GenerateCertificate(docDetails) {
|
||||
page.drawText(x?.Name, {
|
||||
x: 75,
|
||||
y: yPosition2,
|
||||
size: text,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
|
||||
page.drawText('Viewed on :', {
|
||||
x: half + 45,
|
||||
y: yPosition2,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
//new Date(x.ViewedOn).toUTCString()
|
||||
page.drawText(`${formatTimeInTimezone(x.ViewedOn, timezone)}`, {
|
||||
x: half + 102,
|
||||
y: yPosition2,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
if (IsEnableOTP) {
|
||||
page.drawText('Security level :', {
|
||||
x: half + 120,
|
||||
y: yPosition2,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
page.drawText('Email, OTP Auth', {
|
||||
x: half + 190,
|
||||
y: yPosition2,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
}
|
||||
|
||||
page.drawText('Email :', {
|
||||
x: 30,
|
||||
y: yPosition3,
|
||||
size: text,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
@@ -321,70 +328,70 @@ export default async function GenerateCertificate(docDetails) {
|
||||
page.drawText(x?.Email, {
|
||||
x: 75,
|
||||
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,
|
||||
color: textValueColor,
|
||||
});
|
||||
|
||||
page.drawText('Signed on :', {
|
||||
x: half + 45,
|
||||
y: yPosition3 + 5,
|
||||
size: timeText,
|
||||
x: 30,
|
||||
y: yPosition5,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
// new Date(x.SignedOn).toUTCString()
|
||||
page.drawText(`${formatTimeInTimezone(x.SignedOn, timezone)}`, {
|
||||
x: half + 98,
|
||||
y: yPosition3 + 5,
|
||||
size: timeText,
|
||||
page.drawText(`${formatDateTime(x.SignedOn, DateFormat, timezone, Is12Hr)}`, {
|
||||
x: 95,
|
||||
y: yPosition5,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
|
||||
page.drawText('IP address :', {
|
||||
x: 30,
|
||||
y: yPosition4,
|
||||
size: text,
|
||||
y: yPosition6,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
page.drawText(x?.ipAddress, {
|
||||
x: 100,
|
||||
y: yPosition4,
|
||||
size: 13,
|
||||
x: 95,
|
||||
y: yPosition6,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
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 :', {
|
||||
x: 30,
|
||||
y: yPosition5,
|
||||
size: text,
|
||||
y: yPosition7,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
page.drawRectangle({
|
||||
x: 98,
|
||||
y: yPosition5 - 30,
|
||||
y: yPosition7 - 30,
|
||||
width: 104,
|
||||
height: 44,
|
||||
borderColor: rgb(0.22, 0.18, 0.47),
|
||||
@@ -393,24 +400,26 @@ export default async function GenerateCertificate(docDetails) {
|
||||
if (embedPng) {
|
||||
page.drawImage(embedPng, {
|
||||
x: 100,
|
||||
y: yPosition5 - 27,
|
||||
y: yPosition7 - 27,
|
||||
width: 100,
|
||||
height: 40,
|
||||
});
|
||||
}
|
||||
page.drawLine({
|
||||
start: { x: 30, y: yPosition6 },
|
||||
end: { x: width - 30, y: yPosition6 },
|
||||
start: { x: 30, y: yPosition8 },
|
||||
end: { x: width - 30, y: yPosition8 },
|
||||
color: rgb(0.12, 0.12, 0.12),
|
||||
thickness: 0.5,
|
||||
});
|
||||
|
||||
yPosition1 = yPosition6 - 20;
|
||||
yPosition1 = yPosition8 - 20;
|
||||
yPosition2 = yPosition1 - 20;
|
||||
yPosition3 = yPosition2 - 20;
|
||||
yPosition4 = yPosition3 - 20;
|
||||
yPosition5 = yPosition4 - 20;
|
||||
yPosition6 = yPosition6 - 140;
|
||||
yPosition6 = yPosition5 - 20;
|
||||
yPosition7 = yPosition6 - 20;
|
||||
yPosition8 = yPosition8 - 174;
|
||||
});
|
||||
|
||||
if (auditTrail.length > 3) {
|
||||
@@ -420,7 +429,7 @@ export default async function GenerateCertificate(docDetails) {
|
||||
const embedPng = x.Signature ? await pdfDoc.embedPng(x.Signature) : '';
|
||||
|
||||
// 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 (remainingSpace < 90) {
|
||||
@@ -440,7 +449,10 @@ export default async function GenerateCertificate(docDetails) {
|
||||
yPosition3 = yPosition2 - 20;
|
||||
yPosition4 = yPosition3 - 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}`, {
|
||||
@@ -453,7 +465,7 @@ export default async function GenerateCertificate(docDetails) {
|
||||
currentPage.drawText('Name :', {
|
||||
x: 30,
|
||||
y: yPosition2,
|
||||
size: text,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
@@ -461,32 +473,32 @@ export default async function GenerateCertificate(docDetails) {
|
||||
currentPage.drawText(x?.Name, {
|
||||
x: 75,
|
||||
y: yPosition2,
|
||||
size: text,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
|
||||
currentPage.drawText('Viewed on :', {
|
||||
x: half + 45,
|
||||
y: yPosition2,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
// new Date(x.ViewedOn).toUTCString()
|
||||
currentPage.drawText(`${formatTimeInTimezone(x.ViewedOn, timezone)}`, {
|
||||
x: half + 102,
|
||||
y: yPosition2,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
if (IsEnableOTP) {
|
||||
currentPage.drawText('Security level :', {
|
||||
x: half + 120,
|
||||
y: yPosition2,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
currentPage.drawText(`Email, OTP Auth`, {
|
||||
x: half + 190,
|
||||
y: yPosition2,
|
||||
size: timeText,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
}
|
||||
|
||||
currentPage.drawText('Email :', {
|
||||
x: 30,
|
||||
y: yPosition3,
|
||||
size: text,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
@@ -494,70 +506,68 @@ export default async function GenerateCertificate(docDetails) {
|
||||
currentPage.drawText(x?.Email, {
|
||||
x: 75,
|
||||
y: yPosition3,
|
||||
size: text,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textValueColor,
|
||||
});
|
||||
|
||||
currentPage.drawText('Signed on :', {
|
||||
x: half + 45,
|
||||
y: yPosition3 + 5,
|
||||
size: timeText,
|
||||
currentPage.drawText('Viewed on :', {
|
||||
x: 30,
|
||||
y: yPosition4,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
// new Date(x.SignedOn).toUTCString()
|
||||
currentPage.drawText(`${formatTimeInTimezone(x.SignedOn, timezone)}`, {
|
||||
x: half + 98,
|
||||
y: yPosition3 + 5,
|
||||
size: timeText,
|
||||
currentPage.drawText(`${formatDateTime(x.ViewedOn, DateFormat, timezone, Is12Hr)}`, {
|
||||
x: 97,
|
||||
y: yPosition4,
|
||||
size: signertext,
|
||||
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,
|
||||
color: textValueColor,
|
||||
});
|
||||
|
||||
currentPage.drawText('IP address :', {
|
||||
x: 30,
|
||||
y: yPosition4,
|
||||
size: text,
|
||||
y: yPosition6,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
|
||||
currentPage.drawText(x?.ipAddress, {
|
||||
x: 100,
|
||||
y: yPosition4,
|
||||
size: text,
|
||||
y: yPosition6,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
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 :', {
|
||||
x: 30,
|
||||
y: yPosition5,
|
||||
size: text,
|
||||
y: yPosition7,
|
||||
size: signertext,
|
||||
font: timesRomanFont,
|
||||
color: textKeyColor,
|
||||
});
|
||||
currentPage.drawRectangle({
|
||||
x: 98,
|
||||
y: yPosition5 - 27,
|
||||
y: yPosition7 - 27,
|
||||
width: 104,
|
||||
height: 44,
|
||||
borderColor: rgb(0.22, 0.18, 0.47),
|
||||
@@ -566,26 +576,28 @@ export default async function GenerateCertificate(docDetails) {
|
||||
if (embedPng) {
|
||||
currentPage.drawImage(embedPng, {
|
||||
x: 100,
|
||||
y: yPosition5 - 25,
|
||||
y: yPosition7 - 25,
|
||||
width: 100,
|
||||
height: 40,
|
||||
});
|
||||
}
|
||||
|
||||
currentPage.drawLine({
|
||||
start: { x: 30, y: yPosition6 },
|
||||
end: { x: width - 30, y: yPosition6 },
|
||||
start: { x: 30, y: yPosition8 },
|
||||
end: { x: width - 30, y: yPosition8 },
|
||||
color: rgb(0.12, 0.12, 0.12),
|
||||
thickness: 0.5,
|
||||
});
|
||||
|
||||
// Update y positions for the next entry
|
||||
yPosition1 = yPosition6 - 20;
|
||||
yPosition1 = yPosition8 - 20;
|
||||
yPosition2 = yPosition1 - 20;
|
||||
yPosition3 = yPosition2 - 20;
|
||||
yPosition4 = yPosition3 - 20;
|
||||
yPosition5 = yPosition4 - 20;
|
||||
yPosition6 = yPosition6 - 140;
|
||||
yPosition6 = yPosition5 - 20;
|
||||
yPosition7 = yPosition6 - 20;
|
||||
yPosition8 = yPosition8 - 174;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,6 @@ const APPID = process.env.APP_ID;
|
||||
const masterKEY = process.env.MASTER_KEY;
|
||||
const eSignName = 'OpenSign';
|
||||
const eSigncontact = 'hello@opensignlabs.com';
|
||||
const logo =
|
||||
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
|
||||
const opurl = ` <a href=www.opensignlabs.com target=_blank>here</a>`;
|
||||
|
||||
// `updateDoc` is used to create url in from pdfFile
|
||||
async function uploadFile(pdfName, filepath) {
|
||||
@@ -93,8 +90,12 @@ async function updateDoc(docId, url, userId, ipAddress, data, className, sign) {
|
||||
}
|
||||
|
||||
// `sendNotifyMail` is used to send notification mail of signer signed the document
|
||||
async function sendNotifyMail(doc, signUser, mailProvider) {
|
||||
async function sendNotifyMail(doc, signUser, mailProvider, publicUrl) {
|
||||
try {
|
||||
const TenantAppName = appName;
|
||||
const logo =
|
||||
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
|
||||
const opurl = ` <a href=www.opensignlabs.com target=_blank>here</a>`;
|
||||
const auditTrailCount = doc?.AuditTrail?.filter(x => x.Activity === 'Signed')?.length || 0;
|
||||
const signersCount = doc?.Placeholders?.length;
|
||||
const remaingsign = signersCount - auditTrailCount;
|
||||
@@ -105,18 +106,18 @@ async function sendNotifyMail(doc, signUser, mailProvider) {
|
||||
const creatorEmail = doc.ExtUserPtr.Email;
|
||||
const signerName = signUser.Name;
|
||||
const signerEmail = signUser.Email;
|
||||
const viewDocUrl = `${process.env.PUBLIC_URL}/recipientSignPdf/${doc.objectId}`;
|
||||
const viewDocUrl = `${publicUrl}/recipientSignPdf/${doc.objectId}`; // ` ${process.env.PUBLIC_URL}/recipientSignPdf/${doc.objectId}`;
|
||||
const subject = `Document "${pdfName}" has been signed by ${signerName}`;
|
||||
const body =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background-color:white'>" +
|
||||
`<div>${logo}</div><div style='padding:2px;font-family:system-ui;background-color:#47a3ad'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document signed by ${signerName}</p>` +
|
||||
`</div><div style='padding:20px;font-family:system-ui;font-size:14px'><p>Dear ${creatorName},</p><p>${pdfName} has been signed by ${signerName} "${signerEmail}" successfully</p>` +
|
||||
`<p><a href=${viewDocUrl} target=_blank>View Document</a></p></div></div><div><p>This is an automated email from ${appName}. For any queries regarding this email, ` +
|
||||
`please contact the sender ${creatorEmail} directly. If you think this email is inappropriate or spam, you may file a complaint with ${appName}${opurl}.</p></div></div></body></html>`;
|
||||
`<p><a href=${viewDocUrl} target=_blank>View Document</a></p></div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, ` +
|
||||
`please contact the sender ${creatorEmail} directly. If you think this email is inappropriate or spam, you may file a complaint with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
|
||||
|
||||
const params = {
|
||||
extUserId: sender.objectId,
|
||||
from: appName,
|
||||
from: TenantAppName,
|
||||
recipient: creatorEmail,
|
||||
subject: subject,
|
||||
pdfName: pdfName,
|
||||
@@ -142,6 +143,10 @@ async function sendCompletedMail(obj) {
|
||||
const doc = obj.doc;
|
||||
const sender = obj.doc.ExtUserPtr;
|
||||
const pdfName = doc.Name;
|
||||
const TenantAppName = appName;
|
||||
const logo =
|
||||
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
|
||||
const opurl = ` <a href=www.opensignlabs.com target=_blank>here</a>`;
|
||||
let signersMail;
|
||||
if (doc?.Signers?.length > 0) {
|
||||
const isOwnerExistsinSigners = doc?.Signers?.find(x => x.Email === sender.Email);
|
||||
@@ -157,8 +162,8 @@ async function sendCompletedMail(obj) {
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background-color:white'>" +
|
||||
`<div>${logo}</div><div style='padding:2px;font-family:system-ui;background-color:#47a3ad'><p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document signed successfully</p></div><div>` +
|
||||
`<p style='padding:20px;font-family:system-ui;font-size:14px'>All parties have successfully signed the document <b>"${pdfName}"</b>. Kindly download the document from the attachment.</p>` +
|
||||
`</div></div><div><p>This is an automated email from ${appName}. For any queries regarding this email, please contact the sender ${sender.Email} directly.` +
|
||||
`If you think this email is inappropriate or spam, you may file a complaint with ${appName}${opurl}.</p></div></div></body></html>`;
|
||||
`</div></div><div><p>This is an automated email from ${TenantAppName}. For any queries regarding this email, please contact the sender ${sender.Email} directly.` +
|
||||
`If you think this email is inappropriate or spam, you may file a complaint with ${TenantAppName}${opurl}.</p></div></div></body></html>`;
|
||||
|
||||
if (obj?.isCustomMail) {
|
||||
const tenant = sender?.TenantId;
|
||||
@@ -175,7 +180,7 @@ async function sendCompletedMail(obj) {
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
const tenantRes = await tenantQuery.first();
|
||||
const tenantRes = await tenantQuery.first({ useMasterKey: true });
|
||||
if (tenantRes) {
|
||||
const _tenantRes = JSON.parse(JSON.stringify(tenantRes));
|
||||
subject = _tenantRes?.CompletionSubject || '';
|
||||
@@ -209,18 +214,19 @@ async function sendCompletedMail(obj) {
|
||||
subject = replaceVar.subject;
|
||||
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 = {
|
||||
extUserId: sender.objectId,
|
||||
url: url,
|
||||
from: appName,
|
||||
from: TenantAppName,
|
||||
replyto: doc?.ExtUserPtr?.Email || '',
|
||||
recipient: recipient,
|
||||
subject: subject,
|
||||
pdfName: pdfName,
|
||||
html: body,
|
||||
mailProvider: obj.mailProvider,
|
||||
bcc: Bcc,
|
||||
bcc: updatedBcc?.length > 0 ? updatedBcc : '',
|
||||
certificatePath: `./exports/signed_certificate_${doc.objectId}.pdf`,
|
||||
filename: obj?.filename,
|
||||
};
|
||||
@@ -300,6 +306,7 @@ async function PDF(req) {
|
||||
const isCustomMail = req.params.isCustomCompletionMail || false;
|
||||
const mailProvider = req.params.mailProvider || '';
|
||||
const sign = req.params.signature || '';
|
||||
const publicUrl = req.headers.public_url;
|
||||
// below bode is used to get info of docId
|
||||
const docQuery = new Parse.Query('contracts_Document');
|
||||
docQuery.include('ExtUserPtr,Signers,ExtUserPtr.TenantId,Bcc');
|
||||
@@ -425,7 +432,7 @@ async function PDF(req) {
|
||||
className, // className based on flow
|
||||
sign // sign base64
|
||||
);
|
||||
sendNotifyMail(_resDoc, signUser, mailProvider);
|
||||
sendNotifyMail(_resDoc, signUser, mailProvider, publicUrl);
|
||||
saveFileUsage(pdfSize, data.imageUrl, _resDoc?.CreatedBy?.objectId);
|
||||
if (updatedDoc && updatedDoc.isCompleted) {
|
||||
const doc = { ..._resDoc, AuditTrail: updatedDoc.AuditTrail, SignedUrl: data.imageUrl };
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
const randomId = () => Math.floor(1000 + Math.random() * 9000);
|
||||
export default async function saveAsTemplate(request) {
|
||||
const docId = request.params.docId;
|
||||
const Ip = request?.headers?.['x-real-ip'] || '';
|
||||
|
||||
if (!request.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'user is not authenticated.');
|
||||
}
|
||||
try {
|
||||
const docQuery = new Parse.Query('contracts_Document');
|
||||
docQuery.equalTo('objectId', docId);
|
||||
docQuery.equalTo('CreatedBy', request.user);
|
||||
docQuery.include('ExtUserPtr');
|
||||
docQuery.include('ExtUserPtr.TenantId');
|
||||
docQuery.notEqualTo('IsArchive', true);
|
||||
const docRes = await docQuery.first({ useMasterKey: true });
|
||||
if (docRes) {
|
||||
const _docRes = docRes?.toJSON();
|
||||
const templateCls = new Parse.Object('contracts_Template');
|
||||
templateCls.set('URL', _docRes?.URL);
|
||||
templateCls.set('Name', _docRes?.Name);
|
||||
templateCls.set('Note', _docRes?.Note);
|
||||
templateCls.set('Description', _docRes?.Description);
|
||||
templateCls.set('OriginIp', Ip);
|
||||
templateCls.set('SendinOrder', _docRes?.SendinOrder || false);
|
||||
templateCls.set('AutomaticReminders', _docRes?.AutomaticReminders || false);
|
||||
templateCls.set('ExtUserPtr', _docRes?.ExtUserPtr);
|
||||
templateCls.set('CreatedBy', _docRes?.CreatedBy);
|
||||
templateCls.set('IsEnableOTP', _docRes?.IsEnableOTP === true ? true : false);
|
||||
templateCls.set('IsTourEnabled', _docRes?.IsTourEnabled === true ? true : false);
|
||||
templateCls.set('AllowModifications', _docRes?.AllowModifications || false);
|
||||
templateCls.set('EmailSenderName', _docRes?.EmailSenderName);
|
||||
templateCls.set('SenderName', _docRes?.SenderName);
|
||||
templateCls.set('SenderMail', _docRes?.SenderMail);
|
||||
templateCls.set('FileAdapterId', _docRes?.FileAdapterId);
|
||||
templateCls.set('RequestBody', _docRes?.RequestBody);
|
||||
templateCls.set('RequestSubject', _docRes?.RequestSubject);
|
||||
templateCls.set('NextReminderDate', _docRes?.NextReminderDate);
|
||||
templateCls.set('RedirectUrl', _docRes?.RedirectUrl);
|
||||
templateCls.set(
|
||||
'NotifyOnSignatures',
|
||||
_docRes?.NotifyOnSignatures !== undefined ? _docRes?.NotifyOnSignatures : false
|
||||
);
|
||||
templateCls.set(
|
||||
'TimeToCompleteDays',
|
||||
_docRes?.TimeToCompleteDays ? parseInt(_docRes?.TimeToCompleteDays) : 15
|
||||
);
|
||||
if (_docRes?.RemindOnceInEvery) {
|
||||
templateCls.set('RemindOnceInEvery', parseInt(_docRes?.RemindOnceInEvery));
|
||||
}
|
||||
|
||||
if (_docRes?.Placeholders?.length > 0) {
|
||||
if (_docRes?.IsSignyourself) {
|
||||
const placeHolders = {
|
||||
signerObjId: '',
|
||||
signerPtr: {},
|
||||
Id: randomId(),
|
||||
blockColor: '#93a3db',
|
||||
Role: 'Role 1',
|
||||
email: '',
|
||||
placeHolder: _docRes?.Placeholders,
|
||||
};
|
||||
templateCls.set('Placeholders', [placeHolders]);
|
||||
} else {
|
||||
const placeHolders = _docRes?.Placeholders?.map((x, i) => {
|
||||
const email = x.email ? { email: '' } : {};
|
||||
return { ...x, signerObjId: '', signerPtr: {}, Role: 'Role ' + (i + 1), ...email };
|
||||
});
|
||||
templateCls.set('Placeholders', placeHolders);
|
||||
}
|
||||
}
|
||||
if (_docRes?.SignatureType?.length > 0) {
|
||||
templateCls.set('SignatureType', _docRes?.SignatureType);
|
||||
}
|
||||
if (_docRes?.Bcc?.length > 0) {
|
||||
templateCls.set('Bcc', _docRes?.Bcc);
|
||||
}
|
||||
const res = await templateCls.save(null, { useMasterKey: true });
|
||||
return res;
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'document not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err in save as template', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
export default async function savecontact(request) {
|
||||
const name = request.params.name;
|
||||
const phone = request.params.phone;
|
||||
const email = request.params.email;
|
||||
const requestemail = request.params?.email;
|
||||
const email = requestemail?.toLowerCase()?.replace(/\s/g, '');
|
||||
const tenantId = request.params.tenantId;
|
||||
|
||||
if (request.user) {
|
||||
|
||||
@@ -31,120 +31,97 @@ async function sendMailProvider(req, plan, monthchange) {
|
||||
if (req.params.url) {
|
||||
const randomNumber = Math.floor(Math.random() * 5000);
|
||||
const testPdf = `test_${randomNumber}.pdf`;
|
||||
let Pdf = fs.createWriteStream(testPdf);
|
||||
const writeToLocalDisk = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
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() {
|
||||
try {
|
||||
let Pdf = fs.createWriteStream(testPdf);
|
||||
const writeToLocalDisk = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
let PdfBuffer = fs.readFileSync(Pdf.path);
|
||||
resolve(PdfBuffer);
|
||||
}, 100);
|
||||
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');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
// `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;
|
||||
const certificatePath = req.params.certificatePath || `./exports/certificate.pdf`;
|
||||
if (fs.existsSync(certificatePath)) {
|
||||
try {
|
||||
// `certificateBuffer` used to create buffer from pdf file
|
||||
const certificateBuffer = fs.readFileSync(certificatePath);
|
||||
const certificate = {
|
||||
filename: 'certificate.pdf',
|
||||
content: smtpenable ? certificateBuffer : undefined, //fs.readFileSync('./exports/exported_file_1223.pdf'),
|
||||
data: smtpenable ? undefined : certificateBuffer,
|
||||
};
|
||||
attachment = [file, certificate];
|
||||
} catch (err) {
|
||||
let attachment;
|
||||
const certificatePath = req.params.certificatePath || `./exports/certificate.pdf`;
|
||||
if (fs.existsSync(certificatePath)) {
|
||||
try {
|
||||
// `certificateBuffer` used to create buffer from pdf file
|
||||
const certificateBuffer = fs.readFileSync(certificatePath);
|
||||
const certificate = {
|
||||
filename: 'certificate.pdf',
|
||||
content: smtpenable ? certificateBuffer : undefined, //fs.readFileSync('./exports/exported_file_1223.pdf'),
|
||||
data: smtpenable ? undefined : certificateBuffer,
|
||||
};
|
||||
attachment = [file, certificate];
|
||||
} catch (err) {
|
||||
attachment = [file];
|
||||
console.log('Err in read certificate sendmailv3', err);
|
||||
}
|
||||
} else {
|
||||
attachment = [file];
|
||||
console.log('Err in read certificate sendmailv3', err);
|
||||
}
|
||||
} else {
|
||||
attachment = [file];
|
||||
}
|
||||
const from = req.params.from || '';
|
||||
const mailsender = smtpenable ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER;
|
||||
const replyto = req.params?.replyto || '';
|
||||
const messageParams = {
|
||||
from: from + ' <' + mailsender + '>',
|
||||
to: req.params.recipient,
|
||||
subject: req.params.subject,
|
||||
text: req.params.text || 'mail',
|
||||
html: req.params.html || '',
|
||||
attachments: smtpenable ? attachment : undefined,
|
||||
attachment: smtpenable ? undefined : attachment,
|
||||
bcc: req.params.bcc ? req.params.bcc : undefined,
|
||||
replyTo: replyto ? replyto : undefined,
|
||||
};
|
||||
if (transporterSMTP) {
|
||||
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) {
|
||||
const from = req.params.from || '';
|
||||
const mailsender = smtpenable ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER;
|
||||
const replyto = req.params?.replyto || '';
|
||||
const messageParams = {
|
||||
from: from + ' <' + mailsender + '>',
|
||||
to: req.params.recipient,
|
||||
subject: req.params.subject,
|
||||
text: req.params.text || 'mail',
|
||||
html: req.params.html || '',
|
||||
attachments: smtpenable ? attachment : undefined,
|
||||
attachment: smtpenable ? undefined : attachment,
|
||||
bcc: req.params.bcc ? req.params.bcc : undefined,
|
||||
replyTo: replyto ? replyto : undefined,
|
||||
};
|
||||
if (transporterSMTP) {
|
||||
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);
|
||||
}
|
||||
@@ -165,23 +142,60 @@ async function sendMailProvider(req, plan, monthchange) {
|
||||
return { status: 'success' };
|
||||
}
|
||||
} else {
|
||||
if (fs.existsSync(certificatePath)) {
|
||||
try {
|
||||
fs.unlinkSync(certificatePath);
|
||||
} catch (err) {
|
||||
console.log('Err in unlink certificate sendmailv3');
|
||||
if (mailgunApiKey) {
|
||||
const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
|
||||
console.log('mailgun res: ', res?.status);
|
||||
if (res.status === 200) {
|
||||
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' };
|
||||
}
|
||||
}
|
||||
if (fs.existsSync(testPdf)) {
|
||||
try {
|
||||
fs.unlinkSync(testPdf);
|
||||
} catch (err) {
|
||||
console.log('Err in unlink pdf sendmailv3');
|
||||
} else {
|
||||
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: '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 {
|
||||
const from = req.params.from || '';
|
||||
@@ -230,8 +244,8 @@ async function sendMailProvider(req, plan, monthchange) {
|
||||
}
|
||||
|
||||
async function sendmailv3(req) {
|
||||
const nonCustomMail = await sendMailProvider(req);
|
||||
return nonCustomMail;
|
||||
const nonCustomMail = await sendMailProvider(req);
|
||||
return nonCustomMail;
|
||||
}
|
||||
|
||||
export default sendmailv3;
|
||||
|
||||
@@ -48,6 +48,12 @@ export default async function updatePreferences(request) {
|
||||
if (request.params.IsTourEnabled !== undefined) {
|
||||
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 });
|
||||
if (updateUserRes) {
|
||||
const _updateUserRes = JSON.parse(JSON.stringify(updateUserRes));
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
export default async function updateTenant(request) {
|
||||
const { tenantId, details } = request.params;
|
||||
|
||||
if (!tenantId || !details) {
|
||||
throw new Parse.Error(400, 'Missing tenantId or details.');
|
||||
}
|
||||
|
||||
if (!request.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'unauthorized');
|
||||
}
|
||||
try {
|
||||
const tenant = new Parse.Object('partners_Tenant');
|
||||
tenant.id = tenantId;
|
||||
// Update tenant details
|
||||
Object.keys(details).forEach(key => {
|
||||
tenant.set(key, details?.[key]);
|
||||
});
|
||||
|
||||
const tenantRes = await tenant.save(null, { useMasterKey: true });
|
||||
if (tenantRes) {
|
||||
const res = JSON.parse(JSON.stringify(tenantRes));
|
||||
return res;
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
import axios from 'axios';
|
||||
import {
|
||||
cloudServerUrl,
|
||||
} from '../../Utils.js';
|
||||
import { cloudServerUrl } from '../../Utils.js';
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const APPID = process.env.APP_ID;
|
||||
const masterKEY = process.env.MASTER_KEY;
|
||||
@@ -32,7 +30,7 @@ async function saveUser(userDetails) {
|
||||
const user = new Parse.User();
|
||||
user.set('username', userDetails.email);
|
||||
user.set('password', userDetails.password);
|
||||
user.set('email', userDetails.email);
|
||||
user.set('email', userDetails?.email?.toLowerCase()?.replace(/\s/g, ''));
|
||||
if (userDetails?.phone) {
|
||||
user.set('phone', userDetails.phone);
|
||||
}
|
||||
@@ -73,7 +71,7 @@ export default async function usersignup(request) {
|
||||
partnerQuery.set('ContactNumber', userDetails.phone);
|
||||
}
|
||||
partnerQuery.set('TenantName', userDetails.company);
|
||||
partnerQuery.set('EmailAddress', userDetails.email);
|
||||
partnerQuery.set('EmailAddress', userDetails?.email?.toLowerCase()?.replace(/\s/g, ''));
|
||||
partnerQuery.set('IsActive', true);
|
||||
partnerQuery.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
@@ -105,7 +103,7 @@ export default async function usersignup(request) {
|
||||
objectId: user.id,
|
||||
});
|
||||
newObj.set('UserRole', userDetails.role);
|
||||
newObj.set('Email', userDetails.email);
|
||||
newObj.set('Email', userDetails?.email?.toLowerCase()?.replace(/\s/g, ''));
|
||||
newObj.set('Name', userDetails.name);
|
||||
if (userDetails?.phone) {
|
||||
newObj.set('Phone', userDetails?.phone);
|
||||
@@ -131,4 +129,3 @@ export default async function usersignup(request) {
|
||||
console.log('Err ', err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import AWS from 'aws-sdk';
|
||||
import { app as customRoute } from './cloud/customRoute/customApp.js';
|
||||
import { exec } from 'child_process';
|
||||
import { createTransport } from 'nodemailer';
|
||||
import { PostHog } from 'posthog-node';
|
||||
import { appName, cloudServerUrl, smtpenable, smtpsecure, useLocal } from './Utils.js';
|
||||
import { SSOAuth } from './auth/authadapter.js';
|
||||
import createContactIndex from './migrationdb/createContactIndex.js';
|
||||
@@ -161,6 +160,8 @@ app.use(express.json({ limit: '50mb' }));
|
||||
app.use(express.urlencoded({ limit: '50mb', extended: true }));
|
||||
app.use(function (req, res, next) {
|
||||
req.headers['x-real-ip'] = getUserIP(req);
|
||||
const publicUrl = req.protocol + '://' + req.get('host');
|
||||
req.headers['public_url'] = publicUrl; // process.env.PUBLIC_URL
|
||||
next();
|
||||
});
|
||||
function getUserIP(request) {
|
||||
@@ -175,16 +176,6 @@ function getUserIP(request) {
|
||||
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) {
|
||||
const isFilePath = req.path.includes('files') || false;
|
||||
@@ -225,7 +216,6 @@ if (!process.env.TESTING) {
|
||||
// Mount your custom express app
|
||||
app.use('/', customRoute);
|
||||
|
||||
|
||||
// Parse Server plays nicely with the rest of your web routes
|
||||
app.get('/', function (req, res) {
|
||||
res.status(200).send('opensign-server is running !!!');
|
||||
|
||||
Generated
+2352
-2099
File diff suppressed because it is too large
Load Diff
@@ -18,26 +18,26 @@
|
||||
"watch": "nodemon index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.741.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.741.0",
|
||||
"@aws-sdk/client-s3": "^3.775.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.775.0",
|
||||
"@parse/fs-files-adapter": "^3.0.0",
|
||||
"@parse/s3-files-adapter": "^4.1.0",
|
||||
"@pdf-lib/fontkit": "^1.1.1",
|
||||
"@signpdf/placeholder-pdf-lib": "^3.2.4",
|
||||
"@signpdf/signer-p12": "^3.2.4",
|
||||
"@signpdf/signpdf": "^3.2.4",
|
||||
"@signpdf/signpdf": "^3.2.5",
|
||||
"aws-sdk": "^2.1692.0",
|
||||
"axios": "^1.7.9",
|
||||
"axios": "^1.8.4",
|
||||
"cors": "^2.8.5",
|
||||
"date-fns-tz": "^3.2.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"express": "^4.21.1",
|
||||
"form-data": "^4.0.1",
|
||||
"form-data": "^4.0.2",
|
||||
"generate-api-key": "^1.0.2",
|
||||
"googleapis": "^144.0.0",
|
||||
"googleapis": "^148.0.0",
|
||||
"mailgun.js": "^11.1.0",
|
||||
"mongodb": "^6.13.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"mongodb": "^6.15.0",
|
||||
"multer": "^1.4.5-lts.2",
|
||||
"multer-s3": "^3.0.1",
|
||||
"node-forge": "^1.3.1",
|
||||
"nodemailer": "^6.10.0",
|
||||
@@ -46,18 +46,18 @@
|
||||
"parse-server": "^7.4.0",
|
||||
"parse-server-api-mail-adapter": "^4.1.0",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"posthog-node": "^4.5.0",
|
||||
"ws": "^8.18.0"
|
||||
"posthog-node": "^4.10.2",
|
||||
"ws": "^8.18.1"
|
||||
},
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.26.5",
|
||||
"eslint": "^9.20.0",
|
||||
"@babel/eslint-parser": "^7.27.0",
|
||||
"eslint": "^9.23.0",
|
||||
"jasmine": "^5.6.0",
|
||||
"mongodb-runner": "^5.7.1",
|
||||
"mongodb-runner": "^5.8.0",
|
||||
"nodemon": "^3.1.9",
|
||||
"nyc": "^17.1.0",
|
||||
"prettier": "^3.5.0"
|
||||
"prettier": "^3.5.3"
|
||||
},
|
||||
"overrides": {
|
||||
"ws": "$ws",
|
||||
|
||||
+2
-1
@@ -11,7 +11,8 @@ services:
|
||||
env_file: .env.prod
|
||||
environment:
|
||||
- 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:
|
||||
- app-network
|
||||
mongo:
|
||||
|
||||
Reference in New Issue
Block a user