Merge pull request #1648 from OpenSignLabs/updates-13994222227

v2.14.0
This commit is contained in:
prafull-opensignlabs
2025-03-21 20:09:57 +05:30
committed by GitHub
25 changed files with 2046 additions and 1838 deletions
+357 -363
View File
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -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.",
@@ -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") });
}
};
@@ -188,7 +188,7 @@ const EditTemplate = ({ template, onSuccess }) => {
<Tooltip id="istourenabled-tooltip" className="z-50">
<div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">{t("enable-tour")}</p>
<p className="p-[5px]">
<div className="p-[5px]">
<ol className="list-disc">
<li>
<span className="font-bold">{t("yes")}: </span>
@@ -199,7 +199,7 @@ const EditTemplate = ({ template, onSuccess }) => {
<span>{t("istourenabled-help.p2")}</span>
</li>
</ol>
</p>
</div>
<p>{t("istourenabled-help.p3", { appName: appName })}</p>
</div>
</Tooltip>
@@ -25,6 +25,8 @@ const selectFormat = (data) => {
switch (data) {
case "L":
return "MM/dd/yyyy";
case "MM/DD/YYYY":
return "MM/dd/yyyy";
case "DD-MM-YYYY":
return "dd-MM-yyyy";
case "DD/MM/YYYY":
@@ -41,6 +43,8 @@ const selectFormat = (data) => {
return "MM.dd.yyyy";
case "MMM DD, YYYY":
return "MMM dd, yyyy";
case "MMMM DD, YYYY":
return "MMMM dd, yyyy";
case "DD MMMM, YYYY":
return "dd MMMM, yyyy";
default:
@@ -24,7 +24,7 @@ const widgetCls =
function PlaceholderType(props) {
const { t } = useTranslation();
const type = props?.pos?.type;
const widgetTypeTraslation = t(`widgets-name.${props?.pos?.type}`);
const widgetTypeTranslation = t(`widgets-name.${props?.pos?.type}`);
const [selectOption, setSelectOption] = useState("");
const [validatePlaceholder, setValidatePlaceholder] = useState("");
const inputRef = useRef(null);
@@ -342,8 +342,8 @@ function PlaceholderType(props) {
className="font-medium"
>
{props.isNeedSign
? props.pos?.options?.hint || widgetTypeTraslation
: widgetTypeTraslation}
? props.pos?.options?.hint || widgetTypeTranslation
: widgetTypeTranslation}
</div>
)}
</div>
@@ -368,8 +368,8 @@ function PlaceholderType(props) {
className="font-medium"
>
{props.isNeedSign
? props.pos?.options?.hint || widgetTypeTraslation
: widgetTypeTraslation}
? props.pos?.options?.hint || widgetTypeTranslation
: widgetTypeTranslation}
</div>
)}
</div>
@@ -475,7 +475,7 @@ function PlaceholderType(props) {
/>
) : (
<div style={textWidgetStyle} className="select-none-cls">
<span>{textValue || widgetTypeTraslation}</span>
<span>{textValue || widgetTypeTranslation}</span>
</div>
);
case "dropdown":
@@ -538,7 +538,7 @@ function PlaceholderType(props) {
>
{props.pos?.options?.name
? props.pos.options.name
: widgetTypeTraslation}
: widgetTypeTranslation}
<i className="fa-light fa-circle-chevron-down mr-1 "></i>
</div>
);
@@ -562,8 +562,8 @@ function PlaceholderType(props) {
className="font-medium text-center"
>
{props.isNeedSign
? props.pos?.options?.hint || widgetTypeTraslation
: widgetTypeTraslation}
? props.pos?.options?.hint || widgetTypeTranslation
: widgetTypeTranslation}
</div>
)}
</div>
@@ -574,7 +574,7 @@ function PlaceholderType(props) {
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
<textarea
ref={inputRef}
placeholder={hint}
placeholder={hint || widgetTypeTranslation}
rows={1}
onKeyDown={handleEnterPress}
value={textValue}
@@ -597,7 +597,7 @@ function PlaceholderType(props) {
/>
) : (
<div className="flex h-full select-none-cls" style={textWidgetStyle}>
<span>{widgetTypeTraslation}</span>
<span>{widgetTypeTranslation}</span>
</div>
);
case "company":
@@ -606,7 +606,7 @@ function PlaceholderType(props) {
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
<textarea
ref={inputRef}
placeholder={hint}
placeholder={hint || widgetTypeTranslation}
rows={1}
onKeyDown={handleEnterPress}
value={textValue}
@@ -628,7 +628,7 @@ function PlaceholderType(props) {
/>
) : (
<div style={textWidgetStyle} className="select-none-cls">
<span>{widgetTypeTraslation}</span>
<span>{widgetTypeTranslation}</span>
</div>
);
case "job title":
@@ -637,7 +637,7 @@ function PlaceholderType(props) {
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
<textarea
ref={inputRef}
placeholder={hint}
placeholder={hint || widgetTypeTranslation}
rows={1}
onKeyDown={handleEnterPress}
value={textValue}
@@ -659,7 +659,7 @@ function PlaceholderType(props) {
/>
) : (
<div style={textWidgetStyle} className="select-none-cls">
<span>{widgetTypeTraslation}</span>
<span>{widgetTypeTranslation}</span>
</div>
);
case "date":
@@ -748,8 +748,8 @@ function PlaceholderType(props) {
className="font-medium text-center"
>
{props.isNeedSign
? props.pos?.options?.hint || widgetTypeTraslation
: widgetTypeTraslation}
? props.pos?.options?.hint || widgetTypeTranslation
: widgetTypeTranslation}
</div>
)}
</div>
@@ -760,7 +760,7 @@ function PlaceholderType(props) {
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
<textarea
ref={inputRef}
placeholder={hint}
placeholder={hint || widgetTypeTranslation}
rows={1}
onKeyDown={(e) => {
// Prevent new line on Enter key press
@@ -792,7 +792,7 @@ function PlaceholderType(props) {
/>
) : (
<div style={textWidgetStyle} className="select-none-cls">
<span>{widgetTypeTraslation}</span>
<span>{widgetTypeTranslation}</span>
</div>
);
case radioButtonWidget:
@@ -891,8 +891,8 @@ function PlaceholderType(props) {
className="font-medium"
>
{props.isNeedSign
? props.pos?.options?.hint || widgetTypeTraslation
: widgetTypeTraslation}
? props.pos?.options?.hint || widgetTypeTranslation
: widgetTypeTranslation}
</div>
)}
</div>
@@ -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;
+60 -35
View File
@@ -232,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;
@@ -263,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":
@@ -289,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" };
@@ -319,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":
@@ -932,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) {
@@ -966,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
@@ -986,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;
}
}
});
@@ -2167,13 +2192,13 @@ export const fetchUrl = async (url, pdfName) => {
try {
const response = await fetch(url);
if (!response.ok) {
alert("something went wrong, please try again later.");
alert("something went wrong, refreshing this page may solve this issue.");
throw new Error("Network response was not ok");
}
const blob = await response.blob();
saveAs(blob, `${sanitizeFileName(pdfName)}_signed_by_${appName}.pdf`);
} catch (error) {
alert("something went wrong, please try again later.");
alert("something went wrong, refreshing this page may solve this issue.");
console.error("Error downloading the file:", error);
}
};
@@ -2244,7 +2269,7 @@ export const handleDownloadPdf = async (
} catch (err) {
console.log("err in getsignedurl", err);
setIsDownloading("");
alert("something went wrong, please try again later.");
alert("something went wrong, refreshing this page may solve this issue.");
}
}
};
@@ -2302,7 +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.");
}
};
@@ -2388,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.");
}
}
};
+6 -6
View File
@@ -859,7 +859,7 @@ const Forms = (props) => {
<div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">{t("send-in-order")}</p>
<p>{t("send-in-order-help.p1")}</p>
<p className="p-[5px]">
<div className="p-[5px]">
<ol className="list-disc">
<li>
<span className="font-bold">
@@ -874,7 +874,7 @@ const Forms = (props) => {
<span>{t("send-in-order-help.p3")}</span>
</li>
</ol>
</p>
</div>
<p>{t("send-in-order-help.p4")}</p>
</div>
</Tooltip>
@@ -956,7 +956,7 @@ const Forms = (props) => {
{t("send-in-order")}
</p>
<p>{t("send-in-order-help.p1")}</p>
<p className="p-[5px]">
<div className="p-[5px]">
<ol className="list-disc">
<li>
<span className="font-bold">
@@ -975,7 +975,7 @@ const Forms = (props) => {
</span>
</li>
</ol>
</p>
</div>
<p>{t("send-in-order-help.p4")}</p>
</div>
</Tooltip>
@@ -1093,7 +1093,7 @@ const Forms = (props) => {
<Tooltip id="istourenabled-tooltip" className="z-[999]">
<div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">{t("enable-tour")}</p>
<p className="p-[5px]">
<div className="p-[5px]">
<ol className="list-disc">
<li>
<span className="font-bold">
@@ -1106,7 +1106,7 @@ const Forms = (props) => {
<span>{t("istourenabled-help.p2")}</span>
</li>
</ol>
</p>
</div>
<p>
{t("istourenabled-help.p3", { appName: appName })}
</p>
+49 -59
View File
@@ -7,9 +7,7 @@ import { NavLink, useNavigate, useLocation } from "react-router";
import login_img from "../assets/images/login_img.svg";
import { 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
+11 -12
View File
@@ -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
+5 -5
View File
@@ -150,7 +150,6 @@ function PlaceHolderSign() {
status: false,
message: ""
});
const [extUserId, setExtUserId] = useState("");
const [isCustomize, setIsCustomize] = useState(false);
const [zoomPercent, setZoomPercent] = useState(0);
const [scale, setScale] = useState(1);
@@ -164,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",
@@ -286,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) {
@@ -525,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)
};
@@ -556,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)
};
@@ -1225,7 +1225,7 @@ function PlaceHolderSign() {
sigingUrl: signPdf
};
let params = {
extUserId: extUserId,
extUserId: owner?.objectId,
recipient: signerMail[i].Email,
subject: replaceVar?.subject
? replaceVar?.subject
+28 -13
View File
@@ -20,6 +20,7 @@ import EditorToolbar, {
module2,
formats
} from "../components/pdf/EditorToolbar";
import DateFormatSelector from "../components/shared/fields/DateFormatSelector";
const Preferences = () => {
const appName = "OpenSign™";
@@ -47,6 +48,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();
@@ -99,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);
}
@@ -154,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];
@@ -166,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]));
}
@@ -238,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);
@@ -265,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);
@@ -376,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>
@@ -403,7 +412,7 @@ const Preferences = () => {
</span>
</li>
</ol>
</p>
</div>
</div>
</ReactTooltip>
</label>
@@ -481,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">
@@ -501,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">
@@ -514,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>
@@ -563,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">
@@ -576,7 +591,7 @@ const Preferences = () => {
<span>{t("istourenabled-help.p2")}</span>
</li>
</ol>
</p>
</div>
<p>
{t("istourenabled-help.p3", {
appName: appName
+8 -53
View File
@@ -40,7 +40,8 @@ import {
convertBase64ToFile,
generatePdfName,
handleRemoveWidgets,
compressedFileSize
compressedFileSize,
addWidgetSelfsignOptions
} from "../constant/Utils";
import { useParams } from "react-router";
import Tour from "reactour";
@@ -144,6 +145,7 @@ function SignYourSelf() {
isVisible: false,
signId: ""
});
const [owner, setOwner] = useState({});
const [, drop] = useDrop({
accept: "BOX",
drop: (item, monitor) => addPositionOfSignature(item, monitor),
@@ -204,6 +206,7 @@ function SignYourSelf() {
const documentData = await contractDocument(documentId);
if (documentData && documentData.length > 0) {
setOwner(documentData?.[0]?.ExtUserPtr);
setPdfDetails(documentData);
const placeholders =
documentData[0]?.Placeholders?.length > 0
@@ -321,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 });
}
};
@@ -344,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({});
@@ -416,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;
@@ -430,7 +385,7 @@ function SignYourSelf() {
scale: containerScale,
Width: getWidth,
Height: getHeight,
options: addWidgetOptions(dragTypeValue)
options: addWidgetSelfsignOptions(dragTypeValue, getWidgetValue, owner)
};
dropData.push(dropObj);
} else {
@@ -459,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);
@@ -139,6 +139,7 @@ const TemplatePlaceholder = () => {
const [updatedPdfUrl, setUpdatedPdfUrl] = useState("");
const [tempSignerId, setTempSignerId] = useState("");
const [unSignedWidgetId, setUnSignedWidgetId] = useState("");
const [owner, setOwner] = useState({});
useEffect(() => {
fetchTemplate();
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -214,6 +215,7 @@ const TemplatePlaceholder = () => {
: [];
if (documentData && documentData.length > 0) {
setOwner(documentData?.[0]?.ExtUserPtr);
const url = documentData[0] && documentData[0]?.URL;
if (url) {
const arrayBuffer = await convertPdfArrayBuffer(url);
@@ -391,7 +393,7 @@ const TemplatePlaceholder = () => {
scale: containerScale,
zIndex: posZIndex,
type: dragTypeValue,
options: addWidgetOptions(dragTypeValue),
options: addWidgetOptions(dragTypeValue, owner),
Width: widgetWidth / (containerScale * scale),
Height: widgetHeight / (containerScale * scale)
};
@@ -421,7 +423,7 @@ const TemplatePlaceholder = () => {
// isMobile: isMobile,
zIndex: posZIndex,
type: item.text,
options: addWidgetOptions(dragTypeValue),
options: addWidgetOptions(dragTypeValue, owner),
Width: widgetWidth / (containerScale * scale),
Height: widgetHeight / (containerScale * scale)
};
@@ -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);
}
@@ -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));
+805 -626
View File
File diff suppressed because it is too large Load Diff
+12 -12
View File
@@ -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",