mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-03 16:28:56 +02:00
Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a23aabbe4 | ||
|
|
4a85599703 | ||
|
|
3e9b84de72 | ||
|
|
4313d8d0e4 | ||
|
|
3088fdd163 | ||
|
|
8c86fe27ec | ||
|
|
01e09998e5 | ||
|
|
55fdb52bf3 | ||
|
|
08f46a393b | ||
|
|
9345da543a | ||
|
|
208891e10d | ||
|
|
db0fa61b2b | ||
|
|
221f098de6 | ||
|
|
9658761ede | ||
|
|
6aad832e37 | ||
|
|
e4b6be51d9 | ||
|
|
a3b2c797fb |
+4
-3
@@ -8,13 +8,11 @@ PUBLIC_URL=https://localhost:3001
|
||||
GENERATE_SOURCEMAP=false
|
||||
# Set it to the URL from where APIs will be accessible, for local development it should be localhost:3000/api/app (use your local port number instead)
|
||||
# REACT_APP_SERVERURL=http://localhost:8080/app
|
||||
# A 12 character long random app identifier. The value of this should be same as APP_ID which is a variable used by backend API.
|
||||
# (DEPRECATED) This should not be changed if provided; it should be 'opensign'.
|
||||
REACT_APP_APPID=opensign
|
||||
|
||||
|
||||
# Backend ExpressJS config ****************************************************************************************************************************************************************************************
|
||||
# A 12 character long random app identifier. The value of this should be same as REACT_APP_APPID which is a variable used by Frontend React App.
|
||||
APP_ID=opensign
|
||||
# Name of the app. It will be visible in the verification emails sent out.
|
||||
appName=open_sign_server
|
||||
# A 12 character long random secret key that allows access to all the data. It is used in Parse dashboard config to view all the data in the database.
|
||||
@@ -111,3 +109,6 @@ CRUxFgQUDYlgGVxSxuOknhQc256x3++7BDwwMTAhMAkGBSsOAwIaBQAEFFjASdYl
|
||||
|
||||
# Provide Pass pharse of above PFX or p12 document
|
||||
PASS_PHRASE=opensign
|
||||
|
||||
# (DEPRECATED) This should not be changed if provided; it should be 'opensign'.
|
||||
APP_ID=opensign
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{$HOST_URL} {
|
||||
reverse_proxy client:3000
|
||||
handle_path /app/* {
|
||||
handle_path /api/* {
|
||||
reverse_proxy server:8080
|
||||
rewrite * /app{uri}
|
||||
rewrite * {uri}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ COPY apps/OpenSign/.husky .
|
||||
|
||||
# Define environment variables if needed
|
||||
ENV NODE_ENV=production
|
||||
ENV GENERATE_SOURCEMAP=false
|
||||
# build
|
||||
RUN npm run build
|
||||
|
||||
|
||||
Generated
+357
-363
File diff suppressed because it is too large
Load Diff
+18
-18
@@ -4,13 +4,13 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@formkit/auto-animate": "^0.8.2",
|
||||
"@lottiefiles/dotlottie-react": "^0.13.0",
|
||||
"@lottiefiles/dotlottie-react": "^0.13.2",
|
||||
"@pdf-lib/fontkit": "^1.1.1",
|
||||
"@radix-ui/themes": "^3.1.6",
|
||||
"@react-pdf/renderer": "^4.1.6",
|
||||
"@react-pdf/renderer": "^4.3.0",
|
||||
"@reduxjs/toolkit": "^2.5.1",
|
||||
"axios": "^1.7.9",
|
||||
"css-minimizer-webpack-plugin": "^7.0.0",
|
||||
"axios": "^1.8.3",
|
||||
"css-minimizer-webpack-plugin": "^7.0.2",
|
||||
"file-saver": "^2.0.5",
|
||||
"i18next": "^23.16.8",
|
||||
"i18next-browser-languagedetector": "^8.0.2",
|
||||
@@ -25,7 +25,7 @@
|
||||
"radix-ui": "^1.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.10.9",
|
||||
"react-confetti": "^6.2.2",
|
||||
"react-confetti": "^6.4.0",
|
||||
"react-cookie": "^7.2.2",
|
||||
"react-datepicker": "^7.6.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
@@ -38,13 +38,13 @@
|
||||
"react-i18next": "^15.4.0",
|
||||
"react-konva": "^18.2.10",
|
||||
"react-pdf": "^9.2.1",
|
||||
"react-quill-new": "^3.3.3",
|
||||
"react-quill-new": "^3.4.1",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-rnd": "^10.4.14",
|
||||
"react-rnd": "^10.5.2",
|
||||
"react-router": "^7.1.5",
|
||||
"react-scripts": "^5.0.1",
|
||||
"react-scrollbars-custom": "^4.1.1",
|
||||
"react-select": "^5.10.0",
|
||||
"react-select": "^5.10.1",
|
||||
"react-signature-canvas": "^1.0.7",
|
||||
"react-syntax-highlighter": "^15.6.1",
|
||||
"react-timezone-select": "^3.2.8",
|
||||
@@ -53,11 +53,11 @@
|
||||
"reactour": "^1.19.4",
|
||||
"redux": "^5.0.1",
|
||||
"redux-thunk": "^3.1.0",
|
||||
"regex-parser": "^2.3.0",
|
||||
"regex-parser": "^2.3.1",
|
||||
"serve": "^14.2.4",
|
||||
"styled-components": "^5.3.0",
|
||||
"web-vitals": "^4.2.4",
|
||||
"ws": "^8.18.0",
|
||||
"ws": "^8.18.1",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -96,11 +96,11 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.26.9",
|
||||
"@babel/core": "^7.26.10",
|
||||
"@babel/preset-env": "^7.26.9",
|
||||
"@babel/preset-react": "^7.26.3",
|
||||
"@babel/runtime-corejs2": "^7.26.9",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"@babel/runtime-corejs2": "^7.26.10",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"babel-loader": "^9.2.1",
|
||||
"commitizen": "^4.3.1",
|
||||
"concurrently": "^9.1.2",
|
||||
@@ -108,14 +108,14 @@
|
||||
"daisyui": "^4.12.23",
|
||||
"dotenv": "^16.4.7",
|
||||
"dotenv-webpack": "^8.1.0",
|
||||
"eslint": "^9.20.0",
|
||||
"eslint": "^9.22.0",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"lint-staged": "^15.4.3",
|
||||
"lint-staged": "^15.5.0",
|
||||
"mini-css-extract-plugin": "^2.9.2",
|
||||
"postcss": "^8.5.1",
|
||||
"prettier": "^3.5.0",
|
||||
"pretty-quick": "^4.0.0",
|
||||
"postcss": "^8.5.3",
|
||||
"prettier": "^3.5.3",
|
||||
"pretty-quick": "^4.1.1",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"terser-webpack-plugin": "^5.3.11",
|
||||
"webpack-cli": "^5.1.4"
|
||||
|
||||
@@ -247,7 +247,7 @@
|
||||
"generate-token-alert": "Sind Sie sicher, dass Sie das Token neu generieren möchten? Das alte Token wird ablaufen.",
|
||||
"yes": "Ja",
|
||||
"copied": "Kopiert",
|
||||
"something-went-wrong-mssg": "Etwas ist schiefgelaufen. Bitte versuchen Sie es später erneut.",
|
||||
"something-went-wrong-mssg": "Etwas ist schiefgelaufen, Das Aktualisieren dieser Seite kann das Problem lösen.",
|
||||
"token-generated": "Token erfolgreich generiert.",
|
||||
"webhook": "Webhook",
|
||||
"update-webhook": "Webhook aktualisieren",
|
||||
@@ -831,7 +831,7 @@
|
||||
"initial-type": "Ihre Initialen",
|
||||
"redirect-url": "Weiterleitungs-URL",
|
||||
"bulk-send": "Massenversand",
|
||||
"select-timezone": "Wählen Sie Ihre Zeitzone",
|
||||
"select-timezone": "Zeitzone",
|
||||
"current-time": "Aktuelle Uhrzeit",
|
||||
"email-help": "Aus Sicherheitsgründen dürfen Sie die E-Mail-Adresse nicht ändern. Bitte erstellen Sie ein weiteres kostenloses Konto mit der neuen E-Mail-Adresse.",
|
||||
"doc-sent": "Dokument erfolgreich gesendet.",
|
||||
|
||||
@@ -247,7 +247,7 @@
|
||||
"generate-token-alert": "Are you sure you want to regenerate token it will expire old token?",
|
||||
"yes": "Yes",
|
||||
"copied": "Copied",
|
||||
"something-went-wrong-mssg": "Something went wrong, please try again later.",
|
||||
"something-went-wrong-mssg": "Something went wrong, refreshing this page may solve this issue.",
|
||||
"token-generated": "Token generated successfully.",
|
||||
"webhook": "Webhook",
|
||||
"update-webhook": "Update webhook",
|
||||
@@ -831,7 +831,7 @@
|
||||
"initial-type": "Your initials",
|
||||
"redirect-url": "Redirect url",
|
||||
"bulk-send": "Bulk send",
|
||||
"select-timezone": "Select your Timezone",
|
||||
"select-timezone": "Timezone",
|
||||
"current-time": "Current time",
|
||||
"email-help": "You are not allowed to change email address due to security reasons. Please create another free account using the new email address.",
|
||||
"doc-sent": "Document sent successfully.",
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
"generate-token-alert": "¿En definitiva quieres regenerar el token? Esto expirará el token antiguo.",
|
||||
"yes": "Sí",
|
||||
"copied": "Copiado",
|
||||
"something-went-wrong-mssg": "Algo salió mal, por favor, intenta de nuevo más tarde.",
|
||||
"something-went-wrong-mssg": "Un problème est survenu, Actualiser cette page peut résoudre le problème.",
|
||||
"token-generated": "Token generado exitosamente.",
|
||||
"webhook": "Webhook",
|
||||
"update-webhook": "Actualizar webhook",
|
||||
@@ -831,7 +831,7 @@
|
||||
"initial-type": "Tus iniciales",
|
||||
"redirect-url": "URL de redireccionamiento",
|
||||
"bulk-send": "envío masivo",
|
||||
"select-timezone": "Seleccione su zona horaria",
|
||||
"select-timezone": "Zona horaria",
|
||||
"current-time": "Hora actual",
|
||||
"email-help": "No se permite cambiar la dirección de correo electrónico por razones de seguridad. Por favor, cree otra cuenta gratuita utilizando la nueva dirección de correo electrónico.",
|
||||
"doc-sent": "Documento enviado con éxito.",
|
||||
|
||||
@@ -831,7 +831,7 @@
|
||||
"initial-type": "Vos initiales",
|
||||
"redirect-url": "URL de redirection",
|
||||
"bulk-send": "Envoi groupé",
|
||||
"select-timezone": "Sélectionnez votre fuseau horaire",
|
||||
"select-timezone": "Fuseau horaire",
|
||||
"current-time": "Heure actuelle",
|
||||
"email-help": "Vous n'êtes pas autorisé à changer d'adresse e-mail pour des raisons de sécurité. Veuillez créer un autre compte gratuit en utilisant la nouvelle adresse e-mail.",
|
||||
"doc-sent": "Document envoyé avec succès.",
|
||||
|
||||
@@ -247,7 +247,7 @@
|
||||
"generate-token-alert": "Sei sicuro di voler rigenerare il token? Questo invaliderà il vecchio token.",
|
||||
"yes": "Sì",
|
||||
"copied": "Copiato",
|
||||
"something-went-wrong-mssg": "Qualcosa è andato storto, riprova più tardi.",
|
||||
"something-went-wrong-mssg": "Si è verificato un errore, L'aggiornamento della pagina potrebbe risolvere il problema.",
|
||||
"token-generated": "Token generato con successo.",
|
||||
"webhook": "Webhook",
|
||||
"update-webhook": "Aggiorna Webhook",
|
||||
@@ -831,7 +831,7 @@
|
||||
"initial-type": "Le tue iniziali",
|
||||
"redirect-url": "URL di reindirizzamento",
|
||||
"bulk-send": "Invio in blocco",
|
||||
"select-timezone": "Seleziona il tuo fuso orario",
|
||||
"select-timezone": "Fuso orario",
|
||||
"current-time": "Ora corrente",
|
||||
"email-help": "Non ti è permesso cambiare l'indirizzo email per motivi di sicurezza. Ti preghiamo di creare un altro account gratuito utilizzando il nuovo indirizzo email.",
|
||||
"doc-sent": "Documento inviato con successo.",
|
||||
|
||||
@@ -2,13 +2,8 @@ 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 { copytoData, usertimezone } from "../constant/Utils";
|
||||
import { emailRegex } from "../constant/const";
|
||||
import { useTranslation } from "react-i18next";
|
||||
function generatePassword(length) {
|
||||
const characters =
|
||||
@@ -46,9 +41,9 @@ const AddUser = (props) => {
|
||||
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 allUserId =
|
||||
_teamRes.find((x) => x.Name === "All Users")?.objectId || "";
|
||||
setFormdata((prev) => ({ ...prev, team: allUserId }));
|
||||
}
|
||||
};
|
||||
const checkUserExist = async () => {
|
||||
@@ -269,126 +264,120 @@ const AddUser = (props) => {
|
||||
<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 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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -32,13 +32,10 @@ function DraftDocument() {
|
||||
) {
|
||||
setIsLoading({
|
||||
isLoader: false,
|
||||
message: "Error: Something went wrong!"
|
||||
message: t("something-went-wrong-mssg")
|
||||
});
|
||||
} else {
|
||||
setIsLoading({
|
||||
isLoader: false,
|
||||
message: "No data found!"
|
||||
});
|
||||
setIsLoading({ isLoader: false, message: t("no-data") });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
import React, {
|
||||
useState,
|
||||
} from "react";
|
||||
import {
|
||||
getFileName
|
||||
} from "../../constant/Utils";
|
||||
import React, { useState } from "react";
|
||||
import { getFileName } from "../../constant/Utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
import SignersInput from "../shared/fields/SignersInput";
|
||||
|
||||
const EditTemplate = ({
|
||||
template,
|
||||
onSuccess,
|
||||
}) => {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const EditTemplate = ({ template, onSuccess }) => {
|
||||
const appName = "OpenSign™";
|
||||
const { t } = useTranslation();
|
||||
const [formData, setFormData] = useState({
|
||||
Name: template?.Name || "",
|
||||
@@ -196,7 +188,7 @@ const EditTemplate = ({
|
||||
<Tooltip id="istourenabled-tooltip" className="z-50">
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">{t("enable-tour")}</p>
|
||||
<p className="p-[5px]">
|
||||
<div className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">{t("yes")}: </span>
|
||||
@@ -207,7 +199,7 @@ const EditTemplate = ({
|
||||
<span>{t("istourenabled-help.p2")}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
<p>{t("istourenabled-help.p3", { appName: appName })}</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
@@ -254,11 +246,7 @@ const EditTemplate = ({
|
||||
</Tooltip>
|
||||
</label>
|
||||
<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
|
||||
className="mr-[2px] op-radio op-radio-xs"
|
||||
type="radio"
|
||||
@@ -267,11 +255,7 @@ const EditTemplate = ({
|
||||
/>
|
||||
<div className="text-center">{t("yes")}</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
|
||||
className="mr-[2px] op-radio op-radio-xs"
|
||||
type="radio"
|
||||
|
||||
@@ -35,8 +35,7 @@ function EmailComponent({
|
||||
setEmailList([]);
|
||||
}, 1500);
|
||||
setIsLoading(false);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
setIsLoading(false);
|
||||
setIsEmail(false);
|
||||
setIsAlert({
|
||||
|
||||
@@ -1,305 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import { tomorrow } from "react-syntax-highlighter/dist/esm/styles/prism";
|
||||
import { copytoData } from "../../constant/Utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router";
|
||||
|
||||
function EmbedTab(props) {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const tabName = [
|
||||
{ title: "React/Next.js", icon: "fa-brands fa-react", color: "#61dafb" },
|
||||
{ title: "JavaScript", icon: "fa-brands fa-js", color: "#ffd43b" },
|
||||
{ title: "Angular", icon: "fa-brands fa-angular", color: "#ff5733" }
|
||||
];
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
// State to track if the code has been copied
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
const reactCode = [
|
||||
{
|
||||
id: 0,
|
||||
title: "Installation",
|
||||
codeString: `npm install @opensign/react`
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "Usage",
|
||||
codeString: `
|
||||
import React from "react";
|
||||
import Opensign from "@opensign/react";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<div className="app">
|
||||
<Opensign
|
||||
onLoad={() => console.log("success")}
|
||||
onLoadError={(error) => console.log(error)}
|
||||
templateId= "${props.templateId ? props.templateId : "#templateId"}"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
`
|
||||
}
|
||||
];
|
||||
|
||||
const angularCode = [
|
||||
{
|
||||
id: 0,
|
||||
title: "Installation",
|
||||
codeString: `npm install @opensign/angular`
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "Usage",
|
||||
codeString: `
|
||||
import { Component } from '@angular/core';
|
||||
import { OpensignComponent } from "@opensign/angular"
|
||||
|
||||
@Component({
|
||||
selector:'app-root',
|
||||
standalone: true,
|
||||
imports: [OpensignComponent],
|
||||
template:\`<opensign templateId="${props.templateId ? props.templateId : "#templateId"}"
|
||||
(onLoad)="handleLoad()"
|
||||
(onLoadError)="handleError($event)"
|
||||
></opensign>\`,
|
||||
})
|
||||
export class AppComponent {
|
||||
handleLoad() {
|
||||
console.log("success");
|
||||
}
|
||||
handleError(error: string) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
`
|
||||
}
|
||||
];
|
||||
const jsCodeString = `
|
||||
<script
|
||||
src= "${window.location.origin}/static/js/public-template.bundle.js"
|
||||
id="opensign-script"
|
||||
templateId=${props.templateId ? props.templateId : "#templateId"}
|
||||
></script>
|
||||
`;
|
||||
|
||||
const handleCopy = (code, ind) => {
|
||||
copytoData(code);
|
||||
setIsCopied({ ...isCopied, [ind]: true });
|
||||
setTimeout(() => setIsCopied(false), 3000);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`${props.templateId && "border-t-[1px] mt-4"}`}>
|
||||
{props.templateId && (
|
||||
<h3 className="text-base-content font-bold text-lg pt-[15px] pb-[5px]">
|
||||
{t("embed-template")}
|
||||
</h3>
|
||||
)}
|
||||
<div className="flex justify-center items-center mt-2">
|
||||
<div role="tablist" className="op-tabs op-tabs-bordered">
|
||||
{tabName.map((tabData, ind) => (
|
||||
<div
|
||||
onClick={() => setActiveTab(ind)}
|
||||
key={ind}
|
||||
role="tab"
|
||||
className={`${
|
||||
activeTab === ind ? "op-tab-active" : ""
|
||||
} op-tab flex items-center pb-10 md:pb-0`}
|
||||
>
|
||||
<i
|
||||
className={`${tabData.icon}`}
|
||||
style={{ color: tabData.color }}
|
||||
></i>
|
||||
<span className="ml-1 text-[10px] font-medium md:font-normal md:text-[15px]">
|
||||
{tabData.title}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{activeTab === 0 ? (
|
||||
<div className="mt-4">
|
||||
{reactCode.map((data, ind) => {
|
||||
return (
|
||||
<div key={ind}>
|
||||
<p className="font-medium text-[18px]">
|
||||
{t(`${data.title}`)}
|
||||
</p>
|
||||
{ind === 0 && (
|
||||
<p className="text-[15px] mt-2">
|
||||
{t("public-template-mssg-1")}
|
||||
</p>
|
||||
)}
|
||||
<div className="relative p-1">
|
||||
<div
|
||||
onClick={() => handleCopy(data.codeString, ind)}
|
||||
className="absolute top-[20px] right-[20px] cursor-pointer"
|
||||
>
|
||||
<i className="fa-light fa-copy text-white mr-[2px]" />
|
||||
<span className=" text-white">
|
||||
{isCopied[ind] ? t("copied-code") : t("copy-code")}
|
||||
</span>
|
||||
</div>
|
||||
<SyntaxHighlighter
|
||||
customStyle={{
|
||||
borderRadius: "15px"
|
||||
}}
|
||||
language="javascript"
|
||||
style={tomorrow}
|
||||
>
|
||||
{data.codeString}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{props.isEmbedPage && (
|
||||
<p className="text-[15px] my-2">
|
||||
{t("js-snippet-msg-1")}
|
||||
<span
|
||||
className="text-blue-600 cursor-pointer px-1"
|
||||
onClick={() => navigate("/report/6TeaPr321t")}
|
||||
>
|
||||
{t("js-snippet-msg-2")}
|
||||
</span>
|
||||
<span>{t("js-snippet-msg-3")}</span>
|
||||
</p>
|
||||
)}
|
||||
<p className="font-medium mt-3 text-[15px]">
|
||||
{t("public-template-mssg-3")}
|
||||
</p>
|
||||
<p className="my-[6px]">
|
||||
{" "}
|
||||
{t("public-template-mssg-4")}
|
||||
<a
|
||||
href="https://www.npmjs.com/package/@opensign/react"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="cursor-pointer text-blue-700 "
|
||||
>
|
||||
{" "}
|
||||
OpenSign React package{" "}
|
||||
</a>
|
||||
{t("public-template-mssg-5")}
|
||||
</p>
|
||||
</div>
|
||||
) : activeTab === 1 ? (
|
||||
<div className="mt-4">
|
||||
<div>
|
||||
<p className="font-medium text-[18px]">{t(`Usage`)}</p>
|
||||
<p className="text-[15px] my-2">{t("js-snippet-msg")}</p>
|
||||
<div className="relative p-1">
|
||||
<div
|
||||
onClick={() => handleCopy(jsCodeString, 0)}
|
||||
className="absolute top-[20px] right-[20px] cursor-pointer"
|
||||
>
|
||||
<i className="fa-light fa-copy text-white mr-[2px]" />
|
||||
<span className=" text-white">
|
||||
{isCopied[0] ? t("copied-code") : t("copy-code")}
|
||||
</span>
|
||||
</div>
|
||||
<SyntaxHighlighter
|
||||
customStyle={{
|
||||
borderRadius: "15px"
|
||||
}}
|
||||
language="javascript"
|
||||
style={tomorrow}
|
||||
>
|
||||
{jsCodeString}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
{props.isEmbedPage && (
|
||||
<p className="text-[15px] my-2">
|
||||
{t("js-snippet-msg-1")}
|
||||
<span
|
||||
className="text-blue-600 cursor-pointer px-1"
|
||||
onClick={() => navigate("/report/6TeaPr321t")}
|
||||
>
|
||||
{t("js-snippet-msg-2")}
|
||||
</span>
|
||||
<span>{t("js-snippet-msg-3")}</span>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
activeTab === 2 && (
|
||||
<div className="mt-4">
|
||||
{angularCode.map((data, ind) => {
|
||||
return (
|
||||
<div key={ind}>
|
||||
<p className="font-medium text-[18px]">
|
||||
{t(`${data.title}`)}
|
||||
</p>
|
||||
{ind === 0 && (
|
||||
<p className="text-[15px] mt-2">
|
||||
{t("angular-npm-mssg-1")}
|
||||
</p>
|
||||
)}
|
||||
<div className="relative p-1">
|
||||
<div
|
||||
onClick={() => handleCopy(data.codeString, ind)}
|
||||
className="absolute top-[20px] right-[20px] cursor-pointer"
|
||||
>
|
||||
<i className="fa-light fa-copy text-white mr-[2px]" />
|
||||
<span className=" text-white">
|
||||
{isCopied[ind] ? t("copied-code") : t("copy-code")}
|
||||
</span>
|
||||
</div>
|
||||
<SyntaxHighlighter
|
||||
customStyle={{
|
||||
borderRadius: "15px"
|
||||
}}
|
||||
language="javascript"
|
||||
style={tomorrow}
|
||||
>
|
||||
{data.codeString}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{props.isEmbedPage && (
|
||||
<p className="text-[15px] my-2">
|
||||
{t("js-snippet-msg-1")}
|
||||
<span
|
||||
className="text-blue-600 cursor-pointer px-1"
|
||||
onClick={() => navigate("/report/6TeaPr321t")}
|
||||
>
|
||||
{t("js-snippet-msg-2")}
|
||||
</span>
|
||||
<span>{t("js-snippet-msg-3")}</span>
|
||||
</p>
|
||||
)}
|
||||
<p className="font-medium mt-3 text-[15px]">
|
||||
{t("public-template-mssg-3")}
|
||||
</p>
|
||||
<p className="my-[6px]">
|
||||
{" "}
|
||||
{t("public-template-mssg-4")}
|
||||
<a
|
||||
href="https://www.npmjs.com/package/@opensign/angular"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="cursor-pointer text-blue-700 "
|
||||
>
|
||||
{" "}
|
||||
OpenSign Angular package{" "}
|
||||
</a>
|
||||
{t("public-template-mssg-5")}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EmbedTab;
|
||||
@@ -25,6 +25,8 @@ const selectFormat = (data) => {
|
||||
switch (data) {
|
||||
case "L":
|
||||
return "MM/dd/yyyy";
|
||||
case "MM/DD/YYYY":
|
||||
return "MM/dd/yyyy";
|
||||
case "DD-MM-YYYY":
|
||||
return "dd-MM-yyyy";
|
||||
case "DD/MM/YYYY":
|
||||
@@ -41,6 +43,8 @@ const selectFormat = (data) => {
|
||||
return "MM.dd.yyyy";
|
||||
case "MMM DD, YYYY":
|
||||
return "MMM dd, yyyy";
|
||||
case "MMMM DD, YYYY":
|
||||
return "MMMM dd, yyyy";
|
||||
case "DD MMMM, YYYY":
|
||||
return "dd MMMM, yyyy";
|
||||
default:
|
||||
@@ -91,7 +95,7 @@ const getDefaultDate = (dateStr, format) => {
|
||||
return date;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function Placeholder(props) {
|
||||
//'isTouchDevice' is used to detect whether a device has a touchscreen or is mouse-based
|
||||
const isTouchDevice = navigator.maxTouchPoints > 0;
|
||||
|
||||
@@ -24,7 +24,7 @@ const widgetCls =
|
||||
function PlaceholderType(props) {
|
||||
const { t } = useTranslation();
|
||||
const type = props?.pos?.type;
|
||||
const widgetTypeTraslation = t(`widgets-name.${props?.pos?.type}`);
|
||||
const widgetTypeTranslation = t(`widgets-name.${props?.pos?.type}`);
|
||||
const [selectOption, setSelectOption] = useState("");
|
||||
const [validatePlaceholder, setValidatePlaceholder] = useState("");
|
||||
const inputRef = useRef(null);
|
||||
@@ -342,8 +342,8 @@ function PlaceholderType(props) {
|
||||
className="font-medium"
|
||||
>
|
||||
{props.isNeedSign
|
||||
? props.pos?.options?.hint || widgetTypeTraslation
|
||||
: widgetTypeTraslation}
|
||||
? props.pos?.options?.hint || widgetTypeTranslation
|
||||
: widgetTypeTranslation}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -368,8 +368,8 @@ function PlaceholderType(props) {
|
||||
className="font-medium"
|
||||
>
|
||||
{props.isNeedSign
|
||||
? props.pos?.options?.hint || widgetTypeTraslation
|
||||
: widgetTypeTraslation}
|
||||
? props.pos?.options?.hint || widgetTypeTranslation
|
||||
: widgetTypeTranslation}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -475,7 +475,7 @@ function PlaceholderType(props) {
|
||||
/>
|
||||
) : (
|
||||
<div style={textWidgetStyle} className="select-none-cls">
|
||||
<span>{textValue || widgetTypeTraslation}</span>
|
||||
<span>{textValue || widgetTypeTranslation}</span>
|
||||
</div>
|
||||
);
|
||||
case "dropdown":
|
||||
@@ -538,7 +538,7 @@ function PlaceholderType(props) {
|
||||
>
|
||||
{props.pos?.options?.name
|
||||
? props.pos.options.name
|
||||
: widgetTypeTraslation}
|
||||
: widgetTypeTranslation}
|
||||
<i className="fa-light fa-circle-chevron-down mr-1 "></i>
|
||||
</div>
|
||||
);
|
||||
@@ -562,8 +562,8 @@ function PlaceholderType(props) {
|
||||
className="font-medium text-center"
|
||||
>
|
||||
{props.isNeedSign
|
||||
? props.pos?.options?.hint || widgetTypeTraslation
|
||||
: widgetTypeTraslation}
|
||||
? props.pos?.options?.hint || widgetTypeTranslation
|
||||
: widgetTypeTranslation}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -574,7 +574,7 @@ function PlaceholderType(props) {
|
||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||
<textarea
|
||||
ref={inputRef}
|
||||
placeholder={hint}
|
||||
placeholder={hint || widgetTypeTranslation}
|
||||
rows={1}
|
||||
onKeyDown={handleEnterPress}
|
||||
value={textValue}
|
||||
@@ -597,7 +597,7 @@ function PlaceholderType(props) {
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-full select-none-cls" style={textWidgetStyle}>
|
||||
<span>{widgetTypeTraslation}</span>
|
||||
<span>{widgetTypeTranslation}</span>
|
||||
</div>
|
||||
);
|
||||
case "company":
|
||||
@@ -606,7 +606,7 @@ function PlaceholderType(props) {
|
||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||
<textarea
|
||||
ref={inputRef}
|
||||
placeholder={hint}
|
||||
placeholder={hint || widgetTypeTranslation}
|
||||
rows={1}
|
||||
onKeyDown={handleEnterPress}
|
||||
value={textValue}
|
||||
@@ -628,7 +628,7 @@ function PlaceholderType(props) {
|
||||
/>
|
||||
) : (
|
||||
<div style={textWidgetStyle} className="select-none-cls">
|
||||
<span>{widgetTypeTraslation}</span>
|
||||
<span>{widgetTypeTranslation}</span>
|
||||
</div>
|
||||
);
|
||||
case "job title":
|
||||
@@ -637,7 +637,7 @@ function PlaceholderType(props) {
|
||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||
<textarea
|
||||
ref={inputRef}
|
||||
placeholder={hint}
|
||||
placeholder={hint || widgetTypeTranslation}
|
||||
rows={1}
|
||||
onKeyDown={handleEnterPress}
|
||||
value={textValue}
|
||||
@@ -659,7 +659,7 @@ function PlaceholderType(props) {
|
||||
/>
|
||||
) : (
|
||||
<div style={textWidgetStyle} className="select-none-cls">
|
||||
<span>{widgetTypeTraslation}</span>
|
||||
<span>{widgetTypeTranslation}</span>
|
||||
</div>
|
||||
);
|
||||
case "date":
|
||||
@@ -748,8 +748,8 @@ function PlaceholderType(props) {
|
||||
className="font-medium text-center"
|
||||
>
|
||||
{props.isNeedSign
|
||||
? props.pos?.options?.hint || widgetTypeTraslation
|
||||
: widgetTypeTraslation}
|
||||
? props.pos?.options?.hint || widgetTypeTranslation
|
||||
: widgetTypeTranslation}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -760,7 +760,7 @@ function PlaceholderType(props) {
|
||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||
<textarea
|
||||
ref={inputRef}
|
||||
placeholder={hint}
|
||||
placeholder={hint || widgetTypeTranslation}
|
||||
rows={1}
|
||||
onKeyDown={(e) => {
|
||||
// Prevent new line on Enter key press
|
||||
@@ -792,7 +792,7 @@ function PlaceholderType(props) {
|
||||
/>
|
||||
) : (
|
||||
<div style={textWidgetStyle} className="select-none-cls">
|
||||
<span>{widgetTypeTraslation}</span>
|
||||
<span>{widgetTypeTranslation}</span>
|
||||
</div>
|
||||
);
|
||||
case radioButtonWidget:
|
||||
@@ -891,8 +891,8 @@ function PlaceholderType(props) {
|
||||
className="font-medium"
|
||||
>
|
||||
{props.isNeedSign
|
||||
? props.pos?.options?.hint || widgetTypeTraslation
|
||||
: widgetTypeTraslation}
|
||||
? props.pos?.options?.hint || widgetTypeTranslation
|
||||
: widgetTypeTranslation}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -117,7 +117,6 @@ const WidgetNameModal = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const handleCheckboxChange = (index) => {
|
||||
// Update the state with the modified array
|
||||
setSignatureType((prev) =>
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
const DateFormatSelector = (props) => {
|
||||
const [selectedFormat, setSelectedFormat] = useState(props.dateFormat);
|
||||
|
||||
const defaultDate = new Date();
|
||||
const numDate = { year: "numeric", month: "2-digit", day: "2-digit" };
|
||||
const shortMonthDate = { year: "numeric", month: "short", day: "2-digit" };
|
||||
const longMonthDate = { year: "numeric", month: "long", day: "2-digit" };
|
||||
const dateFormats = {
|
||||
"MM/DD/YYYY": (date) =>
|
||||
new Intl.DateTimeFormat("en-US", numDate).format(date),
|
||||
"MMMM DD, YYYY": (date) =>
|
||||
new Intl.DateTimeFormat("en-US", longMonthDate).format(date),
|
||||
"DD MMMM, YYYY": (date) =>
|
||||
new Intl.DateTimeFormat("en-GB", longMonthDate).format(date),
|
||||
"DD-MM-YYYY": (date) =>
|
||||
new Intl.DateTimeFormat("fr-FR", numDate)
|
||||
.format(date)
|
||||
.replace(/\//g, "-"),
|
||||
"DD MMM, YYYY": (date) =>
|
||||
new Intl.DateTimeFormat("en-GB", shortMonthDate).format(date),
|
||||
"YYYY-MM-DD": (date) =>
|
||||
new Intl.DateTimeFormat("sv-SE", numDate).format(date),
|
||||
"MM-DD-YYYY": (date) =>
|
||||
new Intl.DateTimeFormat("en-US", numDate)
|
||||
.format(date)
|
||||
.replace(/\//g, "-"),
|
||||
"MM.DD.YYYY": (date) =>
|
||||
new Intl.DateTimeFormat("de-DE", numDate)
|
||||
.format(date)
|
||||
.replace(/^(\d{2})\.(\d{2})\.(\d{4})$/, "$2.$1.$3"), // Swap day and month to MM.DD.YYYY
|
||||
"MMM DD, YYYY": (date) =>
|
||||
new Intl.DateTimeFormat("en-US", shortMonthDate).format(date)
|
||||
};
|
||||
|
||||
// Handle format change
|
||||
const handleFormatChange = (event) => {
|
||||
setSelectedFormat(event.target.value);
|
||||
props.setDateFormat && props.setDateFormat(event.target.value);
|
||||
};
|
||||
return (
|
||||
<div className="max-w-[400px] pr-[20px]">
|
||||
<label className="text-[14px] mb-[0.7rem] font-medium">
|
||||
Select default date format for date widget
|
||||
</label>
|
||||
<select
|
||||
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full h-full text-[11px]"
|
||||
value={selectedFormat}
|
||||
onChange={handleFormatChange}
|
||||
>
|
||||
{Object.keys(dateFormats).map((format) => (
|
||||
<option key={format} value={format}>
|
||||
{format}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<p className="mt-[12px] ml-[10px] text-[13px] font-medium">
|
||||
<strong>
|
||||
Formatted Date:{" "}
|
||||
{selectedFormat && dateFormats?.[selectedFormat]?.(defaultDate)}
|
||||
</strong>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DateFormatSelector;
|
||||
+111
-118
@@ -7,9 +7,7 @@ import { appInfo } from "./appinfo";
|
||||
import { saveAs } from "file-saver";
|
||||
import printModule from "print-js";
|
||||
import fontkit from "@pdf-lib/fontkit";
|
||||
import {
|
||||
themeColor
|
||||
} from "./const";
|
||||
import { themeColor } from "./const";
|
||||
|
||||
export const fontsizeArr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28];
|
||||
export const fontColorArr = ["red", "black", "blue", "yellow"];
|
||||
@@ -136,14 +134,12 @@ export const pdfNewWidthFun = (divRef) => {
|
||||
};
|
||||
|
||||
//`contractUsers` function is used to get contract_User details
|
||||
export const contractUsers = async (
|
||||
) => {
|
||||
export const contractUsers = async () => {
|
||||
try {
|
||||
const url = `${localStorage.getItem("baseUrl")}functions/getUserDetails`;
|
||||
const parseAppId = localStorage.getItem("parseAppId");
|
||||
const accesstoken = localStorage.getItem("accesstoken");
|
||||
const token =
|
||||
{ "X-Parse-Session-Token": accesstoken };
|
||||
const token = { "X-Parse-Session-Token": accesstoken };
|
||||
const headers = {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -236,17 +232,47 @@ export const widgets = [
|
||||
{ type: "email", icon: "fa-light fa-envelope", iconSize: "20px" }
|
||||
];
|
||||
|
||||
export const getDate = () => {
|
||||
export const getDate = (dateformat) => {
|
||||
const format = dateformat || "MM/DD/YYYY";
|
||||
const date = new Date();
|
||||
const milliseconds = date.getTime();
|
||||
const newDate = moment(milliseconds).format("MM/DD/YYYY");
|
||||
const newDate = moment(milliseconds).format(format);
|
||||
return newDate;
|
||||
};
|
||||
export const addWidgetOptions = (type) => {
|
||||
const defaultOpt = {
|
||||
name: type,
|
||||
status: "required"
|
||||
};
|
||||
|
||||
export const selectFormat = (data) => {
|
||||
switch (data) {
|
||||
case "L":
|
||||
return "MM/dd/yyyy";
|
||||
case "MM/DD/YYYY":
|
||||
return "MM/dd/yyyy";
|
||||
case "DD-MM-YYYY":
|
||||
return "dd-MM-yyyy";
|
||||
case "DD/MM/YYYY":
|
||||
return "dd/MM/yyyy";
|
||||
case "LL":
|
||||
return "MMMM dd, yyyy";
|
||||
case "DD MMM, YYYY":
|
||||
return "dd MMM, yyyy";
|
||||
case "YYYY-MM-DD":
|
||||
return "yyyy-MM-dd";
|
||||
case "MM-DD-YYYY":
|
||||
return "MM-dd-yyyy";
|
||||
case "MM.DD.YYYY":
|
||||
return "MM.dd.yyyy";
|
||||
case "MMM DD, YYYY":
|
||||
return "MMM dd, yyyy";
|
||||
case "MMMM DD, YYYY":
|
||||
return "MMMM dd, yyyy";
|
||||
case "DD MMMM, YYYY":
|
||||
return "dd MMMM, yyyy";
|
||||
default:
|
||||
return "MM/dd/yyyy";
|
||||
}
|
||||
};
|
||||
|
||||
export const addWidgetOptions = (type, signer) => {
|
||||
const defaultOpt = { name: type, status: "required" };
|
||||
switch (type) {
|
||||
case "signature":
|
||||
return defaultOpt;
|
||||
@@ -267,12 +293,16 @@ export const addWidgetOptions = (type) => {
|
||||
return { ...defaultOpt };
|
||||
case "job title":
|
||||
return { ...defaultOpt };
|
||||
case "date":
|
||||
case "date": {
|
||||
const dateFormat = signer?.DateFormat
|
||||
? selectFormat(signer?.DateFormat)
|
||||
: "MM/dd/yyyy";
|
||||
return {
|
||||
...defaultOpt,
|
||||
response: getDate(),
|
||||
validation: { format: "MM/dd/yyyy", type: "date-format" }
|
||||
response: getDate(signer?.DateFormat),
|
||||
validation: { format: dateFormat, type: "date-format" }
|
||||
};
|
||||
}
|
||||
case "image":
|
||||
return defaultOpt;
|
||||
case "email":
|
||||
@@ -293,7 +323,7 @@ export const addWidgetOptions = (type) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const addWidgetSelfsignOptions = (type, getWidgetValue) => {
|
||||
export const addWidgetSelfsignOptions = (type, getWidgetValue, owner) => {
|
||||
switch (type) {
|
||||
case "signature":
|
||||
return { name: "signature" };
|
||||
@@ -323,12 +353,16 @@ export const addWidgetSelfsignOptions = (type, getWidgetValue) => {
|
||||
defaultValue: getWidgetValue(type),
|
||||
validation: { type: "text", pattern: "" }
|
||||
};
|
||||
case "date":
|
||||
case "date": {
|
||||
const dateFormat = owner?.DateFormat
|
||||
? selectFormat(owner?.DateFormat)
|
||||
: "MM/dd/yyyy";
|
||||
return {
|
||||
name: "date",
|
||||
response: getDate(),
|
||||
validation: { format: "MM/dd/yyyy", type: "date-format" }
|
||||
response: getDate(owner?.DateFormat),
|
||||
validation: { format: dateFormat, type: "date-format" }
|
||||
};
|
||||
}
|
||||
case "image":
|
||||
return { name: "image" };
|
||||
case "email":
|
||||
@@ -495,7 +529,7 @@ export const signPdfFun = async (
|
||||
documentId,
|
||||
signerObjectId,
|
||||
objectId,
|
||||
widgets,
|
||||
widgets
|
||||
) => {
|
||||
let isCustomCompletionMail = false;
|
||||
try {
|
||||
@@ -504,10 +538,7 @@ export const signPdfFun = async (
|
||||
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||
return { status: "error", message: "User does not exist." };
|
||||
} else {
|
||||
if (
|
||||
tenantDetails?.CompletionBody &&
|
||||
tenantDetails?.CompletionSubject
|
||||
) {
|
||||
if (tenantDetails?.CompletionBody && tenantDetails?.CompletionSubject) {
|
||||
isCustomCompletionMail = true;
|
||||
}
|
||||
}
|
||||
@@ -939,10 +970,7 @@ export const calculateInitialWidthHeight = (widgetData) => {
|
||||
const height = span.offsetHeight;
|
||||
|
||||
document.body.removeChild(span);
|
||||
return {
|
||||
getWidth: width,
|
||||
getHeight: height
|
||||
};
|
||||
return { getWidth: width, getHeight: height };
|
||||
};
|
||||
export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
||||
function widgetDataValue(type) {
|
||||
@@ -973,9 +1001,7 @@ export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
||||
)
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
...item
|
||||
};
|
||||
return item;
|
||||
}
|
||||
} else if (item.pos && item.pos.length > 0) {
|
||||
// If there is no nested array, add the new field
|
||||
@@ -993,17 +1019,9 @@ export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
||||
...item.options,
|
||||
defaultValue: item?.options?.defaultValue || widgetData
|
||||
}
|
||||
// Width:
|
||||
// calculateInitialWidthHeight(item.type, widgetData).getWidth ||
|
||||
// item?.Width,
|
||||
// Height:
|
||||
// calculateInitialWidthHeight(item.type, widgetData).getHeight ||
|
||||
// item?.Height
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
...item
|
||||
};
|
||||
return item;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1011,8 +1029,7 @@ export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
||||
|
||||
//function for embed document id
|
||||
export const embedDocId = async (pdfDoc, documentId, allPages) => {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
// `fontBytes` is used to embed custom font in pdf
|
||||
const fontBytes = await fileasbytes(
|
||||
"https://cdn.opensignlabs.com/webfonts/times.ttf"
|
||||
@@ -1874,12 +1891,9 @@ export const contactBook = async (objectId) => {
|
||||
};
|
||||
|
||||
//function for getting document details from contract_Documents class
|
||||
export const contractDocument = async (
|
||||
documentId,
|
||||
) => {
|
||||
export const contractDocument = async (documentId) => {
|
||||
const data = { docId: documentId };
|
||||
const token =
|
||||
{ sessionToken: localStorage.getItem("accesstoken") };
|
||||
const token = { sessionToken: localStorage.getItem("accesstoken") };
|
||||
const documentDeatils = await axios
|
||||
.post(`${localStorage.getItem("baseUrl")}functions/getDocument`, data, {
|
||||
headers: {
|
||||
@@ -2063,36 +2077,31 @@ export const getFileName = (fileUrl) => {
|
||||
|
||||
//fetch tenant app logo from `partners_Tenant` class by domain name
|
||||
export const getAppLogo = async () => {
|
||||
const domain = window.location.host;
|
||||
try {
|
||||
const tenant = await Parse.Cloud.run("getlogobydomain", {
|
||||
domain: domain
|
||||
});
|
||||
if (tenant) {
|
||||
localStorage.setItem("appname", "OpenSign™");
|
||||
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" };
|
||||
}
|
||||
const domain = window.location.host;
|
||||
try {
|
||||
const tenant = await Parse.Cloud.run("getlogobydomain", {
|
||||
domain: domain
|
||||
});
|
||||
if (tenant) {
|
||||
localStorage.setItem("appname", "OpenSign™");
|
||||
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" };
|
||||
}
|
||||
}
|
||||
};
|
||||
export const getTenantDetails = async (
|
||||
objectId,
|
||||
contactId
|
||||
) => {
|
||||
export const getTenantDetails = async (objectId, contactId) => {
|
||||
try {
|
||||
const url = `${localStorage.getItem("baseUrl")}functions/gettenant`;
|
||||
const parseAppId = localStorage.getItem("parseAppId");
|
||||
const accesstoken = localStorage.getItem("accesstoken");
|
||||
const token =
|
||||
{ "X-Parse-Session-Token": accesstoken };
|
||||
const data =
|
||||
{ userId: objectId, contactId: contactId };
|
||||
const token = { "X-Parse-Session-Token": accesstoken };
|
||||
const data = { userId: objectId, contactId: contactId };
|
||||
const res = await axios.post(url, data, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -2179,26 +2188,21 @@ export const handleSendOTP = async (email) => {
|
||||
}
|
||||
};
|
||||
export const fetchUrl = async (url, pdfName) => {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
alert("something went wrong, please try again later.");
|
||||
alert("something went wrong, refreshing this page may solve this issue.");
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
const blob = await response.blob();
|
||||
saveAs(blob, `${sanitizeFileName(pdfName)}_signed_by_${appName}.pdf`);
|
||||
} catch (error) {
|
||||
alert("something went wrong, please try again later.");
|
||||
alert("something went wrong, refreshing this page may solve this issue.");
|
||||
console.error("Error downloading the file:", error);
|
||||
}
|
||||
};
|
||||
export const getSignedUrl = async (
|
||||
pdfUrl,
|
||||
docId,
|
||||
templateId
|
||||
) => {
|
||||
export const getSignedUrl = async (pdfUrl, docId, templateId) => {
|
||||
//use only axios here due to public template sign
|
||||
const axiosRes = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
||||
@@ -2259,16 +2263,13 @@ export const handleDownloadPdf = async (
|
||||
setIsDownloading && setIsDownloading("pdf");
|
||||
const docId = pdfDetails?.[0]?.objectId || "";
|
||||
try {
|
||||
const url = await getSignedUrl(
|
||||
pdfUrl,
|
||||
docId,
|
||||
);
|
||||
const url = await getSignedUrl(pdfUrl, docId);
|
||||
await fetchUrl(url, pdfName);
|
||||
setIsDownloading && setIsDownloading("");
|
||||
} catch (err) {
|
||||
console.log("err in getsignedurl", err);
|
||||
setIsDownloading("");
|
||||
alert("something went wrong, please try again later.");
|
||||
alert("something went wrong, refreshing this page may solve this issue.");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2292,7 +2293,7 @@ export const handleToPrint = async (event, setIsDownloading, pdfDetails) => {
|
||||
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
||||
{
|
||||
url: pdfUrl,
|
||||
docId: docId,
|
||||
docId: docId
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
@@ -2326,7 +2327,7 @@ export const handleToPrint = async (event, setIsDownloading, pdfDetails) => {
|
||||
} catch (err) {
|
||||
setIsDownloading("");
|
||||
console.log("err in getsignedurl", err);
|
||||
alert("something went wrong, please try again later.");
|
||||
alert("something went wrong, refreshing this page may solve this issue.");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2336,8 +2337,7 @@ export const handleDownloadCertificate = async (
|
||||
setIsDownloading,
|
||||
isZip
|
||||
) => {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
if (pdfDetails?.length > 0 && pdfDetails[0]?.CertificateUrl) {
|
||||
try {
|
||||
await fetch(pdfDetails[0] && pdfDetails[0]?.CertificateUrl);
|
||||
@@ -2413,7 +2413,7 @@ export const handleDownloadCertificate = async (
|
||||
} catch (err) {
|
||||
setIsDownloading("certificate_err");
|
||||
console.log("err in download in certificate", err);
|
||||
alert("something went wrong, please try again later.");
|
||||
alert("something went wrong, refreshing this page may solve this issue.");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2421,14 +2421,13 @@ export const handleDownloadCertificate = async (
|
||||
export function escapeRegExp(string) {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // Escape special characters
|
||||
}
|
||||
export async function findContact(
|
||||
value,
|
||||
) {
|
||||
export async function findContact(value) {
|
||||
try {
|
||||
const baseURL = localStorage.getItem("baseUrl");
|
||||
const url = `${baseURL}functions/getsigners`;
|
||||
const token =
|
||||
{ "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
|
||||
const token = {
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
};
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
@@ -2640,23 +2639,20 @@ export function base64ToArrayBuffer(base64) {
|
||||
return bytes.buffer;
|
||||
}
|
||||
|
||||
export const convertBase64ToFile = async (
|
||||
pdfName,
|
||||
pdfBase64,
|
||||
) => {
|
||||
export const convertBase64ToFile = async (pdfName, pdfBase64) => {
|
||||
const fileName = sanitizeFileName(pdfName) + ".pdf";
|
||||
try {
|
||||
const pdfFile = new Parse.File(fileName, { base64: pdfBase64 });
|
||||
// Save the Parse File if needed
|
||||
const pdfData = await pdfFile.save();
|
||||
const pdfUrl = pdfData.url();
|
||||
const fileRes = await getSecureUrl(pdfUrl);
|
||||
if (fileRes?.url) {
|
||||
return fileRes.url;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("error in convertbase64tofile", e);
|
||||
try {
|
||||
const pdfFile = new Parse.File(fileName, { base64: pdfBase64 });
|
||||
// Save the Parse File if needed
|
||||
const pdfData = await pdfFile.save();
|
||||
const pdfUrl = pdfData.url();
|
||||
const fileRes = await getSecureUrl(pdfUrl);
|
||||
if (fileRes?.url) {
|
||||
return fileRes.url;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("error in convertbase64tofile", e);
|
||||
}
|
||||
};
|
||||
export const onClickZoomIn = (scale, zoomPercent, setScale, setZoomPercent) => {
|
||||
setScale(scale + 0.1 * scale);
|
||||
@@ -2955,13 +2951,10 @@ export const flattenPdf = async (pdfFile) => {
|
||||
};
|
||||
|
||||
export const mailTemplate = (param) => {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const logo =
|
||||
`<div style='padding:10px'><img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' /></div>`;
|
||||
const appName = "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 body =
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import logo from "../assets/images/logo.png";
|
||||
|
||||
export function serverUrl_fn() {
|
||||
let baseUrl;
|
||||
baseUrl = process.env.REACT_APP_SERVERURL
|
||||
? process.env.REACT_APP_SERVERURL
|
||||
: window.location.origin + "/app";
|
||||
|
||||
let baseUrl = process.env.REACT_APP_SERVERURL
|
||||
? process.env.REACT_APP_SERVERURL
|
||||
: window.location.origin + "/api/app";
|
||||
return baseUrl;
|
||||
}
|
||||
export const appInfo = {
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
Preview
|
||||
} from "react-dnd-multi-backend";
|
||||
import DragElement from "./components/pdf/DragElement";
|
||||
import TagManager from "react-gtm-module";
|
||||
import Parse from "parse";
|
||||
import "./polyfills";
|
||||
import { serverUrl_fn } from "./constant/appinfo";
|
||||
@@ -56,13 +55,6 @@ const generatePreview = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
if (process.env.REACT_APP_GTM) {
|
||||
const tagManagerArgs = {
|
||||
gtmId: process.env.REACT_APP_GTM
|
||||
};
|
||||
TagManager.initialize(tagManagerArgs);
|
||||
}
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById("root"));
|
||||
root.render(
|
||||
<CookiesProvider defaultSetOptions={{ path: "/" }}>
|
||||
|
||||
+186
-213
@@ -36,8 +36,7 @@ function Form() {
|
||||
}
|
||||
|
||||
const Forms = (props) => {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const { t } = useTranslation();
|
||||
const maxFileSize = 20;
|
||||
const abortController = new AbortController();
|
||||
@@ -101,12 +100,12 @@ const Forms = (props) => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
const initializeValues = async () => {
|
||||
setFormData((obj) => ({
|
||||
...obj,
|
||||
NotifyOnSignatures: true,
|
||||
SendinOrder: sendinorder,
|
||||
IsTourEnabled: istourenabled
|
||||
}));
|
||||
setFormData((obj) => ({
|
||||
...obj,
|
||||
NotifyOnSignatures: true,
|
||||
SendinOrder: sendinorder,
|
||||
IsTourEnabled: istourenabled
|
||||
}));
|
||||
};
|
||||
|
||||
function getFileAsArrayBuffer(file) {
|
||||
@@ -144,17 +143,81 @@ const Forms = (props) => {
|
||||
const name = generatePdfName(16);
|
||||
const pdfName = `${name?.split(".")[0]}.pdf`;
|
||||
setfileload(true);
|
||||
try {
|
||||
const res = await getFileAsArrayBuffer(files[0]);
|
||||
const flatPdf = await flattenPdf(res);
|
||||
const parseFile = new Parse.File(
|
||||
pdfName,
|
||||
[...flatPdf],
|
||||
"application/pdf"
|
||||
);
|
||||
try {
|
||||
const res = await getFileAsArrayBuffer(files[0]);
|
||||
const flatPdf = await flattenPdf(res);
|
||||
const parseFile = new Parse.File(
|
||||
pdfName,
|
||||
[...flatPdf],
|
||||
"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
|
||||
// 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 {
|
||||
const response = await parseFile.save({
|
||||
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(
|
||||
@@ -164,16 +227,16 @@ const Forms = (props) => {
|
||||
}
|
||||
}
|
||||
});
|
||||
// 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());
|
||||
|
||||
// Retrieve the URL of the uploaded file
|
||||
if (parseFile.url()) {
|
||||
const fileRes = await getSecureUrl(parseFile.url());
|
||||
if (fileRes.url) {
|
||||
setFileUpload(fileRes.url);
|
||||
setfileload(false);
|
||||
const tenantId = localStorage.getItem("TenantId");
|
||||
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 {
|
||||
@@ -182,95 +245,22 @@ const Forms = (props) => {
|
||||
} else {
|
||||
removeFile(e);
|
||||
}
|
||||
} catch (error) {
|
||||
removeFile(e);
|
||||
console.error("Error uploading file:", error);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err?.message?.includes("is encrypted")) {
|
||||
try {
|
||||
await Parse.Cloud.run("encryptedpdf", {
|
||||
email: Parse.User.current().getEmail()
|
||||
});
|
||||
} catch (err) {
|
||||
console.log("err in sending posthog encryptedpdf", err);
|
||||
}
|
||||
try {
|
||||
setIsDecrypting(true);
|
||||
const size = files?.[0].size;
|
||||
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"
|
||||
});
|
||||
} catch (err) {
|
||||
removeFile();
|
||||
if (err?.response?.status === 401) {
|
||||
setIsPassword(true);
|
||||
} else {
|
||||
console.log("Error uploading file: ", err?.response);
|
||||
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 = "";
|
||||
}
|
||||
e.target.value = "";
|
||||
}
|
||||
} else {
|
||||
console.log("err ", err);
|
||||
setFileUpload("");
|
||||
removeFile(e);
|
||||
}
|
||||
} else {
|
||||
console.log("err ", err);
|
||||
setFileUpload("");
|
||||
removeFile(e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const isImage = files?.[0]?.type.includes("image/");
|
||||
if (isImage) {
|
||||
@@ -295,50 +285,50 @@ const Forms = (props) => {
|
||||
});
|
||||
const size = files?.[0]?.size;
|
||||
const name = generatePdfName(16);
|
||||
const getFile = await pdfDoc.save({
|
||||
useObjectStreams: false
|
||||
});
|
||||
setfileload(true);
|
||||
const pdfName = `${name?.split(".")[0]}.pdf`;
|
||||
const parseFile = new Parse.File(
|
||||
pdfName,
|
||||
[...getFile],
|
||||
"application/pdf"
|
||||
);
|
||||
const getFile = await pdfDoc.save({
|
||||
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
|
||||
// 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);
|
||||
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
|
||||
// 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);
|
||||
}
|
||||
} catch (error) {
|
||||
} else {
|
||||
removeFile(e);
|
||||
console.error("Error uploading file:", error);
|
||||
}
|
||||
} catch (error) {
|
||||
removeFile(e);
|
||||
console.error("Error uploading file:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -401,11 +391,11 @@ const Forms = (props) => {
|
||||
object.set("RemindOnceInEvery", remindOnceInEvery);
|
||||
object.set("IsTourEnabled", isTourEnabled);
|
||||
object.set("TimeToCompleteDays", TimeToCompleteDays);
|
||||
object.set("AllowModifications", false);
|
||||
object.set("IsEnableOTP", false);
|
||||
if (formData.NotifyOnSignatures !== undefined) {
|
||||
object.set("NotifyOnSignatures", formData.NotifyOnSignatures);
|
||||
}
|
||||
object.set("AllowModifications", false);
|
||||
object.set("IsEnableOTP", false);
|
||||
if (formData.NotifyOnSignatures !== undefined) {
|
||||
object.set("NotifyOnSignatures", formData.NotifyOnSignatures);
|
||||
}
|
||||
if (formData?.RedirectUrl) {
|
||||
object.set("RedirectUrl", formData.RedirectUrl);
|
||||
}
|
||||
@@ -444,10 +434,9 @@ const Forms = (props) => {
|
||||
setSigners([]);
|
||||
setBcc([]);
|
||||
setFolder({ ObjectId: "", Name: "" });
|
||||
const notifySign =
|
||||
extUserData?.NotifyOnSignatures
|
||||
? extUserData?.NotifyOnSignatures
|
||||
: true;
|
||||
const notifySign = extUserData?.NotifyOnSignatures
|
||||
? extUserData?.NotifyOnSignatures
|
||||
: true;
|
||||
setFormData({
|
||||
Name: "",
|
||||
Description: "",
|
||||
@@ -523,10 +512,9 @@ const Forms = (props) => {
|
||||
setSigners([]);
|
||||
setBcc([]);
|
||||
setFolder({ ObjectId: "", Name: "" });
|
||||
const notifySign =
|
||||
extUserData?.NotifyOnSignatures
|
||||
? extUserData?.NotifyOnSignatures
|
||||
: true;
|
||||
const notifySign = extUserData?.NotifyOnSignatures
|
||||
? extUserData?.NotifyOnSignatures
|
||||
: true;
|
||||
let obj = {
|
||||
Name: "",
|
||||
Description: "",
|
||||
@@ -580,36 +568,28 @@ const Forms = (props) => {
|
||||
type: "application/pdf"
|
||||
});
|
||||
setIsDecrypting(false);
|
||||
const res = await getFileAsArrayBuffer(pdfFile);
|
||||
const flatPdf = await flattenPdf(res);
|
||||
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(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
|
||||
}
|
||||
const res = await getFileAsArrayBuffer(pdfFile);
|
||||
const flatPdf = await flattenPdf(res);
|
||||
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(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: "" }));
|
||||
@@ -618,6 +598,14 @@ const Forms = (props) => {
|
||||
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) {
|
||||
removeFile();
|
||||
if (err?.response?.status === 401) {
|
||||
@@ -739,9 +727,7 @@ const Forms = (props) => {
|
||||
)}
|
||||
<div className="text-xs">
|
||||
<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>
|
||||
</label>
|
||||
{fileupload.length > 0 ? (
|
||||
@@ -765,9 +751,7 @@ 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"
|
||||
onChange={(e) => handleFileInput(e)}
|
||||
ref={inputFileRef}
|
||||
accept={
|
||||
"application/pdf,image/png,image/jpeg"
|
||||
}
|
||||
accept={"application/pdf,image/png,image/jpeg"}
|
||||
onInvalid={(e) =>
|
||||
e.target.setCustomValidity(t("input-required"))
|
||||
}
|
||||
@@ -868,7 +852,7 @@ const Forms = (props) => {
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">{t("send-in-order")}</p>
|
||||
<p>{t("send-in-order-help.p1")}</p>
|
||||
<p className="p-[5px]">
|
||||
<div className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
@@ -883,7 +867,7 @@ const Forms = (props) => {
|
||||
<span>{t("send-in-order-help.p3")}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
<p>{t("send-in-order-help.p4")}</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
@@ -965,7 +949,7 @@ const Forms = (props) => {
|
||||
{t("send-in-order")}
|
||||
</p>
|
||||
<p>{t("send-in-order-help.p1")}</p>
|
||||
<p className="p-[5px]">
|
||||
<div className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
@@ -984,7 +968,7 @@ const Forms = (props) => {
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
<p>{t("send-in-order-help.p4")}</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
@@ -1057,10 +1041,7 @@ const Forms = (props) => {
|
||||
{isAdvanceOpt && (
|
||||
<div
|
||||
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"
|
||||
></div>
|
||||
@@ -1105,7 +1086,7 @@ const Forms = (props) => {
|
||||
<Tooltip id="istourenabled-tooltip" className="z-[999]">
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">{t("enable-tour")}</p>
|
||||
<p className="p-[5px]">
|
||||
<div className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
@@ -1118,7 +1099,7 @@ const Forms = (props) => {
|
||||
<span>{t("istourenabled-help.p2")}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
{t("istourenabled-help.p3", { appName: appName })}
|
||||
</p>
|
||||
@@ -1169,11 +1150,7 @@ const Forms = (props) => {
|
||||
</Tooltip>
|
||||
</label>
|
||||
<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
|
||||
className="mr-[2px] op-radio op-radio-xs"
|
||||
type="radio"
|
||||
@@ -1182,11 +1159,7 @@ const Forms = (props) => {
|
||||
/>
|
||||
<div className="text-center">{t("yes")}</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
|
||||
className="mr-[2px] op-radio op-radio-xs"
|
||||
type="radio"
|
||||
|
||||
@@ -7,9 +7,7 @@ import { NavLink, useNavigate, useLocation } from "react-router";
|
||||
import login_img from "../assets/images/login_img.svg";
|
||||
import { useWindowSize } from "../hook/useWindowSize";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import {
|
||||
emailRegex,
|
||||
} from "../constant/const";
|
||||
import { emailRegex } from "../constant/const";
|
||||
import Alert from "../primitives/Alert";
|
||||
import { appInfo } from "../constant/appinfo";
|
||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||
@@ -24,8 +22,7 @@ import { useTranslation } from "react-i18next";
|
||||
import SelectLanguage from "../components/pdf/SelectLanguage";
|
||||
|
||||
function Login() {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const { t, i18n } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
@@ -43,7 +40,7 @@ function Login() {
|
||||
baseUrl: localStorage.getItem("baseUrl"),
|
||||
parseAppId: localStorage.getItem("parseAppId"),
|
||||
loading: false,
|
||||
thirdpartyLoader: false,
|
||||
thirdpartyLoader: false
|
||||
});
|
||||
const [userDetails, setUserDetails] = useState({
|
||||
Company: "",
|
||||
@@ -61,9 +58,7 @@ function Login() {
|
||||
const app = await getAppLogo();
|
||||
if (app?.error === "invalid_json") {
|
||||
setErrMsg(t("server-down", { appName: appName }));
|
||||
} else if (
|
||||
app?.user === "not_exist"
|
||||
) {
|
||||
} else if (app?.user === "not_exist") {
|
||||
navigate("/addadmin");
|
||||
}
|
||||
if (app?.logo) {
|
||||
@@ -153,9 +148,9 @@ function Login() {
|
||||
localStorage.setItem("PageLanding", menu.pageId);
|
||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||
localStorage.setItem("pageType", menu.pageType);
|
||||
setState({ ...state, loading: false });
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
setState({ ...state, loading: false });
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
setState({ ...state, loading: false });
|
||||
setIsModal(true);
|
||||
@@ -171,14 +166,14 @@ function Login() {
|
||||
logOutUser();
|
||||
}
|
||||
} else {
|
||||
setState({ ...state, loading: false });
|
||||
setState({
|
||||
...state,
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: "User not found."
|
||||
});
|
||||
logOutUser();
|
||||
setState({ ...state, loading: false });
|
||||
setState({
|
||||
...state,
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: "User not found."
|
||||
});
|
||||
logOutUser();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -186,7 +181,7 @@ function Login() {
|
||||
...state,
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: `Something went wrong.`
|
||||
alertMsg: t("something-went-wrong-mssg")
|
||||
});
|
||||
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
|
||||
console.error("Error while fetching Follow", error);
|
||||
@@ -282,7 +277,7 @@ function Login() {
|
||||
localStorage.setItem("PageLanding", menu.pageId);
|
||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||
localStorage.setItem("pageType", menu.pageType);
|
||||
navigate(redirectUrl);
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
setState({
|
||||
...state,
|
||||
@@ -380,8 +375,8 @@ function Login() {
|
||||
localStorage.setItem("PageLanding", menu.pageId);
|
||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||
localStorage.setItem("pageType", menu.pageType);
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
setState({ ...state, loading: false });
|
||||
logOutUser();
|
||||
@@ -408,7 +403,7 @@ function Login() {
|
||||
setState({
|
||||
...state,
|
||||
alertType: "danger",
|
||||
alertMsg: "Something went wrong, please try again later."
|
||||
alertMsg: t("something-went-wrong-mssg")
|
||||
});
|
||||
console.log("err", error);
|
||||
} finally {
|
||||
@@ -501,7 +496,6 @@ function Login() {
|
||||
localStorage.setItem("parseAppId", appid);
|
||||
};
|
||||
|
||||
|
||||
return errMsg ? (
|
||||
<div className="h-screen flex justify-center text-center items-center p-4 text-gray-500 text-base">
|
||||
{errMsg}
|
||||
@@ -561,39 +555,35 @@ function Login() {
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
/>
|
||||
<hr className="my-1 border-none" />
|
||||
<label className="block text-xs" htmlFor="password">
|
||||
{t("password")}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
id="password"
|
||||
type={
|
||||
state.passwordVisible ? "text" : "password"
|
||||
}
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
name="password"
|
||||
value={state.password}
|
||||
autoComplete="current-password"
|
||||
onChange={handleChange}
|
||||
onInvalid={(e) =>
|
||||
e.target.setCustomValidity(
|
||||
t("input-required")
|
||||
)
|
||||
}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
required
|
||||
/>
|
||||
<span
|
||||
className="absolute cursor-pointer top-[50%] right-[10px] -translate-y-[50%] text-base-content"
|
||||
onClick={togglePasswordVisibility}
|
||||
>
|
||||
{state.passwordVisible ? (
|
||||
<i className="fa-light fa-eye-slash text-xs pb-1" /> // Close eye icon
|
||||
) : (
|
||||
<i className="fa-light fa-eye text-xs pb-1 " /> // Open eye icon
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<label className="block text-xs" htmlFor="password">
|
||||
{t("password")}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
id="password"
|
||||
type={state.passwordVisible ? "text" : "password"}
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
name="password"
|
||||
value={state.password}
|
||||
autoComplete="current-password"
|
||||
onChange={handleChange}
|
||||
onInvalid={(e) =>
|
||||
e.target.setCustomValidity(t("input-required"))
|
||||
}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
required
|
||||
/>
|
||||
<span
|
||||
className="absolute cursor-pointer top-[50%] right-[10px] -translate-y-[50%] text-base-content"
|
||||
onClick={togglePasswordVisibility}
|
||||
>
|
||||
{state.passwordVisible ? (
|
||||
<i className="fa-light fa-eye-slash text-xs pb-1" /> // Close eye icon
|
||||
) : (
|
||||
<i className="fa-light fa-eye text-xs pb-1 " /> // Open eye icon
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="relative mt-1">
|
||||
<NavLink
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import "../styles/opensigndrive.css";
|
||||
import {
|
||||
iconColor,
|
||||
} from "../constant/const";
|
||||
import {
|
||||
getDrive
|
||||
} from "../constant/Utils";
|
||||
import { iconColor } from "../constant/const";
|
||||
import { getDrive } from "../constant/Utils";
|
||||
import { useNavigate } from "react-router";
|
||||
import Title from "../components/Title";
|
||||
import Parse from "parse";
|
||||
@@ -29,8 +25,7 @@ const AppLoader = () => {
|
||||
);
|
||||
};
|
||||
function Opensigndrive() {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
@@ -130,7 +125,7 @@ function Opensigndrive() {
|
||||
}
|
||||
];
|
||||
const getDetails = async () => {
|
||||
getPdfDocumentList();
|
||||
getPdfDocumentList();
|
||||
};
|
||||
//function for get all pdf document list
|
||||
const getPdfDocumentList = async (disbaleLoading) => {
|
||||
@@ -144,7 +139,7 @@ function Opensigndrive() {
|
||||
try {
|
||||
const driveDetails = await getDrive(docId, skip, limit);
|
||||
if (driveDetails && driveDetails === "Error: Something went wrong!") {
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
} else if (driveDetails && driveDetails.length > 0) {
|
||||
const addMoreTour = [
|
||||
{
|
||||
@@ -635,7 +630,9 @@ function Opensigndrive() {
|
||||
<div className="flex flex-row items-center">
|
||||
<div
|
||||
id="folder-menu"
|
||||
className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} hidden md:block`}
|
||||
className={`${
|
||||
isOptions ? "dropdown show dropDownStyle" : "dropdown"
|
||||
} hidden md:block`}
|
||||
onClick={() => setIsOptions(!isOptions)}
|
||||
>
|
||||
<div className="sort" data-tut="reactourSecond">
|
||||
@@ -773,7 +770,9 @@ function Opensigndrive() {
|
||||
</div>
|
||||
<div
|
||||
id="folder-menu"
|
||||
className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} md:hidden`}
|
||||
className={`${
|
||||
isOptions ? "dropdown show dropDownStyle" : "dropdown"
|
||||
} md:hidden`}
|
||||
onClick={() => setIsOptions(!isOptions)}
|
||||
>
|
||||
<div
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -69,8 +69,7 @@ import AddContact from "../primitives/AddContact";
|
||||
function PlaceHolderSign() {
|
||||
const { t } = useTranslation();
|
||||
const copyUrlRef = useRef(null);
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const editorRef = useRef();
|
||||
const { state } = useLocation();
|
||||
const navigate = useNavigate();
|
||||
@@ -151,7 +150,6 @@ function PlaceHolderSign() {
|
||||
status: false,
|
||||
message: ""
|
||||
});
|
||||
const [extUserId, setExtUserId] = useState("");
|
||||
const [isCustomize, setIsCustomize] = useState(false);
|
||||
const [zoomPercent, setZoomPercent] = useState(0);
|
||||
const [scale, setScale] = useState(1);
|
||||
@@ -165,6 +163,7 @@ function PlaceHolderSign() {
|
||||
const [userList, setUserList] = useState([]);
|
||||
const [isAttchSignerModal, setIsAttchSignerModal] = useState(false);
|
||||
const [isNewContact, setIsNewContact] = useState({ status: false, id: "" });
|
||||
const [owner, setOwner] = useState({});
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const [, drop] = useDrop({
|
||||
accept: "BOX",
|
||||
@@ -287,7 +286,7 @@ function PlaceHolderSign() {
|
||||
setPdfArrayBuffer(arrayBuffer);
|
||||
setPdfBase64Url(base64Pdf);
|
||||
}
|
||||
setExtUserId(documentData[0]?.ExtUserPtr?.objectId);
|
||||
setOwner(documentData?.[0]?.ExtUserPtr);
|
||||
const alreadyPlaceholder = documentData[0]?.SignedUrl;
|
||||
// Check if document is sent for signing
|
||||
if (alreadyPlaceholder) {
|
||||
@@ -526,7 +525,7 @@ function PlaceHolderSign() {
|
||||
scale: containerScale,
|
||||
zIndex: posZIndex,
|
||||
type: dragTypeValue,
|
||||
options: addWidgetOptions(dragTypeValue),
|
||||
options: addWidgetOptions(dragTypeValue, owner),
|
||||
Width: widgetWidth / (containerScale * scale),
|
||||
Height: widgetHeight / (containerScale * scale)
|
||||
};
|
||||
@@ -557,7 +556,7 @@ function PlaceHolderSign() {
|
||||
scale: containerScale,
|
||||
zIndex: posZIndex,
|
||||
type: dragTypeValue,
|
||||
options: addWidgetOptions(dragTypeValue),
|
||||
options: addWidgetOptions(dragTypeValue, owner),
|
||||
Width: widgetWidth / (containerScale * scale),
|
||||
Height: widgetHeight / (containerScale * scale)
|
||||
};
|
||||
@@ -864,11 +863,7 @@ function PlaceHolderSign() {
|
||||
scale
|
||||
);
|
||||
const pdfName = generatePdfName(16);
|
||||
const pdfUrl = await convertBase64ToFile(
|
||||
pdfName,
|
||||
pdfBase64,
|
||||
"",
|
||||
);
|
||||
const pdfUrl = await convertBase64ToFile(pdfName, pdfBase64, "");
|
||||
const tenantId = localStorage.getItem("TenantId");
|
||||
const buffer = atob(pdfBase64);
|
||||
SaveFileSize(buffer.length, pdfUrl, tenantId);
|
||||
@@ -880,11 +875,7 @@ function PlaceHolderSign() {
|
||||
} else if (pdfBase64Url) {
|
||||
try {
|
||||
const pdfName = generatePdfName(16);
|
||||
const pdfUrl = await convertBase64ToFile(
|
||||
pdfName,
|
||||
pdfBase64Url,
|
||||
"",
|
||||
);
|
||||
const pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
||||
return pdfUrl;
|
||||
} catch (err) {
|
||||
console.log("error to convertBase64ToFile in placeholder flow", err);
|
||||
@@ -990,11 +981,7 @@ function PlaceHolderSign() {
|
||||
let pdfUrl;
|
||||
if (isUploadPdf) {
|
||||
const pdfName = generatePdfName(16);
|
||||
pdfUrl = await convertBase64ToFile(
|
||||
pdfName,
|
||||
pdfBase64Url,
|
||||
"",
|
||||
);
|
||||
pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
||||
}
|
||||
try {
|
||||
const docCls = new Parse.Object("contracts_Document");
|
||||
@@ -1153,8 +1140,7 @@ function PlaceHolderSign() {
|
||||
year: "numeric"
|
||||
});
|
||||
|
||||
let senderEmail =
|
||||
pdfDetails?.[0]?.ExtUserPtr?.Email;
|
||||
let senderEmail = pdfDetails?.[0]?.ExtUserPtr?.Email;
|
||||
let senderPhone = pdfDetails?.[0]?.ExtUserPtr?.Phone;
|
||||
let signerMail = signersdata.slice();
|
||||
|
||||
@@ -1180,16 +1166,11 @@ function PlaceHolderSign() {
|
||||
const orgName = 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}`;
|
||||
let replaceVar;
|
||||
|
||||
if (
|
||||
requestBody &&
|
||||
requestSubject &&
|
||||
isCustomize
|
||||
) {
|
||||
if (requestBody && requestSubject && isCustomize) {
|
||||
const replacedRequestBody = requestBody.replace(/"/g, "'");
|
||||
htmlReqBody =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
|
||||
@@ -1213,10 +1194,7 @@ function PlaceHolderSign() {
|
||||
htmlReqBody,
|
||||
variables
|
||||
);
|
||||
} else if (
|
||||
tenantMailTemplate?.body &&
|
||||
tenantMailTemplate?.subject
|
||||
) {
|
||||
} else if (tenantMailTemplate?.body && tenantMailTemplate?.subject) {
|
||||
const mailBody = tenantMailTemplate?.body;
|
||||
const mailSubject = tenantMailTemplate?.subject;
|
||||
const replacedRequestBody = mailBody.replace(/"/g, "'");
|
||||
@@ -1247,14 +1225,13 @@ function PlaceHolderSign() {
|
||||
sigingUrl: signPdf
|
||||
};
|
||||
let params = {
|
||||
extUserId: extUserId,
|
||||
extUserId: owner?.objectId,
|
||||
recipient: signerMail[i].Email,
|
||||
subject: replaceVar?.subject
|
||||
? replaceVar?.subject
|
||||
: mailTemplate(mailparam).subject,
|
||||
replyto: senderEmail,
|
||||
from:
|
||||
senderEmail,
|
||||
from: senderEmail,
|
||||
html: replaceVar?.body
|
||||
? replaceVar?.body
|
||||
: mailTemplate(mailparam).body
|
||||
@@ -1269,20 +1246,13 @@ function PlaceHolderSign() {
|
||||
setMailStatus("success");
|
||||
try {
|
||||
let data;
|
||||
if (
|
||||
requestBody &&
|
||||
requestSubject &&
|
||||
isCustomize
|
||||
) {
|
||||
if (requestBody && requestSubject && isCustomize) {
|
||||
data = {
|
||||
RequestBody: htmlReqBody,
|
||||
RequestSubject: requestSubject,
|
||||
SendMail: true
|
||||
};
|
||||
} else if (
|
||||
tenantMailTemplate?.body &&
|
||||
tenantMailTemplate?.subject
|
||||
) {
|
||||
} else if (tenantMailTemplate?.body && tenantMailTemplate?.subject) {
|
||||
data = {
|
||||
RequestBody: tenantMailTemplate?.body,
|
||||
RequestSubject: tenantMailTemplate?.subject,
|
||||
@@ -1320,8 +1290,7 @@ function PlaceHolderSign() {
|
||||
setIsSend(true);
|
||||
setIsMailSend(true);
|
||||
setIsUiLoading(false);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
setMailStatus("failed");
|
||||
setIsSend(true);
|
||||
setIsMailSend(true);
|
||||
@@ -1562,8 +1531,7 @@ function PlaceHolderSign() {
|
||||
status: defaultdata?.status || "required",
|
||||
hint: defaultdata?.hint || "",
|
||||
defaultValue: defaultdata?.defaultValue || "",
|
||||
validation:
|
||||
{},
|
||||
validation: {},
|
||||
fontSize:
|
||||
fontSize || currWidgetsDetails?.options?.fontSize || 12,
|
||||
fontColor:
|
||||
@@ -2038,30 +2006,26 @@ function PlaceHolderSign() {
|
||||
{!isCustomize && (
|
||||
<span>{t("placeholder-alert-3")}</span>
|
||||
)}
|
||||
{
|
||||
isCustomize && (
|
||||
<>
|
||||
<EmailBody
|
||||
editorRef={editorRef}
|
||||
requestBody={requestBody}
|
||||
requestSubject={requestSubject}
|
||||
handleOnchangeRequest={
|
||||
handleOnchangeRequest
|
||||
}
|
||||
setRequestSubject={setRequestSubject}
|
||||
/>
|
||||
<div
|
||||
className="flex justify-end items-center gap-1 mt-2 op-link op-link-primary"
|
||||
onClick={() => {
|
||||
setRequestBody(defaultBody);
|
||||
setRequestSubject(defaultSubject);
|
||||
}}
|
||||
>
|
||||
<span>{t("reset-to-default")}</span>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
{isCustomize && (
|
||||
<>
|
||||
<EmailBody
|
||||
editorRef={editorRef}
|
||||
requestBody={requestBody}
|
||||
requestSubject={requestSubject}
|
||||
handleOnchangeRequest={handleOnchangeRequest}
|
||||
setRequestSubject={setRequestSubject}
|
||||
/>
|
||||
<div
|
||||
className="flex justify-end items-center gap-1 mt-2 op-link op-link-primary"
|
||||
onClick={() => {
|
||||
setRequestBody(defaultBody);
|
||||
setRequestSubject(defaultSubject);
|
||||
}}
|
||||
>
|
||||
<span>{t("reset-to-default")}</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className="flex flex-row items-center gap-2 md:gap-6 mt-2">
|
||||
<div className="flex flex-row gap-2">
|
||||
<button
|
||||
@@ -2079,16 +2043,14 @@ function PlaceHolderSign() {
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{
|
||||
!isCustomize && (
|
||||
<span
|
||||
className="op-link op-link-accent text-sm"
|
||||
onClick={() => setIsCustomize(!isCustomize)}
|
||||
>
|
||||
{t("cutomize-email")}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
{!isCustomize && (
|
||||
<span
|
||||
className="op-link op-link-accent text-sm"
|
||||
onClick={() => setIsCustomize(!isCustomize)}
|
||||
>
|
||||
{t("cutomize-email")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -20,10 +20,10 @@ import EditorToolbar, {
|
||||
module2,
|
||||
formats
|
||||
} from "../components/pdf/EditorToolbar";
|
||||
import DateFormatSelector from "../components/shared/fields/DateFormatSelector";
|
||||
|
||||
const Preferences = () => {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const { t } = useTranslation();
|
||||
const editorRef = useRef();
|
||||
const editorRefCom = useRef();
|
||||
@@ -48,6 +48,7 @@ const Preferences = () => {
|
||||
const [tab, setTab] = useState([generaltab]);
|
||||
const [sendinOrder, setSendinOrder] = useState(true);
|
||||
const [isTourEnabled, setIsTourEnabled] = useState(false);
|
||||
const [dateFormat, setDateFormat] = useState("MM/DD/YYYY");
|
||||
|
||||
useEffect(() => {
|
||||
fetchSignType();
|
||||
@@ -100,10 +101,15 @@ const Preferences = () => {
|
||||
? _getUser?.IsTourEnabled
|
||||
: true;
|
||||
setIsTourEnabled(istourenabled);
|
||||
const DateFormat =
|
||||
_getUser?.DateFormat !== undefined
|
||||
? _getUser?.DateFormat
|
||||
: "MM/DD/YYYY";
|
||||
setDateFormat(DateFormat);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err while getting user details", err);
|
||||
setErrMsg("Something went wrong");
|
||||
setErrMsg(t("something-went-wrong-mssg"));
|
||||
} finally {
|
||||
setIsTopLoader(false);
|
||||
}
|
||||
@@ -155,11 +161,12 @@ const Preferences = () => {
|
||||
params = {
|
||||
...params,
|
||||
SendinOrder: sendinOrder,
|
||||
IsTourEnabled: isTourEnabled
|
||||
IsTourEnabled: isTourEnabled,
|
||||
DateFormat: dateFormat
|
||||
};
|
||||
const updateRes = await Parse.Cloud.run("updatepreferences", params);
|
||||
if (updateRes) {
|
||||
setIsAlert({ type: "success", msg: "Saved successfully." });
|
||||
setIsAlert({ type: "success", msg: t("saved-successfully") });
|
||||
let extUser =
|
||||
localStorage.getItem("Extand_Class") &&
|
||||
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||
@@ -167,6 +174,7 @@ const Preferences = () => {
|
||||
extUser.NotifyOnSignatures = isNotifyOnSignatures;
|
||||
extUser.SendinOrder = sendinOrder;
|
||||
extUser.IsTourEnabled = isTourEnabled;
|
||||
extUser.DateFormat = dateFormat;
|
||||
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||
localStorage.setItem("Extand_Class", JSON.stringify([_extUser]));
|
||||
}
|
||||
@@ -239,12 +247,12 @@ const Preferences = () => {
|
||||
const updateRes = JSON.parse(JSON.stringify(res));
|
||||
SetCompletionBody(updateRes?.CompletionBody);
|
||||
setCompletionSubject(updateRes?.CompletionSubject);
|
||||
setIsAlert({ type: "success", msg: "Saved successfully." });
|
||||
setIsAlert({ type: "success", msg: t("saved-successfully") });
|
||||
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err", err);
|
||||
setIsAlert({ type: "danger", msg: "Something went wrong." });
|
||||
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
|
||||
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
|
||||
} finally {
|
||||
setIsLoader(false);
|
||||
@@ -266,12 +274,12 @@ const Preferences = () => {
|
||||
const updateRes = JSON.parse(JSON.stringify(res));
|
||||
setRequestBody(updateRes?.RequestBody);
|
||||
setRequestSubject(updateRes?.RequestSubject);
|
||||
setIsAlert({ type: "success", msg: "Saved successfully." });
|
||||
setIsAlert({ type: "success", msg: t("saved-successfully") });
|
||||
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err", err);
|
||||
setIsAlert({ type: "danger", msg: "Something went wrong." });
|
||||
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
|
||||
setTimeout(() => setIsAlert({ type: "", msg: "" }), 1500);
|
||||
} finally {
|
||||
setIsLoader(false);
|
||||
@@ -342,7 +350,9 @@ const Preferences = () => {
|
||||
onClick={() => setactiveTab(ind)}
|
||||
key={ind}
|
||||
role="tab"
|
||||
className={`${activeTab === ind ? "op-tab-active" : ""} op-tab text-xs md:text-base pb-2 md:pb-0 }`}
|
||||
className={`${
|
||||
activeTab === ind ? "op-tab-active" : ""
|
||||
} op-tab text-xs md:text-base pb-2 md:pb-0 }`}
|
||||
>
|
||||
<i className={tabData.icon}></i>
|
||||
<span className="ml-1 md:ml-2">{tabData.title}</span>
|
||||
@@ -375,7 +385,7 @@ const Preferences = () => {
|
||||
{t("allowed-signature-types")}
|
||||
</p>
|
||||
<p>{t("allowed-signature-types-help.p1")}</p>
|
||||
<p className="p-[5px] ml-2">
|
||||
<div className="p-[5px] ml-2">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">Draw: </span>
|
||||
@@ -402,7 +412,7 @@ const Preferences = () => {
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</ReactTooltip>
|
||||
</label>
|
||||
@@ -450,11 +460,7 @@ const Preferences = () => {
|
||||
</ReactTooltip>
|
||||
</label>
|
||||
<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
|
||||
className="mr-[2px] op-radio op-radio-xs"
|
||||
type="radio"
|
||||
@@ -465,11 +471,7 @@ const Preferences = () => {
|
||||
{t("yes")}
|
||||
</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
|
||||
className="mr-[2px] op-radio op-radio-xs"
|
||||
type="radio"
|
||||
@@ -488,6 +490,12 @@ const Preferences = () => {
|
||||
setTimezone={setTimezone}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-[0.75rem]">
|
||||
<DateFormatSelector
|
||||
dateFormat={dateFormat}
|
||||
setDateFormat={setDateFormat}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-[0.75rem] text-[12px]">
|
||||
<label className="block mb-[0.7rem]">
|
||||
<span className="text-[14px] font-medium">
|
||||
@@ -508,7 +516,7 @@ const Preferences = () => {
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">{t("send-in-order")}</p>
|
||||
<p>{t("send-in-order-help.p1")}</p>
|
||||
<p className="p-[5px]">
|
||||
<div className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
@@ -521,7 +529,7 @@ const Preferences = () => {
|
||||
<span>{t("send-in-order-help.p3")}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
<p>{t("send-in-order-help.p4")}</p>
|
||||
</div>
|
||||
</ReactTooltip>
|
||||
@@ -570,7 +578,7 @@ const Preferences = () => {
|
||||
>
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">{t("enable-tour")}</p>
|
||||
<p className="p-[5px]">
|
||||
<div className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
@@ -583,7 +591,7 @@ const Preferences = () => {
|
||||
<span>{t("istourenabled-help.p2")}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
{t("istourenabled-help.p3", {
|
||||
appName: appName
|
||||
@@ -642,7 +650,9 @@ const Preferences = () => {
|
||||
{t("subject")}
|
||||
<Tooltip
|
||||
id={"request-sub-tooltip"}
|
||||
message={`${t("variables-use")}: {{sender_name}} {{document_title}}`}
|
||||
message={`${t(
|
||||
"variables-use"
|
||||
)}: {{sender_name}} {{document_title}}`}
|
||||
/>
|
||||
</label>
|
||||
<input
|
||||
@@ -651,7 +661,9 @@ const Preferences = () => {
|
||||
onChange={(e) =>
|
||||
setRequestSubject(e.target.value)
|
||||
}
|
||||
placeholder={`{{sender_name}} ${t("send-to-sign")} {{document_title}}`}
|
||||
placeholder={`{{sender_name}} ${t(
|
||||
"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"
|
||||
/>
|
||||
</div>
|
||||
@@ -660,7 +672,9 @@ const Preferences = () => {
|
||||
{t("body")}
|
||||
<Tooltip
|
||||
id={"request-body-tooltip"}
|
||||
message={`${t("variables-use")}: {{sender_name}} {{document_title}}`}
|
||||
message={`${t(
|
||||
"variables-use"
|
||||
)}: {{sender_name}} {{document_title}}`}
|
||||
/>
|
||||
</label>
|
||||
<EditorToolbar containerId="toolbar1" />
|
||||
@@ -706,7 +720,9 @@ const Preferences = () => {
|
||||
{t("subject")}
|
||||
<Tooltip
|
||||
id={"complete-sub-tooltip"}
|
||||
message={`${t("variables-use")}:{{sender_name}} {{document_title}}`}
|
||||
message={`${t(
|
||||
"variables-use"
|
||||
)}:{{sender_name}} {{document_title}}`}
|
||||
/>
|
||||
</label>
|
||||
<input
|
||||
@@ -715,7 +731,9 @@ const Preferences = () => {
|
||||
onChange={(e) =>
|
||||
setCompletionSubject(e.target.value)
|
||||
}
|
||||
placeholder={`{{sender_name}} ${t("send-to-sign")} {{document_title}}`}
|
||||
placeholder={`{{sender_name}} ${t(
|
||||
"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"
|
||||
/>
|
||||
</div>
|
||||
@@ -724,7 +742,9 @@ const Preferences = () => {
|
||||
{t("body")}
|
||||
<Tooltip
|
||||
id={"complete-body-tooltip"}
|
||||
message={`${t("variables-use")}:{{sender_name}} {{document_title}} {{signing_url}}`}
|
||||
message={`${t(
|
||||
"variables-use"
|
||||
)}:{{sender_name}} {{document_title}} {{signing_url}}`}
|
||||
/>
|
||||
</label>
|
||||
<EditorToolbar containerId="toolbar2" />
|
||||
|
||||
@@ -40,7 +40,8 @@ import {
|
||||
convertBase64ToFile,
|
||||
generatePdfName,
|
||||
handleRemoveWidgets,
|
||||
compressedFileSize
|
||||
compressedFileSize,
|
||||
addWidgetSelfsignOptions
|
||||
} from "../constant/Utils";
|
||||
import { useParams } from "react-router";
|
||||
import Tour from "reactour";
|
||||
@@ -66,8 +67,7 @@ import LoaderWithMsg from "../primitives/LoaderWithMsg";
|
||||
function SignYourSelf() {
|
||||
const { t } = useTranslation();
|
||||
const { docId } = useParams();
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const divRef = useRef(null);
|
||||
const nodeRef = useRef(null);
|
||||
const imageRef = useRef(null);
|
||||
@@ -145,6 +145,7 @@ function SignYourSelf() {
|
||||
isVisible: false,
|
||||
signId: ""
|
||||
});
|
||||
const [owner, setOwner] = useState({});
|
||||
const [, drop] = useDrop({
|
||||
accept: "BOX",
|
||||
drop: (item, monitor) => addPositionOfSignature(item, monitor),
|
||||
@@ -205,6 +206,7 @@ function SignYourSelf() {
|
||||
const documentData = await contractDocument(documentId);
|
||||
|
||||
if (documentData && documentData.length > 0) {
|
||||
setOwner(documentData?.[0]?.ExtUserPtr);
|
||||
setPdfDetails(documentData);
|
||||
const placeholders =
|
||||
documentData[0]?.Placeholders?.length > 0
|
||||
@@ -322,7 +324,7 @@ function SignYourSelf() {
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Error: error in getDocumentDetails", err);
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
setIsLoading({ isLoad: false });
|
||||
}
|
||||
};
|
||||
@@ -345,54 +347,6 @@ function SignYourSelf() {
|
||||
}
|
||||
};
|
||||
|
||||
const addWidgetOptions = (type) => {
|
||||
switch (type) {
|
||||
case "signature":
|
||||
return { name: "signature" };
|
||||
case "stamp":
|
||||
return { name: "stamp" };
|
||||
case "checkbox":
|
||||
return { name: "checkbox" };
|
||||
case textWidget:
|
||||
return { name: "text" };
|
||||
case "initials":
|
||||
return { name: "initials" };
|
||||
case "name":
|
||||
return {
|
||||
name: "name",
|
||||
defaultValue: getWidgetValue(type),
|
||||
validation: { type: "text", pattern: "" }
|
||||
};
|
||||
case "company":
|
||||
return {
|
||||
name: "company",
|
||||
defaultValue: getWidgetValue(type),
|
||||
validation: { type: "text", pattern: "" }
|
||||
};
|
||||
case "job title":
|
||||
return {
|
||||
name: "job title",
|
||||
defaultValue: getWidgetValue(type),
|
||||
validation: { type: "text", pattern: "" }
|
||||
};
|
||||
case "date":
|
||||
return {
|
||||
name: "date",
|
||||
response: getDate(),
|
||||
validation: { format: "MM/dd/yyyy", type: "date-format" }
|
||||
};
|
||||
case "image":
|
||||
return { name: "image" };
|
||||
case "email":
|
||||
return {
|
||||
name: "email",
|
||||
defaultValue: getWidgetValue(type),
|
||||
validation: { type: "email", pattern: "" }
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
};
|
||||
//function for setting position after drop signature button over pdf
|
||||
const addPositionOfSignature = (item, monitor) => {
|
||||
setCurrWidgetsDetails({});
|
||||
@@ -417,7 +371,7 @@ function SignYourSelf() {
|
||||
// `getBoundingClientRect()` is used to get accurate measurement height of the div
|
||||
const divHeight = divRef.current.getBoundingClientRect().height;
|
||||
const getWidth = widgetTypeExist
|
||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
|
||||
? calculateInitialWidthHeight(widgetValue).getWidth
|
||||
: defaultWidthHeight(dragTypeValue).width;
|
||||
const getHeight = defaultWidthHeight(dragTypeValue).height;
|
||||
|
||||
@@ -431,7 +385,7 @@ function SignYourSelf() {
|
||||
scale: containerScale,
|
||||
Width: getWidth,
|
||||
Height: getHeight,
|
||||
options: addWidgetOptions(dragTypeValue)
|
||||
options: addWidgetSelfsignOptions(dragTypeValue, getWidgetValue, owner)
|
||||
};
|
||||
dropData.push(dropObj);
|
||||
} else {
|
||||
@@ -460,7 +414,7 @@ function SignYourSelf() {
|
||||
type: dragTypeValue,
|
||||
Width: getWidth / (containerScale * scale),
|
||||
Height: getHeight / (containerScale * scale),
|
||||
options: addWidgetOptions(dragTypeValue),
|
||||
options: addWidgetSelfsignOptions(dragTypeValue, getWidgetValue, owner),
|
||||
scale: containerScale
|
||||
};
|
||||
dropData.push(dropObj);
|
||||
@@ -562,11 +516,7 @@ function SignYourSelf() {
|
||||
let pdfUrl;
|
||||
if (isUploadPdf) {
|
||||
const pdfName = generatePdfName(16);
|
||||
pdfUrl = await convertBase64ToFile(
|
||||
pdfName,
|
||||
pdfBase64Url,
|
||||
"",
|
||||
);
|
||||
pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
||||
}
|
||||
const widgetsType = ["signature", "stamp", "image", "initials"];
|
||||
let updatedXYPosition;
|
||||
@@ -752,10 +702,7 @@ function SignYourSelf() {
|
||||
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||
alert(t("user-not-exist"));
|
||||
} else {
|
||||
if (
|
||||
tenantDetails?.CompletionBody &&
|
||||
tenantDetails?.CompletionSubject
|
||||
) {
|
||||
if (tenantDetails?.CompletionBody && tenantDetails?.CompletionSubject) {
|
||||
isCustomCompletionMail = true;
|
||||
}
|
||||
}
|
||||
@@ -791,7 +738,7 @@ function SignYourSelf() {
|
||||
pdfFile: base64Url,
|
||||
docId: documentId,
|
||||
isCustomCompletionMail: isCustomCompletionMail,
|
||||
signature: suffixbase64,
|
||||
signature: suffixbase64
|
||||
};
|
||||
const resSignPdf = await Parse.Cloud.run("signPdf", params);
|
||||
if (resSignPdf) {
|
||||
@@ -1366,7 +1313,7 @@ function SignYourSelf() {
|
||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||
/>
|
||||
)}
|
||||
{/*render email component to send email after finish signature on document
|
||||
{/*render email component to send email after finish signature on document */}
|
||||
<EmailComponent
|
||||
isEmail={isEmail}
|
||||
setIsEmail={setIsEmail}
|
||||
@@ -1375,7 +1322,6 @@ function SignYourSelf() {
|
||||
setIsAlert={setIsAlert}
|
||||
setIsDownloadModal={setIsDownloadModal}
|
||||
/>
|
||||
*/}
|
||||
{/* pdf header which contain funish back button */}
|
||||
<Header
|
||||
pageNumber={pageNumber}
|
||||
|
||||
@@ -139,6 +139,7 @@ const TemplatePlaceholder = () => {
|
||||
const [updatedPdfUrl, setUpdatedPdfUrl] = useState("");
|
||||
const [tempSignerId, setTempSignerId] = useState("");
|
||||
const [unSignedWidgetId, setUnSignedWidgetId] = useState("");
|
||||
const [owner, setOwner] = useState({});
|
||||
useEffect(() => {
|
||||
fetchTemplate();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@@ -165,7 +166,6 @@ const TemplatePlaceholder = () => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [divRef.current, isHeader]);
|
||||
|
||||
|
||||
//function to fetch tenant Details
|
||||
const fetchTenantDetails = async () => {
|
||||
const user = JSON.parse(
|
||||
@@ -215,6 +215,7 @@ const TemplatePlaceholder = () => {
|
||||
: [];
|
||||
|
||||
if (documentData && documentData.length > 0) {
|
||||
setOwner(documentData?.[0]?.ExtUserPtr);
|
||||
const url = documentData[0] && documentData[0]?.URL;
|
||||
if (url) {
|
||||
const arrayBuffer = await convertPdfArrayBuffer(url);
|
||||
@@ -392,7 +393,7 @@ const TemplatePlaceholder = () => {
|
||||
scale: containerScale,
|
||||
zIndex: posZIndex,
|
||||
type: dragTypeValue,
|
||||
options: addWidgetOptions(dragTypeValue),
|
||||
options: addWidgetOptions(dragTypeValue, owner),
|
||||
Width: widgetWidth / (containerScale * scale),
|
||||
Height: widgetHeight / (containerScale * scale)
|
||||
};
|
||||
@@ -422,7 +423,7 @@ const TemplatePlaceholder = () => {
|
||||
// isMobile: isMobile,
|
||||
zIndex: posZIndex,
|
||||
type: item.text,
|
||||
options: addWidgetOptions(dragTypeValue),
|
||||
options: addWidgetOptions(dragTypeValue, owner),
|
||||
Width: widgetWidth / (containerScale * scale),
|
||||
Height: widgetHeight / (containerScale * scale)
|
||||
};
|
||||
@@ -778,11 +779,7 @@ const TemplatePlaceholder = () => {
|
||||
let pdfUrl;
|
||||
if (isUploadPdf) {
|
||||
const pdfName = generatePdfName(16);
|
||||
pdfUrl = await convertBase64ToFile(
|
||||
pdfName,
|
||||
pdfBase64Url,
|
||||
"",
|
||||
);
|
||||
pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
||||
}
|
||||
if (signersdata?.length > 0) {
|
||||
signersdata.forEach((x) => {
|
||||
@@ -849,11 +846,7 @@ const TemplatePlaceholder = () => {
|
||||
scale
|
||||
);
|
||||
const pdfName = generatePdfName(16);
|
||||
const pdfUrl = await convertBase64ToFile(
|
||||
pdfName,
|
||||
pdfBase64,
|
||||
"",
|
||||
);
|
||||
const pdfUrl = await convertBase64ToFile(pdfName, pdfBase64, "");
|
||||
const tenantId = localStorage.getItem("TenantId");
|
||||
const buffer = atob(pdfBase64);
|
||||
SaveFileSize(buffer.length, pdfUrl, tenantId);
|
||||
@@ -865,11 +858,7 @@ const TemplatePlaceholder = () => {
|
||||
} else if (pdfBase64Url) {
|
||||
try {
|
||||
const pdfName = generatePdfName(16);
|
||||
const pdfUrl = await convertBase64ToFile(
|
||||
pdfName,
|
||||
pdfBase64Url,
|
||||
"",
|
||||
);
|
||||
const pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
||||
return pdfUrl;
|
||||
} catch (err) {
|
||||
console.log("error to convertBase64ToFile in placeholder flow", err);
|
||||
@@ -1469,8 +1458,7 @@ const TemplatePlaceholder = () => {
|
||||
status: defaultdata?.status || "required",
|
||||
hint: defaultdata?.hint || "",
|
||||
defaultValue: defaultdata?.defaultValue || "",
|
||||
validation:
|
||||
{},
|
||||
validation: {},
|
||||
fontSize:
|
||||
fontSize || currWidgetsDetails?.options?.fontSize || 12,
|
||||
fontColor:
|
||||
|
||||
@@ -7,8 +7,7 @@ import Title from "../components/Title";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { emailRegex } from "../constant/const";
|
||||
const UpdateExistUserAdmin = () => {
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const [formdata, setFormdata] = useState({ email: "", masterkey: "" });
|
||||
@@ -30,7 +29,7 @@ const UpdateExistUserAdmin = () => {
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err in checkadminexist", err);
|
||||
setErrMsg("Something went wrong.");
|
||||
setErrMsg(t("something-went-wrong-mssg"));
|
||||
} finally {
|
||||
setLoader(false);
|
||||
}
|
||||
|
||||
+177
-187
@@ -206,197 +206,187 @@ const UserList = () => {
|
||||
</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>
|
||||
{!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 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 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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,9 +4,7 @@ import { useLocation, useNavigate } from "react-router";
|
||||
import axios from "axios";
|
||||
import ModalUi from "./ModalUi";
|
||||
import AddSigner from "../components/AddSigner";
|
||||
import {
|
||||
emailRegex,
|
||||
} from "../constant/const";
|
||||
import { emailRegex } from "../constant/const";
|
||||
import Alert from "./Alert";
|
||||
import Tooltip from "./Tooltip";
|
||||
import { RWebShare } from "react-web-share";
|
||||
@@ -39,8 +37,7 @@ import EditContactForm from "../components/EditContactForm";
|
||||
|
||||
const ReportTable = (props) => {
|
||||
const copyUrlRef = useRef(null);
|
||||
const appName =
|
||||
"OpenSign™";
|
||||
const appName = "OpenSign™";
|
||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
@@ -157,14 +154,14 @@ const ReportTable = (props) => {
|
||||
const teamtRes = await Parse.Cloud.run("getteams", { active: true });
|
||||
if (teamtRes.length > 0) {
|
||||
const _teamRes = JSON.parse(JSON.stringify(teamtRes));
|
||||
const selected = _teamRes.map(
|
||||
(x) =>
|
||||
x.Name === "All Users" && {
|
||||
label: x.Name,
|
||||
value: x.objectId
|
||||
}
|
||||
);
|
||||
setSelectedTeam(selected);
|
||||
const selected = _teamRes.map(
|
||||
(x) =>
|
||||
x.Name === "All Users" && {
|
||||
label: x.Name,
|
||||
value: x.objectId
|
||||
}
|
||||
);
|
||||
setSelectedTeam(selected);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -225,7 +222,7 @@ const ReportTable = (props) => {
|
||||
const handleURL = async (item, act) => {
|
||||
if (props.ReportName === "Templates") {
|
||||
if (act.hoverLabel === "Edit") {
|
||||
navigate(`/${act.redirectUrl}/${item.objectId}`);
|
||||
navigate(`/${act.redirectUrl}/${item.objectId}`);
|
||||
} else {
|
||||
setActLoader({ [`${item.objectId}_${act.btnId}`]: true });
|
||||
try {
|
||||
@@ -411,8 +408,7 @@ const ReportTable = (props) => {
|
||||
setSelectedTeam(formatedList);
|
||||
}
|
||||
setIsShareWith({ [item.objectId]: true });
|
||||
}
|
||||
else if (act.action === "duplicate") {
|
||||
} else if (act.action === "duplicate") {
|
||||
setIsModal({ [`duplicate_${item.objectId}`]: true });
|
||||
} else if (act.action === "rename") {
|
||||
setIsModal({ [`rename_${item.objectId}`]: true });
|
||||
@@ -496,8 +492,7 @@ const ReportTable = (props) => {
|
||||
setActLoader({});
|
||||
}
|
||||
};
|
||||
const handleClose = (
|
||||
) => {
|
||||
const handleClose = () => {
|
||||
setIsRevoke({});
|
||||
setIsDeleteModal({});
|
||||
setReason("");
|
||||
@@ -656,11 +651,7 @@ const ReportTable = (props) => {
|
||||
if (isCompleted) {
|
||||
setIsDownloadModal({ [item.objectId]: true });
|
||||
} else {
|
||||
const signedUrl = await getSignedUrl(
|
||||
url,
|
||||
docId,
|
||||
templateId
|
||||
);
|
||||
const signedUrl = await getSignedUrl(url, docId, templateId);
|
||||
await fetchUrl(signedUrl, pdfName);
|
||||
}
|
||||
setActLoader({});
|
||||
@@ -687,10 +678,8 @@ const ReportTable = (props) => {
|
||||
const signPdf = `${window.location.origin}/login/${encodeBase64}`;
|
||||
const variables = {
|
||||
document_title: doc.Name,
|
||||
sender_name:
|
||||
doc.ExtUserPtr.Name,
|
||||
sender_mail:
|
||||
doc.ExtUserPtr.Email,
|
||||
sender_name: doc.ExtUserPtr.Name,
|
||||
sender_mail: doc.ExtUserPtr.Email,
|
||||
sender_phone: doc.ExtUserPtr?.Phone || "",
|
||||
receiver_name: userDetails?.Name || "",
|
||||
receiver_email: userDetails?.Email,
|
||||
@@ -718,10 +707,8 @@ const ReportTable = (props) => {
|
||||
const signPdf = `${window.location.origin}/login/${encodeBase64}`;
|
||||
const variables = {
|
||||
document_title: doc.Name,
|
||||
sender_name:
|
||||
doc.ExtUserPtr.Name,
|
||||
sender_mail:
|
||||
doc.ExtUserPtr.Email,
|
||||
sender_name: doc.ExtUserPtr.Name,
|
||||
sender_mail: doc.ExtUserPtr.Email,
|
||||
sender_phone: doc.ExtUserPtr?.Phone || "",
|
||||
receiver_name: userDetails?.Name || "",
|
||||
receiver_email: userDetails?.Email || "",
|
||||
@@ -761,10 +748,8 @@ const ReportTable = (props) => {
|
||||
const signPdf = `${window.location.origin}/login/${encodeBase64}`;
|
||||
const variables = {
|
||||
document_title: doc.Name,
|
||||
sender_name:
|
||||
doc.ExtUserPtr.Name,
|
||||
sender_mail:
|
||||
doc.ExtUserPtr.Email,
|
||||
sender_name: doc.ExtUserPtr.Name,
|
||||
sender_mail: doc.ExtUserPtr.Email,
|
||||
sender_phone: doc.ExtUserPtr?.Phone || "",
|
||||
receiver_name: user?.signerPtr?.Name || "",
|
||||
receiver_email: user?.email ? user?.email : user?.signerPtr?.Email,
|
||||
@@ -794,14 +779,11 @@ const ReportTable = (props) => {
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
};
|
||||
let params = {
|
||||
replyto:
|
||||
doc?.ExtUserPtr?.Email ||
|
||||
"",
|
||||
replyto: doc?.ExtUserPtr?.Email || "",
|
||||
extUserId: doc?.ExtUserPtr?.objectId,
|
||||
recipient: userDetails?.Email,
|
||||
subject: mail.subject,
|
||||
from:
|
||||
doc?.ExtUserPtr?.Email,
|
||||
from: doc?.ExtUserPtr?.Email,
|
||||
html: mail.body
|
||||
};
|
||||
try {
|
||||
@@ -810,8 +792,7 @@ const ReportTable = (props) => {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({ type: "success", message: t("mail-sent-alert") });
|
||||
setIsResendMail({});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
@@ -1745,11 +1726,7 @@ const ReportTable = (props) => {
|
||||
<i className={act.btnIcon}></i>
|
||||
{act.btnLabel && (
|
||||
<span className="uppercase font-medium">
|
||||
{
|
||||
`${t(
|
||||
`btnLabel.${act.btnLabel}`
|
||||
)}`
|
||||
}
|
||||
{`${t(`btnLabel.${act.btnLabel}`)}`}
|
||||
</span>
|
||||
)}
|
||||
{/* template report */}
|
||||
@@ -1829,7 +1806,9 @@ const ReportTable = (props) => {
|
||||
title={t(`btnLabel.${act.hoverLabel}`)}
|
||||
className={
|
||||
act.action !== "option"
|
||||
? `${act?.btnColor || ""} op-btn op-btn-sm mr-1`
|
||||
? `${
|
||||
act?.btnColor || ""
|
||||
} op-btn op-btn-sm mr-1`
|
||||
: "text-base-content focus:outline-none text-lg mr-2 relative"
|
||||
}
|
||||
>
|
||||
@@ -1916,28 +1895,26 @@ const ReportTable = (props) => {
|
||||
{isShareWith[item.objectId] && (
|
||||
<div className="op-modal op-modal-open">
|
||||
<div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative">
|
||||
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||
{t("share-with")}
|
||||
</h3>
|
||||
<div
|
||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
||||
onClick={() => setIsShareWith({})}
|
||||
>
|
||||
✕
|
||||
</div>
|
||||
<div className="px-2 mt-3 w-full h-full">
|
||||
<div className="op-input op-input-bordered op-input-sm w-full h-full text-[13px] break-all">
|
||||
{selectedTeam?.[0]?.label}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={(e) =>
|
||||
handleShareWith(e, item)
|
||||
}
|
||||
className="op-btn op-btn-primary ml-[10px] my-3"
|
||||
>
|
||||
{t("submit")}
|
||||
</button>
|
||||
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||
{t("share-with")}
|
||||
</h3>
|
||||
<div
|
||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
||||
onClick={() => setIsShareWith({})}
|
||||
>
|
||||
✕
|
||||
</div>
|
||||
<div className="px-2 mt-3 w-full h-full">
|
||||
<div className="op-input op-input-bordered op-input-sm w-full h-full text-[13px] break-all">
|
||||
{selectedTeam?.[0]?.label}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={(e) => handleShareWith(e, item)}
|
||||
className="op-btn op-btn-primary ml-[10px] my-3"
|
||||
>
|
||||
{t("submit")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -2030,9 +2007,7 @@ const ReportTable = (props) => {
|
||||
{isBulkSend[item.objectId] && (
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={
|
||||
t("quick-send")
|
||||
}
|
||||
title={t("quick-send")}
|
||||
handleClose={() => setIsBulkSend({})}
|
||||
>
|
||||
{isLoader[item.objectId] ? (
|
||||
|
||||
@@ -5,12 +5,7 @@ import { PDFDocument } from 'pdf-lib';
|
||||
dotenv.config();
|
||||
|
||||
export const cloudServerUrl = 'http://localhost:8080/app';
|
||||
export const appName =
|
||||
'OpenSign™';
|
||||
export function customAPIurl() {
|
||||
const url = new URL(cloudServerUrl);
|
||||
return url.pathname === '/api/app' ? url.origin + '/api' : url.origin;
|
||||
}
|
||||
export const appName = 'OpenSign™';
|
||||
|
||||
export const color = [
|
||||
'#93a3db',
|
||||
@@ -151,7 +146,6 @@ export const smtpsecure = process.env.SMTP_PORT && process.env.SMTP_PORT !== '46
|
||||
export const smtpenable =
|
||||
process.env.SMTP_ENABLE && process.env.SMTP_ENABLE.toLowerCase() === 'true' ? true : false;
|
||||
|
||||
|
||||
// `generateId` is used to unique Id for fileAdapter
|
||||
export function generateId(length) {
|
||||
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
||||
@@ -231,11 +225,9 @@ export const flattenPdf = async pdfFile => {
|
||||
export const mailTemplate = param => {
|
||||
const themeColor = '#47a3ad';
|
||||
const subject = `${param.senderName} has requested you to sign "${param.title}"`;
|
||||
const logo =
|
||||
`<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' />`;
|
||||
const logo = `<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' />`;
|
||||
|
||||
const opurl =
|
||||
` <a href='www.opensignlabs.com' target=_blank>here</a>`;
|
||||
const opurl = ` <a href='www.opensignlabs.com' target=_blank>here</a>`;
|
||||
|
||||
const body =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html;charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background:white;padding-bottom:20px'><div style='padding:10px'>" +
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import PDF from './parsefunction/pdf/PDF.js';
|
||||
import sendmailv3 from './parsefunction/sendMailv3.js';
|
||||
import usersignup from './parsefunction/usersignup.js';
|
||||
@@ -22,7 +21,6 @@ import UserAfterFind from './parsefunction/UserAfterFInd.js';
|
||||
import SignatureAfterFind from './parsefunction/SignatureAfterFind.js';
|
||||
import TenantAterFind from './parsefunction/TenantAfterFind.js';
|
||||
import VerifyEmail from './parsefunction/VerifyEmail.js';
|
||||
import encryptedpdf from './parsefunction/encryptedPdf.js';
|
||||
import { getSignedUrl } from './parsefunction/getSignedUrl.js';
|
||||
import createBatchDocs from './parsefunction/createBatchDocs.js';
|
||||
import linkContactToDoc from './parsefunction/linkContactToDoc.js';
|
||||
@@ -53,7 +51,6 @@ import getUserListByOrg from './parsefunction/getUserListByOrg.js';
|
||||
import editContact from './parsefunction/editContact.js';
|
||||
import forwardDoc from './parsefunction/ForwardDoc.js';
|
||||
|
||||
|
||||
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
|
||||
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
|
||||
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
|
||||
@@ -85,7 +82,6 @@ Parse.Cloud.define('getReport', getReport);
|
||||
Parse.Cloud.define('getTemplate', GetTemplate);
|
||||
Parse.Cloud.define('callwebhook', callWebhook);
|
||||
Parse.Cloud.define('verifyemail', VerifyEmail);
|
||||
Parse.Cloud.define('encryptedpdf', encryptedpdf);
|
||||
Parse.Cloud.define('getsignedurl', getSignedUrl);
|
||||
Parse.Cloud.define('batchdocuments', createBatchDocs);
|
||||
Parse.Cloud.define('linkcontacttodoc', linkContactToDoc);
|
||||
|
||||
@@ -28,20 +28,15 @@ export default async function forwardDoc(request) {
|
||||
const docName = _docRes.Name;
|
||||
const fileAdapterId = _docRes?.FileAdapterId || '';
|
||||
const extUserId = _docRes?.ExtUserPtr?.objectId;
|
||||
const from =
|
||||
_docRes?.ExtUserPtr?.Email;
|
||||
const replyTo =
|
||||
_docRes?.ExtUserPtr?.Email;
|
||||
const senderName =
|
||||
_docRes?.ExtUserPtr?.Name;
|
||||
const from = _docRes?.ExtUserPtr?.Email;
|
||||
const replyTo = _docRes?.ExtUserPtr?.Email;
|
||||
const senderName = _docRes?.ExtUserPtr?.Name;
|
||||
|
||||
try {
|
||||
let mailRes;
|
||||
for (let i = 0; i < recipients.length; i++) {
|
||||
const logo =
|
||||
`<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>`;
|
||||
const opurl =
|
||||
` <a href='www.opensignlabs.com' target=_blank>here</a>`;
|
||||
const logo = `<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>`;
|
||||
const opurl = ` <a href='www.opensignlabs.com' target=_blank>here</a>`;
|
||||
const themeColor = '#47a3ad';
|
||||
|
||||
let params = {
|
||||
|
||||
@@ -4,7 +4,7 @@ export default async function Newsletter(request) {
|
||||
const email = request.params.email;
|
||||
const domain = request.params.domain;
|
||||
try {
|
||||
const envAppId = process.env.REACT_APP_APPID || 'legadranaxn';
|
||||
const envAppId = process.env.REACT_APP_APPID || 'opensign';
|
||||
const headers = { 'Content-Type': 'application/json', 'X-Parse-Application-Id': envAppId };
|
||||
const envProdServer = process.env.REACT_APP_SERVERURL || 'https://app.opensignlabs.com/api/app';
|
||||
const newsletter = await axios.post(
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { PostHog } from 'posthog-node';
|
||||
const ph_project_api_key = process.env.PH_PROJECT_API_KEY;
|
||||
const client = ph_project_api_key ? new PostHog(ph_project_api_key) : '';
|
||||
export default async function encryptedpdf(request) {
|
||||
const email = request.params.email;
|
||||
if (client) {
|
||||
client?.capture({
|
||||
distinctId: email,
|
||||
event: 'encrypted_pdf_error',
|
||||
properties: { response_code: 200 },
|
||||
});
|
||||
}
|
||||
return { message: 'success' };
|
||||
}
|
||||
@@ -12,17 +12,14 @@ const eSignName = 'OpenSign';
|
||||
const eSigncontact = 'hello@opensignlabs.com';
|
||||
|
||||
// `uploadFile` is used to create url in from pdfFile
|
||||
async function uploadFile(
|
||||
pdfName,
|
||||
filepath,
|
||||
) {
|
||||
async function uploadFile(pdfName, filepath) {
|
||||
try {
|
||||
const filedata = fs.readFileSync(filepath);
|
||||
let fileUrl;
|
||||
const file = new Parse.File(pdfName, [...filedata], 'application/pdf');
|
||||
await file.save({ useMasterKey: true });
|
||||
const fileRes = getSecureUrl(file.url());
|
||||
fileUrl = fileRes.url;
|
||||
const file = new Parse.File(pdfName, [...filedata], 'application/pdf');
|
||||
await file.save({ useMasterKey: true });
|
||||
const fileRes = getSecureUrl(file.url());
|
||||
fileUrl = fileRes.url;
|
||||
return { imageUrl: fileUrl };
|
||||
} catch (err) {
|
||||
console.log('Err ', err);
|
||||
@@ -86,10 +83,7 @@ export default async function generateCertificatebydocId(req) {
|
||||
|
||||
//below is used to save signed certificate in exports folder
|
||||
fs.writeFileSync(certificatePath, signedCertificate);
|
||||
const file = await uploadFile(
|
||||
'certificate.pdf',
|
||||
certificatePath,
|
||||
);
|
||||
const file = await uploadFile('certificate.pdf', certificatePath);
|
||||
const updateDoc = new Parse.Object('contracts_Document');
|
||||
updateDoc.id = doc.objectId;
|
||||
updateDoc.set('CertificateUrl', file.imageUrl);
|
||||
|
||||
@@ -9,28 +9,29 @@ import {
|
||||
appName,
|
||||
} from '../../../Utils.js';
|
||||
import GenerateCertificate from './GenerateCertificate.js';
|
||||
import DigitalSign, { retryAsync } from './DigitalSign.js';
|
||||
import { pdflibAddPlaceholder } from '@signpdf/placeholder-pdf-lib';
|
||||
import { Placeholder } from './Placeholder.js';
|
||||
import { SignPdf } from '@signpdf/signpdf';
|
||||
import { P12Signer } from '@signpdf/signer-p12';
|
||||
|
||||
const serverUrl = cloudServerUrl; // process.env.SERVER_URL;
|
||||
const APPID = process.env.APP_ID;
|
||||
const masterKEY = process.env.MASTER_KEY;
|
||||
const eSignName = 'OpenSign';
|
||||
const eSigncontact = 'hello@opensignlabs.com';
|
||||
const logo =
|
||||
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
|
||||
const opurl =
|
||||
` <a href=www.opensignlabs.com target=_blank>here</a>`;
|
||||
"<img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' style='padding:20px'/>";
|
||||
const opurl = ` <a href=www.opensignlabs.com target=_blank>here</a>`;
|
||||
|
||||
// `updateDoc` is used to create url in from pdfFile
|
||||
async function uploadFile(
|
||||
pdfName,
|
||||
filepath,
|
||||
) {
|
||||
async function uploadFile(pdfName, filepath) {
|
||||
try {
|
||||
const filedata = fs.readFileSync(filepath);
|
||||
let fileUrl;
|
||||
const file = new Parse.File(pdfName, [...filedata], 'application/pdf');
|
||||
await file.save({ useMasterKey: true });
|
||||
const fileRes = getSecureUrl(file.url());
|
||||
fileUrl = fileRes.url;
|
||||
const file = new Parse.File(pdfName, [...filedata], 'application/pdf');
|
||||
await file.save({ useMasterKey: true });
|
||||
const fileRes = getSecureUrl(file.url());
|
||||
fileUrl = fileRes.url;
|
||||
|
||||
return { imageUrl: fileUrl };
|
||||
} catch (err) {
|
||||
@@ -195,8 +196,7 @@ async function sendCompletedMail(obj) {
|
||||
|
||||
const variables = {
|
||||
document_title: pdfName,
|
||||
sender_name:
|
||||
sender.Name,
|
||||
sender_name: sender.Name,
|
||||
sender_mail: doc?.SenderMail || sender.Email,
|
||||
sender_phone: sender?.Phone || '',
|
||||
receiver_name: sender.Name,
|
||||
@@ -213,11 +213,8 @@ async function sendCompletedMail(obj) {
|
||||
const params = {
|
||||
extUserId: sender.objectId,
|
||||
url: url,
|
||||
from:
|
||||
appName,
|
||||
replyto:
|
||||
doc?.ExtUserPtr?.Email ||
|
||||
'',
|
||||
from: appName,
|
||||
replyto: doc?.ExtUserPtr?.Email || '',
|
||||
recipient: recipient,
|
||||
subject: subject,
|
||||
pdfName: pdfName,
|
||||
@@ -244,82 +241,48 @@ async function sendCompletedMail(obj) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// `sendMailsaveCertifcate` is used send completion mail and update complete status of document
|
||||
async function sendMailsaveCertifcate(
|
||||
doc,
|
||||
pfx,
|
||||
isCustomMail,
|
||||
mailProvider,
|
||||
filename,
|
||||
) {
|
||||
async function sendMailsaveCertifcate(doc, pfx, isCustomMail, mailProvider, filename) {
|
||||
const certificate = await GenerateCertificate(doc);
|
||||
const certificatePdf = await PDFDocument.load(certificate);
|
||||
|
||||
const P12Buffer = fs.readFileSync(pfx.name);
|
||||
const p12 = new P12Signer(P12Buffer, { passphrase: pfx.passphrase || null });
|
||||
// `pdflibAddPlaceholder` is used to add code of only digitial sign in certificate
|
||||
pdflibAddPlaceholder({
|
||||
pdfDoc: certificatePdf,
|
||||
reason: `Digitally signed by ${eSignName}.`,
|
||||
location: 'n/a',
|
||||
name: eSignName,
|
||||
contactInfo: eSigncontact,
|
||||
signatureLength: 15000,
|
||||
});
|
||||
const pdfWithPlaceholderBytes = await certificatePdf.save();
|
||||
const CertificateBuffer = Buffer.from(pdfWithPlaceholderBytes);
|
||||
//`new signPDF` create new instance of CertificateBuffer and p12Buffer
|
||||
const certificateOBJ = new SignPdf();
|
||||
// `signedCertificate` is used to sign certificate digitally
|
||||
const signedCertificate = await certificateOBJ.sign(CertificateBuffer, p12);
|
||||
const certificatePath = `./exports/signed_certificate_${doc.objectId}.pdf`;
|
||||
|
||||
let certificatePath = `./exports/certificate_${doc.objectId}.pdf`;
|
||||
//below is used to save signed certificate in exports folder
|
||||
fs.writeFileSync(certificatePath, CertificateBuffer);
|
||||
const details = { reason: `Digitally signed by ${eSignName}.`, location: 'n/a', name: eSignName };
|
||||
|
||||
const res = await retryAsync(DigitalSign, [certificatePath, pfx, details]);
|
||||
// console.log('res', res);
|
||||
// const res = await DigitalSign(certificatePath, pfx, details);
|
||||
if (res) {
|
||||
const CreatedBy = {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: doc.CreatedBy.objectId,
|
||||
};
|
||||
let logbody = {
|
||||
documentId: doc.objectId,
|
||||
attempt: res.attempt,
|
||||
createdBy: CreatedBy,
|
||||
email: doc.ExtUserPtr.Email,
|
||||
};
|
||||
if (fs.existsSync(certificatePath)) {
|
||||
fs.unlinkSync(certificatePath);
|
||||
certificatePath = `./exports/signed_certificate_${doc.objectId}.pdf`;
|
||||
const file = await uploadFile(
|
||||
'certificate.pdf',
|
||||
certificatePath,
|
||||
);
|
||||
const body = { CertificateUrl: file.imageUrl };
|
||||
await axios.put(serverUrl + '/classes/contracts_Document/' + doc.objectId, body, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': APPID,
|
||||
'X-Parse-Master-Key': masterKEY,
|
||||
},
|
||||
});
|
||||
// used in API only
|
||||
if (doc.IsSendMail === false) {
|
||||
console.log("don't send mail");
|
||||
} else {
|
||||
sendCompletedMail({ isCustomMail, doc, mailProvider, filename });
|
||||
}
|
||||
saveFileUsage(CertificateBuffer.length, file.imageUrl, doc?.CreatedBy?.objectId);
|
||||
fs.unlinkSync(pfx.name);
|
||||
if (res.attempt > 1) {
|
||||
logbody = { ...logbody, status: 'success' };
|
||||
axios.post(`${cloudServerUrl}/classes/logs_SignRetry`, logbody, {
|
||||
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
|
||||
});
|
||||
}
|
||||
} else {
|
||||
fs.unlinkSync(certificatePath);
|
||||
fs.unlinkSync(pfx.name);
|
||||
const error = new Error('certificate: ' + res.error);
|
||||
error.code = 400; // Set the error code (e.g., 400 for bad request)
|
||||
logbody = { ...logbody, status: 'failure', stackTrace: 'certificate: ' + res.error };
|
||||
axios.post(`${cloudServerUrl}/classes/logs_SignRetry`, logbody, {
|
||||
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
fs.writeFileSync(certificatePath, signedCertificate);
|
||||
const file = await uploadFile('certificate.pdf', certificatePath);
|
||||
const body = { CertificateUrl: file.imageUrl };
|
||||
await axios.put(serverUrl + '/classes/contracts_Document/' + doc.objectId, body, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': APPID,
|
||||
'X-Parse-Master-Key': masterKEY,
|
||||
},
|
||||
});
|
||||
// used in API only
|
||||
if (doc.IsSendMail === false) {
|
||||
console.log("don't send mail");
|
||||
} else {
|
||||
sendCompletedMail({ isCustomMail, doc, mailProvider, filename });
|
||||
}
|
||||
saveFileUsage(CertificateBuffer.length, file.imageUrl, doc?.CreatedBy?.objectId);
|
||||
fs.unlinkSync(pfx.name);
|
||||
}
|
||||
/**
|
||||
*
|
||||
@@ -420,54 +383,27 @@ async function PDF(req) {
|
||||
form.updateFieldAppearances();
|
||||
// Flattens the form, converting all form fields into non-editable, static content
|
||||
form.flatten();
|
||||
const pdfWithPlaceholderBytes = await pdfDoc.save();
|
||||
PdfBuffer = Buffer.from(pdfWithPlaceholderBytes);
|
||||
|
||||
// `saveUrl` is used to save signed pdf in exports folder
|
||||
fs.writeFileSync(filePath, PdfBuffer);
|
||||
const details = {
|
||||
const p12Cert = new P12Signer(P12Buffer, { passphrase: passphrase || null });
|
||||
signedFilePath = `./exports/signed_${name}`;
|
||||
Placeholder({
|
||||
pdfDoc: pdfDoc,
|
||||
reason: `Digitally signed by ${eSignName} for ${reason}`,
|
||||
location: 'n/a',
|
||||
name: eSignName,
|
||||
};
|
||||
const res = await retryAsync(DigitalSign, [filePath, pfx, details]);
|
||||
// const res = await DigitalSign(filePath, pfx, details);
|
||||
// console.log('res', res);
|
||||
if (res) {
|
||||
signedFilePath = `./exports/signed_${name}`;
|
||||
const CreatedBy = {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: _resDoc.CreatedBy.objectId,
|
||||
};
|
||||
let logbody = {
|
||||
documentId: _resDoc.objectId,
|
||||
attempt: res.attempt,
|
||||
createdBy: CreatedBy,
|
||||
email: _resDoc.ExtUserPtr.Email,
|
||||
};
|
||||
if (fs.existsSync(signedFilePath)) {
|
||||
const signedPdf = fs.readFileSync(signedFilePath);
|
||||
pdfSize = signedPdf.length;
|
||||
console.log(`✅ New Signed PDF created called: ${signedFilePath} \n`);
|
||||
fs.unlinkSync(filePath);
|
||||
if (res.attempt > 1) {
|
||||
logbody = { ...logbody, status: 'success' };
|
||||
axios.post(`${cloudServerUrl}/classes/logs_SignRetry`, logbody, {
|
||||
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
|
||||
});
|
||||
}
|
||||
} else {
|
||||
fs.unlinkSync(filePath);
|
||||
const error = new Error(res.error);
|
||||
error.code = 400; // Set the error code (e.g., 400 for bad request)
|
||||
logbody = { ...logbody, status: 'failure', stackTrace: res.error };
|
||||
axios.post(`${cloudServerUrl}/classes/logs_SignRetry`, logbody, {
|
||||
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
contactInfo: eSigncontact,
|
||||
signatureLength: 15000,
|
||||
});
|
||||
const pdfWithPlaceholderBytes = await pdfDoc.save();
|
||||
PdfBuffer = Buffer.from(pdfWithPlaceholderBytes);
|
||||
//`new signPDF` create new instance of pdfBuffer and p12Buffer
|
||||
const OBJ = new SignPdf();
|
||||
// `signedDocs` is used to signpdf digitally
|
||||
const signedDocs = await OBJ.sign(PdfBuffer, p12Cert);
|
||||
|
||||
//`saveUrl` is used to save signed pdf in exports folder
|
||||
fs.writeFileSync(signedFilePath, signedDocs);
|
||||
pdfSize = signedDocs.length;
|
||||
console.log(`✅ PDF digitally signed created: ${signedFilePath} \n`);
|
||||
} else {
|
||||
//`saveUrl` is used to save signed pdf in exports folder
|
||||
fs.writeFileSync(signedFilePath, PdfBuffer);
|
||||
@@ -476,10 +412,7 @@ async function PDF(req) {
|
||||
}
|
||||
|
||||
// `uploadFile` is used to upload pdf to aws s3 and get it's url
|
||||
const data = await uploadFile(
|
||||
`signed_${name}`,
|
||||
signedFilePath,
|
||||
);
|
||||
const data = await uploadFile(`signed_${name}`, signedFilePath);
|
||||
|
||||
if (data && data.imageUrl) {
|
||||
// `axios` is used to update signed pdf url in contracts_Document classes for given DocId
|
||||
@@ -496,13 +429,7 @@ async function PDF(req) {
|
||||
saveFileUsage(pdfSize, data.imageUrl, _resDoc?.CreatedBy?.objectId);
|
||||
if (updatedDoc && updatedDoc.isCompleted) {
|
||||
const doc = { ..._resDoc, AuditTrail: updatedDoc.AuditTrail, SignedUrl: data.imageUrl };
|
||||
sendMailsaveCertifcate(
|
||||
doc,
|
||||
pfx,
|
||||
isCustomMail,
|
||||
mailProvider,
|
||||
`signed_${name}`,
|
||||
);
|
||||
sendMailsaveCertifcate(doc, pfx, isCustomMail, mailProvider, `signed_${name}`);
|
||||
} else {
|
||||
fs.unlinkSync(pfxname);
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ export default async function updatePreferences(request) {
|
||||
if (request.params.IsTourEnabled !== undefined) {
|
||||
newOrg.set('IsTourEnabled', request.params.IsTourEnabled);
|
||||
}
|
||||
if (request.params.DateFormat) {
|
||||
newOrg.set('DateFormat', request.params.DateFormat);
|
||||
}
|
||||
const updateUserRes = await newOrg.save(null, { useMasterKey: true });
|
||||
if (updateUserRes) {
|
||||
const _updateUserRes = JSON.parse(JSON.stringify(updateUserRes));
|
||||
|
||||
@@ -15,7 +15,6 @@ import AWS from 'aws-sdk';
|
||||
import { app as customRoute } from './cloud/customRoute/customApp.js';
|
||||
import { exec } from 'child_process';
|
||||
import { createTransport } from 'nodemailer';
|
||||
import { PostHog } from 'posthog-node';
|
||||
import { appName, cloudServerUrl, smtpenable, smtpsecure, useLocal } from './Utils.js';
|
||||
import { SSOAuth } from './auth/authadapter.js';
|
||||
import createContactIndex from './migrationdb/createContactIndex.js';
|
||||
@@ -175,16 +174,6 @@ function getUserIP(request) {
|
||||
return request.socket.remoteAddress;
|
||||
}
|
||||
}
|
||||
app.use(function (req, res, next) {
|
||||
const ph_project_api_key = process.env.PH_PROJECT_API_KEY;
|
||||
try {
|
||||
req.posthog = new PostHog(ph_project_api_key);
|
||||
} catch (err) {
|
||||
// console.log('Err', err);
|
||||
req.posthog = '';
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(async function (req, res, next) {
|
||||
const isFilePath = req.path.includes('files') || false;
|
||||
@@ -225,7 +214,6 @@ if (!process.env.TESTING) {
|
||||
// Mount your custom express app
|
||||
app.use('/', customRoute);
|
||||
|
||||
|
||||
// Parse Server plays nicely with the rest of your web routes
|
||||
app.get('/', function (req, res) {
|
||||
res.status(200).send('opensign-server is running !!!');
|
||||
|
||||
Generated
+805
-626
File diff suppressed because it is too large
Load Diff
@@ -18,25 +18,25 @@
|
||||
"watch": "nodemon index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.741.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.741.0",
|
||||
"@aws-sdk/client-s3": "^3.758.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.758.0",
|
||||
"@parse/fs-files-adapter": "^3.0.0",
|
||||
"@parse/s3-files-adapter": "^4.1.0",
|
||||
"@pdf-lib/fontkit": "^1.1.1",
|
||||
"@signpdf/placeholder-pdf-lib": "^3.2.4",
|
||||
"@signpdf/signer-p12": "^3.2.4",
|
||||
"@signpdf/signpdf": "^3.2.4",
|
||||
"@signpdf/signpdf": "^3.2.5",
|
||||
"aws-sdk": "^2.1692.0",
|
||||
"axios": "^1.7.9",
|
||||
"axios": "^1.8.3",
|
||||
"cors": "^2.8.5",
|
||||
"date-fns-tz": "^3.2.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"express": "^4.21.1",
|
||||
"form-data": "^4.0.1",
|
||||
"form-data": "^4.0.2",
|
||||
"generate-api-key": "^1.0.2",
|
||||
"googleapis": "^144.0.0",
|
||||
"mailgun.js": "^11.1.0",
|
||||
"mongodb": "^6.13.0",
|
||||
"mongodb": "^6.15.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"multer-s3": "^3.0.1",
|
||||
"node-forge": "^1.3.1",
|
||||
@@ -46,18 +46,18 @@
|
||||
"parse-server": "^7.4.0",
|
||||
"parse-server-api-mail-adapter": "^4.1.0",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"posthog-node": "^4.5.0",
|
||||
"ws": "^8.18.0"
|
||||
"posthog-node": "^4.10.1",
|
||||
"ws": "^8.18.1"
|
||||
},
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.26.5",
|
||||
"eslint": "^9.20.0",
|
||||
"@babel/eslint-parser": "^7.26.10",
|
||||
"eslint": "^9.22.0",
|
||||
"jasmine": "^5.6.0",
|
||||
"mongodb-runner": "^5.7.1",
|
||||
"mongodb-runner": "^5.8.0",
|
||||
"nodemon": "^3.1.9",
|
||||
"nyc": "^17.1.0",
|
||||
"prettier": "^3.5.0"
|
||||
"prettier": "^3.5.3"
|
||||
},
|
||||
"overrides": {
|
||||
"ws": "$ws",
|
||||
|
||||
+2
-1
@@ -11,7 +11,8 @@ services:
|
||||
env_file: .env.prod
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- SERVER_URL=${HOST_URL:-https://localhost:3001}/app
|
||||
- SERVER_URL=${HOST_URL:-https://localhost:3001}/api/app
|
||||
- PUBLIC_URL=${HOST_URL:-https://localhost:3001}
|
||||
networks:
|
||||
- app-network
|
||||
mongo:
|
||||
|
||||
Reference in New Issue
Block a user