mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-05 01:07:39 +02:00
Compare commits
24
Commits
@@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta name="description" content="The fastest way to sign PDFs & request signatures from others" />
|
<meta name="description" content="The fastest way to sign PDFs & request signatures from others" />
|
||||||
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> -->
|
<!-- <link rel="apple-touch-icon" href="/logo192.png" /> -->
|
||||||
|
|
||||||
<link rel="manifest" href="/manifest.json" />
|
<link rel="manifest" href="/manifest.json" />
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
|
||||||
@@ -17,5 +17,6 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root" style="touch-action:pan-x pan-y;"></div>
|
<div id="root" style="touch-action:pan-x pan-y;"></div>
|
||||||
|
<script type="module" src="/src/index.jsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Generated
+3397
-651
File diff suppressed because it is too large
Load Diff
+29
-16
@@ -4,22 +4,22 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formkit/auto-animate": "^0.8.2",
|
"@formkit/auto-animate": "^0.8.2",
|
||||||
"@lottiefiles/dotlottie-react": "^0.13.4",
|
"@lottiefiles/dotlottie-react": "^0.13.5",
|
||||||
"@pdf-lib/fontkit": "^1.1.1",
|
"@pdf-lib/fontkit": "^1.1.1",
|
||||||
"@radix-ui/themes": "^3.1.6",
|
"@radix-ui/themes": "^3.1.6",
|
||||||
"@reduxjs/toolkit": "^2.7.0",
|
"@reduxjs/toolkit": "^2.7.0",
|
||||||
"axios": "^1.8.4",
|
"axios": "^1.9.0",
|
||||||
"css-minimizer-webpack-plugin": "^7.0.2",
|
"css-minimizer-webpack-plugin": "^7.0.2",
|
||||||
"date-fns-tz": "^3.2.0",
|
"date-fns-tz": "^3.2.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"i18next": "^23.16.8",
|
"i18next": "^23.16.8",
|
||||||
"i18next-browser-languagedetector": "^8.0.5",
|
"i18next-browser-languagedetector": "^8.1.0",
|
||||||
"i18next-http-backend": "^3.0.2",
|
"i18next-http-backend": "^3.0.2",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"nth-check": "^2.1.1",
|
"nth-check": "^2.1.1",
|
||||||
"parse": "^5.3.0",
|
"parse": "^6.1.1",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
"radix-ui": "^1.0.1",
|
"radix-ui": "^1.0.1",
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
"react-quill-new": "^3.4.6",
|
"react-quill-new": "^3.4.6",
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
"react-rnd": "^10.5.2",
|
"react-rnd": "^10.5.2",
|
||||||
"react-router": "^7.5.2",
|
"react-router": "^7.5.3",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"react-scrollbars-custom": "^4.1.1",
|
"react-scrollbars-custom": "^4.1.1",
|
||||||
"react-select": "^5.10.1",
|
"react-select": "^5.10.1",
|
||||||
@@ -57,18 +57,20 @@
|
|||||||
"serve": "^14.2.4",
|
"serve": "^14.2.4",
|
||||||
"styled-components": "^5.3.0",
|
"styled-components": "^5.3.0",
|
||||||
"web-vitals": "^4.2.4",
|
"web-vitals": "^4.2.4",
|
||||||
"ws": "^8.18.1",
|
"ws": "^8.18.2",
|
||||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run version && react-scripts build",
|
"build": "npm run version && NODE_OPTIONS=\"--max-old-space-size=8192\" vite build",
|
||||||
"start-dev": "react-scripts start",
|
"start-dev": "vite",
|
||||||
|
"dev": "vite",
|
||||||
|
"preview": "vite preview",
|
||||||
"start": "serve -s build",
|
"start": "serve -s build",
|
||||||
"version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
|
"version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
|
||||||
"version-win": "powershell -Command \"Invoke-RestMethod -Uri 'https://api.github.com/repos/opensignlabs/opensign/releases/latest' | Select-Object -ExpandProperty tag_name | Out-File -FilePath ./public/version.txt\"",
|
"version-win": "powershell -Command \"Invoke-RestMethod -Uri 'https://api.github.com/repos/opensignlabs/opensign/releases/latest' | Select-Object -ExpandProperty tag_name | Out-File -FilePath ./public/version.txt\"",
|
||||||
"build-win": "npm run version-win && react-scripts build",
|
"build-win": "npm run version-win && vite build",
|
||||||
"test": "react-scripts test",
|
"test": "vitest run",
|
||||||
"eject": "react-scripts eject",
|
"test:watch": "vitest",
|
||||||
"release": "standard-version",
|
"release": "standard-version",
|
||||||
"commit": "cz"
|
"commit": "cz"
|
||||||
},
|
},
|
||||||
@@ -96,10 +98,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.26.10",
|
"@babel/core": "^7.27.1",
|
||||||
"@babel/preset-env": "^7.26.9",
|
"@babel/preset-env": "^7.27.1",
|
||||||
"@babel/preset-react": "^7.26.3",
|
"@babel/preset-react": "^7.27.1",
|
||||||
"@babel/runtime-corejs2": "^7.27.0",
|
"@babel/runtime-corejs2": "^7.27.1",
|
||||||
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
|
"@testing-library/react": "^16.3.0",
|
||||||
|
"@testing-library/user-event": "^14.6.1",
|
||||||
|
"@types/react": "^18.3.21",
|
||||||
|
"@vitejs/plugin-react": "^4.4.1",
|
||||||
|
"@vitejs/plugin-react-swc": "^3.9.0",
|
||||||
"autoprefixer": "^10.4.21",
|
"autoprefixer": "^10.4.21",
|
||||||
"babel-loader": "^10.0.0",
|
"babel-loader": "^10.0.0",
|
||||||
"commitizen": "^4.3.1",
|
"commitizen": "^4.3.1",
|
||||||
@@ -109,15 +117,20 @@
|
|||||||
"dotenv": "^16.5.0",
|
"dotenv": "^16.5.0",
|
||||||
"dotenv-webpack": "^8.1.0",
|
"dotenv-webpack": "^8.1.0",
|
||||||
"eslint": "^8.57.1",
|
"eslint": "^8.57.1",
|
||||||
"eslint-plugin-prettier": "^5.2.6",
|
"eslint-plugin-prettier": "^5.4.0",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
"lint-staged": "^15.5.1",
|
"lint-staged": "^15.5.1",
|
||||||
"mini-css-extract-plugin": "^2.9.2",
|
"mini-css-extract-plugin": "^2.9.2",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"pretty-quick": "^4.1.1",
|
"pretty-quick": "^4.1.1",
|
||||||
|
"rollup-plugin-node-polyfills": "^0.2.1",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.17",
|
||||||
"terser-webpack-plugin": "^5.3.14",
|
"terser-webpack-plugin": "^5.3.14",
|
||||||
|
"vite": "^6.3.5",
|
||||||
|
"vite-plugin-svgr": "^4.3.0",
|
||||||
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
|
"vitest": "^3.1.3",
|
||||||
"webpack-cli": "^5.1.4"
|
"webpack-cli": "^5.1.4"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
|
|||||||
@@ -153,7 +153,8 @@
|
|||||||
"Duplicate": "Duplikat",
|
"Duplicate": "Duplikat",
|
||||||
"daily-mail-quota": "Tägliches E-Mail-Kontingent",
|
"daily-mail-quota": "Tägliches E-Mail-Kontingent",
|
||||||
"Save as template": "Als Vorlage speichern",
|
"Save as template": "Als Vorlage speichern",
|
||||||
"Fix & resend": "Korrigieren und erneut senden"
|
"Fix & resend": "Korrigieren und erneut senden",
|
||||||
|
"Kiosk Mode": "Kiosk Modus"
|
||||||
},
|
},
|
||||||
"report-heading": {
|
"report-heading": {
|
||||||
"Sr.No": "Nr.",
|
"Sr.No": "Nr.",
|
||||||
@@ -304,7 +305,7 @@
|
|||||||
"send": "Senden",
|
"send": "Senden",
|
||||||
"quick-send-alert-1": "Alle Rollen in diesem Dokument sind derzeit mit Kontakten verknüpft. Um Kopien dieser Vorlage schnell an mehrere Unterzeichner zu senden, stellen Sie sicher, dass mindestens eine Rolle keinem Kontakt zugeordnet ist.",
|
"quick-send-alert-1": "Alle Rollen in diesem Dokument sind derzeit mit Kontakten verknüpft. Um Kopien dieser Vorlage schnell an mehrere Unterzeichner zu senden, stellen Sie sicher, dass mindestens eine Rolle keinem Kontakt zugeordnet ist.",
|
||||||
"quick-send-alert-2": "Bitte stellen Sie sicher, dass für alle Empfänger mindestens ein Signatur-Widget hinzugefügt wurde.",
|
"quick-send-alert-2": "Bitte stellen Sie sicher, dass für alle Empfänger mindestens ein Signatur-Widget hinzugefügt wurde.",
|
||||||
"quick-send-alert-3": "Bitte fügen Sie mindestens eine Rolle zu dieser Vorlage hinzu, um Kopien davon schnell an mehrere Unterzeichner zu senden.",
|
"quick-send-alert-3": "Bitte fügen Sie diesem template mindestens eine Rolle hinzu.",
|
||||||
"quick-send-alert-4": "Das Limit für Schnellsendungen wurde erreicht.",
|
"quick-send-alert-4": "Das Limit für Schnellsendungen wurde erreicht.",
|
||||||
"copy-link": "Link kopieren",
|
"copy-link": "Link kopieren",
|
||||||
"copy": "Kopieren",
|
"copy": "Kopieren",
|
||||||
@@ -965,5 +966,10 @@
|
|||||||
"p1": "Administre la configuración de seguridad de su cuenta para mantener sus datos seguros. OpenSign admite métodos de autenticación avanzados para mejorar la protección de la cuenta.",
|
"p1": "Administre la configuración de seguridad de su cuenta para mantener sus datos seguros. OpenSign admite métodos de autenticación avanzados para mejorar la protección de la cuenta.",
|
||||||
"2fa-auth-help": "Agregue una capa adicional de seguridad activando 2FA. Esto requiere ingresar un código de verificación desde una aplicación autenticadora después de su contraseña.",
|
"2fa-auth-help": "Agregue una capa adicional de seguridad activando 2FA. Esto requiere ingresar un código de verificación desde una aplicación autenticadora después de su contraseña.",
|
||||||
"passkey-auth-help": "Use claves de acceso para iniciar sesión sin contraseña con verificación biométrica o basada en el dispositivo, proporcionando una seguridad sólida y comodidad."
|
"passkey-auth-help": "Use claves de acceso para iniciar sesión sin contraseña con verificación biométrica o basada en el dispositivo, proporcionando una seguridad sólida y comodidad."
|
||||||
}
|
},
|
||||||
|
"signer-already-present": "Unterzeichner bereits vorhanden",
|
||||||
|
"kiosk-sign": "Kiosk-Unterschrift",
|
||||||
|
"dont-have-access-to-template": "Das template wurde gelöscht oder Sie haben keinen Zugriff. Bitte kontaktieren Sie den Absender.",
|
||||||
|
"kiosk-info": "Kiosk Modus ermöglicht es Ihnen, persönliche Unterschriften schnell und effizient zu erfassen. Ideal für Messen, Veranstaltungen oder Laufkundschaft, bei denen alle Unterzeichner physisch anwesend sind. ",
|
||||||
|
"learn-more": "Mehr erfahren"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,7 +153,8 @@
|
|||||||
"Duplicate": "Duplicate",
|
"Duplicate": "Duplicate",
|
||||||
"daily-mail-quota": "Daily Email Quota",
|
"daily-mail-quota": "Daily Email Quota",
|
||||||
"Save as template": "Save as template",
|
"Save as template": "Save as template",
|
||||||
"Fix & resend": "Fix & Resend"
|
"Fix & resend": "Fix & Resend",
|
||||||
|
"Kiosk Mode": "Kiosk Mode"
|
||||||
},
|
},
|
||||||
"report-heading": {
|
"report-heading": {
|
||||||
"Sr.No": "Sr.No",
|
"Sr.No": "Sr.No",
|
||||||
@@ -304,7 +305,7 @@
|
|||||||
"send": "Send",
|
"send": "Send",
|
||||||
"quick-send-alert-1": "All roles in this document are currently linked to contacts. To quick send copies of this template to multiple signers, please ensure that at least one role is not linked to any contact.",
|
"quick-send-alert-1": "All roles in this document are currently linked to contacts. To quick send copies of this template to multiple signers, please ensure that at least one role is not linked to any contact.",
|
||||||
"quick-send-alert-2": "Please ensure there's at least one signature widget added for all recipients.",
|
"quick-send-alert-2": "Please ensure there's at least one signature widget added for all recipients.",
|
||||||
"quick-send-alert-3": "Please add at least one role to this template in order to 'quick send' copies of it to multiple signers.",
|
"quick-send-alert-3": "Please add at least one role to this template.",
|
||||||
"quick-send-alert-4": "Quick send reached limit.",
|
"quick-send-alert-4": "Quick send reached limit.",
|
||||||
"copy-link": "Copy link",
|
"copy-link": "Copy link",
|
||||||
"copy": "Copy",
|
"copy": "Copy",
|
||||||
@@ -965,5 +966,10 @@
|
|||||||
"p1":"Manage your account's security settings to keep your data safe. OpenSign supports advanced authentication methods to enhance account protection.",
|
"p1":"Manage your account's security settings to keep your data safe. OpenSign supports advanced authentication methods to enhance account protection.",
|
||||||
"2fa-auth-help":" Add an extra layer of security by enabling 2FA. This requires you to enter a verification code from an authenticator app after your password.",
|
"2fa-auth-help":" Add an extra layer of security by enabling 2FA. This requires you to enter a verification code from an authenticator app after your password.",
|
||||||
"passkey-auth-help":"Use passkeys for passwordless sign-in with biometric or device-based verification, providing both strong security and convenience."
|
"passkey-auth-help":"Use passkeys for passwordless sign-in with biometric or device-based verification, providing both strong security and convenience."
|
||||||
}
|
},
|
||||||
|
"signer-already-present": "Signer already present",
|
||||||
|
"kiosk-sign": "Kiosk Sign",
|
||||||
|
"dont-have-access-to-template": "The template has been deleted or you don't have access. Please contact the sender.",
|
||||||
|
"kiosk-info": "Kiosk Mode lets you collect in-person signatures quickly and efficiently. Ideal for trade shows, events, or walk-in scenarios where all signers are physically present. ",
|
||||||
|
"learn-more": "Learn more"
|
||||||
}
|
}
|
||||||
@@ -153,7 +153,8 @@
|
|||||||
"Duplicate": "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",
|
"Save as template": "Guardar como plantilla",
|
||||||
"Fix & resend": "Corregir y reenviar"
|
"Fix & resend": "Corregir y reenviar",
|
||||||
|
"Kiosk Mode": "Modo Kiosco"
|
||||||
},
|
},
|
||||||
"report-heading": {
|
"report-heading": {
|
||||||
"Sr.No": "Nº",
|
"Sr.No": "Nº",
|
||||||
@@ -305,7 +306,7 @@
|
|||||||
"send": "Enviar",
|
"send": "Enviar",
|
||||||
"quick-send-alert-1": "Todos los roles de este documento están actualmente vinculados a contactos. Para enviar rápidamente copias de esta plantilla a varios firmantes, por favor, asegúrate de que al menos un rol no esté vinculado a ningún contacto.",
|
"quick-send-alert-1": "Todos los roles de este documento están actualmente vinculados a contactos. Para enviar rápidamente copias de esta plantilla a varios firmantes, por favor, asegúrate de que al menos un rol no esté vinculado a ningún contacto.",
|
||||||
"quick-send-alert-2": "Por favor, asegúrate de que hay al menos un widget de firma añadido para cada destinatario.",
|
"quick-send-alert-2": "Por favor, asegúrate de que hay al menos un widget de firma añadido para cada destinatario.",
|
||||||
"quick-send-alert-3": "Por favor, añade al menos un rol a esta plantilla para poder hacer un «envío rápido» de copias a varios firmantes.",
|
"quick-send-alert-3": "Veuillez ajouter au moins un rôle à ce template.",
|
||||||
"quick-send-alert-4": "El envío rápido ha alcanzado el límite.",
|
"quick-send-alert-4": "El envío rápido ha alcanzado el límite.",
|
||||||
"copy-link": "Copiar enlace",
|
"copy-link": "Copiar enlace",
|
||||||
"copy": "Copiar",
|
"copy": "Copiar",
|
||||||
@@ -965,5 +966,10 @@
|
|||||||
"p1": "Administre la configuración de seguridad de su cuenta para mantener sus datos seguros. OpenSign admite métodos de autenticación avanzados para mejorar la protección de la cuenta.",
|
"p1": "Administre la configuración de seguridad de su cuenta para mantener sus datos seguros. OpenSign admite métodos de autenticación avanzados para mejorar la protección de la cuenta.",
|
||||||
"2fa-auth-help": "Agregue una capa adicional de seguridad activando 2FA. Esto requiere ingresar un código de verificación desde una aplicación autenticadora después de su contraseña.",
|
"2fa-auth-help": "Agregue una capa adicional de seguridad activando 2FA. Esto requiere ingresar un código de verificación desde una aplicación autenticadora después de su contraseña.",
|
||||||
"passkey-auth-help": "Use claves de acceso para iniciar sesión sin contraseña con verificación biométrica o basada en el dispositivo, proporcionando una seguridad sólida y comodidad."
|
"passkey-auth-help": "Use claves de acceso para iniciar sesión sin contraseña con verificación biométrica o basada en el dispositivo, proporcionando una seguridad sólida y comodidad."
|
||||||
}
|
},
|
||||||
|
"signer-already-present": "Firmante ya presente",
|
||||||
|
"kiosk-sign": "Firma en quiosco",
|
||||||
|
"dont-have-access-to-template": "El template ha sido eliminado o no tiene acceso. Por favor, contacte al remitente.",
|
||||||
|
"kiosk-info": "El Modo Kiosco le permite recopilar firmas en persona de forma rápida y eficiente. Ideal para ferias, eventos o situaciones con personas que firman en el lugar. ",
|
||||||
|
"learn-more": "Más información"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,7 +174,8 @@
|
|||||||
"Duplicate": "Double",
|
"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",
|
"Save as template": "Enregistrer comme modèle",
|
||||||
"Fix & resend": "Corriger et renvoyer"
|
"Fix & resend": "Corriger et renvoyer",
|
||||||
|
"Kiosk Mode": "Mode Kiosque"
|
||||||
},
|
},
|
||||||
"report-help": {
|
"report-help": {
|
||||||
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
|
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
|
||||||
@@ -304,7 +305,7 @@
|
|||||||
"send": "envoyer",
|
"send": "envoyer",
|
||||||
"quick-send-alert-1": "Tous les rôles dans ce document sont actuellement liés à des contacts. Pour envoyer rapidement des copies de ce modèle à plusieurs signataires, veuillez vous assurer qu'au moins un rôle n'est lié à aucun contact.",
|
"quick-send-alert-1": "Tous les rôles dans ce document sont actuellement liés à des contacts. Pour envoyer rapidement des copies de ce modèle à plusieurs signataires, veuillez vous assurer qu'au moins un rôle n'est lié à aucun contact.",
|
||||||
"quick-send-alert-2": "Veuillez vous assurer qu'au moins un widget de signature est ajouté pour tous les destinataires.",
|
"quick-send-alert-2": "Veuillez vous assurer qu'au moins un widget de signature est ajouté pour tous les destinataires.",
|
||||||
"quick-send-alert-3": "Veuillez ajouter au moins un rôle à ce modèle afin d'en « envoyer rapidement » des copies à plusieurs signataires.",
|
"quick-send-alert-3": "Veuillez ajouter au moins un rôle à ce template.",
|
||||||
"quick-send-alert-4": "L'envoi rapide a atteint la limite.",
|
"quick-send-alert-4": "L'envoi rapide a atteint la limite.",
|
||||||
"copy-link": "Copier le lien",
|
"copy-link": "Copier le lien",
|
||||||
"copy": "Copier",
|
"copy": "Copier",
|
||||||
@@ -965,5 +966,10 @@
|
|||||||
"p1": "Gérez les paramètres de sécurité de votre compte pour protéger vos données. OpenSign prend en charge des méthodes d'authentification avancées pour renforcer la protection de votre compte.",
|
"p1": "Gérez les paramètres de sécurité de votre compte pour protéger vos données. OpenSign prend en charge des méthodes d'authentification avancées pour renforcer la protection de votre compte.",
|
||||||
"2fa-auth-help": "Ajoutez une couche de sécurité supplémentaire en activant 2FA. Cela vous demandera de saisir un code de vérification provenant d’une application d’authentification après votre mot de passe.",
|
"2fa-auth-help": "Ajoutez une couche de sécurité supplémentaire en activant 2FA. Cela vous demandera de saisir un code de vérification provenant d’une application d’authentification après votre mot de passe.",
|
||||||
"passkey-auth-help": "Utilisez des passkeys pour une connexion sans mot de passe grâce à une vérification biométrique ou basée sur l’appareil, offrant à la fois une sécurité renforcée et une grande commodité."
|
"passkey-auth-help": "Utilisez des passkeys pour une connexion sans mot de passe grâce à une vérification biométrique ou basée sur l’appareil, offrant à la fois une sécurité renforcée et une grande commodité."
|
||||||
}
|
},
|
||||||
|
"signer-already-present": "Signataire déjà présent",
|
||||||
|
"kiosk-sign": "Signature sur kiosque",
|
||||||
|
"dont-have-access-to-template": "Le template a été supprimé ou vous n'y avez pas accès. Veuillez contacter l'expéditeur.",
|
||||||
|
"kiosk-info": "Le Mode Kiosque vous permet de recueillir des signatures en personne rapidement et efficacement. Idéal pour les salons, événements ou situations où tous les signataires sont physiquement présents. ",
|
||||||
|
"learn-more": "En savoir plus"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,7 +153,8 @@
|
|||||||
"Duplicate": "Duplica",
|
"Duplicate": "Duplica",
|
||||||
"daily-mail-quota": "Quota e-mail giornaliera",
|
"daily-mail-quota": "Quota e-mail giornaliera",
|
||||||
"Save as template": "Salva come modello",
|
"Save as template": "Salva come modello",
|
||||||
"Fix & resend": "Correggi e reinvia"
|
"Fix & resend": "Correggi e reinvia",
|
||||||
|
"Kiosk Mode": "Modalità Kiosk"
|
||||||
},
|
},
|
||||||
"report-heading": {
|
"report-heading": {
|
||||||
"Sr.No": "Nr.",
|
"Sr.No": "Nr.",
|
||||||
@@ -304,7 +305,7 @@
|
|||||||
"send": "Invia",
|
"send": "Invia",
|
||||||
"quick-send-alert-1": "Tutti i ruoli in questo documento sono attualmente collegati a contatti. Per inviare rapidamente copie di questo modello a più firmatari, assicurati che almeno un ruolo non sia collegato a nessun contatto.",
|
"quick-send-alert-1": "Tutti i ruoli in questo documento sono attualmente collegati a contatti. Per inviare rapidamente copie di questo modello a più firmatari, assicurati che almeno un ruolo non sia collegato a nessun contatto.",
|
||||||
"quick-send-alert-2": "Assicurati che ci sia almeno un widget firma aggiunto per tutti i destinatari.",
|
"quick-send-alert-2": "Assicurati che ci sia almeno un widget firma aggiunto per tutti i destinatari.",
|
||||||
"quick-send-alert-3": "Aggiungi almeno un ruolo a questo modello per 'invio rapido' a più firmatari.",
|
"quick-send-alert-3": "Si prega di aggiungere almeno un ruolo a questo template.",
|
||||||
"quick-send-alert-4": "Limite di invio rapido raggiunto.",
|
"quick-send-alert-4": "Limite di invio rapido raggiunto.",
|
||||||
"copy-link": "Copia link",
|
"copy-link": "Copia link",
|
||||||
"copy": "Copia",
|
"copy": "Copia",
|
||||||
@@ -965,5 +966,10 @@
|
|||||||
"p1": "Gestisci le impostazioni di sicurezza del tuo account per proteggere i tuoi dati. OpenSign supporta metodi di autenticazione avanzati per migliorare la protezione dell’account.",
|
"p1": "Gestisci le impostazioni di sicurezza del tuo account per proteggere i tuoi dati. OpenSign supporta metodi di autenticazione avanzati per migliorare la protezione dell’account.",
|
||||||
"2fa-auth-help": "Aggiungi un ulteriore livello di sicurezza abilitando 2FA. Ti verrà richiesto di inserire un codice di verifica da un'app di autenticazione dopo la password.",
|
"2fa-auth-help": "Aggiungi un ulteriore livello di sicurezza abilitando 2FA. Ti verrà richiesto di inserire un codice di verifica da un'app di autenticazione dopo la password.",
|
||||||
"passkey-auth-help": "Usa le passkey per accedere senza password con verifica biometrica o basata sul dispositivo, garantendo sicurezza elevata e praticità."
|
"passkey-auth-help": "Usa le passkey per accedere senza password con verifica biometrica o basata sul dispositivo, garantendo sicurezza elevata e praticità."
|
||||||
}
|
},
|
||||||
|
"signer-already-present": "Firmatario già presente",
|
||||||
|
"kiosk-sign": "Firma su chiosco",
|
||||||
|
"dont-have-access-to-template": "Il template è stato eliminato o non hai accesso. Si prega di contattare il mittente.",
|
||||||
|
"kiosk-info": "La Modalità Kiosk consente di raccogliere firme in presenza in modo rapido ed efficiente. Ideale per fiere, eventi o situazioni con firmatari fisicamente presenti. ",
|
||||||
|
"learn-more": "Scopri di più"
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
import "@testing-library/jest-dom";
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import React, { useState, useEffect, lazy } from "react";
|
import React, { useState, useEffect, lazy } from "react";
|
||||||
import { Routes, Route, BrowserRouter } from "react-router";
|
import { Routes, Route, BrowserRouter } from "react-router";
|
||||||
import { pdfjs } from "react-pdf";
|
import { pdfjs } from "react-pdf";
|
||||||
import Login from "./pages/Login";
|
|
||||||
import Form from "./pages/Form";
|
import Form from "./pages/Form";
|
||||||
import Report from "./pages/Report";
|
import Report from "./pages/Report";
|
||||||
import Dashboard from "./pages/Dashboard";
|
import Dashboard from "./pages/Dashboard";
|
||||||
@@ -30,6 +29,7 @@ const ManageSign = lazy(() => import("./pages/Managesign"));
|
|||||||
const AddAdmin = lazy(() => import("./pages/AddAdmin"));
|
const AddAdmin = lazy(() => import("./pages/AddAdmin"));
|
||||||
const UpdateExistUserAdmin = lazy(() => import("./pages/UpdateExistUserAdmin"));
|
const UpdateExistUserAdmin = lazy(() => import("./pages/UpdateExistUserAdmin"));
|
||||||
const Preferences = lazy(() => import("./pages/Preferences"));
|
const Preferences = lazy(() => import("./pages/Preferences"));
|
||||||
|
const Login = lazy(() => import("./pages/Login"));
|
||||||
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
|
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
|
||||||
const AppLoader = () => {
|
const AppLoader = () => {
|
||||||
@@ -67,7 +67,7 @@ function App() {
|
|||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route element={<ValidateRoute />}>
|
<Route element={<ValidateRoute />}>
|
||||||
<Route exact path="/" element={<Login />} />
|
<Route exact path="/" element={<LazyPage Page={Login} />} />
|
||||||
<Route
|
<Route
|
||||||
path="/addadmin"
|
path="/addadmin"
|
||||||
element={<LazyPage Page={AddAdmin} />}
|
element={<LazyPage Page={AddAdmin} />}
|
||||||
@@ -1,275 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import Parse from "parse";
|
|
||||||
import Title from "./Title";
|
|
||||||
import Loader from "../primitives/Loader";
|
|
||||||
import { copytoData, usertimezone } from "../constant/Utils";
|
|
||||||
import { emailRegex } from "../constant/const";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
function generatePassword(length) {
|
|
||||||
const characters =
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
||||||
let result = "";
|
|
||||||
const charactersLength = characters.length;
|
|
||||||
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AddUser = (props) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [formdata, setFormdata] = useState({
|
|
||||||
name: "",
|
|
||||||
phone: "",
|
|
||||||
email: "",
|
|
||||||
team: "",
|
|
||||||
password: "",
|
|
||||||
role: ""
|
|
||||||
});
|
|
||||||
const [isFormLoader, setIsFormLoader] = useState(false);
|
|
||||||
const [teamList, setTeamList] = useState([]);
|
|
||||||
const role = ["OrgAdmin", "Editor", "User"];
|
|
||||||
useEffect(() => {
|
|
||||||
getTeamList();
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const getTeamList = async () => {
|
|
||||||
setFormdata((prev) => ({ ...prev, password: generatePassword(12) }));
|
|
||||||
const teamRes = await Parse.Cloud.run("getteams", { active: true });
|
|
||||||
if (teamRes.length > 0) {
|
|
||||||
const _teamRes = JSON.parse(JSON.stringify(teamRes));
|
|
||||||
setTeamList(_teamRes);
|
|
||||||
const allUserId =
|
|
||||||
_teamRes.find((x) => x.Name === "All Users")?.objectId || "";
|
|
||||||
setFormdata((prev) => ({ ...prev, team: allUserId }));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const checkUserExist = async () => {
|
|
||||||
try {
|
|
||||||
const res = await Parse.Cloud.run("getUserDetails", {
|
|
||||||
email: formdata.email
|
|
||||||
});
|
|
||||||
if (res) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log("err", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Define a function to handle form submission
|
|
||||||
const handleSubmit = async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
if (!emailRegex.test(formdata.email)) {
|
|
||||||
alert("Please enter a valid email address.");
|
|
||||||
} else {
|
|
||||||
const localUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
|
||||||
setIsFormLoader(true);
|
|
||||||
const res = await checkUserExist();
|
|
||||||
if (res) {
|
|
||||||
props.showAlert("danger", t("user-already-exist"));
|
|
||||||
setIsFormLoader(false);
|
|
||||||
} else {
|
|
||||||
if (localStorage.getItem("TenantId")) {
|
|
||||||
const timezone = usertimezone;
|
|
||||||
try {
|
|
||||||
const params = {
|
|
||||||
name: formdata.name,
|
|
||||||
email: formdata.email,
|
|
||||||
phone: formdata.phone,
|
|
||||||
password: formdata.password,
|
|
||||||
role: formdata.role,
|
|
||||||
team: formdata.team,
|
|
||||||
timezone: timezone,
|
|
||||||
tenantId: localStorage.getItem("TenantId"),
|
|
||||||
organization: {
|
|
||||||
objectId: localUser?.OrganizationId?.objectId,
|
|
||||||
company: localUser?.Company
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const res = await Parse.Cloud.run("adduser", params);
|
|
||||||
const parseData = JSON.parse(JSON.stringify(res));
|
|
||||||
console.log("parseData ", parseData);
|
|
||||||
if (props.closePopup) {
|
|
||||||
props.closePopup();
|
|
||||||
}
|
|
||||||
if (props.handleUserData) {
|
|
||||||
if (formdata?.team) {
|
|
||||||
const team = teamList.find((x) => x.objectId === formdata.team);
|
|
||||||
parseData.TeamIds = parseData.TeamIds.map((y) =>
|
|
||||||
y.objectId === team.objectId ? team : y
|
|
||||||
);
|
|
||||||
}
|
|
||||||
props.handleUserData(parseData);
|
|
||||||
}
|
|
||||||
setIsFormLoader(false);
|
|
||||||
setFormdata({
|
|
||||||
name: "",
|
|
||||||
email: "",
|
|
||||||
phone: "",
|
|
||||||
team: "",
|
|
||||||
role: ""
|
|
||||||
});
|
|
||||||
props.showAlert("success", t("user-created-successfully"));
|
|
||||||
} catch (err) {
|
|
||||||
console.log("err", err);
|
|
||||||
setIsFormLoader(false);
|
|
||||||
props.showAlert("danger", t("something-went-wrong-mssg"));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
props.showAlert("danger", t("something-went-wrong-mssg"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Define a function to handle the "add yourself" checkbox
|
|
||||||
const handleReset = () => {
|
|
||||||
setFormdata({ name: "", email: "", phone: "", team: "", role: "" });
|
|
||||||
if (props.closePopup) {
|
|
||||||
props.closePopup();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleChange = (event) => {
|
|
||||||
let { name, value } = event.target;
|
|
||||||
if (name === "email") {
|
|
||||||
value = value?.toLowerCase()?.replace(/\s/g, "");
|
|
||||||
}
|
|
||||||
setFormdata((prev) => ({ ...prev, [name]: value }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const copytoclipboard = (text) => {
|
|
||||||
copytoData(text);
|
|
||||||
props.showAlert("success", t("copied"));
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className="shadow-md rounded-box my-[1px] p-3 bg-base-100 relative">
|
|
||||||
<Title title={t("add-user")} />
|
|
||||||
{isFormLoader && (
|
|
||||||
<div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50">
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="w-full mx-auto">
|
|
||||||
<form onSubmit={handleSubmit}>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="name"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
{t("name")}
|
|
||||||
<span className="text-[red] text-[13px]"> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="name"
|
|
||||||
value={formdata.name}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
|
||||||
required
|
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="email"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
{t("email")}
|
|
||||||
<span className="text-[red] text-[13px]"> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
name="email"
|
|
||||||
value={formdata.email}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
required
|
|
||||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label className="block text-xs text-gray-700 font-semibold">
|
|
||||||
{t("password")}
|
|
||||||
</label>
|
|
||||||
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm text-base-content w-full h-full text-[13px]">
|
|
||||||
<div className="break-all">{formdata?.password}</div>
|
|
||||||
<i
|
|
||||||
onClick={() => copytoclipboard(formdata?.password)}
|
|
||||||
className="fa-light fa-copy rounded-full hover:bg-base-300 p-[8px] cursor-pointer "
|
|
||||||
></i>
|
|
||||||
</div>
|
|
||||||
<div className="text-[12px] ml-2 mb-0 text-[red] select-none">
|
|
||||||
{t("password-generateed")}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="phone"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
{t("phone")}
|
|
||||||
{/* <span className="text-[red] text-[13px]"> *</span> */}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="phone"
|
|
||||||
placeholder={t("phone-optional")}
|
|
||||||
value={formdata.phone}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="phone"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
{t("Role")}
|
|
||||||
<span className="text-[red] text-[13px]"> *</span>
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
value={formdata.role}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
name="role"
|
|
||||||
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
|
||||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<option defaultValue={""} value={""}>
|
|
||||||
{t("Select")}
|
|
||||||
</option>
|
|
||||||
{role.length > 0 &&
|
|
||||||
role.map((x) => (
|
|
||||||
<option key={x} value={x}>
|
|
||||||
{x}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center mt-3 gap-2 text-white">
|
|
||||||
<button type="submit" className="op-btn op-btn-primary">
|
|
||||||
{t("submit")}
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
type="button"
|
|
||||||
onClick={() => handleReset()}
|
|
||||||
className="op-btn op-btn-secondary"
|
|
||||||
>
|
|
||||||
{t("cancel")}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AddUser;
|
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import Parse from "parse";
|
||||||
|
import Title from "./Title";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
import {
|
||||||
|
copytoData,
|
||||||
|
usertimezone
|
||||||
|
} from "../constant/Utils";
|
||||||
|
import {
|
||||||
|
emailRegex,
|
||||||
|
} from "../constant/const";
|
||||||
|
import {
|
||||||
|
useTranslation
|
||||||
|
} from "react-i18next";
|
||||||
|
function generatePassword(length) {
|
||||||
|
const characters =
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
let result = "";
|
||||||
|
const charactersLength = characters.length;
|
||||||
|
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AddUser = (props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [formdata, setFormdata] = useState({
|
||||||
|
name: "",
|
||||||
|
phone: "",
|
||||||
|
email: "",
|
||||||
|
team: "",
|
||||||
|
password: "",
|
||||||
|
role: ""
|
||||||
|
});
|
||||||
|
const [isFormLoader, setIsFormLoader] = useState(false);
|
||||||
|
const [teamList, setTeamList] = useState([]);
|
||||||
|
const role = ["OrgAdmin", "Editor", "User"];
|
||||||
|
useEffect(() => {
|
||||||
|
getTeamList();
|
||||||
|
// eslint-disable-next-line
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getTeamList = async () => {
|
||||||
|
setFormdata((prev) => ({ ...prev, password: generatePassword(12) }));
|
||||||
|
const teamRes = await Parse.Cloud.run("getteams", { active: true });
|
||||||
|
if (teamRes.length > 0) {
|
||||||
|
const _teamRes = JSON.parse(JSON.stringify(teamRes));
|
||||||
|
setTeamList(_teamRes);
|
||||||
|
const allUserId =
|
||||||
|
_teamRes.find((x) => x.Name === "All Users")?.objectId || "";
|
||||||
|
setFormdata((prev) => ({ ...prev, team: allUserId }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const checkUserExist = async () => {
|
||||||
|
try {
|
||||||
|
const res = await Parse.Cloud.run("getUserDetails", {
|
||||||
|
email: formdata.email
|
||||||
|
});
|
||||||
|
if (res) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Define a function to handle form submission
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
if (!emailRegex.test(formdata.email)) {
|
||||||
|
alert("Please enter a valid email address.");
|
||||||
|
} else {
|
||||||
|
const localUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
|
setIsFormLoader(true);
|
||||||
|
const res = await checkUserExist();
|
||||||
|
if (res) {
|
||||||
|
props.showAlert("danger", t("user-already-exist"));
|
||||||
|
setIsFormLoader(false);
|
||||||
|
} else {
|
||||||
|
if (localStorage.getItem("TenantId")) {
|
||||||
|
const timezone = usertimezone;
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
name: formdata.name,
|
||||||
|
email: formdata.email,
|
||||||
|
phone: formdata.phone,
|
||||||
|
password: formdata.password,
|
||||||
|
role: formdata.role,
|
||||||
|
team: formdata.team,
|
||||||
|
timezone: timezone,
|
||||||
|
tenantId: localStorage.getItem("TenantId"),
|
||||||
|
organization: {
|
||||||
|
objectId: localUser?.OrganizationId?.objectId,
|
||||||
|
company: localUser?.Company
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const res = await Parse.Cloud.run("adduser", params);
|
||||||
|
const parseData = JSON.parse(JSON.stringify(res));
|
||||||
|
console.log("parseData ", parseData);
|
||||||
|
if (props.closePopup) {
|
||||||
|
props.closePopup();
|
||||||
|
}
|
||||||
|
if (props.handleUserData) {
|
||||||
|
if (formdata?.team) {
|
||||||
|
const team = teamList.find((x) => x.objectId === formdata.team);
|
||||||
|
parseData.TeamIds = parseData.TeamIds.map((y) =>
|
||||||
|
y.objectId === team.objectId ? team : y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
props.handleUserData(parseData);
|
||||||
|
}
|
||||||
|
setIsFormLoader(false);
|
||||||
|
setFormdata({
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
phone: "",
|
||||||
|
team: "",
|
||||||
|
role: ""
|
||||||
|
});
|
||||||
|
props.showAlert("success", t("user-created-successfully"));
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err", err);
|
||||||
|
setIsFormLoader(false);
|
||||||
|
props.showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
props.showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define a function to handle the "add yourself" checkbox
|
||||||
|
const handleReset = () => {
|
||||||
|
setFormdata({ name: "", email: "", phone: "", team: "", role: "" });
|
||||||
|
if (props.closePopup) {
|
||||||
|
props.closePopup();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleChange = (event) => {
|
||||||
|
let { name, value } = event.target;
|
||||||
|
if (name === "email") {
|
||||||
|
value = value?.toLowerCase()?.replace(/\s/g, "");
|
||||||
|
}
|
||||||
|
setFormdata((prev) => ({ ...prev, [name]: value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const copytoclipboard = (text) => {
|
||||||
|
copytoData(text);
|
||||||
|
props.showAlert("success", t("copied"));
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="shadow-md rounded-box my-[1px] p-3 bg-base-100 relative">
|
||||||
|
<Title title={t("add-user")} />
|
||||||
|
{isFormLoader && (
|
||||||
|
<div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="w-full mx-auto">
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label
|
||||||
|
htmlFor="name"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("name")}
|
||||||
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
value={formdata.name}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
onInvalid={(e) =>
|
||||||
|
e.target.setCustomValidity(t("input-required"))
|
||||||
|
}
|
||||||
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
|
required
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label
|
||||||
|
htmlFor="email"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("email")}
|
||||||
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
value={formdata.email}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
required
|
||||||
|
onInvalid={(e) =>
|
||||||
|
e.target.setCustomValidity(t("input-required"))
|
||||||
|
}
|
||||||
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label className="block text-xs text-gray-700 font-semibold">
|
||||||
|
{t("password")}
|
||||||
|
</label>
|
||||||
|
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm text-base-content w-full h-full text-[13px]">
|
||||||
|
<div className="break-all">{formdata?.password}</div>
|
||||||
|
<i
|
||||||
|
onClick={() => copytoclipboard(formdata?.password)}
|
||||||
|
className="fa-light fa-copy rounded-full hover:bg-base-300 p-[8px] cursor-pointer "
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
<div className="text-[12px] ml-2 mb-0 text-[red] select-none">
|
||||||
|
{t("password-generateed")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label
|
||||||
|
htmlFor="phone"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("phone")}
|
||||||
|
{/* <span className="text-[red] text-[13px]"> *</span> */}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="phone"
|
||||||
|
placeholder={t("phone-optional")}
|
||||||
|
value={formdata.phone}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label
|
||||||
|
htmlFor="phone"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("Role")}
|
||||||
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={formdata.role}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
name="role"
|
||||||
|
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
onInvalid={(e) =>
|
||||||
|
e.target.setCustomValidity(t("input-required"))
|
||||||
|
}
|
||||||
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<option defaultValue={""} value={""}>
|
||||||
|
{t("Select")}
|
||||||
|
</option>
|
||||||
|
{role.length > 0 &&
|
||||||
|
role.map((x) => (
|
||||||
|
<option key={x} value={x}>
|
||||||
|
{x}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center mt-3 gap-2 text-white">
|
||||||
|
<button type="submit" className="op-btn op-btn-primary">
|
||||||
|
{t("submit")}
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleReset()}
|
||||||
|
className="op-btn op-btn-secondary"
|
||||||
|
>
|
||||||
|
{t("cancel")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddUser;
|
||||||
+80
-77
@@ -3,7 +3,9 @@ import axios from "axios";
|
|||||||
import SuggestionInput from "./shared/fields/SuggestionInput";
|
import SuggestionInput from "./shared/fields/SuggestionInput";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { emailRegex } from "../constant/const";
|
import {
|
||||||
|
emailRegex,
|
||||||
|
} from "../constant/const";
|
||||||
const BulkSendUi = (props) => {
|
const BulkSendUi = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [forms, setForms] = useState([]);
|
const [forms, setForms] = useState([]);
|
||||||
@@ -20,15 +22,15 @@ const BulkSendUi = (props) => {
|
|||||||
|
|
||||||
//function to check atleast one signature field exist
|
//function to check atleast one signature field exist
|
||||||
const signatureExist = async () => {
|
const signatureExist = async () => {
|
||||||
setIsDisableBulkSend(false);
|
setIsDisableBulkSend(false);
|
||||||
const getPlaceholder = props?.Placeholders;
|
const getPlaceholder = props?.Placeholders;
|
||||||
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
|
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
|
||||||
placeholderObj?.placeHolder?.some((holder) =>
|
placeholderObj?.placeHolder?.some((holder) =>
|
||||||
holder?.pos?.some((posItem) => posItem?.type === "signature")
|
holder?.pos?.some((posItem) => posItem?.type === "signature")
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
setIsSignatureExist(checkIsSignatureExistt);
|
setIsSignatureExist(checkIsSignatureExistt);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (scrollOnNextUpdate && formRef.current) {
|
if (scrollOnNextUpdate && formRef.current) {
|
||||||
@@ -72,6 +74,7 @@ const BulkSendUi = (props) => {
|
|||||||
setForms(newForms);
|
setForms(newForms);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleRemoveForm = (index) => {
|
const handleRemoveForm = (index) => {
|
||||||
const updatedForms = forms.filter((_, i) => i !== index);
|
const updatedForms = forms.filter((_, i) => i !== index);
|
||||||
setForms(updatedForms);
|
setForms(updatedForms);
|
||||||
@@ -92,83 +95,82 @@ const BulkSendUi = (props) => {
|
|||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIsSubmit(true);
|
setIsSubmit(true);
|
||||||
if (validateEmails(forms)) {
|
if (validateEmails(forms)) {
|
||||||
// Create a copy of Placeholders array from props.item
|
// Create a copy of Placeholders array from props.item
|
||||||
let Placeholders = [...props.Placeholders];
|
let Placeholders = [...props.Placeholders];
|
||||||
// Initialize an empty array to store updated documents
|
// Initialize an empty array to store updated documents
|
||||||
let Documents = [];
|
let Documents = [];
|
||||||
// Loop through each form
|
// Loop through each form
|
||||||
forms.forEach((form) => {
|
forms.forEach((form) => {
|
||||||
//checking if user enter email which already exist as a signer then add user in a signers array
|
//checking if user enter email which already exist as a signer then add user in a signers array
|
||||||
let existSigner = [];
|
let existSigner = [];
|
||||||
form.fields.map((data) => {
|
form.fields.map((data) => {
|
||||||
if (data.signer) {
|
if (data.signer) {
|
||||||
existSigner.push(data.signer);
|
existSigner.push(data.signer);
|
||||||
}
|
|
||||||
});
|
|
||||||
// Map through the copied Placeholders array to update email values
|
|
||||||
const updatedPlaceholders = Placeholders.map((placeholder) => {
|
|
||||||
// Find the field in the current form that matches the placeholder Id
|
|
||||||
const field = form.fields.find(
|
|
||||||
(element) => parseInt(element.fieldId) === placeholder.Id
|
|
||||||
);
|
|
||||||
// If a matching field is found, update the email value in the placeholder
|
|
||||||
const signer = field?.signer?.objectId ? field.signer : "";
|
|
||||||
if (field) {
|
|
||||||
if (signer) {
|
|
||||||
return {
|
|
||||||
...placeholder,
|
|
||||||
signerObjId: field?.signer?.objectId || "",
|
|
||||||
signerPtr: signer
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
...placeholder,
|
|
||||||
email: field.email,
|
|
||||||
signerObjId: field?.signer?.objectId || "",
|
|
||||||
signerPtr: signer
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
// If no matching field is found, keep the placeholder as is
|
// Map through the copied Placeholders array to update email values
|
||||||
return placeholder;
|
const updatedPlaceholders = Placeholders.map((placeholder) => {
|
||||||
});
|
// Find the field in the current form that matches the placeholder Id
|
||||||
|
const field = form.fields.find(
|
||||||
|
(element) => parseInt(element.fieldId) === placeholder.Id
|
||||||
|
);
|
||||||
|
// If a matching field is found, update the email value in the placeholder
|
||||||
|
const signer = field?.signer?.objectId ? field.signer : "";
|
||||||
|
if (field) {
|
||||||
|
if (signer) {
|
||||||
|
return {
|
||||||
|
...placeholder,
|
||||||
|
signerObjId: field?.signer?.objectId || "",
|
||||||
|
signerPtr: signer
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
...placeholder,
|
||||||
|
email: field.email,
|
||||||
|
signerObjId: field?.signer?.objectId || "",
|
||||||
|
signerPtr: signer
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If no matching field is found, keep the placeholder as is
|
||||||
|
return placeholder;
|
||||||
|
});
|
||||||
|
|
||||||
// Push a new document object with updated Placeholders into the Documents array
|
// Push a new document object with updated Placeholders into the Documents array
|
||||||
if (existSigner?.length > 0) {
|
if (existSigner?.length > 0) {
|
||||||
Documents.push({
|
Documents.push({
|
||||||
...props.item,
|
...props.item,
|
||||||
Placeholders: updatedPlaceholders,
|
Placeholders: updatedPlaceholders,
|
||||||
Signers: props.item.Signers
|
Signers: props.item.Signers
|
||||||
? [...props.item.Signers, ...existSigner]
|
? [...props.item.Signers, ...existSigner]
|
||||||
: [...existSigner]
|
: [...existSigner]
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Documents.push({
|
Documents.push({
|
||||||
...props.item,
|
...props.item,
|
||||||
Placeholders: updatedPlaceholders,
|
Placeholders: updatedPlaceholders,
|
||||||
SignatureType: props.signatureType
|
SignatureType: props.signatureType
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await batchQuery(Documents);
|
await batchQuery(Documents);
|
||||||
} else {
|
} else {
|
||||||
setIsSubmit(false);
|
setIsSubmit(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const batchQuery = async (Documents) => {
|
const batchQuery = async (Documents) => {
|
||||||
const token = {
|
const token =
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
{ "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
|
||||||
};
|
|
||||||
const functionsUrl = `${localStorage.getItem(
|
const functionsUrl = `${localStorage.getItem(
|
||||||
"baseUrl"
|
"baseUrl"
|
||||||
)}functions/batchdocuments`;
|
)}functions/batchdocuments`;
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
...token
|
...token,
|
||||||
};
|
};
|
||||||
const params = { Documents: JSON.stringify(Documents) };
|
const params = { Documents: JSON.stringify(Documents) };
|
||||||
try {
|
try {
|
||||||
@@ -275,7 +277,8 @@ const BulkSendUi = (props) => {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -32,14 +32,15 @@ const Header = ({ showSidebar, setIsMenu, isConsole }) => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
async function initializeHead() {
|
async function initializeHead() {
|
||||||
const applogo = await getAppLogo();
|
const applogo = await getAppLogo();
|
||||||
if (applogo?.logo) {
|
if (applogo?.logo) {
|
||||||
setAppLogo(applogo?.logo);
|
setAppLogo(applogo?.logo);
|
||||||
} else {
|
} else {
|
||||||
const logo = localStorage.getItem("appLogo") || appInfo.applogo;
|
const logo = localStorage.getItem("appLogo") || appInfo.applogo;
|
||||||
setAppLogo(logo);
|
setAppLogo(logo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeDropdown = async () => {
|
const closeDropdown = async () => {
|
||||||
@@ -152,15 +153,15 @@ const Header = ({ showSidebar, setIsMenu, isConsole }) => {
|
|||||||
>
|
>
|
||||||
{!isConsole && (
|
{!isConsole && (
|
||||||
<>
|
<>
|
||||||
<li
|
<li
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
openInNewTab("https://docs.opensignlabs.com")
|
openInNewTab("https://docs.opensignlabs.com")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
<i className="fa-light fa-book"></i> {t("docs")}
|
<i className="fa-light fa-book"></i> {t("docs")}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
+21
-6
@@ -1,4 +1,7 @@
|
|||||||
import React, { useState, useRef } from "react";
|
import React, {
|
||||||
|
useState,
|
||||||
|
useRef,
|
||||||
|
} from "react";
|
||||||
import {
|
import {
|
||||||
base64ToArrayBuffer,
|
base64ToArrayBuffer,
|
||||||
convertBase64ToFile,
|
convertBase64ToFile,
|
||||||
@@ -24,9 +27,10 @@ const EditTemplate = ({
|
|||||||
template,
|
template,
|
||||||
onSuccess,
|
onSuccess,
|
||||||
setPdfArrayBuffer,
|
setPdfArrayBuffer,
|
||||||
setPdfBase64Url
|
setPdfBase64Url,
|
||||||
}) => {
|
}) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const inputFileRef = useRef(null);
|
const inputFileRef = useRef(null);
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
@@ -165,7 +169,10 @@ const EditTemplate = ({
|
|||||||
}
|
}
|
||||||
let pdfUrl;
|
let pdfUrl;
|
||||||
if (uploadPdf?.base64) {
|
if (uploadPdf?.base64) {
|
||||||
pdfUrl = await convertBase64ToFile(uploadPdf.name, uploadPdf.base64);
|
pdfUrl = await convertBase64ToFile(
|
||||||
|
uploadPdf.name,
|
||||||
|
uploadPdf.base64,
|
||||||
|
);
|
||||||
setUploadPdf((prev) => ({ ...prev, url: pdfUrl }));
|
setUploadPdf((prev) => ({ ...prev, url: pdfUrl }));
|
||||||
const pdfBuffer = base64ToArrayBuffer(uploadPdf.base64);
|
const pdfBuffer = base64ToArrayBuffer(uploadPdf.base64);
|
||||||
setPdfArrayBuffer && setPdfArrayBuffer(pdfBuffer);
|
setPdfArrayBuffer && setPdfArrayBuffer(pdfBuffer);
|
||||||
@@ -447,7 +454,11 @@ const EditTemplate = ({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</label>
|
</label>
|
||||||
<div className="flex flex-col md:flex-row md:gap-4">
|
<div className="flex flex-col md:flex-row md:gap-4">
|
||||||
<div className={`flex items-center gap-2 ml-2 mb-1`}>
|
<div
|
||||||
|
className={
|
||||||
|
`flex items-center gap-2 ml-2 mb-1`
|
||||||
|
}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
className="mr-[2px] op-radio op-radio-xs"
|
className="mr-[2px] op-radio op-radio-xs"
|
||||||
type="radio"
|
type="radio"
|
||||||
@@ -456,7 +467,11 @@ const EditTemplate = ({
|
|||||||
/>
|
/>
|
||||||
<div className="text-center">{t("yes")}</div>
|
<div className="text-center">{t("yes")}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={`flex items-center gap-2 ml-2 mb-1`}>
|
<div
|
||||||
|
className={
|
||||||
|
`flex items-center gap-2 ml-2 mb-1`
|
||||||
|
}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
className="mr-[2px] op-radio op-radio-xs"
|
className="mr-[2px] op-radio op-radio-xs"
|
||||||
type="radio"
|
type="radio"
|
||||||
+8
-3
@@ -1,6 +1,10 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { handleToPrint } from "../../constant/Utils";
|
import {
|
||||||
import { emailRegex } from "../../constant/const";
|
handleToPrint,
|
||||||
|
} from "../../constant/Utils";
|
||||||
|
import {
|
||||||
|
emailRegex,
|
||||||
|
} from "../../constant/const";
|
||||||
import Loader from "../../primitives/Loader";
|
import Loader from "../../primitives/Loader";
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -37,7 +41,8 @@ function EmailComponent({
|
|||||||
setEmailList([]);
|
setEmailList([]);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
setIsEmail(false);
|
setIsEmail(false);
|
||||||
setIsAlert({
|
setIsAlert({
|
||||||
+20
-13
@@ -28,8 +28,12 @@ function Header(props) {
|
|||||||
const enabledBackBtn = props?.disabledBackBtn === true ? false : true;
|
const enabledBackBtn = props?.disabledBackBtn === true ? false : true;
|
||||||
//function for show decline alert
|
//function for show decline alert
|
||||||
const handleDeclinePdfAlert = async () => {
|
const handleDeclinePdfAlert = async () => {
|
||||||
const currentDecline = { currnt: "Sure", isDeclined: true };
|
if (props?.handleDecline) {
|
||||||
props?.setIsDecline(currentDecline);
|
props.handleDecline();
|
||||||
|
} else {
|
||||||
|
const currentDecline = { currnt: "Sure", isDeclined: true };
|
||||||
|
props?.setIsDecline(currentDecline);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const handleDetelePage = async () => {
|
const handleDetelePage = async () => {
|
||||||
props?.setIsUploadPdf && props?.setIsUploadPdf(true);
|
props?.setIsUploadPdf && props?.setIsUploadPdf(true);
|
||||||
@@ -102,7 +106,6 @@ function Header(props) {
|
|||||||
console.error("Error merging PDF:", error);
|
console.error("Error merging PDF:", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex py-[5px]">
|
<div className="flex py-[5px]">
|
||||||
{isMobile && props?.isShowHeader ? (
|
{isMobile && props?.isShowHeader ? (
|
||||||
@@ -273,6 +276,20 @@ function Header(props) {
|
|||||||
className="bg-white shadow-md rounded-md px-3 py-2"
|
className="bg-white shadow-md rounded-md px-3 py-2"
|
||||||
sideOffset={5}
|
sideOffset={5}
|
||||||
>
|
>
|
||||||
|
{props?.setIsEditTemplate && (
|
||||||
|
<DropdownMenu.Item
|
||||||
|
className="DropdownMenuItem"
|
||||||
|
onClick={() => props?.setIsEditTemplate(true)}
|
||||||
|
>
|
||||||
|
<div className="flex flex-row">
|
||||||
|
<i
|
||||||
|
className="fa-light fa-gear mr-[3px]"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
<span className="font-[500]">{t("Edit")}</span>
|
||||||
|
</div>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
)}
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Item
|
||||||
className="DropdownMenuItem"
|
className="DropdownMenuItem"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -502,16 +519,6 @@ function Header(props) {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex" data-tut="reactourFifth">
|
<div className="flex" data-tut="reactourFifth">
|
||||||
{(!props?.templateId && !props?.isSelfSign) ||
|
|
||||||
(!props.isGuestSignFlow && (
|
|
||||||
<button
|
|
||||||
onClick={() => window.history.go(-2)}
|
|
||||||
type="button"
|
|
||||||
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
|
||||||
>
|
|
||||||
{t("back")}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
{props?.currentSigner && (
|
{props?.currentSigner && (
|
||||||
<>
|
<>
|
||||||
{props?.templateId && (
|
{props?.templateId && (
|
||||||
+29
-52
@@ -3,6 +3,7 @@ import BorderResize from "./BorderResize";
|
|||||||
import PlaceholderBorder from "./PlaceholderBorder";
|
import PlaceholderBorder from "./PlaceholderBorder";
|
||||||
import { Rnd } from "react-rnd";
|
import { Rnd } from "react-rnd";
|
||||||
import {
|
import {
|
||||||
|
changeDateToMomentFormat,
|
||||||
defaultWidthHeight,
|
defaultWidthHeight,
|
||||||
fontColorArr,
|
fontColorArr,
|
||||||
fontsizeArr,
|
fontsizeArr,
|
||||||
@@ -52,32 +53,6 @@ const selectFormat = (data) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeDateToMomentFormat = (format) => {
|
|
||||||
switch (format) {
|
|
||||||
case "MM/dd/yyyy":
|
|
||||||
return "L";
|
|
||||||
case "dd-MM-yyyy":
|
|
||||||
return "DD-MM-YYYY";
|
|
||||||
case "dd/MM/yyyy":
|
|
||||||
return "DD/MM/YYYY";
|
|
||||||
case "MMMM dd, yyyy":
|
|
||||||
return "LL";
|
|
||||||
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 "dd MMMM, yyyy":
|
|
||||||
return "DD MMMM, YYYY";
|
|
||||||
default:
|
|
||||||
return "L";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//function to get default format
|
//function to get default format
|
||||||
const getDefaultFormat = (dateFormat) => dateFormat || "MM/dd/yyyy";
|
const getDefaultFormat = (dateFormat) => dateFormat || "MM/dd/yyyy";
|
||||||
|
|
||||||
@@ -199,7 +174,7 @@ function Placeholder(props) {
|
|||||||
}, [selectDate]);
|
}, [selectDate]);
|
||||||
|
|
||||||
//`handleWidgetIdandPopup` is used to set current widget id and open relative popup
|
//`handleWidgetIdandPopup` is used to set current widget id and open relative popup
|
||||||
const handleWidgetIdandPopup = () => {
|
const handleWidgetIdandPopup = async () => {
|
||||||
if (props.setSelectWidgetId) {
|
if (props.setSelectWidgetId) {
|
||||||
props.setSelectWidgetId(props.pos.key);
|
props.setSelectWidgetId(props.pos.key);
|
||||||
}
|
}
|
||||||
@@ -222,31 +197,31 @@ function Placeholder(props) {
|
|||||||
if (props?.ispublicTemplate) {
|
if (props?.ispublicTemplate) {
|
||||||
props.handleUserDetails();
|
props.handleUserDetails();
|
||||||
} else {
|
} else {
|
||||||
if (props?.isNeedSign) {
|
if (props?.isNeedSign) {
|
||||||
//funcion is used to height widgets on top if two widgets on overlap
|
//funcion is used to heightlight widgets on top if two widgets on overlap
|
||||||
const getCurrentSignerPos = props.xyPosition.find(
|
const getCurrentSignerPos = props.xyPosition.find(
|
||||||
(x) => x.Id === props.uniqueId
|
(x) => x.Id === props.uniqueId
|
||||||
);
|
);
|
||||||
const updateZindex = handleHeighlightWidget(
|
const updateZindex = handleHeighlightWidget(
|
||||||
getCurrentSignerPos,
|
getCurrentSignerPos,
|
||||||
props.pos.key,
|
props.pos.key,
|
||||||
props.pageNumber
|
props.pageNumber
|
||||||
);
|
);
|
||||||
const updatesignerPos = props.xyPosition.map((x) =>
|
const updatesignerPos = props.xyPosition.map((x) =>
|
||||||
x.Id === props.uniqueId ? { ...x, placeHolder: updateZindex } : x
|
x.Id === props.uniqueId ? { ...x, placeHolder: updateZindex } : x
|
||||||
);
|
);
|
||||||
props.setXyPosition(updatesignerPos);
|
props.setXyPosition(updatesignerPos);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
["signature", "stamp", "image", "initials"].includes(props.pos.type)
|
["signature", "stamp", "image", "initials"].includes(props.pos.type)
|
||||||
) {
|
) {
|
||||||
props.setIsSignPad(true);
|
props.setIsSignPad(true);
|
||||||
props.setSignKey(props.pos.key);
|
props.setSignKey(props.pos.key);
|
||||||
props.setIsStamp(props.pos.isStamp);
|
props.setIsStamp(props.pos.isStamp);
|
||||||
}
|
}
|
||||||
if (props.pos.type === "initials") {
|
if (props.pos.type === "initials") {
|
||||||
props.setIsInitial(true);
|
props.setIsInitial(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
props.isPlaceholder &&
|
props.isPlaceholder &&
|
||||||
@@ -367,6 +342,8 @@ function Placeholder(props) {
|
|||||||
} else {
|
} else {
|
||||||
widgetClickHandler();
|
widgetClickHandler();
|
||||||
}
|
}
|
||||||
|
// }
|
||||||
|
// }
|
||||||
} else {
|
} else {
|
||||||
//The else condition is used to handle the case when the user clicks on a widget and open signature pad to draw sign
|
//The else condition is used to handle the case when the user clicks on a widget and open signature pad to draw sign
|
||||||
props.setCurrWidgetsDetails && props.setCurrWidgetsDetails(props.pos);
|
props.setCurrWidgetsDetails && props.setCurrWidgetsDetails(props.pos);
|
||||||
+24
-42
@@ -7,7 +7,8 @@ import {
|
|||||||
radioButtonWidget,
|
radioButtonWidget,
|
||||||
range,
|
range,
|
||||||
textInputWidget,
|
textInputWidget,
|
||||||
textWidget
|
textWidget,
|
||||||
|
widgetDataValue
|
||||||
} from "../../constant/Utils";
|
} from "../../constant/Utils";
|
||||||
import DatePicker from "react-datepicker";
|
import DatePicker from "react-datepicker";
|
||||||
import "react-datepicker/dist/react-datepicker.css";
|
import "react-datepicker/dist/react-datepicker.css";
|
||||||
@@ -24,6 +25,8 @@ const widgetCls =
|
|||||||
function PlaceholderType(props) {
|
function PlaceholderType(props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const type = props?.pos?.type;
|
const type = props?.pos?.type;
|
||||||
|
const widgetData =
|
||||||
|
props.pos?.options?.defaultValue || props.pos?.options?.response;
|
||||||
const widgetTypeTranslation = t(`widgets-name.${props?.pos?.type}`);
|
const widgetTypeTranslation = t(`widgets-name.${props?.pos?.type}`);
|
||||||
const [selectOption, setSelectOption] = useState("");
|
const [selectOption, setSelectOption] = useState("");
|
||||||
const [validatePlaceholder, setValidatePlaceholder] = useState("");
|
const [validatePlaceholder, setValidatePlaceholder] = useState("");
|
||||||
@@ -141,29 +144,6 @@ function PlaceholderType(props) {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (
|
|
||||||
["name", "email", "job title", "company"].includes(props.pos?.type) &&
|
|
||||||
props.isNeedSign &&
|
|
||||||
props.data?.signerObjId === props?.signerObjId
|
|
||||||
) {
|
|
||||||
const defaultData = props.pos?.options?.defaultValue;
|
|
||||||
if (defaultData) {
|
|
||||||
setTextValue(defaultData);
|
|
||||||
}
|
|
||||||
if (props.pos?.options?.hint) {
|
|
||||||
setHint(props.pos?.options.hint);
|
|
||||||
} else {
|
|
||||||
setHint(props.pos?.type);
|
|
||||||
}
|
|
||||||
} else if ([textInputWidget].includes(props.pos?.type)) {
|
|
||||||
const defaultData = props.pos?.options?.defaultValue;
|
|
||||||
if (defaultData) {
|
|
||||||
setTextValue(defaultData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [props.pos?.options?.defaultValue]);
|
|
||||||
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
|
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -176,32 +156,30 @@ function PlaceholderType(props) {
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
<i className="fa-light fa-calendar ml-[5px]"></i>
|
<i className="fa-light fa-calendar ml-[5px]"></i>
|
||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
ExampleCustomInput.displayName = "ExampleCustomInput";
|
ExampleCustomInput.displayName = "ExampleCustomInput";
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
["name", "email", "job title", "company"].includes(type) &&
|
["name", "email", "job title", "company", textInputWidget].includes(
|
||||||
|
type
|
||||||
|
) &&
|
||||||
props.isNeedSign &&
|
props.isNeedSign &&
|
||||||
props.data?.signerObjId === props.signerObjId
|
props.data?.signerObjId === props.signerObjId
|
||||||
) {
|
) {
|
||||||
const isDefault = true;
|
if (widgetData) {
|
||||||
const senderUser = localStorage.getItem(`Extand_Class`);
|
setTextValue(widgetData);
|
||||||
const jsonSender = JSON.parse(senderUser);
|
}
|
||||||
onChangeInput(
|
}
|
||||||
jsonSender && jsonSender[0],
|
|
||||||
null,
|
if (props.pos?.options?.hint) {
|
||||||
props.xyPosition,
|
setHint(props.pos?.options.hint);
|
||||||
null,
|
} else {
|
||||||
props.setXyPosition,
|
setHint(props.pos?.type);
|
||||||
props.data.Id,
|
|
||||||
isDefault
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [type]);
|
}, [type, widgetData]);
|
||||||
//function for show checked checkbox
|
//function for show checked checkbox
|
||||||
const selectCheckbox = (ind) => {
|
const selectCheckbox = (ind) => {
|
||||||
const res = props.pos.options?.response;
|
const res = props.pos.options?.response;
|
||||||
@@ -462,10 +440,14 @@ function PlaceholderType(props) {
|
|||||||
props.isNeedSign &&
|
props.isNeedSign &&
|
||||||
(props.pos.options?.isReadOnly ||
|
(props.pos.options?.isReadOnly ||
|
||||||
props.data?.signerObjId !== props.signerObjId)
|
props.data?.signerObjId !== props.signerObjId)
|
||||||
? " bg-black/68 select-none "
|
? "select-none"
|
||||||
: "" + textWidgetCls
|
: "" + textWidgetCls
|
||||||
}`}
|
}`}
|
||||||
style={{ fontSize: fontSize, color: fontColor }}
|
style={{
|
||||||
|
fontSize: fontSize,
|
||||||
|
color: fontColor,
|
||||||
|
background: props.data?.blockColor
|
||||||
|
}}
|
||||||
disabled={
|
disabled={
|
||||||
props.isNeedSign &&
|
props.isNeedSign &&
|
||||||
(props.pos.options?.isReadOnly ||
|
(props.pos.options?.isReadOnly ||
|
||||||
+1
@@ -403,6 +403,7 @@ function RenderPdf(props) {
|
|||||||
onGetAnnotationsError={(error) => {
|
onGetAnnotationsError={(error) => {
|
||||||
console.log("annotation error", error);
|
console.log("annotation error", error);
|
||||||
}}
|
}}
|
||||||
|
className="select-none touch-callout-none"
|
||||||
/>
|
/>
|
||||||
</Document>
|
</Document>
|
||||||
</div>
|
</div>
|
||||||
+62
-22
@@ -71,8 +71,15 @@ function SignPad(props) {
|
|||||||
} else if (tab === "typed") {
|
} else if (tab === "typed") {
|
||||||
setIsTab("type");
|
setIsTab("type");
|
||||||
} else if (tab === "default") {
|
} else if (tab === "default") {
|
||||||
setIsDefaultSign(true);
|
if (
|
||||||
setIsTab("mysignature");
|
(props?.isInitial && props?.myInitial) ||
|
||||||
|
(!props?.isInitial && props?.defaultSign)
|
||||||
|
) {
|
||||||
|
setIsDefaultSign(true);
|
||||||
|
setIsTab("mysignature");
|
||||||
|
} else {
|
||||||
|
setIsTab("draw");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setIsTab(true);
|
setIsTab(true);
|
||||||
}
|
}
|
||||||
@@ -630,26 +637,59 @@ function SignPad(props) {
|
|||||||
<div className="p-[20px] h-full">
|
<div className="p-[20px] h-full">
|
||||||
{isDefaultSign ? (
|
{isDefaultSign ? (
|
||||||
<>
|
<>
|
||||||
<div className="flex justify-center">
|
{!props?.isInitial &&
|
||||||
<div
|
props?.defaultSign &&
|
||||||
className={`${props?.isInitial ? "intialSignatureCanvas" : "signatureCanvas"} bg-white border-[1.3px] border-[#007bff] flex flex-col justify-center items-center mb-[6px] cursor-pointer`}
|
isTabEnabled("default") && (
|
||||||
>
|
<>
|
||||||
<img
|
<div className="flex justify-center">
|
||||||
alt="stamp img"
|
<div
|
||||||
className="w-full h-full object-contain bg-white"
|
className={`${props?.isInitial ? "intialSignatureCanvas" : "signatureCanvas"} bg-white border-[1.3px] border-[#007bff] flex flex-col justify-center items-center mb-[6px] cursor-pointer`}
|
||||||
draggable="false"
|
>
|
||||||
src={
|
<img
|
||||||
props?.isInitial
|
alt="stamp img"
|
||||||
? props?.myInitial
|
className="w-full h-full object-contain bg-white"
|
||||||
: props?.defaultSign
|
draggable="false"
|
||||||
}
|
src={
|
||||||
/>
|
props?.isInitial
|
||||||
</div>
|
? props?.myInitial
|
||||||
</div>
|
: props?.defaultSign
|
||||||
{props.setIsAutoSign && autoSignAll()}
|
}
|
||||||
<div className="flex justify-end">
|
/>
|
||||||
<SaveBtn />
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{props.setIsAutoSign && autoSignAll()}
|
||||||
|
<div className="flex justify-end">
|
||||||
|
<SaveBtn />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{props?.isInitial &&
|
||||||
|
props?.myInitial &&
|
||||||
|
isTabEnabled("default") && (
|
||||||
|
<>
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<div
|
||||||
|
className={`${props?.isInitial ? "intialSignatureCanvas" : "signatureCanvas"} bg-white border-[1.3px] border-[#007bff] flex flex-col justify-center items-center mb-[6px] cursor-pointer`}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt="stamp img"
|
||||||
|
className="w-full h-full object-contain bg-white"
|
||||||
|
draggable="false"
|
||||||
|
src={
|
||||||
|
props?.isInitial
|
||||||
|
? props?.myInitial
|
||||||
|
: props?.defaultSign
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{props.setIsAutoSign && autoSignAll()}
|
||||||
|
<div className="flex justify-end">
|
||||||
|
<SaveBtn />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
) : props?.isImageSelect || props?.isStamp ? (
|
) : props?.isImageSelect || props?.isStamp ? (
|
||||||
!props?.image ? (
|
!props?.image ? (
|
||||||
+1
@@ -117,6 +117,7 @@ const WidgetNameModal = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const handleCheckboxChange = (index) => {
|
const handleCheckboxChange = (index) => {
|
||||||
// Update the state with the modified array
|
// Update the state with the modified array
|
||||||
setSignatureType((prev) =>
|
setSignatureType((prev) =>
|
||||||
+2
-1
@@ -6,7 +6,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
|
|
||||||
const FolderModal = (props) => {
|
const FolderModal = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||||
const [clickFolder, setClickFolder] = useState("");
|
const [clickFolder, setClickFolder] = useState("");
|
||||||
const [folderList, setFolderList] = useState([]);
|
const [folderList, setFolderList] = useState([]);
|
||||||
+2
-1
@@ -6,7 +6,8 @@ import Tooltip from "../../../primitives/Tooltip";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [isOpen, SetIsOpen] = useState(false);
|
const [isOpen, SetIsOpen] = useState(false);
|
||||||
+4
-4
@@ -117,7 +117,9 @@ const SignersInput = (props) => {
|
|||||||
};
|
};
|
||||||
const loadOptions = async (inputValue) => {
|
const loadOptions = async (inputValue) => {
|
||||||
try {
|
try {
|
||||||
const contactRes = await findContact(inputValue);
|
const contactRes = await findContact(
|
||||||
|
inputValue,
|
||||||
|
);
|
||||||
if (contactRes) {
|
if (contactRes) {
|
||||||
const res = JSON.parse(JSON.stringify(contactRes));
|
const res = JSON.parse(JSON.stringify(contactRes));
|
||||||
//compareArrays is a function where compare between two array (total signersList and dcument signers list)
|
//compareArrays is a function where compare between two array (total signersList and dcument signers list)
|
||||||
@@ -152,9 +154,7 @@ const SignersInput = (props) => {
|
|||||||
{props.label ? props.label : t("signers")}
|
{props.label ? props.label : t("signers")}
|
||||||
{props.required && <span className="text-red-500 text-[13px]">*</span>}
|
{props.required && <span className="text-red-500 text-[13px]">*</span>}
|
||||||
<span
|
<span
|
||||||
className={`z-[${
|
className={`z-[${props?.helptextZindex ? props.helptextZindex : 30}] absolute ml-1 text-xs`}
|
||||||
props?.helptextZindex ? props.helptextZindex : 30
|
|
||||||
}] absolute ml-1 text-xs`}
|
|
||||||
>
|
>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
id={`${props.label ? props.label : "signers"}-tooltip`}
|
id={`${props.label ? props.label : "signers"}-tooltip`}
|
||||||
+2
-1
@@ -3,7 +3,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { NavLink } from "react-router";
|
import { NavLink } from "react-router";
|
||||||
|
|
||||||
const Menu = ({ item, isOpen, closeSidebar }) => {
|
const Menu = ({ item, isOpen, closeSidebar }) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
+2
-1
@@ -3,7 +3,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { NavLink } from "react-router";
|
import { NavLink } from "react-router";
|
||||||
|
|
||||||
const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
|
const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { title, icon, children } = item;
|
const { title, icon, children } = item;
|
||||||
@@ -7,7 +7,9 @@ import { appInfo } from "./appinfo";
|
|||||||
import { saveAs } from "file-saver";
|
import { saveAs } from "file-saver";
|
||||||
import printModule from "print-js";
|
import printModule from "print-js";
|
||||||
import fontkit from "@pdf-lib/fontkit";
|
import fontkit from "@pdf-lib/fontkit";
|
||||||
import { themeColor } from "./const";
|
import {
|
||||||
|
themeColor
|
||||||
|
} from "./const";
|
||||||
import { format, toZonedTime } from "date-fns-tz";
|
import { format, toZonedTime } from "date-fns-tz";
|
||||||
|
|
||||||
export const fontsizeArr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28];
|
export const fontsizeArr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28];
|
||||||
@@ -135,12 +137,15 @@ export const pdfNewWidthFun = (divRef) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//`contractUsers` function is used to get contract_User details
|
//`contractUsers` function is used to get contract_User details
|
||||||
export const contractUsers = async () => {
|
export const contractUsers = async (
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const url = `${localStorage.getItem("baseUrl")}functions/getUserDetails`;
|
const url = `${localStorage.getItem("baseUrl")}functions/getUserDetails`;
|
||||||
const parseAppId = localStorage.getItem("parseAppId");
|
const parseAppId = localStorage.getItem("parseAppId");
|
||||||
const accesstoken = localStorage.getItem("accesstoken");
|
const accesstoken =
|
||||||
const token = { "X-Parse-Session-Token": accesstoken };
|
localStorage.getItem("accesstoken");
|
||||||
|
const token =
|
||||||
|
{ "X-Parse-Session-Token": accesstoken };
|
||||||
const headers = {
|
const headers = {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -272,7 +277,33 @@ export const selectFormat = (data) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addWidgetOptions = (type, signer) => {
|
export const changeDateToMomentFormat = (format) => {
|
||||||
|
switch (format) {
|
||||||
|
case "MM/dd/yyyy":
|
||||||
|
return "L";
|
||||||
|
case "dd-MM-yyyy":
|
||||||
|
return "DD-MM-YYYY";
|
||||||
|
case "dd/MM/yyyy":
|
||||||
|
return "DD/MM/YYYY";
|
||||||
|
case "MMMM dd, yyyy":
|
||||||
|
return "LL";
|
||||||
|
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 "dd MMMM, yyyy":
|
||||||
|
return "DD MMMM, YYYY";
|
||||||
|
default:
|
||||||
|
return "L";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export const addWidgetOptions = (type, signer, widgetValue) => {
|
||||||
const defaultOpt = { name: type, status: "required" };
|
const defaultOpt = { name: type, status: "required" };
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "signature":
|
case "signature":
|
||||||
@@ -289,11 +320,11 @@ export const addWidgetOptions = (type, signer) => {
|
|||||||
case "initials":
|
case "initials":
|
||||||
return defaultOpt;
|
return defaultOpt;
|
||||||
case "name":
|
case "name":
|
||||||
return { ...defaultOpt };
|
return { ...defaultOpt, defaultValue: widgetValue ? widgetValue : "" };
|
||||||
case "company":
|
case "company":
|
||||||
return { ...defaultOpt };
|
return { ...defaultOpt, defaultValue: widgetValue ? widgetValue : "" };
|
||||||
case "job title":
|
case "job title":
|
||||||
return { ...defaultOpt };
|
return { ...defaultOpt, defaultValue: widgetValue ? widgetValue : "" };
|
||||||
case "date": {
|
case "date": {
|
||||||
const dateFormat = signer?.DateFormat
|
const dateFormat = signer?.DateFormat
|
||||||
? selectFormat(signer?.DateFormat)
|
? selectFormat(signer?.DateFormat)
|
||||||
@@ -307,7 +338,11 @@ export const addWidgetOptions = (type, signer) => {
|
|||||||
case "image":
|
case "image":
|
||||||
return defaultOpt;
|
return defaultOpt;
|
||||||
case "email":
|
case "email":
|
||||||
return { ...defaultOpt, validation: { type: "email", pattern: "" } };
|
return {
|
||||||
|
...defaultOpt,
|
||||||
|
validation: { type: "email", pattern: "" },
|
||||||
|
defaultValue: widgetValue ? widgetValue : ""
|
||||||
|
};
|
||||||
case "dropdown":
|
case "dropdown":
|
||||||
return defaultOpt;
|
return defaultOpt;
|
||||||
case radioButtonWidget:
|
case radioButtonWidget:
|
||||||
@@ -530,7 +565,7 @@ export const signPdfFun = async (
|
|||||||
documentId,
|
documentId,
|
||||||
signerObjectId,
|
signerObjectId,
|
||||||
objectId,
|
objectId,
|
||||||
widgets
|
widgets,
|
||||||
) => {
|
) => {
|
||||||
let isCustomCompletionMail = false;
|
let isCustomCompletionMail = false;
|
||||||
try {
|
try {
|
||||||
@@ -539,7 +574,10 @@ export const signPdfFun = async (
|
|||||||
if (tenantDetails && tenantDetails === "user does not exist!") {
|
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||||
return { status: "error", message: "User does not exist." };
|
return { status: "error", message: "User does not exist." };
|
||||||
} else {
|
} else {
|
||||||
if (tenantDetails?.CompletionBody && tenantDetails?.CompletionSubject) {
|
if (
|
||||||
|
tenantDetails?.CompletionBody &&
|
||||||
|
tenantDetails?.CompletionSubject
|
||||||
|
) {
|
||||||
isCustomCompletionMail = true;
|
isCustomCompletionMail = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -829,7 +867,8 @@ export const onChangeInput = (
|
|||||||
...position,
|
...position,
|
||||||
options: {
|
options: {
|
||||||
...position.options,
|
...position.options,
|
||||||
response: value
|
response: value,
|
||||||
|
defaultValue:""
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -983,21 +1022,21 @@ export const calculateInitialWidthHeight = (widgetData) => {
|
|||||||
document.body.removeChild(span);
|
document.body.removeChild(span);
|
||||||
return { getWidth: width, getHeight: height };
|
return { getWidth: width, getHeight: height };
|
||||||
};
|
};
|
||||||
export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
export const widgetDataValue = (type, value) => {
|
||||||
function widgetDataValue(type) {
|
switch (type) {
|
||||||
switch (type) {
|
case "name":
|
||||||
case "name":
|
return value?.Name;
|
||||||
return value?.Name;
|
case "company":
|
||||||
case "company":
|
return value?.Company;
|
||||||
return value?.Company;
|
case "job title":
|
||||||
case "job title":
|
return value?.JobTitle;
|
||||||
return value?.JobTitle;
|
case "email":
|
||||||
case "email":
|
return value?.Email;
|
||||||
return value?.Email;
|
default:
|
||||||
default:
|
return "";
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
||||||
return signerPos.map((item) => {
|
return signerPos.map((item) => {
|
||||||
if (item.placeHolder && item.placeHolder.length > 0) {
|
if (item.placeHolder && item.placeHolder.length > 0) {
|
||||||
// If there is a nested array, recursively add the field to the last object
|
// If there is a nested array, recursively add the field to the last object
|
||||||
@@ -1022,7 +1061,7 @@ export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
|||||||
// Adjust this line to add the desired field
|
// Adjust this line to add the desired field
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const widgetData = widgetDataValue(item.type);
|
const widgetData = widgetDataValue(item.type, value);
|
||||||
if (["name", "company", "job title", "email"].includes(item.type)) {
|
if (["name", "company", "job title", "email"].includes(item.type)) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -1040,7 +1079,8 @@ export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
|||||||
|
|
||||||
//function for embed document id
|
//function for embed document id
|
||||||
export const embedDocId = async (pdfDoc, documentId, allPages) => {
|
export const embedDocId = async (pdfDoc, documentId, allPages) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
// `fontBytes` is used to embed custom font in pdf
|
// `fontBytes` is used to embed custom font in pdf
|
||||||
const fontBytes = await fileasbytes(
|
const fontBytes = await fileasbytes(
|
||||||
"https://cdn.opensignlabs.com/webfonts/times.ttf"
|
"https://cdn.opensignlabs.com/webfonts/times.ttf"
|
||||||
@@ -1049,7 +1089,8 @@ export const embedDocId = async (pdfDoc, documentId, allPages) => {
|
|||||||
const font = await pdfDoc.embedFont(fontBytes, { subset: true });
|
const font = await pdfDoc.embedFont(fontBytes, { subset: true });
|
||||||
for (let i = 0; i < allPages; i++) {
|
for (let i = 0; i < allPages; i++) {
|
||||||
const fontSize = 10;
|
const fontSize = 10;
|
||||||
const textContent = documentId && `${appName} DocumentId: ${documentId} `;
|
const textContent =
|
||||||
|
documentId && `${appName} DocumentId: ${documentId} `;
|
||||||
const pages = pdfDoc.getPages();
|
const pages = pdfDoc.getPages();
|
||||||
const page = pages[i];
|
const page = pages[i];
|
||||||
try {
|
try {
|
||||||
@@ -1874,7 +1915,9 @@ export const placeholderHeight = (pos) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//function for getting contracts_contactbook details
|
//function for getting contracts_contactbook details
|
||||||
export const contactBook = async (objectId) => {
|
export const contactBook = async (
|
||||||
|
objectId,
|
||||||
|
) => {
|
||||||
const result = await axios
|
const result = await axios
|
||||||
.get(
|
.get(
|
||||||
`${localStorage.getItem(
|
`${localStorage.getItem(
|
||||||
@@ -1884,7 +1927,8 @@ export const contactBook = async (objectId) => {
|
|||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
"X-Parse-Session-Token":
|
||||||
|
localStorage.getItem("accesstoken")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1902,9 +1946,12 @@ export const contactBook = async (objectId) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//function for getting document details from contract_Documents class
|
//function for getting document details from contract_Documents class
|
||||||
export const contractDocument = async (documentId) => {
|
export const contractDocument = async (
|
||||||
|
documentId,
|
||||||
|
) => {
|
||||||
const data = { docId: documentId };
|
const data = { docId: documentId };
|
||||||
const token = { sessionToken: localStorage.getItem("accesstoken") };
|
const token =
|
||||||
|
{ sessionToken: localStorage.getItem("accesstoken") };
|
||||||
const documentDeatils = await axios
|
const documentDeatils = await axios
|
||||||
.post(`${localStorage.getItem("baseUrl")}functions/getDocument`, data, {
|
.post(`${localStorage.getItem("baseUrl")}functions/getDocument`, data, {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -2088,31 +2135,36 @@ export const getFileName = (fileUrl) => {
|
|||||||
|
|
||||||
//fetch tenant app logo from `partners_Tenant` class by domain name
|
//fetch tenant app logo from `partners_Tenant` class by domain name
|
||||||
export const getAppLogo = async () => {
|
export const getAppLogo = async () => {
|
||||||
const domain = window.location.host;
|
const domain = window.location.host;
|
||||||
try {
|
try {
|
||||||
const tenant = await Parse.Cloud.run("getlogobydomain", {
|
const tenant = await Parse.Cloud.run("getlogobydomain", {
|
||||||
domain: domain
|
domain: domain
|
||||||
});
|
});
|
||||||
if (tenant) {
|
if (tenant) {
|
||||||
localStorage.setItem("appname", "OpenSign™");
|
localStorage.setItem("appname", "OpenSign™");
|
||||||
return { logo: tenant?.logo, user: tenant?.user };
|
return { logo: tenant?.logo, user: tenant?.user };
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in getlogo ", err);
|
||||||
|
if (err?.message?.includes("valid JSON")) {
|
||||||
|
return { logo: appInfo.applogo, user: "exist", error: "invalid_json" };
|
||||||
|
} else {
|
||||||
|
return { logo: appInfo.applogo, user: "exist" };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
console.log("err in getlogo ", err);
|
|
||||||
if (err?.message?.includes("valid JSON")) {
|
|
||||||
return { logo: appInfo.applogo, user: "exist", error: "invalid_json" };
|
|
||||||
} else {
|
|
||||||
return { logo: appInfo.applogo, user: "exist" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
export const getTenantDetails = async (objectId, contactId) => {
|
export const getTenantDetails = async (
|
||||||
|
objectId,
|
||||||
|
contactId
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const url = `${localStorage.getItem("baseUrl")}functions/gettenant`;
|
const url = `${localStorage.getItem("baseUrl")}functions/gettenant`;
|
||||||
const parseAppId = localStorage.getItem("parseAppId");
|
const parseAppId = localStorage.getItem("parseAppId");
|
||||||
const accesstoken = localStorage.getItem("accesstoken");
|
const accesstoken = localStorage.getItem("accesstoken");
|
||||||
const token = { "X-Parse-Session-Token": accesstoken };
|
const token =
|
||||||
const data = { userId: objectId, contactId: contactId };
|
{ "X-Parse-Session-Token": accesstoken };
|
||||||
|
const data =
|
||||||
|
{ userId: objectId, contactId: contactId };
|
||||||
const res = await axios.post(url, data, {
|
const res = await axios.post(url, data, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -2193,7 +2245,7 @@ export const handleSendOTP = async (email) => {
|
|||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
|
||||||
};
|
};
|
||||||
const body = {
|
const body = {
|
||||||
email: email
|
email: email,
|
||||||
};
|
};
|
||||||
await axios.post(url, body, { headers: headers });
|
await axios.post(url, body, { headers: headers });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -2201,7 +2253,8 @@ export const handleSendOTP = async (email) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
export const fetchUrl = async (url, pdfName) => {
|
export const fetchUrl = async (url, pdfName) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -2215,7 +2268,11 @@ export const fetchUrl = async (url, pdfName) => {
|
|||||||
console.error("Error downloading the file:", error);
|
console.error("Error downloading the file:", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
export const getSignedUrl = async (pdfUrl, docId, templateId) => {
|
export const getSignedUrl = async (
|
||||||
|
pdfUrl,
|
||||||
|
docId,
|
||||||
|
templateId
|
||||||
|
) => {
|
||||||
//use only axios here due to public template sign
|
//use only axios here due to public template sign
|
||||||
const axiosRes = await axios.post(
|
const axiosRes = await axios.post(
|
||||||
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
||||||
@@ -2276,7 +2333,10 @@ export const handleDownloadPdf = async (
|
|||||||
setIsDownloading && setIsDownloading("pdf");
|
setIsDownloading && setIsDownloading("pdf");
|
||||||
const docId = pdfDetails?.[0]?.objectId || "";
|
const docId = pdfDetails?.[0]?.objectId || "";
|
||||||
try {
|
try {
|
||||||
const url = await getSignedUrl(pdfUrl, docId);
|
const url = await getSignedUrl(
|
||||||
|
pdfUrl,
|
||||||
|
docId,
|
||||||
|
);
|
||||||
await fetchUrl(url, pdfName);
|
await fetchUrl(url, pdfName);
|
||||||
setIsDownloading && setIsDownloading("");
|
setIsDownloading && setIsDownloading("");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -2306,7 +2366,7 @@ export const handleToPrint = async (event, setIsDownloading, pdfDetails) => {
|
|||||||
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
||||||
{
|
{
|
||||||
url: pdfUrl,
|
url: pdfUrl,
|
||||||
docId: docId
|
docId: docId,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -2350,7 +2410,8 @@ export const handleDownloadCertificate = async (
|
|||||||
setIsDownloading,
|
setIsDownloading,
|
||||||
isZip
|
isZip
|
||||||
) => {
|
) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
if (pdfDetails?.length > 0 && pdfDetails[0]?.CertificateUrl) {
|
if (pdfDetails?.length > 0 && pdfDetails[0]?.CertificateUrl) {
|
||||||
try {
|
try {
|
||||||
await fetch(pdfDetails[0] && pdfDetails[0]?.CertificateUrl);
|
await fetch(pdfDetails[0] && pdfDetails[0]?.CertificateUrl);
|
||||||
@@ -2434,13 +2495,14 @@ export const handleDownloadCertificate = async (
|
|||||||
export function escapeRegExp(string) {
|
export function escapeRegExp(string) {
|
||||||
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // Escape special characters
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // Escape special characters
|
||||||
}
|
}
|
||||||
export async function findContact(value) {
|
export async function findContact(
|
||||||
|
value,
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const baseURL = localStorage.getItem("baseUrl");
|
const baseURL = localStorage.getItem("baseUrl");
|
||||||
const url = `${baseURL}functions/getsigners`;
|
const url = `${baseURL}functions/getsigners`;
|
||||||
const token = {
|
const token =
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
{ "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
|
||||||
};
|
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
@@ -2652,20 +2714,23 @@ export function base64ToArrayBuffer(base64) {
|
|||||||
return bytes.buffer;
|
return bytes.buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const convertBase64ToFile = async (pdfName, pdfBase64) => {
|
export const convertBase64ToFile = async (
|
||||||
|
pdfName,
|
||||||
|
pdfBase64,
|
||||||
|
) => {
|
||||||
const fileName = sanitizeFileName(pdfName) + ".pdf";
|
const fileName = sanitizeFileName(pdfName) + ".pdf";
|
||||||
try {
|
try {
|
||||||
const pdfFile = new Parse.File(fileName, { base64: pdfBase64 });
|
const pdfFile = new Parse.File(fileName, { base64: pdfBase64 });
|
||||||
// Save the Parse File if needed
|
// Save the Parse File if needed
|
||||||
const pdfData = await pdfFile.save();
|
const pdfData = await pdfFile.save();
|
||||||
const pdfUrl = pdfData.url();
|
const pdfUrl = pdfData.url();
|
||||||
const fileRes = await getSecureUrl(pdfUrl);
|
const fileRes = await getSecureUrl(pdfUrl);
|
||||||
if (fileRes?.url) {
|
if (fileRes?.url) {
|
||||||
return fileRes.url;
|
return fileRes.url;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("error in convertbase64tofile", e);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
console.log("error in convertbase64tofile", e);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
export const onClickZoomIn = (scale, zoomPercent, setScale, setZoomPercent) => {
|
export const onClickZoomIn = (scale, zoomPercent, setScale, setZoomPercent) => {
|
||||||
setScale(scale + 0.1 * scale);
|
setScale(scale + 0.1 * scale);
|
||||||
@@ -2955,10 +3020,13 @@ export const flattenPdf = async (pdfFile) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const mailTemplate = (param) => {
|
export const mailTemplate = (param) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
const logo = `<div style='padding:10px'><img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' /></div>`;
|
"OpenSign™";
|
||||||
|
const logo =
|
||||||
|
`<div style='padding:10px'><img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' /></div>`;
|
||||||
|
|
||||||
const opurl = ` <a href='https://www.opensignlabs.com' target=_blank>here</a>.</p></div></div></body></html>`;
|
const opurl =
|
||||||
|
` <a href='https://www.opensignlabs.com' target=_blank>here</a>.</p></div></div></body></html>`;
|
||||||
|
|
||||||
const subject = `${param.senderName} has requested you to sign "${param.title}"`;
|
const subject = `${param.senderName} has requested you to sign "${param.title}"`;
|
||||||
const body =
|
const body =
|
||||||
@@ -3000,3 +3068,52 @@ export function formatDateTime(date, dateFormat, timeZone, is12Hour) {
|
|||||||
)
|
)
|
||||||
: formatTimeInTimezone(date, timeZone);
|
: formatTimeInTimezone(date, timeZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const updateDateWidgetsRes = (documentData, signerId, journey) => {
|
||||||
|
const extUser =
|
||||||
|
localStorage.getItem("Extand_Class");
|
||||||
|
const contactUser = documentData?.Signers.find(
|
||||||
|
(data) => data.objectId === signerId
|
||||||
|
);
|
||||||
|
const placeHolders = documentData?.Placeholders;
|
||||||
|
const userDetails = extUser ? JSON.parse(extUser)[0] : contactUser;
|
||||||
|
return placeHolders?.map((item) => {
|
||||||
|
if (item?.signerObjId === signerId) {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
placeHolder: item.placeHolder.map((ph) => ({
|
||||||
|
...ph,
|
||||||
|
pos: ph.pos.map((widget) => {
|
||||||
|
// only for date widgets *and* missing response
|
||||||
|
if (widget.type === "date" && !widget.options.response) {
|
||||||
|
return {
|
||||||
|
...widget,
|
||||||
|
options: {
|
||||||
|
...widget.options,
|
||||||
|
response: getDate(
|
||||||
|
changeDateToMomentFormat(widget.options.validation.format)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else if (
|
||||||
|
["name", "email", "job title", "company"].includes(widget.type) &&
|
||||||
|
!widget.options.defaultValue &&
|
||||||
|
!widget.options.response
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
...widget,
|
||||||
|
options: {
|
||||||
|
...widget.options,
|
||||||
|
response: widgetDataValue(widget.type, userDetails)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return widget;
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -11,9 +11,6 @@ export const appInfo = {
|
|||||||
appId: process.env.REACT_APP_APPID ? process.env.REACT_APP_APPID : "opensign",
|
appId: process.env.REACT_APP_APPID ? process.env.REACT_APP_APPID : "opensign",
|
||||||
baseUrl: serverUrl_fn(),
|
baseUrl: serverUrl_fn(),
|
||||||
defaultRole: "contracts_User",
|
defaultRole: "contracts_User",
|
||||||
fbAppId: process.env.REACT_APP_FBAPPID
|
|
||||||
? `${process.env.REACT_APP_FBAPPID}`
|
|
||||||
: "",
|
|
||||||
fev_Icon:
|
fev_Icon:
|
||||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC",
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC",
|
||||||
googleClietId: process.env.REACT_APP_GOOGLECLIENTID
|
googleClietId: process.env.REACT_APP_GOOGLECLIENTID
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
export default function linkURL(url) {
|
|
||||||
let newURL = (url && decodeURIComponent(url)) || "";
|
|
||||||
return newURL.substring(newURL.indexOf(".com/") + 5, newURL.indexOf("_"));
|
|
||||||
}
|
|
||||||
@@ -13,15 +13,13 @@ import {
|
|||||||
MouseTransition,
|
MouseTransition,
|
||||||
Preview
|
Preview
|
||||||
} from "react-dnd-multi-backend";
|
} from "react-dnd-multi-backend";
|
||||||
import DragElement from "./components/pdf/DragElement";
|
import DragElement from "./components/pdf/DragElement.jsx";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import "./polyfills";
|
import "./polyfills";
|
||||||
import { serverUrl_fn } from "./constant/appinfo";
|
import { serverUrl_fn } from "./constant/appinfo";
|
||||||
import "./i18n";
|
import "./i18n";
|
||||||
|
|
||||||
const appId = process.env.REACT_APP_APPID
|
const appId = import.meta.env.VITE_APPID || process.env.REACT_APP_APPID || "opensign";
|
||||||
? process.env.REACT_APP_APPID
|
|
||||||
: "opensign";
|
|
||||||
const serverUrl = serverUrl_fn();
|
const serverUrl = serverUrl_fn();
|
||||||
Parse.initialize(appId);
|
Parse.initialize(appId);
|
||||||
Parse.serverURL = serverUrl;
|
Parse.serverURL = serverUrl;
|
||||||
@@ -55,6 +53,7 @@ const generatePreview = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById("root"));
|
const root = ReactDOM.createRoot(document.getElementById("root"));
|
||||||
root.render(
|
root.render(
|
||||||
<CookiesProvider defaultSetOptions={{ path: "/" }}>
|
<CookiesProvider defaultSetOptions={{ path: "/" }}>
|
||||||
@@ -36,7 +36,7 @@ const dashboardJson = [
|
|||||||
queryType: "",
|
queryType: "",
|
||||||
class: "contracts_Document",
|
class: "contracts_Document",
|
||||||
query:
|
query:
|
||||||
'where={"Type":{"#*ne":"Folder"},"Signers":{"#*exists":true,"#*ne":[]},"Placeholders":{"#*ne":null},"SignedUrl":{"#*ne":null},"IsCompleted":{"#*ne":true},"IsDeclined":{"#*ne":true},"IsArchive":{"#*ne":true},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"#UserId.objectId#"},"ExpiryDate":{"#*gt":{"__type":"#Date#","iso":"#today#"}}}&count=1',
|
'where={"Type":null,"Signers":{"#*exists":true},"Placeholders":{"#*exists":true},"SignedUrl":{"#*exists":true},"IsCompleted":false,"IsDeclined":false,"IsArchive":null,"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"#UserId.objectId#"},"ExpiryDate":{"#*gt":{"__type":"#Date#","iso":"#today#"}}}&keys=Name,ExpiryDate,SignedUrl,Signers&count=1',
|
||||||
key: "count",
|
key: "count",
|
||||||
Redirect_type: "Report",
|
Redirect_type: "Report",
|
||||||
Redirect_id: "1MwEuxLEkF",
|
Redirect_id: "1MwEuxLEkF",
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ import { showHeader } from "../redux/reducers/showHeader";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
const HomeLayout = () => {
|
const HomeLayout = () => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -53,8 +54,8 @@ const HomeLayout = () => {
|
|||||||
});
|
});
|
||||||
if (user) {
|
if (user) {
|
||||||
localStorage.setItem("profileImg", user.get("ProfilePic") || "");
|
localStorage.setItem("profileImg", user.get("ProfilePic") || "");
|
||||||
setIsUserValid(true);
|
setIsUserValid(true);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
} else {
|
} else {
|
||||||
setIsUserValid(false);
|
setIsUserValid(false);
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { emailRegex } from "../constant/const";
|
import { emailRegex } from "../constant/const";
|
||||||
|
|
||||||
const AddAdmin = () => {
|
const AddAdmin = () => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@@ -175,7 +176,6 @@ const AddAdmin = () => {
|
|||||||
localStorage.setItem("accesstoken", sessionToken);
|
localStorage.setItem("accesstoken", sessionToken);
|
||||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
||||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
localStorage.setItem("accesstoken", _user.sessionToken);
|
||||||
localStorage.setItem("scriptId", true);
|
|
||||||
if (_user.ProfilePic) {
|
if (_user.ProfilePic) {
|
||||||
localStorage.setItem("profileImg", _user.ProfilePic);
|
localStorage.setItem("profileImg", _user.ProfilePic);
|
||||||
} else {
|
} else {
|
||||||
+1
-1
@@ -5,7 +5,7 @@ import {
|
|||||||
getBase64FromUrl,
|
getBase64FromUrl,
|
||||||
handleDownloadCertificate,
|
handleDownloadCertificate,
|
||||||
handleDownloadPdf,
|
handleDownloadPdf,
|
||||||
handleToPrint
|
handleToPrint,
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
+5
-3
@@ -7,7 +7,9 @@ import Alert from "../primitives/Alert";
|
|||||||
import { appInfo } from "../constant/appinfo";
|
import { appInfo } from "../constant/appinfo";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
import { emailRegex } from "../constant/const";
|
import {
|
||||||
|
emailRegex,
|
||||||
|
} from "../constant/const";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
|
|
||||||
@@ -46,7 +48,7 @@ function ForgotPassword() {
|
|||||||
if (state.email) {
|
if (state.email) {
|
||||||
const username = state.email;
|
const username = state.email;
|
||||||
try {
|
try {
|
||||||
await Parse.User.requestPasswordReset(username);
|
await Parse.User.requestPasswordReset(username);
|
||||||
setToast({ type: "success", message: t("reset-password-alert-1") });
|
setToast({ type: "success", message: t("reset-password-alert-1") });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err ", err.code);
|
console.log("err ", err.code);
|
||||||
@@ -76,7 +78,7 @@ function ForgotPassword() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err while logging out ", err);
|
console.log("err while logging out ", err);
|
||||||
}
|
}
|
||||||
setImage(appInfo?.applogo || undefined);
|
setImage(appInfo?.applogo || undefined);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -42,7 +42,8 @@ function Form() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Forms = (props) => {
|
const Forms = (props) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
const inputFileRef = useRef(null);
|
const inputFileRef = useRef(null);
|
||||||
@@ -105,12 +106,12 @@ const Forms = (props) => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
const initializeValues = async () => {
|
const initializeValues = async () => {
|
||||||
setFormData((obj) => ({
|
setFormData((obj) => ({
|
||||||
...obj,
|
...obj,
|
||||||
NotifyOnSignatures: true,
|
NotifyOnSignatures: true,
|
||||||
SendinOrder: sendinorder,
|
SendinOrder: sendinorder,
|
||||||
IsTourEnabled: istourenabled
|
IsTourEnabled: istourenabled
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
function getFileAsArrayBuffer(file) {
|
function getFileAsArrayBuffer(file) {
|
||||||
@@ -148,81 +149,17 @@ const Forms = (props) => {
|
|||||||
const name = generatePdfName(16);
|
const name = generatePdfName(16);
|
||||||
const pdfName = `${name?.split(".")[0]}.pdf`;
|
const pdfName = `${name?.split(".")[0]}.pdf`;
|
||||||
setfileload(true);
|
setfileload(true);
|
||||||
try {
|
|
||||||
const res = await getFileAsArrayBuffer(files[0]);
|
|
||||||
const flatPdf = await flattenPdf(res);
|
|
||||||
const parseFile = new Parse.File(
|
|
||||||
pdfName,
|
|
||||||
[...flatPdf],
|
|
||||||
"application/pdf"
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await parseFile.save({
|
const res = await getFileAsArrayBuffer(files[0]);
|
||||||
progress: (progressValue, loaded, total, { type }) => {
|
const flatPdf = await flattenPdf(res);
|
||||||
if (type === "upload" && progressValue !== null) {
|
const parseFile = new Parse.File(
|
||||||
const percentCompleted = Math.round(
|
pdfName,
|
||||||
(loaded * 100) / total
|
[...flatPdf],
|
||||||
);
|
"application/pdf"
|
||||||
setpercentage(percentCompleted);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// The response object will contain information about the uploaded file
|
|
||||||
// You can access the URL of the uploaded file using response.url()
|
|
||||||
if (response.url()) {
|
|
||||||
const fileRes = await getSecureUrl(response.url());
|
|
||||||
if (fileRes.url) {
|
|
||||||
setFileUpload(fileRes.url);
|
|
||||||
setfileload(false);
|
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
|
||||||
const title = generateTitleFromFilename(files?.[0]?.name);
|
|
||||||
setFormData((obj) => ({ ...obj, Name: title }));
|
|
||||||
SaveFileSize(size, fileRes.url, tenantId);
|
|
||||||
return fileRes.url;
|
|
||||||
} else {
|
|
||||||
removeFile(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
removeFile(e);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
removeFile(e);
|
|
||||||
console.error("Error uploading file:", error);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
if (err?.message?.includes("is encrypted")) {
|
|
||||||
try {
|
|
||||||
setIsDecrypting(true);
|
|
||||||
const size = files?.[0].size;
|
|
||||||
const name = generatePdfName(16);
|
|
||||||
const url = "https://ai.nxglabs.in/decryptpdf"; //
|
|
||||||
let formData = new FormData();
|
|
||||||
formData.append("file", files[0]);
|
|
||||||
formData.append("password", "");
|
|
||||||
const config = {
|
|
||||||
headers: { "content-type": "multipart/form-data" },
|
|
||||||
responseType: "blob"
|
|
||||||
};
|
|
||||||
const response = await axios.post(url, formData, config);
|
|
||||||
const pdfBlob = new Blob([response.data], {
|
|
||||||
type: "application/pdf"
|
|
||||||
});
|
|
||||||
const pdfFile = new File([pdfBlob], name, {
|
|
||||||
type: "application/pdf"
|
|
||||||
});
|
|
||||||
setIsDecrypting(false);
|
|
||||||
setfileload(true);
|
|
||||||
const res = await getFileAsArrayBuffer(pdfFile);
|
|
||||||
const flatPdf = await flattenPdf(res);
|
|
||||||
// Upload the file to Parse Server
|
|
||||||
const parseFile = new Parse.File(
|
|
||||||
name,
|
|
||||||
[...flatPdf],
|
|
||||||
"application/pdf"
|
|
||||||
);
|
|
||||||
|
|
||||||
await parseFile.save({
|
try {
|
||||||
|
const response = await parseFile.save({
|
||||||
progress: (progressValue, loaded, total, { type }) => {
|
progress: (progressValue, loaded, total, { type }) => {
|
||||||
if (type === "upload" && progressValue !== null) {
|
if (type === "upload" && progressValue !== null) {
|
||||||
const percentCompleted = Math.round(
|
const percentCompleted = Math.round(
|
||||||
@@ -232,16 +169,16 @@ const Forms = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// The response object will contain information about the uploaded file
|
||||||
// Retrieve the URL of the uploaded file
|
// You can access the URL of the uploaded file using response.url()
|
||||||
if (parseFile.url()) {
|
if (response.url()) {
|
||||||
const fileRes = await getSecureUrl(parseFile.url());
|
const fileRes = await getSecureUrl(response.url());
|
||||||
if (fileRes.url) {
|
if (fileRes.url) {
|
||||||
setFileUpload(fileRes.url);
|
setFileUpload(fileRes.url);
|
||||||
removeFile();
|
setfileload(false);
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
const title = generateTitleFromFilename(files?.[0]?.name);
|
const title = generateTitleFromFilename(files?.[0]?.name);
|
||||||
setFormData((obj) => ({ ...obj, Name: title }));
|
setFormData((obj) => ({ ...obj, Name: title }));
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
|
||||||
SaveFileSize(size, fileRes.url, tenantId);
|
SaveFileSize(size, fileRes.url, tenantId);
|
||||||
return fileRes.url;
|
return fileRes.url;
|
||||||
} else {
|
} else {
|
||||||
@@ -250,22 +187,88 @@ const Forms = (props) => {
|
|||||||
} else {
|
} else {
|
||||||
removeFile(e);
|
removeFile(e);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
removeFile();
|
removeFile(e);
|
||||||
if (err?.response?.status === 401) {
|
console.error("Error uploading file:", error);
|
||||||
setIsPassword(true);
|
}
|
||||||
} else {
|
} catch (err) {
|
||||||
console.log("Error uploading file: ", err?.response);
|
if (err?.message?.includes("is encrypted")) {
|
||||||
setIsDecrypting(false);
|
try {
|
||||||
e.target.value = "";
|
setIsDecrypting(true);
|
||||||
}
|
const size = files?.[0].size;
|
||||||
|
const name = generatePdfName(16);
|
||||||
|
const url = "https://ai.nxglabs.in/decryptpdf"; //
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append("file", files[0]);
|
||||||
|
formData.append("password", "");
|
||||||
|
const config = {
|
||||||
|
headers: { "content-type": "multipart/form-data" },
|
||||||
|
responseType: "blob"
|
||||||
|
};
|
||||||
|
const response = await axios.post(url, formData, config);
|
||||||
|
const pdfBlob = new Blob([response.data], {
|
||||||
|
type: "application/pdf"
|
||||||
|
});
|
||||||
|
const pdfFile = new File([pdfBlob], name, {
|
||||||
|
type: "application/pdf"
|
||||||
|
});
|
||||||
|
setIsDecrypting(false);
|
||||||
|
setfileload(true);
|
||||||
|
const res = await getFileAsArrayBuffer(pdfFile);
|
||||||
|
const flatPdf = await flattenPdf(res);
|
||||||
|
// Upload the file to Parse Server
|
||||||
|
const parseFile = new Parse.File(
|
||||||
|
name,
|
||||||
|
[...flatPdf],
|
||||||
|
"application/pdf"
|
||||||
|
);
|
||||||
|
|
||||||
|
await parseFile.save({
|
||||||
|
progress: (progressValue, loaded, total, { type }) => {
|
||||||
|
if (type === "upload" && progressValue !== null) {
|
||||||
|
const percentCompleted = Math.round(
|
||||||
|
(loaded * 100) / total
|
||||||
|
);
|
||||||
|
setpercentage(percentCompleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Retrieve the URL of the uploaded file
|
||||||
|
if (parseFile.url()) {
|
||||||
|
const fileRes = await getSecureUrl(parseFile.url());
|
||||||
|
if (fileRes.url) {
|
||||||
|
setFileUpload(fileRes.url);
|
||||||
|
removeFile();
|
||||||
|
const title = generateTitleFromFilename(
|
||||||
|
files?.[0]?.name
|
||||||
|
);
|
||||||
|
setFormData((obj) => ({ ...obj, Name: title }));
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
SaveFileSize(size, fileRes.url, tenantId);
|
||||||
|
return fileRes.url;
|
||||||
|
} else {
|
||||||
|
removeFile(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removeFile(e);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
removeFile();
|
||||||
|
if (err?.response?.status === 401) {
|
||||||
|
setIsPassword(true);
|
||||||
|
} else {
|
||||||
|
console.log("Error uploading file: ", err?.response);
|
||||||
|
setIsDecrypting(false);
|
||||||
|
e.target.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("err ", err);
|
||||||
|
setFileUpload("");
|
||||||
|
removeFile(e);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
console.log("err ", err);
|
|
||||||
setFileUpload("");
|
|
||||||
removeFile(e);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const isImage = files?.[0]?.type.includes("image/");
|
const isImage = files?.[0]?.type.includes("image/");
|
||||||
if (isImage) {
|
if (isImage) {
|
||||||
@@ -290,50 +293,50 @@ const Forms = (props) => {
|
|||||||
});
|
});
|
||||||
const size = files?.[0]?.size;
|
const size = files?.[0]?.size;
|
||||||
const name = generatePdfName(16);
|
const name = generatePdfName(16);
|
||||||
const getFile = await pdfDoc.save({
|
const getFile = await pdfDoc.save({
|
||||||
useObjectStreams: false
|
useObjectStreams: false
|
||||||
});
|
|
||||||
setfileload(true);
|
|
||||||
const pdfName = `${name?.split(".")[0]}.pdf`;
|
|
||||||
const parseFile = new Parse.File(
|
|
||||||
pdfName,
|
|
||||||
[...getFile],
|
|
||||||
"application/pdf"
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await parseFile.save({
|
|
||||||
progress: (progressValue, loaded, total, { type }) => {
|
|
||||||
if (type === "upload" && progressValue !== null) {
|
|
||||||
const percentCompleted = Math.round(
|
|
||||||
(loaded * 100) / total
|
|
||||||
);
|
|
||||||
setpercentage(percentCompleted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
// The response object will contain information about the uploaded file
|
setfileload(true);
|
||||||
// You can access the URL of the uploaded file using response.url()
|
const pdfName = `${name?.split(".")[0]}.pdf`;
|
||||||
if (response.url()) {
|
const parseFile = new Parse.File(
|
||||||
const fileRes = await getSecureUrl(response.url());
|
pdfName,
|
||||||
if (fileRes.url) {
|
[...getFile],
|
||||||
setFileUpload(fileRes.url);
|
"application/pdf"
|
||||||
setfileload(false);
|
);
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
|
||||||
const title = generateTitleFromFilename(files?.[0]?.name);
|
try {
|
||||||
setFormData((obj) => ({ ...obj, Name: title }));
|
const response = await parseFile.save({
|
||||||
SaveFileSize(size, fileRes.url, tenantId);
|
progress: (progressValue, loaded, total, { type }) => {
|
||||||
return fileRes.url;
|
if (type === "upload" && progressValue !== null) {
|
||||||
|
const percentCompleted = Math.round(
|
||||||
|
(loaded * 100) / total
|
||||||
|
);
|
||||||
|
setpercentage(percentCompleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// The response object will contain information about the uploaded file
|
||||||
|
// You can access the URL of the uploaded file using response.url()
|
||||||
|
if (response.url()) {
|
||||||
|
const fileRes = await getSecureUrl(response.url());
|
||||||
|
if (fileRes.url) {
|
||||||
|
setFileUpload(fileRes.url);
|
||||||
|
setfileload(false);
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
const title = generateTitleFromFilename(files?.[0]?.name);
|
||||||
|
setFormData((obj) => ({ ...obj, Name: title }));
|
||||||
|
SaveFileSize(size, fileRes.url, tenantId);
|
||||||
|
return fileRes.url;
|
||||||
|
} else {
|
||||||
|
removeFile(e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
removeFile(e);
|
removeFile(e);
|
||||||
}
|
}
|
||||||
} else {
|
} catch (error) {
|
||||||
removeFile(e);
|
removeFile(e);
|
||||||
|
console.error("Error uploading file:", error);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
removeFile(e);
|
|
||||||
console.error("Error uploading file:", error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -408,11 +411,11 @@ const Forms = (props) => {
|
|||||||
object.set("RemindOnceInEvery", remindOnceInEvery);
|
object.set("RemindOnceInEvery", remindOnceInEvery);
|
||||||
object.set("IsTourEnabled", isTourEnabled);
|
object.set("IsTourEnabled", isTourEnabled);
|
||||||
object.set("TimeToCompleteDays", TimeToCompleteDays);
|
object.set("TimeToCompleteDays", TimeToCompleteDays);
|
||||||
object.set("AllowModifications", false);
|
object.set("AllowModifications", false);
|
||||||
object.set("IsEnableOTP", false);
|
object.set("IsEnableOTP", false);
|
||||||
if (formData.NotifyOnSignatures !== undefined) {
|
if (formData.NotifyOnSignatures !== undefined) {
|
||||||
object.set("NotifyOnSignatures", formData.NotifyOnSignatures);
|
object.set("NotifyOnSignatures", formData.NotifyOnSignatures);
|
||||||
}
|
}
|
||||||
if (formData?.RedirectUrl) {
|
if (formData?.RedirectUrl) {
|
||||||
object.set("RedirectUrl", formData.RedirectUrl);
|
object.set("RedirectUrl", formData.RedirectUrl);
|
||||||
}
|
}
|
||||||
@@ -451,9 +454,10 @@ const Forms = (props) => {
|
|||||||
setSigners([]);
|
setSigners([]);
|
||||||
setBcc([]);
|
setBcc([]);
|
||||||
setFolder({ ObjectId: "", Name: "" });
|
setFolder({ ObjectId: "", Name: "" });
|
||||||
const notifySign = extUserData?.NotifyOnSignatures
|
const notifySign =
|
||||||
? extUserData?.NotifyOnSignatures
|
extUserData?.NotifyOnSignatures
|
||||||
: true;
|
? extUserData?.NotifyOnSignatures
|
||||||
|
: true;
|
||||||
setFormData({
|
setFormData({
|
||||||
Name: "",
|
Name: "",
|
||||||
Description: "",
|
Description: "",
|
||||||
@@ -529,9 +533,10 @@ const Forms = (props) => {
|
|||||||
setSigners([]);
|
setSigners([]);
|
||||||
setBcc([]);
|
setBcc([]);
|
||||||
setFolder({ ObjectId: "", Name: "" });
|
setFolder({ ObjectId: "", Name: "" });
|
||||||
const notifySign = extUserData?.NotifyOnSignatures
|
const notifySign =
|
||||||
? extUserData?.NotifyOnSignatures
|
extUserData?.NotifyOnSignatures
|
||||||
: true;
|
? extUserData?.NotifyOnSignatures
|
||||||
|
: true;
|
||||||
let obj = {
|
let obj = {
|
||||||
Name: "",
|
Name: "",
|
||||||
Description: "",
|
Description: "",
|
||||||
@@ -585,28 +590,36 @@ const Forms = (props) => {
|
|||||||
type: "application/pdf"
|
type: "application/pdf"
|
||||||
});
|
});
|
||||||
setIsDecrypting(false);
|
setIsDecrypting(false);
|
||||||
const res = await getFileAsArrayBuffer(pdfFile);
|
const res = await getFileAsArrayBuffer(pdfFile);
|
||||||
const flatPdf = await flattenPdf(res);
|
const flatPdf = await flattenPdf(res);
|
||||||
const parseFile = new Parse.File(name, [...flatPdf], "application/pdf");
|
const parseFile = new Parse.File(name, [...flatPdf], "application/pdf");
|
||||||
await parseFile.save({
|
await parseFile.save({
|
||||||
progress: (progressValue, loaded, total, { type }) => {
|
progress: (progressValue, loaded, total, { type }) => {
|
||||||
if (type === "upload" && progressValue !== null) {
|
if (type === "upload" && progressValue !== null) {
|
||||||
const percentCompleted = Math.round((loaded * 100) / total);
|
const percentCompleted = Math.round((loaded * 100) / total);
|
||||||
setpercentage(percentCompleted);
|
setpercentage(percentCompleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Retrieve the URL of the uploaded file
|
||||||
|
if (parseFile.url()) {
|
||||||
|
const fileRes = await getSecureUrl(parseFile.url());
|
||||||
|
if (fileRes.url) {
|
||||||
|
setFileUpload(fileRes.url);
|
||||||
|
removeFile();
|
||||||
|
const title = generateTitleFromFilename(formData?.file?.name);
|
||||||
|
setFormData((obj) => ({ ...obj, password: "", Name: title }));
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
SaveFileSize(size, fileRes.url, tenantId);
|
||||||
|
return fileRes.url;
|
||||||
|
} else {
|
||||||
|
removeFile();
|
||||||
|
setFormData((prev) => ({ ...prev, password: "" }));
|
||||||
|
setIsDecrypting(false);
|
||||||
|
if (inputFileRef.current) {
|
||||||
|
inputFileRef.current.value = ""; // Set file input value to empty string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
// Retrieve the URL of the uploaded file
|
|
||||||
if (parseFile.url()) {
|
|
||||||
const fileRes = await getSecureUrl(parseFile.url());
|
|
||||||
if (fileRes.url) {
|
|
||||||
setFileUpload(fileRes.url);
|
|
||||||
removeFile();
|
|
||||||
const title = generateTitleFromFilename(formData?.file?.name);
|
|
||||||
setFormData((obj) => ({ ...obj, password: "", Name: title }));
|
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
|
||||||
SaveFileSize(size, fileRes.url, tenantId);
|
|
||||||
return fileRes.url;
|
|
||||||
} else {
|
} else {
|
||||||
removeFile();
|
removeFile();
|
||||||
setFormData((prev) => ({ ...prev, password: "" }));
|
setFormData((prev) => ({ ...prev, password: "" }));
|
||||||
@@ -615,14 +628,6 @@ const Forms = (props) => {
|
|||||||
inputFileRef.current.value = ""; // Set file input value to empty string
|
inputFileRef.current.value = ""; // Set file input value to empty string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
removeFile();
|
|
||||||
setFormData((prev) => ({ ...prev, password: "" }));
|
|
||||||
setIsDecrypting(false);
|
|
||||||
if (inputFileRef.current) {
|
|
||||||
inputFileRef.current.value = ""; // Set file input value to empty string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
removeFile();
|
removeFile();
|
||||||
if (err?.response?.status === 401) {
|
if (err?.response?.status === 401) {
|
||||||
@@ -744,7 +749,9 @@ const Forms = (props) => {
|
|||||||
)}
|
)}
|
||||||
<div className="text-xs">
|
<div className="text-xs">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
{`${`${t("report-heading.File")} (${t("file-type")}`}${")"}`}
|
{`${`${t("report-heading.File")} (${t("file-type")}`}${
|
||||||
|
")"
|
||||||
|
}`}
|
||||||
<span className="text-red-500 text-[13px]">*</span>
|
<span className="text-red-500 text-[13px]">*</span>
|
||||||
</label>
|
</label>
|
||||||
{fileupload.length > 0 ? (
|
{fileupload.length > 0 ? (
|
||||||
@@ -768,7 +775,9 @@ const Forms = (props) => {
|
|||||||
className="op-file-input op-file-input-bordered op-file-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
className="op-file-input op-file-input-bordered op-file-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
onChange={(e) => handleFileInput(e)}
|
onChange={(e) => handleFileInput(e)}
|
||||||
ref={inputFileRef}
|
ref={inputFileRef}
|
||||||
accept={"application/pdf,image/png,image/jpeg"}
|
accept={
|
||||||
|
"application/pdf,image/png,image/jpeg"
|
||||||
|
}
|
||||||
onInvalid={(e) =>
|
onInvalid={(e) =>
|
||||||
e.target.setCustomValidity(t("input-required"))
|
e.target.setCustomValidity(t("input-required"))
|
||||||
}
|
}
|
||||||
@@ -1058,7 +1067,10 @@ const Forms = (props) => {
|
|||||||
{isAdvanceOpt && (
|
{isAdvanceOpt && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
height: props.title === "New Template" ? "100px" : "280px"
|
height:
|
||||||
|
props.title === "New Template"
|
||||||
|
? "100px"
|
||||||
|
: "280px"
|
||||||
}}
|
}}
|
||||||
className="w-[1px] bg-gray-300 m-auto hidden md:inline-block"
|
className="w-[1px] bg-gray-300 m-auto hidden md:inline-block"
|
||||||
></div>
|
></div>
|
||||||
@@ -1167,7 +1179,11 @@ const Forms = (props) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</label>
|
</label>
|
||||||
<div className="flex flex-col md:flex-row md:gap-4">
|
<div className="flex flex-col md:flex-row md:gap-4">
|
||||||
<div className={`flex items-center gap-2 ml-2 mb-1`}>
|
<div
|
||||||
|
className={
|
||||||
|
`flex items-center gap-2 ml-2 mb-1`
|
||||||
|
}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
className="mr-[2px] op-radio op-radio-xs"
|
className="mr-[2px] op-radio op-radio-xs"
|
||||||
type="radio"
|
type="radio"
|
||||||
@@ -1176,7 +1192,11 @@ const Forms = (props) => {
|
|||||||
/>
|
/>
|
||||||
<div className="text-center">{t("yes")}</div>
|
<div className="text-center">{t("yes")}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={`flex items-center gap-2 ml-2 mb-1`}>
|
<div
|
||||||
|
className={
|
||||||
|
`flex items-center gap-2 ml-2 mb-1`
|
||||||
|
}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
className="mr-[2px] op-radio op-radio-xs"
|
className="mr-[2px] op-radio op-radio-xs"
|
||||||
type="radio"
|
type="radio"
|
||||||
@@ -1,8 +1,13 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useNavigate, useParams } from "react-router";
|
import { useNavigate, useParams } from "react-router";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { emailRegex } from "../constant/const";
|
import {
|
||||||
import { contractUsers, saveLanguageInLocal } from "../constant/Utils";
|
emailRegex,
|
||||||
|
} from "../constant/const";
|
||||||
|
import {
|
||||||
|
contractUsers,
|
||||||
|
saveLanguageInLocal
|
||||||
|
} from "../constant/Utils";
|
||||||
import logo from "../assets/images/logo.png";
|
import logo from "../assets/images/logo.png";
|
||||||
import { appInfo } from "../constant/appinfo";
|
import { appInfo } from "../constant/appinfo";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
@@ -33,6 +38,7 @@ function GuestLogin() {
|
|||||||
const [sendmail, setSendmail] = useState();
|
const [sendmail, setSendmail] = useState();
|
||||||
const [contact, setContact] = useState({ name: "", phone: "", email: "" });
|
const [contact, setContact] = useState({ name: "", phone: "", email: "" });
|
||||||
|
|
||||||
|
|
||||||
const navigateToDoc = async (docId, contactId) => {
|
const navigateToDoc = async (docId, contactId) => {
|
||||||
try {
|
try {
|
||||||
const docDetails = await Parse.Cloud.run("getDocument", {
|
const docDetails = await Parse.Cloud.run("getDocument", {
|
||||||
@@ -62,12 +68,16 @@ function GuestLogin() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
//function generate serverUrl and parseAppId from url and save it in local storage
|
//function generate serverUrl and parseAppId from url and save it in local storage
|
||||||
const handleServerUrl = async () => {
|
const handleServerUrl = async () => {
|
||||||
setAppLogo(logo);
|
setAppLogo(logo);
|
||||||
|
|
||||||
localStorage.clear(); // Clears everything
|
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
|
//save isGuestSigner true in local to handle login flow header in mobile view
|
||||||
localStorage.setItem("isGuestSigner", true);
|
localStorage.setItem("isGuestSigner", true);
|
||||||
saveLanguageInLocal(i18n);
|
saveLanguageInLocal(i18n);
|
||||||
@@ -119,7 +129,7 @@ function GuestLogin() {
|
|||||||
try {
|
try {
|
||||||
const params = {
|
const params = {
|
||||||
email: email?.toLowerCase()?.replace(/\s/g, "")?.toString(),
|
email: email?.toLowerCase()?.replace(/\s/g, "")?.toString(),
|
||||||
docId: documentId
|
docId: documentId,
|
||||||
};
|
};
|
||||||
const Otp = await Parse.Cloud.run("SendOTPMailV1", params);
|
const Otp = await Parse.Cloud.run("SendOTPMailV1", params);
|
||||||
if (Otp) {
|
if (Otp) {
|
||||||
@@ -200,6 +210,7 @@ function GuestLogin() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleUserData = async (e) => {
|
const handleUserData = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!emailRegex.test(contact.email?.toLowerCase()?.replace(/\s/g, ""))) {
|
if (!emailRegex.test(contact.email?.toLowerCase()?.replace(/\s/g, ""))) {
|
||||||
@@ -323,12 +334,12 @@ function GuestLogin() {
|
|||||||
className="op-btn op-btn-primary flex items-center"
|
className="op-btn op-btn-primary flex items-center"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
SendOtp();
|
SendOtp();
|
||||||
}}
|
}}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<i className="fa-light fa-message-sms mr-2"></i>
|
<i className="fa-light fa-message-sms mr-2"></i>
|
||||||
{loading ? t("loading") : t("get-verification-code")}
|
{loading ? t("loading") : t("get-verification-code")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -7,7 +7,9 @@ import { NavLink, useNavigate, useLocation } from "react-router";
|
|||||||
import login_img from "../assets/images/login_img.svg";
|
import login_img from "../assets/images/login_img.svg";
|
||||||
import { useWindowSize } from "../hook/useWindowSize";
|
import { useWindowSize } from "../hook/useWindowSize";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import { emailRegex } from "../constant/const";
|
import {
|
||||||
|
emailRegex,
|
||||||
|
} from "../constant/const";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
import { appInfo } from "../constant/appinfo";
|
import { appInfo } from "../constant/appinfo";
|
||||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
@@ -22,7 +24,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
import SelectLanguage from "../components/pdf/SelectLanguage";
|
import SelectLanguage from "../components/pdf/SelectLanguage";
|
||||||
|
|
||||||
function Login() {
|
function Login() {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -30,17 +33,12 @@ function Login() {
|
|||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
email: "",
|
email: "",
|
||||||
|
password: "",
|
||||||
alertType: "success",
|
alertType: "success",
|
||||||
alertMsg: "",
|
alertMsg: "",
|
||||||
password: "",
|
|
||||||
passwordVisible: false,
|
passwordVisible: false,
|
||||||
mobile: "",
|
|
||||||
phone: "",
|
|
||||||
scanResult: "",
|
|
||||||
baseUrl: localStorage.getItem("baseUrl"),
|
|
||||||
parseAppId: localStorage.getItem("parseAppId"),
|
|
||||||
loading: false,
|
loading: false,
|
||||||
thirdpartyLoader: false
|
thirdpartyLoader: false,
|
||||||
});
|
});
|
||||||
const [userDetails, setUserDetails] = useState({
|
const [userDetails, setUserDetails] = useState({
|
||||||
Company: "",
|
Company: "",
|
||||||
@@ -54,6 +52,18 @@ function Login() {
|
|||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
const setLocalVar = (user) => {
|
||||||
|
localStorage.setItem("accesstoken", user.sessionToken);
|
||||||
|
localStorage.setItem("UserInformation", JSON.stringify(user));
|
||||||
|
localStorage.setItem("userEmail", user.email);
|
||||||
|
if (user.ProfilePic) {
|
||||||
|
localStorage.setItem("profileImg", user.ProfilePic);
|
||||||
|
} else {
|
||||||
|
localStorage.setItem("profileImg", "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const showToast = (type, msg) => {
|
const showToast = (type, msg) => {
|
||||||
setState({ ...state, loading: false, alertType: type, alertMsg: msg });
|
setState({ ...state, loading: false, alertType: type, alertMsg: msg });
|
||||||
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
|
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
|
||||||
@@ -62,7 +72,9 @@ function Login() {
|
|||||||
const app = await getAppLogo();
|
const app = await getAppLogo();
|
||||||
if (app?.error === "invalid_json") {
|
if (app?.error === "invalid_json") {
|
||||||
setErrMsg(t("server-down", { appName: appName }));
|
setErrMsg(t("server-down", { appName: appName }));
|
||||||
} else if (app?.user === "not_exist") {
|
} else if (
|
||||||
|
app?.user === "not_exist"
|
||||||
|
) {
|
||||||
navigate("/addadmin");
|
navigate("/addadmin");
|
||||||
}
|
}
|
||||||
if (app?.logo) {
|
if (app?.logo) {
|
||||||
@@ -109,21 +121,11 @@ function Login() {
|
|||||||
// Get extended user data (including 2FA status) using cloud function
|
// Get extended user data (including 2FA status) using cloud function
|
||||||
try {
|
try {
|
||||||
await Parse.User.become(_user.sessionToken);
|
await Parse.User.become(_user.sessionToken);
|
||||||
// Store basic user info needed for further steps
|
setLocalVar(_user);
|
||||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
|
||||||
localStorage.setItem("userEmail", email);
|
|
||||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
|
||||||
localStorage.setItem("scriptId", true);
|
|
||||||
if (_user.ProfilePic) {
|
|
||||||
localStorage.setItem("profileImg", _user.ProfilePic);
|
|
||||||
} else {
|
|
||||||
localStorage.setItem("profileImg", "");
|
|
||||||
}
|
|
||||||
await continueLoginFlow();
|
await continueLoginFlow();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error checking 2FA status:", error);
|
console.error("Error checking 2FA status:", error);
|
||||||
showToast("danger", t("something-went-wrong-mssg"));
|
showToast("danger", t("something-went-wrong-mssg"));
|
||||||
setState({ ...state, loading: false });
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error while logging in user", error);
|
console.error("Error while logging in user", error);
|
||||||
@@ -134,6 +136,7 @@ function Login() {
|
|||||||
const setThirdpartyLoader = (value) => {
|
const setThirdpartyLoader = (value) => {
|
||||||
setState({ ...state, thirdpartyLoader: value });
|
setState({ ...state, thirdpartyLoader: value });
|
||||||
};
|
};
|
||||||
|
|
||||||
const thirdpartyLoginfn = async (sessionToken) => {
|
const thirdpartyLoginfn = async (sessionToken) => {
|
||||||
const baseUrl = localStorage.getItem("baseUrl");
|
const baseUrl = localStorage.getItem("baseUrl");
|
||||||
const parseAppId = localStorage.getItem("parseAppId");
|
const parseAppId = localStorage.getItem("parseAppId");
|
||||||
@@ -148,74 +151,57 @@ function Login() {
|
|||||||
});
|
});
|
||||||
if (res.data) {
|
if (res.data) {
|
||||||
let _user = res.data;
|
let _user = res.data;
|
||||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
setLocalVar(_user);
|
||||||
localStorage.setItem("userEmail", _user.email);
|
|
||||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
|
||||||
localStorage.setItem("scriptId", true);
|
|
||||||
if (_user.ProfilePic) {
|
|
||||||
localStorage.setItem("profileImg", _user.ProfilePic);
|
|
||||||
} else {
|
|
||||||
localStorage.setItem("profileImg", "");
|
|
||||||
}
|
|
||||||
// Check extended class user role and tenentId
|
// Check extended class user role and tenentId
|
||||||
try {
|
try {
|
||||||
const userSettings = appInfo.settings;
|
const userSettings = appInfo.settings;
|
||||||
await Parse.Cloud.run("getUserDetails")
|
const extUser = await Parse.Cloud.run("getUserDetails");
|
||||||
.then(async (extUser) => {
|
if (extUser) {
|
||||||
if (extUser) {
|
const IsDisabled = extUser?.get("IsDisabled") || false;
|
||||||
const IsDisabled = extUser?.get("IsDisabled") || false;
|
if (!IsDisabled) {
|
||||||
if (!IsDisabled) {
|
const userRole = extUser?.get("UserRole");
|
||||||
const userRole = extUser?.get("UserRole");
|
const menu =
|
||||||
const menu =
|
userRole && userSettings.find((menu) => menu.role === userRole);
|
||||||
userRole &&
|
if (menu) {
|
||||||
userSettings.find((menu) => menu.role === userRole);
|
const _currentRole = userRole;
|
||||||
if (menu) {
|
const redirectUrl =
|
||||||
const _currentRole = userRole;
|
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
||||||
const redirectUrl =
|
const _role = _currentRole.replace("contracts_", "");
|
||||||
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
const extInfo = JSON.parse(JSON.stringify(extUser));
|
||||||
const _role = _currentRole.replace("contracts_", "");
|
localStorage.setItem("_user_role", _role);
|
||||||
localStorage.setItem("_user_role", _role);
|
localStorage.setItem("Extand_Class", JSON.stringify([extUser]));
|
||||||
const results = [extUser];
|
localStorage.setItem("userEmail", extInfo?.Email);
|
||||||
const extUser_stringify = JSON.stringify(results);
|
localStorage.setItem("username", extInfo?.Name);
|
||||||
localStorage.setItem("Extand_Class", extUser_stringify);
|
if (extInfo?.TenantId) {
|
||||||
const extInfo = JSON.parse(JSON.stringify(extUser));
|
const tenant = {
|
||||||
localStorage.setItem("userEmail", extInfo?.Email);
|
Id: extInfo?.TenantId?.objectId || "",
|
||||||
localStorage.setItem("username", extInfo?.Name);
|
Name: extInfo?.TenantId?.TenantName || ""
|
||||||
if (extInfo?.TenantId) {
|
};
|
||||||
const tenant = {
|
localStorage.setItem("TenantId", tenant?.Id);
|
||||||
Id: extInfo?.TenantId?.objectId || "",
|
dispatch(showTenant(tenant?.Name));
|
||||||
Name: extInfo?.TenantId?.TenantName || ""
|
localStorage.setItem("TenantName", tenant?.Name);
|
||||||
};
|
|
||||||
localStorage.setItem("TenantId", tenant?.Id);
|
|
||||||
dispatch(showTenant(tenant?.Name));
|
|
||||||
localStorage.setItem("TenantName", tenant?.Name);
|
|
||||||
}
|
|
||||||
localStorage.setItem("PageLanding", menu.pageId);
|
|
||||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
|
||||||
localStorage.setItem("pageType", menu.pageType);
|
|
||||||
navigate(redirectUrl);
|
|
||||||
} else {
|
|
||||||
showToast("danger", t("role-not-found"));
|
|
||||||
logOutUser();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
showToast("danger", t("do-not-access-contact-admin"));
|
|
||||||
logOutUser();
|
|
||||||
}
|
}
|
||||||
|
localStorage.setItem("PageLanding", menu.pageId);
|
||||||
|
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||||
|
localStorage.setItem("pageType", menu.pageType);
|
||||||
|
navigate(redirectUrl);
|
||||||
} else {
|
} else {
|
||||||
showToast("danger", t("user-not-found"));
|
showToast("danger", t("role-not-found"));
|
||||||
logOutUser();
|
logOutUser();
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
.catch((err) => {
|
showToast("danger", t("do-not-access-contact-admin"));
|
||||||
console.error("err in fetching extUser", err);
|
logOutUser();
|
||||||
showToast("danger", `${err.message}`);
|
}
|
||||||
const payload = { sessionToken: sessionToken };
|
} else {
|
||||||
handleSubmitbtn(payload);
|
showToast("danger", t("user-not-found"));
|
||||||
});
|
logOutUser();
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showToast("danger", `${error.message}`);
|
console.error("err in fetching extUser", err);
|
||||||
console.log(error);
|
showToast("danger", `${err.message}`);
|
||||||
|
const payload = { sessionToken: _user.sessionToken };
|
||||||
|
handleSubmitbtn(payload);
|
||||||
} finally {
|
} finally {
|
||||||
setThirdpartyLoader(false);
|
setThirdpartyLoader(false);
|
||||||
}
|
}
|
||||||
@@ -227,14 +213,7 @@ function Login() {
|
|||||||
try {
|
try {
|
||||||
const user = await Parse.User.become(localStorage.getItem("accesstoken"));
|
const user = await Parse.User.become(localStorage.getItem("accesstoken"));
|
||||||
const _user = user.toJSON();
|
const _user = user.toJSON();
|
||||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
setLocalVar(_user);
|
||||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
|
||||||
localStorage.setItem("scriptId", true);
|
|
||||||
if (_user.ProfilePic) {
|
|
||||||
localStorage.setItem("profileImg", _user.ProfilePic);
|
|
||||||
} else {
|
|
||||||
localStorage.setItem("profileImg", "");
|
|
||||||
}
|
|
||||||
const userSettings = appInfo.settings;
|
const userSettings = appInfo.settings;
|
||||||
const extUser = await Parse.Cloud.run("getUserDetails");
|
const extUser = await Parse.Cloud.run("getUserDetails");
|
||||||
if (extUser) {
|
if (extUser) {
|
||||||
@@ -245,14 +224,12 @@ function Login() {
|
|||||||
const menu =
|
const menu =
|
||||||
userRole && userSettings.find((menu) => menu.role === userRole);
|
userRole && userSettings.find((menu) => menu.role === userRole);
|
||||||
if (menu) {
|
if (menu) {
|
||||||
|
const extInfo = JSON.parse(JSON.stringify(extUser));
|
||||||
const _role = _currentRole.replace("contracts_", "");
|
const _role = _currentRole.replace("contracts_", "");
|
||||||
localStorage.setItem("_user_role", _role);
|
localStorage.setItem("_user_role", _role);
|
||||||
const redirectUrl =
|
const redirectUrl =
|
||||||
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
||||||
const results = [extUser];
|
localStorage.setItem("Extand_Class", JSON.stringify([extUser]));
|
||||||
const extendedInfo_stringify = JSON.stringify(results);
|
|
||||||
localStorage.setItem("Extand_Class", extendedInfo_stringify);
|
|
||||||
const extInfo = JSON.parse(JSON.stringify(extUser));
|
|
||||||
localStorage.setItem("userEmail", extInfo.Email);
|
localStorage.setItem("userEmail", extInfo.Email);
|
||||||
localStorage.setItem("username", extInfo.Name);
|
localStorage.setItem("username", extInfo.Name);
|
||||||
if (extInfo?.TenantId) {
|
if (extInfo?.TenantId) {
|
||||||
@@ -267,8 +244,7 @@ function Login() {
|
|||||||
localStorage.setItem("PageLanding", menu.pageId);
|
localStorage.setItem("PageLanding", menu.pageId);
|
||||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||||
localStorage.setItem("pageType", menu.pageType);
|
localStorage.setItem("pageType", menu.pageType);
|
||||||
// Redirect to the appropriate URL after successful login
|
navigate(redirectUrl);
|
||||||
navigate(redirectUrl);
|
|
||||||
} else {
|
} else {
|
||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
logOutUser();
|
logOutUser();
|
||||||
@@ -377,18 +353,15 @@ function Login() {
|
|||||||
const _currentRole = userRole;
|
const _currentRole = userRole;
|
||||||
const redirectUrl =
|
const redirectUrl =
|
||||||
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
||||||
let _role = _currentRole.replace("contracts_", "");
|
const _role = _currentRole.replace("contracts_", "");
|
||||||
localStorage.setItem("_user_role", _role);
|
localStorage.setItem("_user_role", _role);
|
||||||
const checkLanguage = extUser?.get("Language");
|
const checkLanguage = extUser?.get("Language");
|
||||||
if (checkLanguage) {
|
if (checkLanguage) {
|
||||||
checkLanguage && i18n.changeLanguage(checkLanguage);
|
checkLanguage && i18n.changeLanguage(checkLanguage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Continue with storing user data and redirecting
|
|
||||||
const results = [extUser];
|
|
||||||
const extUser_str = JSON.stringify(results);
|
|
||||||
localStorage.setItem("Extand_Class", extUser_str);
|
|
||||||
const extInfo = JSON.parse(JSON.stringify(extUser));
|
const extInfo = JSON.parse(JSON.stringify(extUser));
|
||||||
|
// Continue with storing user data and redirecting
|
||||||
|
localStorage.setItem("Extand_Class", JSON.stringify([extUser]));
|
||||||
localStorage.setItem("userEmail", extInfo.Email);
|
localStorage.setItem("userEmail", extInfo.Email);
|
||||||
localStorage.setItem("username", extInfo.Name);
|
localStorage.setItem("username", extInfo.Name);
|
||||||
if (extInfo?.TenantId) {
|
if (extInfo?.TenantId) {
|
||||||
@@ -403,9 +376,8 @@ function Login() {
|
|||||||
localStorage.setItem("PageLanding", menu.pageId);
|
localStorage.setItem("PageLanding", menu.pageId);
|
||||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||||
localStorage.setItem("pageType", menu.pageType);
|
localStorage.setItem("pageType", menu.pageType);
|
||||||
|
setState({ ...state, loading: false });
|
||||||
setState({ ...state, loading: false });
|
navigate(redirectUrl);
|
||||||
navigate(redirectUrl);
|
|
||||||
} else {
|
} else {
|
||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
setIsModal(true);
|
setIsModal(true);
|
||||||
@@ -415,8 +387,8 @@ function Login() {
|
|||||||
logOutUser();
|
logOutUser();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showToast("danger", t("user-not-found"));
|
showToast("danger", t("user-not-found"));
|
||||||
logOutUser();
|
logOutUser();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error during login flow", error);
|
console.error("Error during login flow", error);
|
||||||
@@ -483,35 +455,39 @@ function Login() {
|
|||||||
onInput={(e) => e.target.setCustomValidity("")}
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
/>
|
/>
|
||||||
<hr className="my-1 border-none" />
|
<hr className="my-1 border-none" />
|
||||||
<label className="block text-xs" htmlFor="password">
|
<label className="block text-xs" htmlFor="password">
|
||||||
{t("password")}
|
{t("password")}
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<input
|
<input
|
||||||
id="password"
|
id="password"
|
||||||
type={state.passwordVisible ? "text" : "password"}
|
type={
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
state.passwordVisible ? "text" : "password"
|
||||||
name="password"
|
}
|
||||||
value={state.password}
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
autoComplete="current-password"
|
name="password"
|
||||||
onChange={handleChange}
|
value={state.password}
|
||||||
onInvalid={(e) =>
|
autoComplete="current-password"
|
||||||
e.target.setCustomValidity(t("input-required"))
|
onChange={handleChange}
|
||||||
}
|
onInvalid={(e) =>
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
e.target.setCustomValidity(
|
||||||
required
|
t("input-required")
|
||||||
/>
|
)
|
||||||
<span
|
}
|
||||||
className="absolute cursor-pointer top-[50%] right-[10px] -translate-y-[50%] text-base-content"
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
onClick={togglePasswordVisibility}
|
required
|
||||||
>
|
/>
|
||||||
{state.passwordVisible ? (
|
<span
|
||||||
<i className="fa-light fa-eye-slash text-xs pb-1" /> // Close eye icon
|
className="absolute cursor-pointer top-[50%] right-[10px] -translate-y-[50%] text-base-content"
|
||||||
) : (
|
onClick={togglePasswordVisibility}
|
||||||
<i className="fa-light fa-eye text-xs pb-1 " /> // Open eye icon
|
>
|
||||||
)}
|
{state.passwordVisible ? (
|
||||||
</span>
|
<i className="fa-light fa-eye-slash text-xs pb-1" /> // Close eye icon
|
||||||
</div>
|
) : (
|
||||||
|
<i className="fa-light fa-eye text-xs pb-1 " /> // Open eye icon
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="relative mt-1">
|
<div className="relative mt-1">
|
||||||
<NavLink
|
<NavLink
|
||||||
+12
-13
@@ -1,7 +1,11 @@
|
|||||||
import React, { useEffect, useState, useRef } from "react";
|
import React, { useEffect, useState, useRef } from "react";
|
||||||
import "../styles/opensigndrive.css";
|
import "../styles/opensigndrive.css";
|
||||||
import { iconColor } from "../constant/const";
|
import {
|
||||||
import { getDrive } from "../constant/Utils";
|
iconColor,
|
||||||
|
} from "../constant/const";
|
||||||
|
import {
|
||||||
|
getDrive
|
||||||
|
} from "../constant/Utils";
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
@@ -25,7 +29,8 @@ const AppLoader = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
function Opensigndrive() {
|
function Opensigndrive() {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -128,7 +133,7 @@ function Opensigndrive() {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
const getDetails = async () => {
|
const getDetails = async () => {
|
||||||
getPdfDocumentList();
|
getPdfDocumentList();
|
||||||
};
|
};
|
||||||
//function for get all pdf document list
|
//function for get all pdf document list
|
||||||
const getPdfDocumentList = async (disbaleLoading) => {
|
const getPdfDocumentList = async (disbaleLoading) => {
|
||||||
@@ -669,9 +674,7 @@ function Opensigndrive() {
|
|||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
id="folder-menu"
|
id="folder-menu"
|
||||||
className={`${
|
className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} hidden md:block cursor-pointer hover:bg-gray-200 p-2 rounded-md`}
|
||||||
isOptions ? "dropdown show dropDownStyle" : "dropdown"
|
|
||||||
} hidden md:block cursor-pointer hover:bg-gray-200 p-2 rounded-md`}
|
|
||||||
onClick={() => setIsOptions(!isOptions)}
|
onClick={() => setIsOptions(!isOptions)}
|
||||||
>
|
>
|
||||||
<div data-tut="reactourSecond">
|
<div data-tut="reactourSecond">
|
||||||
@@ -789,18 +792,14 @@ function Opensigndrive() {
|
|||||||
onClick={() => setIsList(!isList)}
|
onClick={() => setIsList(!isList)}
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
className={`${
|
className={`${isList ? "fa-light fa-th-large" : "fa-light fa-list"} text-[20px]`}
|
||||||
isList ? "fa-light fa-th-large" : "fa-light fa-list"
|
|
||||||
} text-[20px]`}
|
|
||||||
style={{ color: `${iconColor}` }}
|
style={{ color: `${iconColor}` }}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
id="folder-menu"
|
id="folder-menu"
|
||||||
className={`${
|
className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} md:hidden`}
|
||||||
isOptions ? "dropdown show dropDownStyle" : "dropdown"
|
|
||||||
} md:hidden`}
|
|
||||||
onClick={() => setIsOptions(!isOptions)}
|
onClick={() => setIsOptions(!isOptions)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
+672
-608
File diff suppressed because it is too large
Load Diff
+83
-45
@@ -3,7 +3,9 @@ import axios from "axios";
|
|||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import "../styles/signature.css";
|
import "../styles/signature.css";
|
||||||
import { PDFDocument } from "pdf-lib";
|
import { PDFDocument } from "pdf-lib";
|
||||||
import { maxTitleLength } from "../constant/const";
|
import {
|
||||||
|
maxTitleLength
|
||||||
|
} from "../constant/const";
|
||||||
import { DndProvider } from "react-dnd";
|
import { DndProvider } from "react-dnd";
|
||||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||||
import { useDrop } from "react-dnd";
|
import { useDrop } from "react-dnd";
|
||||||
@@ -70,7 +72,8 @@ import AddContact from "../primitives/AddContact";
|
|||||||
function PlaceHolderSign() {
|
function PlaceHolderSign() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const copyUrlRef = useRef(null);
|
const copyUrlRef = useRef(null);
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const editorRef = useRef();
|
const editorRef = useRef();
|
||||||
const { state } = useLocation();
|
const { state } = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -869,7 +872,11 @@ function PlaceHolderSign() {
|
|||||||
scale
|
scale
|
||||||
);
|
);
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
const pdfUrl = await convertBase64ToFile(pdfName, pdfBase64, "");
|
const pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64,
|
||||||
|
"",
|
||||||
|
);
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
const buffer = atob(pdfBase64);
|
const buffer = atob(pdfBase64);
|
||||||
SaveFileSize(buffer.length, pdfUrl, tenantId);
|
SaveFileSize(buffer.length, pdfUrl, tenantId);
|
||||||
@@ -881,7 +888,11 @@ function PlaceHolderSign() {
|
|||||||
} else if (pdfBase64Url) {
|
} else if (pdfBase64Url) {
|
||||||
try {
|
try {
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
const pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
const pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64Url,
|
||||||
|
"",
|
||||||
|
);
|
||||||
return pdfUrl;
|
return pdfUrl;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("error to convertBase64ToFile in placeholder flow", err);
|
console.log("error to convertBase64ToFile in placeholder flow", err);
|
||||||
@@ -987,7 +998,11 @@ function PlaceHolderSign() {
|
|||||||
let pdfUrl;
|
let pdfUrl;
|
||||||
if (isUploadPdf) {
|
if (isUploadPdf) {
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64Url,
|
||||||
|
"",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const docCls = new Parse.Object("contracts_Document");
|
const docCls = new Parse.Object("contracts_Document");
|
||||||
@@ -1058,9 +1073,7 @@ function PlaceHolderSign() {
|
|||||||
ExpiryDate: { iso: updateExpiryDate, __type: "Date" }
|
ExpiryDate: { iso: updateExpiryDate, __type: "Date" }
|
||||||
};
|
};
|
||||||
await axios.put(
|
await axios.put(
|
||||||
`${localStorage.getItem(
|
`${localStorage.getItem("baseUrl")}classes/contracts_Document/${documentId}`,
|
||||||
"baseUrl"
|
|
||||||
)}classes/contracts_Document/${documentId}`,
|
|
||||||
data,
|
data,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -1152,7 +1165,8 @@ function PlaceHolderSign() {
|
|||||||
year: "numeric"
|
year: "numeric"
|
||||||
});
|
});
|
||||||
|
|
||||||
let senderEmail = pdfDetails?.[0]?.ExtUserPtr?.Email;
|
let senderEmail =
|
||||||
|
pdfDetails?.[0]?.ExtUserPtr?.Email;
|
||||||
let senderPhone = pdfDetails?.[0]?.ExtUserPtr?.Phone;
|
let senderPhone = pdfDetails?.[0]?.ExtUserPtr?.Phone;
|
||||||
let signerMail = signersdata.slice();
|
let signerMail = signersdata.slice();
|
||||||
|
|
||||||
@@ -1178,11 +1192,16 @@ function PlaceHolderSign() {
|
|||||||
const orgName = pdfDetails[0]?.ExtUserPtr.Company
|
const orgName = pdfDetails[0]?.ExtUserPtr.Company
|
||||||
? pdfDetails[0].ExtUserPtr.Company
|
? pdfDetails[0].ExtUserPtr.Company
|
||||||
: "";
|
: "";
|
||||||
const senderName = pdfDetails?.[0].ExtUserPtr.Name;
|
const senderName =
|
||||||
|
pdfDetails?.[0].ExtUserPtr.Name;
|
||||||
const documentName = `${pdfDetails?.[0].Name}`;
|
const documentName = `${pdfDetails?.[0].Name}`;
|
||||||
let replaceVar;
|
let replaceVar;
|
||||||
|
|
||||||
if (requestBody && requestSubject && isCustomize) {
|
if (
|
||||||
|
requestBody &&
|
||||||
|
requestSubject &&
|
||||||
|
isCustomize
|
||||||
|
) {
|
||||||
const replacedRequestBody = requestBody.replace(/"/g, "'");
|
const replacedRequestBody = requestBody.replace(/"/g, "'");
|
||||||
htmlReqBody =
|
htmlReqBody =
|
||||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
|
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
|
||||||
@@ -1207,7 +1226,10 @@ function PlaceHolderSign() {
|
|||||||
htmlReqBody,
|
htmlReqBody,
|
||||||
variables
|
variables
|
||||||
);
|
);
|
||||||
} else if (tenantMailTemplate?.body && tenantMailTemplate?.subject) {
|
} else if (
|
||||||
|
tenantMailTemplate?.body &&
|
||||||
|
tenantMailTemplate?.subject
|
||||||
|
) {
|
||||||
const mailBody = tenantMailTemplate?.body;
|
const mailBody = tenantMailTemplate?.body;
|
||||||
const mailSubject = tenantMailTemplate?.subject;
|
const mailSubject = tenantMailTemplate?.subject;
|
||||||
const replacedRequestBody = mailBody.replace(/"/g, "'");
|
const replacedRequestBody = mailBody.replace(/"/g, "'");
|
||||||
@@ -1246,7 +1268,8 @@ function PlaceHolderSign() {
|
|||||||
? replaceVar?.subject
|
? replaceVar?.subject
|
||||||
: mailTemplate(mailparam).subject,
|
: mailTemplate(mailparam).subject,
|
||||||
replyto: senderEmail,
|
replyto: senderEmail,
|
||||||
from: senderEmail,
|
from:
|
||||||
|
senderEmail,
|
||||||
html: replaceVar?.body
|
html: replaceVar?.body
|
||||||
? replaceVar?.body
|
? replaceVar?.body
|
||||||
: mailTemplate(mailparam).body
|
: mailTemplate(mailparam).body
|
||||||
@@ -1261,13 +1284,20 @@ function PlaceHolderSign() {
|
|||||||
setMailStatus("success");
|
setMailStatus("success");
|
||||||
try {
|
try {
|
||||||
let data;
|
let data;
|
||||||
if (requestBody && requestSubject && isCustomize) {
|
if (
|
||||||
|
requestBody &&
|
||||||
|
requestSubject &&
|
||||||
|
isCustomize
|
||||||
|
) {
|
||||||
data = {
|
data = {
|
||||||
RequestBody: htmlReqBody,
|
RequestBody: htmlReqBody,
|
||||||
RequestSubject: requestSubject,
|
RequestSubject: requestSubject,
|
||||||
SendMail: true
|
SendMail: true
|
||||||
};
|
};
|
||||||
} else if (tenantMailTemplate?.body && tenantMailTemplate?.subject) {
|
} else if (
|
||||||
|
tenantMailTemplate?.body &&
|
||||||
|
tenantMailTemplate?.subject
|
||||||
|
) {
|
||||||
data = {
|
data = {
|
||||||
RequestBody: tenantMailTemplate?.body,
|
RequestBody: tenantMailTemplate?.body,
|
||||||
RequestSubject: tenantMailTemplate?.subject,
|
RequestSubject: tenantMailTemplate?.subject,
|
||||||
@@ -1305,7 +1335,8 @@ function PlaceHolderSign() {
|
|||||||
setIsSend(true);
|
setIsSend(true);
|
||||||
setIsMailSend(true);
|
setIsMailSend(true);
|
||||||
setIsUiLoading(false);
|
setIsUiLoading(false);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
setMailStatus("failed");
|
setMailStatus("failed");
|
||||||
setIsSend(true);
|
setIsSend(true);
|
||||||
setIsMailSend(true);
|
setIsMailSend(true);
|
||||||
@@ -1546,7 +1577,8 @@ function PlaceHolderSign() {
|
|||||||
status: defaultdata?.status || "required",
|
status: defaultdata?.status || "required",
|
||||||
hint: defaultdata?.hint || "",
|
hint: defaultdata?.hint || "",
|
||||||
defaultValue: defaultdata?.defaultValue || "",
|
defaultValue: defaultdata?.defaultValue || "",
|
||||||
validation: {},
|
validation:
|
||||||
|
{},
|
||||||
fontSize:
|
fontSize:
|
||||||
fontSize || currWidgetsDetails?.options?.fontSize || 12,
|
fontSize || currWidgetsDetails?.options?.fontSize || 12,
|
||||||
fontColor:
|
fontColor:
|
||||||
@@ -2029,26 +2061,30 @@ function PlaceHolderSign() {
|
|||||||
{!isCustomize && (
|
{!isCustomize && (
|
||||||
<span>{t("placeholder-alert-3")}</span>
|
<span>{t("placeholder-alert-3")}</span>
|
||||||
)}
|
)}
|
||||||
{isCustomize && (
|
{
|
||||||
<>
|
isCustomize && (
|
||||||
<EmailBody
|
<>
|
||||||
editorRef={editorRef}
|
<EmailBody
|
||||||
requestBody={requestBody}
|
editorRef={editorRef}
|
||||||
requestSubject={requestSubject}
|
requestBody={requestBody}
|
||||||
handleOnchangeRequest={handleOnchangeRequest}
|
requestSubject={requestSubject}
|
||||||
setRequestSubject={setRequestSubject}
|
handleOnchangeRequest={
|
||||||
/>
|
handleOnchangeRequest
|
||||||
<div
|
}
|
||||||
className="flex justify-end items-center gap-1 mt-2 op-link op-link-primary"
|
setRequestSubject={setRequestSubject}
|
||||||
onClick={() => {
|
/>
|
||||||
setRequestBody(defaultBody);
|
<div
|
||||||
setRequestSubject(defaultSubject);
|
className="flex justify-end items-center gap-1 mt-2 op-link op-link-primary"
|
||||||
}}
|
onClick={() => {
|
||||||
>
|
setRequestBody(defaultBody);
|
||||||
<span>{t("reset-to-default")}</span>
|
setRequestSubject(defaultSubject);
|
||||||
</div>
|
}}
|
||||||
</>
|
>
|
||||||
)}
|
<span>{t("reset-to-default")}</span>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
<div className="flex flex-row items-center gap-2 md:gap-6 mt-2">
|
<div className="flex flex-row items-center gap-2 md:gap-6 mt-2">
|
||||||
<div className="flex flex-row gap-2">
|
<div className="flex flex-row gap-2">
|
||||||
<button
|
<button
|
||||||
@@ -2066,14 +2102,16 @@ function PlaceHolderSign() {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!isCustomize && (
|
{
|
||||||
<span
|
!isCustomize && (
|
||||||
className="op-link op-link-accent text-sm"
|
<span
|
||||||
onClick={() => setIsCustomize(!isCustomize)}
|
className="op-link op-link-accent text-sm"
|
||||||
>
|
onClick={() => setIsCustomize(!isCustomize)}
|
||||||
{t("cutomize-email")}
|
>
|
||||||
</span>
|
{t("cutomize-email")}
|
||||||
)}
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -23,7 +23,8 @@ import EditorToolbar, {
|
|||||||
import DateFormatSelector from "../components/shared/fields/DateFormatSelector";
|
import DateFormatSelector from "../components/shared/fields/DateFormatSelector";
|
||||||
|
|
||||||
const Preferences = () => {
|
const Preferences = () => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const editorRef = useRef();
|
const editorRef = useRef();
|
||||||
const editorRefCom = useRef();
|
const editorRefCom = useRef();
|
||||||
@@ -44,7 +45,11 @@ const Preferences = () => {
|
|||||||
const [isNotifyOnSignatures, setIsNotifyOnSignatures] = useState();
|
const [isNotifyOnSignatures, setIsNotifyOnSignatures] = useState();
|
||||||
const [timezone, setTimezone] = useState(usertimezone);
|
const [timezone, setTimezone] = useState(usertimezone);
|
||||||
const [activeTab, setactiveTab] = useState(0);
|
const [activeTab, setactiveTab] = useState(0);
|
||||||
const generaltab = { title: t("general"), icon: "fa-light fa-gears" };
|
const generaltab = {
|
||||||
|
name: "general",
|
||||||
|
title: t("general"),
|
||||||
|
icon: "fa-light fa-gears"
|
||||||
|
};
|
||||||
const [tab, setTab] = useState([generaltab]);
|
const [tab, setTab] = useState([generaltab]);
|
||||||
const [sendinOrder, setSendinOrder] = useState(true);
|
const [sendinOrder, setSendinOrder] = useState(true);
|
||||||
const [isTourEnabled, setIsTourEnabled] = useState(false);
|
const [isTourEnabled, setIsTourEnabled] = useState(false);
|
||||||
@@ -60,9 +65,12 @@ const Preferences = () => {
|
|||||||
setIsTopLoader(true);
|
setIsTopLoader(true);
|
||||||
const EmailTab =
|
const EmailTab =
|
||||||
extClass?.[0]?.UserRole === "contracts_Admin"
|
extClass?.[0]?.UserRole === "contracts_Admin"
|
||||||
? [{ title: t("email"), icon: "fa-light fa-envelope" }]
|
? [{ name: "email", title: t("email"), icon: "fa-light fa-envelope" }]
|
||||||
: [];
|
: [];
|
||||||
const arr = [generaltab, ...EmailTab];
|
const arr = [
|
||||||
|
generaltab,
|
||||||
|
...EmailTab,
|
||||||
|
];
|
||||||
setTab(arr);
|
setTab(arr);
|
||||||
try {
|
try {
|
||||||
const user = JSON.parse(
|
const user = JSON.parse(
|
||||||
@@ -326,7 +334,7 @@ const Preferences = () => {
|
|||||||
|
|
||||||
const handleTourInput = () => setIsTourEnabled(!isTourEnabled);
|
const handleTourInput = () => setIsTourEnabled(!isTourEnabled);
|
||||||
const handleSendinOrderInput = () => setSendinOrder(!sendinOrder);
|
const handleSendinOrderInput = () => setSendinOrder(!sendinOrder);
|
||||||
|
const tabName = (ind) => tab.find((t, i) => i === ind)?.name;
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Title title={t("Preferences")} />
|
<Title title={t("Preferences")} />
|
||||||
@@ -364,9 +372,7 @@ const Preferences = () => {
|
|||||||
onClick={() => setactiveTab(ind)}
|
onClick={() => setactiveTab(ind)}
|
||||||
key={ind}
|
key={ind}
|
||||||
role="tab"
|
role="tab"
|
||||||
className={`${
|
className={`${activeTab === ind ? "op-tab-active" : ""} op-tab text-xs md:text-base pb-2 md:pb-0 transition-all `}
|
||||||
activeTab === ind ? "op-tab-active" : ""
|
|
||||||
} op-tab text-xs md:text-base pb-2 md:pb-0 transition-all `}
|
|
||||||
aria-selected={activeTab === ind}
|
aria-selected={activeTab === ind}
|
||||||
aria-controls={`panel-${tabData.title}`}
|
aria-controls={`panel-${tabData.title}`}
|
||||||
>
|
>
|
||||||
@@ -382,7 +388,7 @@ const Preferences = () => {
|
|||||||
aria-labelledby="tab-general"
|
aria-labelledby="tab-general"
|
||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
>
|
>
|
||||||
{activeTab === 0 ? (
|
{tabName(activeTab) === "general" && (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-12 md:gap-x-8">
|
<div className="grid grid-cols-1 md:grid-cols-12 md:gap-x-8">
|
||||||
{/* Left Column - Signature Settings */}
|
{/* Left Column - Signature Settings */}
|
||||||
<div className="md:col-span-5 flex flex-col">
|
<div className="md:col-span-5 flex flex-col">
|
||||||
@@ -487,7 +493,11 @@ const Preferences = () => {
|
|||||||
</ReactTooltip>
|
</ReactTooltip>
|
||||||
</label>
|
</label>
|
||||||
<div className="flex flex-row gap-6">
|
<div className="flex flex-row gap-6">
|
||||||
<div className={"flex items-center gap-2"}>
|
<div
|
||||||
|
className={
|
||||||
|
"flex items-center gap-2"
|
||||||
|
}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
id="notify-yes"
|
id="notify-yes"
|
||||||
className="op-radio op-radio-xs"
|
className="op-radio op-radio-xs"
|
||||||
@@ -502,7 +512,11 @@ const Preferences = () => {
|
|||||||
{t("yes")}
|
{t("yes")}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className={"flex items-center gap-2"}>
|
<div
|
||||||
|
className={
|
||||||
|
"flex items-center gap-2"
|
||||||
|
}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
id="notify-no"
|
id="notify-no"
|
||||||
className="op-radio op-radio-xs"
|
className="op-radio op-radio-xs"
|
||||||
@@ -706,7 +720,8 @@ const Preferences = () => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : activeTab === 1 ? (
|
)}
|
||||||
|
{tabName(activeTab) === "email" && (
|
||||||
<div className="flex flex-col mb-4">
|
<div className="flex flex-col mb-4">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<h1 className="text-[14px] mb-[0.7rem] font-medium">
|
<h1 className="text-[14px] mb-[0.7rem] font-medium">
|
||||||
@@ -722,9 +737,7 @@ const Preferences = () => {
|
|||||||
{t("subject")}{" "}
|
{t("subject")}{" "}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
id={"request-sub-tooltip"}
|
id={"request-sub-tooltip"}
|
||||||
message={`${t(
|
message={`${t("variables-use")}: {{sender_name}} {{document_title}}`}
|
||||||
"variables-use"
|
|
||||||
)}: {{sender_name}} {{document_title}}`}
|
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -733,9 +746,7 @@ const Preferences = () => {
|
|||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setRequestSubject(e.target.value)
|
setRequestSubject(e.target.value)
|
||||||
}
|
}
|
||||||
placeholder={`{{sender_name}} ${t(
|
placeholder={`{{sender_name}} ${t("send-to-sign")} {{document_title}}`}
|
||||||
"send-to-sign"
|
|
||||||
)} {{document_title}}`}
|
|
||||||
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -744,9 +755,7 @@ const Preferences = () => {
|
|||||||
{t("body")}{" "}
|
{t("body")}{" "}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
id={"request-body-tooltip"}
|
id={"request-body-tooltip"}
|
||||||
message={`${t(
|
message={`${t("variables-use")}: {{sender_name}} {{document_title}}`}
|
||||||
"variables-use"
|
|
||||||
)}: {{sender_name}} {{document_title}}`}
|
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<EditorToolbar containerId="toolbar1" />
|
<EditorToolbar containerId="toolbar1" />
|
||||||
@@ -792,9 +801,7 @@ const Preferences = () => {
|
|||||||
{t("subject")}{" "}
|
{t("subject")}{" "}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
id={"complete-sub-tooltip"}
|
id={"complete-sub-tooltip"}
|
||||||
message={`${t(
|
message={`${t("variables-use")}:{{sender_name}} {{document_title}}`}
|
||||||
"variables-use"
|
|
||||||
)}:{{sender_name}} {{document_title}}`}
|
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -803,9 +810,7 @@ const Preferences = () => {
|
|||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setCompletionSubject(e.target.value)
|
setCompletionSubject(e.target.value)
|
||||||
}
|
}
|
||||||
placeholder={`{{sender_name}} ${t(
|
placeholder={`{{sender_name}} ${t("send-to-sign")} {{document_title}}`}
|
||||||
"send-to-sign"
|
|
||||||
)} {{document_title}}`}
|
|
||||||
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -814,9 +819,7 @@ const Preferences = () => {
|
|||||||
{t("body")}{" "}
|
{t("body")}{" "}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
id={"complete-body-tooltip"}
|
id={"complete-body-tooltip"}
|
||||||
message={`${t(
|
message={`${t("variables-use")}:{{sender_name}} {{document_title}} {{signing_url}}`}
|
||||||
"variables-use"
|
|
||||||
)}:{{sender_name}} {{document_title}} {{signing_url}}`}
|
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<EditorToolbar containerId="toolbar2" />
|
<EditorToolbar containerId="toolbar2" />
|
||||||
@@ -851,8 +854,10 @@ const Preferences = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
)}
|
||||||
<></>
|
{tabName(activeTab) === "security" && (
|
||||||
|
<>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
+12
-4
@@ -67,7 +67,8 @@ import LoaderWithMsg from "../primitives/LoaderWithMsg";
|
|||||||
function SignYourSelf() {
|
function SignYourSelf() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { docId } = useParams();
|
const { docId } = useParams();
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const divRef = useRef(null);
|
const divRef = useRef(null);
|
||||||
const nodeRef = useRef(null);
|
const nodeRef = useRef(null);
|
||||||
const imageRef = useRef(null);
|
const imageRef = useRef(null);
|
||||||
@@ -520,7 +521,11 @@ function SignYourSelf() {
|
|||||||
let pdfUrl;
|
let pdfUrl;
|
||||||
if (isUploadPdf) {
|
if (isUploadPdf) {
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64Url,
|
||||||
|
"",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const widgetsType = ["signature", "stamp", "image", "initials"];
|
const widgetsType = ["signature", "stamp", "image", "initials"];
|
||||||
let updatedXYPosition;
|
let updatedXYPosition;
|
||||||
@@ -706,7 +711,10 @@ function SignYourSelf() {
|
|||||||
if (tenantDetails && tenantDetails === "user does not exist!") {
|
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||||
alert(t("user-not-exist"));
|
alert(t("user-not-exist"));
|
||||||
} else {
|
} else {
|
||||||
if (tenantDetails?.CompletionBody && tenantDetails?.CompletionSubject) {
|
if (
|
||||||
|
tenantDetails?.CompletionBody &&
|
||||||
|
tenantDetails?.CompletionSubject
|
||||||
|
) {
|
||||||
isCustomCompletionMail = true;
|
isCustomCompletionMail = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -742,7 +750,7 @@ function SignYourSelf() {
|
|||||||
pdfFile: base64Url,
|
pdfFile: base64Url,
|
||||||
docId: documentId,
|
docId: documentId,
|
||||||
isCustomCompletionMail: isCustomCompletionMail,
|
isCustomCompletionMail: isCustomCompletionMail,
|
||||||
signature: suffixbase64
|
signature: suffixbase64,
|
||||||
};
|
};
|
||||||
const resSignPdf = await Parse.Cloud.run("signPdf", params);
|
const resSignPdf = await Parse.Cloud.run("signPdf", params);
|
||||||
if (resSignPdf) {
|
if (resSignPdf) {
|
||||||
+20
-5
@@ -166,6 +166,7 @@ const TemplatePlaceholder = () => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [divRef.current, isHeader]);
|
}, [divRef.current, isHeader]);
|
||||||
|
|
||||||
|
|
||||||
//function to fetch tenant Details
|
//function to fetch tenant Details
|
||||||
const fetchTenantDetails = async () => {
|
const fetchTenantDetails = async () => {
|
||||||
const user = JSON.parse(
|
const user = JSON.parse(
|
||||||
@@ -777,7 +778,11 @@ const TemplatePlaceholder = () => {
|
|||||||
let pdfUrl;
|
let pdfUrl;
|
||||||
if (isUploadPdf) {
|
if (isUploadPdf) {
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64Url,
|
||||||
|
"",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (signersdata?.length > 0) {
|
if (signersdata?.length > 0) {
|
||||||
signersdata.forEach((x) => {
|
signersdata.forEach((x) => {
|
||||||
@@ -844,7 +849,11 @@ const TemplatePlaceholder = () => {
|
|||||||
scale
|
scale
|
||||||
);
|
);
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
const pdfUrl = await convertBase64ToFile(pdfName, pdfBase64, "");
|
const pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64,
|
||||||
|
"",
|
||||||
|
);
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
const buffer = atob(pdfBase64);
|
const buffer = atob(pdfBase64);
|
||||||
SaveFileSize(buffer.length, pdfUrl, tenantId);
|
SaveFileSize(buffer.length, pdfUrl, tenantId);
|
||||||
@@ -856,7 +865,11 @@ const TemplatePlaceholder = () => {
|
|||||||
} else if (pdfBase64Url) {
|
} else if (pdfBase64Url) {
|
||||||
try {
|
try {
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
const pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
const pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64Url,
|
||||||
|
"",
|
||||||
|
);
|
||||||
return pdfUrl;
|
return pdfUrl;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("error to convertBase64ToFile in placeholder flow", err);
|
console.log("error to convertBase64ToFile in placeholder flow", err);
|
||||||
@@ -1280,7 +1293,6 @@ const TemplatePlaceholder = () => {
|
|||||||
const handleCloseRoleModal = () => {
|
const handleCloseRoleModal = () => {
|
||||||
setIsModalRole(false);
|
setIsModalRole(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveWidgetsOptions = (
|
const handleSaveWidgetsOptions = (
|
||||||
dropdownName,
|
dropdownName,
|
||||||
dropdownOptions,
|
dropdownOptions,
|
||||||
@@ -1457,7 +1469,9 @@ const TemplatePlaceholder = () => {
|
|||||||
status: defaultdata?.status || "required",
|
status: defaultdata?.status || "required",
|
||||||
hint: defaultdata?.hint || "",
|
hint: defaultdata?.hint || "",
|
||||||
defaultValue: defaultdata?.defaultValue || "",
|
defaultValue: defaultdata?.defaultValue || "",
|
||||||
validation: {},
|
isReadOnly: defaultdata?.isReadOnly || false,
|
||||||
|
validation:
|
||||||
|
{},
|
||||||
fontSize:
|
fontSize:
|
||||||
fontSize || currWidgetsDetails?.options?.fontSize || 12,
|
fontSize || currWidgetsDetails?.options?.fontSize || 12,
|
||||||
fontColor:
|
fontColor:
|
||||||
@@ -1578,6 +1592,7 @@ const TemplatePlaceholder = () => {
|
|||||||
style: { fontSize: "13px" }
|
style: { fontSize: "13px" }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const textFieldTour = [
|
const textFieldTour = [
|
||||||
{
|
{
|
||||||
selector: '[data-tut="IsSigned"]',
|
selector: '[data-tut="IsSigned"]',
|
||||||
+2
-1
@@ -7,7 +7,8 @@ import Title from "../components/Title";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { emailRegex } from "../constant/const";
|
import { emailRegex } from "../constant/const";
|
||||||
const UpdateExistUserAdmin = () => {
|
const UpdateExistUserAdmin = () => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [formdata, setFormdata] = useState({ email: "", masterkey: "" });
|
const [formdata, setFormdata] = useState({ email: "", masterkey: "" });
|
||||||
@@ -1,394 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import Parse from "parse";
|
|
||||||
import Alert from "../primitives/Alert";
|
|
||||||
import Loader from "../primitives/Loader";
|
|
||||||
import { useLocation } from "react-router";
|
|
||||||
import ModalUi from "../primitives/ModalUi";
|
|
||||||
import pad from "../assets/images/pad.svg";
|
|
||||||
import Tooltip from "../primitives/Tooltip";
|
|
||||||
import AddUser from "../components/AddUser";
|
|
||||||
import Title from "../components/Title";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"];
|
|
||||||
const UserList = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [userList, setUserList] = useState([]);
|
|
||||||
const [isLoader, setIsLoader] = useState(false);
|
|
||||||
const [isModal, setIsModal] = useState({
|
|
||||||
form: false,
|
|
||||||
addseats: false,
|
|
||||||
options: false
|
|
||||||
});
|
|
||||||
const location = useLocation();
|
|
||||||
const isDashboard =
|
|
||||||
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
|
||||||
const [isActiveModal, setIsActiveModal] = useState({});
|
|
||||||
const [isActLoader, setIsActLoader] = useState({});
|
|
||||||
const [isAdmin, setIsAdmin] = useState(false);
|
|
||||||
const [formHeader, setFormHeader] = useState(t("add-user"));
|
|
||||||
const recordperPage = 10;
|
|
||||||
const startIndex = (currentPage - 1) * recordperPage; // user per page
|
|
||||||
|
|
||||||
const getPaginationRange = () => {
|
|
||||||
const totalPageNumbers = 7; // Adjust this value to show more/less page numbers
|
|
||||||
const pages = [];
|
|
||||||
const totalPages = Math.ceil(userList.length / recordperPage);
|
|
||||||
if (totalPages <= totalPageNumbers) {
|
|
||||||
for (let i = 1; i <= totalPages; i++) {
|
|
||||||
pages.push(i);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const leftSiblingIndex = Math.max(currentPage - 1, 1);
|
|
||||||
const rightSiblingIndex = Math.min(currentPage + 1, totalPages);
|
|
||||||
|
|
||||||
const showLeftDots = leftSiblingIndex > 2;
|
|
||||||
const showRightDots = rightSiblingIndex < totalPages - 2;
|
|
||||||
|
|
||||||
const firstPageIndex = 1;
|
|
||||||
const lastPageIndex = totalPages;
|
|
||||||
|
|
||||||
if (!showLeftDots && showRightDots) {
|
|
||||||
let leftItemCount = 3;
|
|
||||||
let leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1);
|
|
||||||
|
|
||||||
pages.push(...leftRange);
|
|
||||||
pages.push("...");
|
|
||||||
pages.push(totalPages);
|
|
||||||
} else if (showLeftDots && !showRightDots) {
|
|
||||||
let rightItemCount = 3;
|
|
||||||
let rightRange = Array.from(
|
|
||||||
{ length: rightItemCount },
|
|
||||||
(_, i) => totalPages - rightItemCount + i + 1
|
|
||||||
);
|
|
||||||
|
|
||||||
pages.push(firstPageIndex);
|
|
||||||
pages.push("...");
|
|
||||||
pages.push(...rightRange);
|
|
||||||
} else if (showLeftDots && showRightDots) {
|
|
||||||
let middleRange = Array.from(
|
|
||||||
{ length: 3 },
|
|
||||||
(_, i) => leftSiblingIndex + i
|
|
||||||
);
|
|
||||||
|
|
||||||
pages.push(firstPageIndex);
|
|
||||||
pages.push("...");
|
|
||||||
pages.push(...middleRange);
|
|
||||||
pages.push("...");
|
|
||||||
pages.push(lastPageIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pages;
|
|
||||||
};
|
|
||||||
const pageNumbers = getPaginationRange();
|
|
||||||
// to slice out 10 objects from array for current page
|
|
||||||
const indexOfLastDoc = currentPage * recordperPage;
|
|
||||||
const indexOfFirstDoc = indexOfLastDoc - recordperPage;
|
|
||||||
const currentList = userList?.slice(indexOfFirstDoc, indexOfLastDoc);
|
|
||||||
useEffect(() => {
|
|
||||||
fetchUserList();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
async function fetchUserList() {
|
|
||||||
try {
|
|
||||||
setIsLoader(true);
|
|
||||||
const extUser =
|
|
||||||
localStorage.getItem("Extand_Class") &&
|
|
||||||
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
|
||||||
|
|
||||||
if (extUser) {
|
|
||||||
const admin =
|
|
||||||
extUser?.UserRole &&
|
|
||||||
(extUser?.UserRole === "contracts_Admin" ||
|
|
||||||
extUser?.UserRole === "contracts_OrgAdmin")
|
|
||||||
? true
|
|
||||||
: false;
|
|
||||||
setIsAdmin(admin);
|
|
||||||
}
|
|
||||||
const res = await Parse.Cloud.run("getuserlistbyorg", {
|
|
||||||
organizationId: extUser.OrganizationId.objectId
|
|
||||||
});
|
|
||||||
const _userRes = JSON.parse(JSON.stringify(res));
|
|
||||||
setUserList(_userRes);
|
|
||||||
} catch (err) {
|
|
||||||
console.log("Err in fetch userlist", err);
|
|
||||||
showAlert("danger", t("something-went-wrong-mssg"));
|
|
||||||
} finally {
|
|
||||||
setIsLoader(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const handleModal = (modalName) => {
|
|
||||||
setIsModal((obj) => ({ ...obj, [modalName]: !obj[modalName] }));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Change page
|
|
||||||
const paginateFront = () => {
|
|
||||||
const lastValue = pageNumbers?.[pageNumbers?.length - 1];
|
|
||||||
if (currentPage < lastValue) {
|
|
||||||
setCurrentPage(currentPage + 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const paginateBack = () => {
|
|
||||||
if (startIndex > 0) {
|
|
||||||
setCurrentPage(currentPage - 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUserData = (userData) => {
|
|
||||||
if (userData) {
|
|
||||||
setUserList((prev) => [userData, ...prev]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// `formatRow` is used to show data in poper manner like
|
|
||||||
// if data is of array type then it will join array items with ","
|
|
||||||
// if data is of object type then it Name values will be show in row
|
|
||||||
// if no data available it will show hyphen "-"
|
|
||||||
const formatRow = (row) => {
|
|
||||||
if (Array.isArray(row)) {
|
|
||||||
let updateArr = row.map((x) => x.Name);
|
|
||||||
return updateArr.join(", ");
|
|
||||||
} else if (typeof row === "object" && row !== null) {
|
|
||||||
return row?.Name || "-";
|
|
||||||
} else {
|
|
||||||
return "-";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleClose = () => setIsActiveModal({});
|
|
||||||
|
|
||||||
const handleToggleSubmit = async (user) => {
|
|
||||||
const index = userList.findIndex((obj) => obj.objectId === user.objectId);
|
|
||||||
if (index !== -1) {
|
|
||||||
setIsActiveModal({});
|
|
||||||
setIsActLoader({ [user.objectId]: true });
|
|
||||||
const newArray = [...userList];
|
|
||||||
const IsDisabled = newArray[index]?.IsDisabled;
|
|
||||||
newArray[index] = { ...newArray[index], IsDisabled: !IsDisabled };
|
|
||||||
setUserList(newArray);
|
|
||||||
try {
|
|
||||||
const extUser = new Parse.Object("contracts_Users");
|
|
||||||
extUser.id = user.objectId;
|
|
||||||
extUser.set("IsDisabled", !IsDisabled);
|
|
||||||
await extUser.save();
|
|
||||||
showAlert(
|
|
||||||
!IsDisabled === true ? "danger" : "success",
|
|
||||||
!IsDisabled === true ? t("user-deactivated") : t("user-activated")
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
showAlert("danger", t("something-went-wrong-mssg"));
|
|
||||||
console.log("err in disable team", err);
|
|
||||||
} finally {
|
|
||||||
setIsActLoader({});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleToggleBtn = (user) => {
|
|
||||||
setIsActiveModal({ [user.objectId]: true });
|
|
||||||
};
|
|
||||||
|
|
||||||
// `showAlert` handle show/hide alert
|
|
||||||
const showAlert = (type, msg) => {
|
|
||||||
setIsAlert({ type, msg });
|
|
||||||
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className="relative">
|
|
||||||
<Title title={isAdmin ? "Users" : "Page not found"} />
|
|
||||||
{isLoader && (
|
|
||||||
<div className="absolute w-full h-[300px] md:h-[400px] flex justify-center items-center z-30 rounded-box">
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{Object.keys(isActLoader)?.length > 0 && (
|
|
||||||
<div className="absolute w-full h-full flex justify-center items-center bg-black/30 z-30 rounded-box">
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!isLoader && (
|
|
||||||
<>
|
|
||||||
{isAdmin ? (
|
|
||||||
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
|
|
||||||
{isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
|
|
||||||
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
|
||||||
<div className="font-light">
|
|
||||||
{t("report-name.Users")}{" "}
|
|
||||||
<span className="text-xs md:text-[13px] font-normal">
|
|
||||||
<Tooltip message={t("users-from-teams")} />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-row gap-2 items-center">
|
|
||||||
<div
|
|
||||||
className="cursor-pointer"
|
|
||||||
onClick={() => handleModal("form")}
|
|
||||||
>
|
|
||||||
<i className="fa-light fa-square-plus text-accent text-[30px] md:text-[40px]"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-full overflow-x-auto">
|
|
||||||
<table className="op-table border-collapse w-full mb-[50px]">
|
|
||||||
<thead className="text-[14px]">
|
|
||||||
<tr className="border-y-[1px]">
|
|
||||||
{heading?.map((item, index) => (
|
|
||||||
<th key={index} className="px-4 py-2">
|
|
||||||
{t(`report-heading.${item}`)}
|
|
||||||
</th>
|
|
||||||
))}
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
{userList?.length > 0 && (
|
|
||||||
<tbody className="text-[12px]">
|
|
||||||
{currentList.map((item, index) => (
|
|
||||||
<tr className="border-y-[1px]" key={index}>
|
|
||||||
{heading.includes("Sr.No") && (
|
|
||||||
<th className="px-4 py-2">
|
|
||||||
{startIndex + index + 1}
|
|
||||||
</th>
|
|
||||||
)}
|
|
||||||
<td className="px-4 py-2 font-semibold">
|
|
||||||
{item?.Name}{" "}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 ">{item?.Email || "-"}</td>
|
|
||||||
<td className="px-4 py-2">{item?.Phone || "-"}</td>
|
|
||||||
<td className="px-4 py-2">
|
|
||||||
{item?.UserRole?.split("_").pop() || "-"}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2">
|
|
||||||
{formatRow(item.TeamIds)}
|
|
||||||
</td>
|
|
||||||
{item.UserRole !== "contracts_Admin" ? (
|
|
||||||
<td className="px-4 py-2 font-semibold">
|
|
||||||
<label className="cursor-pointer relative block items-center mb-0">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
className="op-toggle transition-all op-toggle-secondary"
|
|
||||||
checked={item?.IsDisabled !== true}
|
|
||||||
onChange={() => handleToggleBtn(item)}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
{isActiveModal[item.objectId] && (
|
|
||||||
<ModalUi
|
|
||||||
isOpen
|
|
||||||
title={t("user-status")}
|
|
||||||
handleClose={handleClose}
|
|
||||||
>
|
|
||||||
<div className="m-[20px]">
|
|
||||||
<div className="text-lg font-normal text-black">
|
|
||||||
{t("are-you-sure")}{" "}
|
|
||||||
{item?.IsDisabled
|
|
||||||
? t("activate")
|
|
||||||
: t("deactivate")}{" "}
|
|
||||||
{t("this-user")}?
|
|
||||||
</div>
|
|
||||||
<hr className="bg-[#ccc] mt-4 " />
|
|
||||||
<div className="flex items-center mt-3 gap-2 text-white">
|
|
||||||
<button
|
|
||||||
onClick={() => handleToggleSubmit(item)}
|
|
||||||
className="op-btn op-btn-primary"
|
|
||||||
>
|
|
||||||
{t("yes")}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={handleClose}
|
|
||||||
className="op-btn op-btn-secondary"
|
|
||||||
>
|
|
||||||
{t("no")}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ModalUi>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
) : (
|
|
||||||
<td className="px-4 py-2 font-semibold"></td>
|
|
||||||
)}
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
)}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-row justify-between items-center text-xs font-medium">
|
|
||||||
<div className="op-join flex flex-wrap items-center p-2">
|
|
||||||
{userList.length > recordperPage && (
|
|
||||||
<button
|
|
||||||
onClick={() => paginateBack()}
|
|
||||||
className="op-join-item op-btn op-btn-sm"
|
|
||||||
>
|
|
||||||
{t("prev")}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{pageNumbers.map((x, i) => (
|
|
||||||
<button
|
|
||||||
key={i}
|
|
||||||
onClick={() => setCurrentPage(x)}
|
|
||||||
disabled={x === "..."}
|
|
||||||
className={`${
|
|
||||||
x === currentPage ? "op-btn-active" : ""
|
|
||||||
} op-join-item op-btn op-btn-sm`}
|
|
||||||
>
|
|
||||||
{x}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
{userList.length > recordperPage && (
|
|
||||||
<button
|
|
||||||
onClick={() => paginateFront()}
|
|
||||||
className="op-join-item op-btn op-btn-sm"
|
|
||||||
>
|
|
||||||
{t("next")}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{userList?.length <= 0 && (
|
|
||||||
<div
|
|
||||||
className={`${
|
|
||||||
isDashboard ? "h-[317px]" : ""
|
|
||||||
} flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`}
|
|
||||||
>
|
|
||||||
<div className="w-[60px] h-[60px] overflow-hidden">
|
|
||||||
<img
|
|
||||||
className="w-full h-full object-contain"
|
|
||||||
src={pad}
|
|
||||||
alt="img"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="text-sm font-semibold">
|
|
||||||
{t("no-data-avaliable")}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<ModalUi
|
|
||||||
isOpen={isModal.form}
|
|
||||||
title={formHeader}
|
|
||||||
handleClose={() => handleModal("form")}
|
|
||||||
>
|
|
||||||
<AddUser
|
|
||||||
showAlert={showAlert}
|
|
||||||
handleUserData={handleUserData}
|
|
||||||
closePopup={() => handleModal("form")}
|
|
||||||
setFormHeader={setFormHeader}
|
|
||||||
/>
|
|
||||||
</ModalUi>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
|
|
||||||
<div className="text-center">
|
|
||||||
<h1 className="text-[60px] lg:text-[120px] font-semibold">
|
|
||||||
404
|
|
||||||
</h1>
|
|
||||||
<p className="text-[30px] lg:text-[50px]">
|
|
||||||
{t("page-not-found")}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default UserList;
|
|
||||||
@@ -0,0 +1,406 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import Parse from "parse";
|
||||||
|
import Alert from "../primitives/Alert";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
import { useLocation } from "react-router";
|
||||||
|
import ModalUi from "../primitives/ModalUi";
|
||||||
|
import pad from "../assets/images/pad.svg";
|
||||||
|
import Tooltip from "../primitives/Tooltip";
|
||||||
|
import AddUser from "../components/AddUser";
|
||||||
|
import Title from "../components/Title";
|
||||||
|
import {
|
||||||
|
useTranslation
|
||||||
|
} from "react-i18next";
|
||||||
|
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"];
|
||||||
|
const UserList = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [userList, setUserList] = useState([]);
|
||||||
|
const [isLoader, setIsLoader] = useState(false);
|
||||||
|
const [isModal, setIsModal] = useState({
|
||||||
|
form: false,
|
||||||
|
addseats: false,
|
||||||
|
options: false
|
||||||
|
});
|
||||||
|
const location = useLocation();
|
||||||
|
const isDashboard =
|
||||||
|
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
|
||||||
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||||
|
const [isActiveModal, setIsActiveModal] = useState({});
|
||||||
|
const [isActLoader, setIsActLoader] = useState({});
|
||||||
|
const [isAdmin, setIsAdmin] = useState(false);
|
||||||
|
const [formHeader, setFormHeader] = useState(t("add-user"));
|
||||||
|
const recordperPage = 10;
|
||||||
|
const startIndex = (currentPage - 1) * recordperPage; // user per page
|
||||||
|
|
||||||
|
const getPaginationRange = () => {
|
||||||
|
const totalPageNumbers = 7; // Adjust this value to show more/less page numbers
|
||||||
|
const pages = [];
|
||||||
|
const totalPages = Math.ceil(userList.length / recordperPage);
|
||||||
|
if (totalPages <= totalPageNumbers) {
|
||||||
|
for (let i = 1; i <= totalPages; i++) {
|
||||||
|
pages.push(i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const leftSiblingIndex = Math.max(currentPage - 1, 1);
|
||||||
|
const rightSiblingIndex = Math.min(currentPage + 1, totalPages);
|
||||||
|
|
||||||
|
const showLeftDots = leftSiblingIndex > 2;
|
||||||
|
const showRightDots = rightSiblingIndex < totalPages - 2;
|
||||||
|
|
||||||
|
const firstPageIndex = 1;
|
||||||
|
const lastPageIndex = totalPages;
|
||||||
|
|
||||||
|
if (!showLeftDots && showRightDots) {
|
||||||
|
let leftItemCount = 3;
|
||||||
|
let leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1);
|
||||||
|
|
||||||
|
pages.push(...leftRange);
|
||||||
|
pages.push("...");
|
||||||
|
pages.push(totalPages);
|
||||||
|
} else if (showLeftDots && !showRightDots) {
|
||||||
|
let rightItemCount = 3;
|
||||||
|
let rightRange = Array.from(
|
||||||
|
{ length: rightItemCount },
|
||||||
|
(_, i) => totalPages - rightItemCount + i + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
pages.push(firstPageIndex);
|
||||||
|
pages.push("...");
|
||||||
|
pages.push(...rightRange);
|
||||||
|
} else if (showLeftDots && showRightDots) {
|
||||||
|
let middleRange = Array.from(
|
||||||
|
{ length: 3 },
|
||||||
|
(_, i) => leftSiblingIndex + i
|
||||||
|
);
|
||||||
|
|
||||||
|
pages.push(firstPageIndex);
|
||||||
|
pages.push("...");
|
||||||
|
pages.push(...middleRange);
|
||||||
|
pages.push("...");
|
||||||
|
pages.push(lastPageIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pages;
|
||||||
|
};
|
||||||
|
const pageNumbers = getPaginationRange();
|
||||||
|
// to slice out 10 objects from array for current page
|
||||||
|
const indexOfLastDoc = currentPage * recordperPage;
|
||||||
|
const indexOfFirstDoc = indexOfLastDoc - recordperPage;
|
||||||
|
const currentList = userList?.slice(indexOfFirstDoc, indexOfLastDoc);
|
||||||
|
useEffect(() => {
|
||||||
|
fetchUserList();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
async function fetchUserList() {
|
||||||
|
try {
|
||||||
|
setIsLoader(true);
|
||||||
|
const extUser =
|
||||||
|
localStorage.getItem("Extand_Class") &&
|
||||||
|
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
|
|
||||||
|
if (extUser) {
|
||||||
|
const admin =
|
||||||
|
extUser?.UserRole &&
|
||||||
|
(extUser?.UserRole === "contracts_Admin" ||
|
||||||
|
extUser?.UserRole === "contracts_OrgAdmin")
|
||||||
|
? true
|
||||||
|
: false;
|
||||||
|
setIsAdmin(admin);
|
||||||
|
}
|
||||||
|
const res = await Parse.Cloud.run("getuserlistbyorg", {
|
||||||
|
organizationId: extUser.OrganizationId.objectId
|
||||||
|
});
|
||||||
|
const _userRes = JSON.parse(JSON.stringify(res));
|
||||||
|
setUserList(_userRes);
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err in fetch userlist", err);
|
||||||
|
showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
|
} finally {
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleModal = (modalName) => {
|
||||||
|
setIsModal((obj) => ({ ...obj, [modalName]: !obj[modalName] }));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Change page
|
||||||
|
const paginateFront = () => {
|
||||||
|
const lastValue = pageNumbers?.[pageNumbers?.length - 1];
|
||||||
|
if (currentPage < lastValue) {
|
||||||
|
setCurrentPage(currentPage + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const paginateBack = () => {
|
||||||
|
if (startIndex > 0) {
|
||||||
|
setCurrentPage(currentPage - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUserData = (userData) => {
|
||||||
|
if (userData) {
|
||||||
|
setUserList((prev) => [userData, ...prev]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// `formatRow` is used to show data in poper manner like
|
||||||
|
// if data is of array type then it will join array items with ","
|
||||||
|
// if data is of object type then it Name values will be show in row
|
||||||
|
// if no data available it will show hyphen "-"
|
||||||
|
const formatRow = (row) => {
|
||||||
|
if (Array.isArray(row)) {
|
||||||
|
let updateArr = row.map((x) => x.Name);
|
||||||
|
return updateArr.join(", ");
|
||||||
|
} else if (typeof row === "object" && row !== null) {
|
||||||
|
return row?.Name || "-";
|
||||||
|
} else {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleClose = () => setIsActiveModal({});
|
||||||
|
|
||||||
|
const handleToggleSubmit = async (user) => {
|
||||||
|
const index = userList.findIndex((obj) => obj.objectId === user.objectId);
|
||||||
|
if (index !== -1) {
|
||||||
|
setIsActiveModal({});
|
||||||
|
setIsActLoader({ [user.objectId]: true });
|
||||||
|
const newArray = [...userList];
|
||||||
|
const IsDisabled = newArray[index]?.IsDisabled;
|
||||||
|
newArray[index] = { ...newArray[index], IsDisabled: !IsDisabled };
|
||||||
|
setUserList(newArray);
|
||||||
|
try {
|
||||||
|
const extUser = new Parse.Object("contracts_Users");
|
||||||
|
extUser.id = user.objectId;
|
||||||
|
extUser.set("IsDisabled", !IsDisabled);
|
||||||
|
await extUser.save();
|
||||||
|
showAlert(
|
||||||
|
!IsDisabled === true ? "danger" : "success",
|
||||||
|
!IsDisabled === true ? t("user-deactivated") : t("user-activated")
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
|
console.log("err in disable team", err);
|
||||||
|
} finally {
|
||||||
|
setIsActLoader({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleToggleBtn = (user) => {
|
||||||
|
setIsActiveModal({ [user.objectId]: true });
|
||||||
|
};
|
||||||
|
|
||||||
|
// `showAlert` handle show/hide alert
|
||||||
|
const showAlert = (type, msg) => {
|
||||||
|
setIsAlert({ type, msg });
|
||||||
|
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="relative">
|
||||||
|
<Title title={isAdmin ? "Users" : "Page not found"} />
|
||||||
|
{isLoader && (
|
||||||
|
<div className="absolute w-full h-[300px] md:h-[400px] flex justify-center items-center z-30 rounded-box">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{Object.keys(isActLoader)?.length > 0 && (
|
||||||
|
<div className="absolute w-full h-full flex justify-center items-center bg-black/30 z-30 rounded-box">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{
|
||||||
|
!isLoader && (
|
||||||
|
<>
|
||||||
|
{isAdmin ? (
|
||||||
|
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
|
||||||
|
{isAlert.msg && (
|
||||||
|
<Alert type={isAlert.type}>{isAlert.msg}</Alert>
|
||||||
|
)}
|
||||||
|
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
||||||
|
<div className="font-light">
|
||||||
|
{t("report-name.Users")}{" "}
|
||||||
|
<span className="text-xs md:text-[13px] font-normal">
|
||||||
|
<Tooltip message={t("users-from-teams")} />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row gap-2 items-center">
|
||||||
|
<div
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => handleModal("form")}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-square-plus text-accent text-[30px] md:text-[40px]"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full overflow-x-auto">
|
||||||
|
<table className="op-table border-collapse w-full mb-[50px]">
|
||||||
|
<thead className="text-[14px]">
|
||||||
|
<tr className="border-y-[1px]">
|
||||||
|
{heading?.map((item, index) => (
|
||||||
|
<th key={index} className="px-4 py-2">
|
||||||
|
{t(`report-heading.${item}`)}
|
||||||
|
</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
{userList?.length > 0 && (
|
||||||
|
<tbody className="text-[12px]">
|
||||||
|
{currentList.map((item, index) => (
|
||||||
|
<tr className="border-y-[1px]" key={index}>
|
||||||
|
{heading.includes("Sr.No") && (
|
||||||
|
<th className="px-4 py-2">
|
||||||
|
{startIndex + index + 1}
|
||||||
|
</th>
|
||||||
|
)}
|
||||||
|
<td className="px-4 py-2 font-semibold">
|
||||||
|
{item?.Name}{" "}
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-2 ">
|
||||||
|
{item?.Email || "-"}
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-2">
|
||||||
|
{item?.Phone || "-"}
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-2">
|
||||||
|
{item?.UserRole?.split("_").pop() || "-"}
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-2">
|
||||||
|
{formatRow(item.TeamIds)}
|
||||||
|
</td>
|
||||||
|
{item.UserRole !== "contracts_Admin" ? (
|
||||||
|
<td className="px-4 py-2 font-semibold">
|
||||||
|
<label className="cursor-pointer relative block items-center mb-0">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="op-toggle transition-all op-toggle-secondary"
|
||||||
|
checked={item?.IsDisabled !== true}
|
||||||
|
onChange={() => handleToggleBtn(item)}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
{isActiveModal[item.objectId] && (
|
||||||
|
<ModalUi
|
||||||
|
isOpen
|
||||||
|
title={t("user-status")}
|
||||||
|
handleClose={handleClose}
|
||||||
|
>
|
||||||
|
<div className="m-[20px]">
|
||||||
|
<div className="text-lg font-normal text-black">
|
||||||
|
{t("are-you-sure")}{" "}
|
||||||
|
{item?.IsDisabled
|
||||||
|
? t("activate")
|
||||||
|
: t("deactivate")}{" "}
|
||||||
|
{t("this-user")}?
|
||||||
|
</div>
|
||||||
|
<hr className="bg-[#ccc] mt-4 " />
|
||||||
|
<div className="flex items-center mt-3 gap-2 text-white">
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
handleToggleSubmit(item)
|
||||||
|
}
|
||||||
|
className="op-btn op-btn-primary"
|
||||||
|
>
|
||||||
|
{t("yes")}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleClose}
|
||||||
|
className="op-btn op-btn-secondary"
|
||||||
|
>
|
||||||
|
{t("no")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
) : (
|
||||||
|
<td className="px-4 py-2 font-semibold"></td>
|
||||||
|
)}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
)}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row justify-between items-center text-xs font-medium">
|
||||||
|
<div className="op-join flex flex-wrap items-center p-2">
|
||||||
|
{userList.length > recordperPage && (
|
||||||
|
<button
|
||||||
|
onClick={() => paginateBack()}
|
||||||
|
className="op-join-item op-btn op-btn-sm"
|
||||||
|
>
|
||||||
|
{t("prev")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{pageNumbers.map((x, i) => (
|
||||||
|
<button
|
||||||
|
key={i}
|
||||||
|
onClick={() => setCurrentPage(x)}
|
||||||
|
disabled={x === "..."}
|
||||||
|
className={`${
|
||||||
|
x === currentPage ? "op-btn-active" : ""
|
||||||
|
} op-join-item op-btn op-btn-sm`}
|
||||||
|
>
|
||||||
|
{x}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
{userList.length > recordperPage && (
|
||||||
|
<button
|
||||||
|
onClick={() => paginateFront()}
|
||||||
|
className="op-join-item op-btn op-btn-sm"
|
||||||
|
>
|
||||||
|
{t("next")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{userList?.length <= 0 && (
|
||||||
|
<div
|
||||||
|
className={`${
|
||||||
|
isDashboard ? "h-[317px]" : ""
|
||||||
|
} flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`}
|
||||||
|
>
|
||||||
|
<div className="w-[60px] h-[60px] overflow-hidden">
|
||||||
|
<img
|
||||||
|
className="w-full h-full object-contain"
|
||||||
|
src={pad}
|
||||||
|
alt="img"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-sm font-semibold">
|
||||||
|
{t("no-data-avaliable")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<ModalUi
|
||||||
|
isOpen={isModal.form}
|
||||||
|
title={formHeader}
|
||||||
|
handleClose={() => handleModal("form")}
|
||||||
|
>
|
||||||
|
<AddUser
|
||||||
|
showAlert={showAlert}
|
||||||
|
handleUserData={handleUserData}
|
||||||
|
closePopup={() => handleModal("form")}
|
||||||
|
setFormHeader={setFormHeader}
|
||||||
|
/>
|
||||||
|
</ModalUi>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
|
||||||
|
<div className="text-center">
|
||||||
|
<h1 className="text-[60px] lg:text-[120px] font-semibold">
|
||||||
|
404
|
||||||
|
</h1>
|
||||||
|
<p className="text-[30px] lg:text-[50px]">
|
||||||
|
{t("page-not-found")}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserList;
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, {
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
} from "react";
|
||||||
import { Navigate, useNavigate } from "react-router";
|
import { Navigate, useNavigate } from "react-router";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import { SaveFileSize } from "../constant/saveFileSize";
|
import { SaveFileSize } from "../constant/saveFileSize";
|
||||||
@@ -7,7 +10,10 @@ import Title from "../components/Title";
|
|||||||
import sanitizeFileName from "../primitives/sanitizeFileName";
|
import sanitizeFileName from "../primitives/sanitizeFileName";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Tooltip from "../primitives/Tooltip";
|
import Tooltip from "../primitives/Tooltip";
|
||||||
import { getSecureUrl, handleSendOTP } from "../constant/Utils";
|
import {
|
||||||
|
getSecureUrl,
|
||||||
|
handleSendOTP,
|
||||||
|
} from "../constant/Utils";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -121,7 +127,7 @@ function UserProfile() {
|
|||||||
Name: obj.Name,
|
Name: obj.Name,
|
||||||
JobTitle: jobTitle,
|
JobTitle: jobTitle,
|
||||||
Company: company,
|
Company: company,
|
||||||
Language: obj?.language || ""
|
Language: obj?.language || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
await axios.put(
|
await axios.put(
|
||||||
@@ -406,7 +412,7 @@ function UserProfile() {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
editmode ? handleSubmit(e) : setEditMode(true);
|
editmode ? handleSubmit(e) : setEditMode(true);
|
||||||
}}
|
}}
|
||||||
className="op-btn op-btn-primary w-[100px]"
|
className="op-btn op-btn-primary w-[100px]"
|
||||||
>
|
>
|
||||||
+9
-7
@@ -33,9 +33,8 @@ const AddContact = (props) => {
|
|||||||
try {
|
try {
|
||||||
const baseURL = localStorage.getItem("baseUrl");
|
const baseURL = localStorage.getItem("baseUrl");
|
||||||
const url = `${baseURL}functions/isuserincontactbook`;
|
const url = `${baseURL}functions/isuserincontactbook`;
|
||||||
const token = {
|
const token =
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
{ "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
|
||||||
};
|
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
@@ -64,15 +63,18 @@ const AddContact = (props) => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
const userId = user?.objectId || "";
|
const userId = user?.objectId || "";
|
||||||
const tenantDetails = await getTenantDetails(userId);
|
const tenantDetails = await getTenantDetails(
|
||||||
|
userId,
|
||||||
|
);
|
||||||
const tenantId = tenantDetails?.objectId || "";
|
const tenantId = tenantDetails?.objectId || "";
|
||||||
if (tenantId) {
|
if (tenantId) {
|
||||||
try {
|
try {
|
||||||
const baseURL = localStorage.getItem("baseUrl");
|
const baseURL = localStorage.getItem("baseUrl");
|
||||||
const url = `${baseURL}functions/savecontact`;
|
const url = `${baseURL}functions/savecontact`;
|
||||||
const token = {
|
const token =
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
{
|
||||||
};
|
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||||
|
};
|
||||||
const data = { name, email, phone, tenantId };
|
const data = { name, email, phone, tenantId };
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user