mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-08-17 21:25:54 +02:00
feat: validation for signature type
This commit is contained in:
@@ -94,6 +94,7 @@
|
||||
"My Signature": "My Signature",
|
||||
"API Token": "API Token",
|
||||
"Webhook": "Webhook",
|
||||
"Preferences": "Preferences",
|
||||
"Teams": "Teams",
|
||||
"Team-update-successfully": "Team Updated successfully.",
|
||||
"Users": "Users"
|
||||
@@ -684,6 +685,7 @@
|
||||
"add-user-template": "You need to add a role before you can add fields for it.",
|
||||
"pdf-uncompatible": "This pdf is not compatible with opensign, please contact <support@opensignlabs.com>",
|
||||
"text-field-tour":"Fields of type 'Text' must be filled in advance before the document is sent. If you need the signers to provide input, use the 'Text Input' field instead.",
|
||||
"attach-signer-tour":"You need to attach a Signer to every role. You can do that by clicking this icon. Once you select a Signer it will be attached to all the fields associated with that role which appear in the same colour."
|
||||
|
||||
"attach-signer-tour":"You need to attach a Signer to every role. You can do that by clicking this icon. Once you select a Signer it will be attached to all the fields associated with that role which appear in the same colour.",
|
||||
"allowed-signature-types": "Allowed signature types",
|
||||
"at-least-one-signature-type": "At least one signature type should be enabled."
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
"My Signature": "Mi firma",
|
||||
"API Token": "Token API",
|
||||
"Webhook": "Webhook",
|
||||
"Preferences": "Preferencias",
|
||||
"Teams": "Equipos",
|
||||
"Team-update-successfully": "Equipo actualizado correctamente.",
|
||||
"Users": "Usuarios"
|
||||
@@ -684,6 +685,7 @@
|
||||
"form-title-1": "Configuración del flujo de documentos",
|
||||
"form-title-2": "Configuración de seguridad",
|
||||
"text-field-tour":"Los campos de tipo 'Texto' deben completarse con anticipación antes de enviar el documento. Si necesita que los firmantes proporcionen información, utilice el campo 'Entrada de texto'",
|
||||
"attach-signer-tour" :"Debe adjuntar un firmante a cada función. Puede hacerlo haciendo clic en este icono. Una vez que seleccione un Firmante, se adjuntará a todos los campos asociados con ese rol que aparecen en el mismo color."
|
||||
|
||||
"attach-signer-tour" :"Debe adjuntar un firmante a cada función. Puede hacerlo haciendo clic en este icono. Una vez que seleccione un Firmante, se adjuntará a todos los campos asociados con ese rol que aparecen en el mismo color.",
|
||||
"allowed-signature-types": "Tipos de firma permitidos",
|
||||
"at-least-one-signature-type": "Se debe habilitar al menos un tipo de firma."
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
"My Signature": "Ma signature",
|
||||
"API Token": "Jeton API",
|
||||
"Webhook": "Webhook",
|
||||
"Preferences": "Préférences",
|
||||
"Teams": "Équipe",
|
||||
"Team-update-successfully": "Équipe mise à jour avec succès.",
|
||||
"Users": "Utilisateurs"
|
||||
@@ -683,7 +684,7 @@
|
||||
"add-user-template":"Vous devez ajouter un rôle avant de pouvoir lui ajouter des champs. ",
|
||||
"pdf-uncompatible":"Ce pdf n'est pas compatible avec opensign, veuillez contacter <support@opensignlabs.com>",
|
||||
"text-field-tour" :"Les champs de type 'Texte' doivent être remplis à l'avance avant l'envoi du document. Si vous avez besoin que les signataires fournissent des informations, utilisez plutôt le champ 'Saisie de texte'.",
|
||||
"attach-signer-tour" :"Vous devez associer un signataire à chaque rôle. Vous pouvez le faire en cliquant sur cette icône. Une fois que vous avez sélectionné un signataire, il sera attaché à tous les champs associés à ce rôle qui apparaissent dans la même couleur."
|
||||
|
||||
|
||||
"attach-signer-tour" :"Vous devez associer un signataire à chaque rôle. Vous pouvez le faire en cliquant sur cette icône. Une fois que vous avez sélectionné un signataire, il sera attaché à tous les champs associés à ce rôle qui apparaissent dans la même couleur.",
|
||||
"allowed-signature-types": "Types de signature autorisés",
|
||||
"at-least-one-signature-type": "Au moins un type de signature doit être activé."
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ const Webhook = lazy(() => import("./pages/Webhook"));
|
||||
const AddAdmin = lazy(() => import("./pages/AddAdmin"));
|
||||
const UpdateExistUserAdmin = lazy(() => import("./pages/UpdateExistUserAdmin"));
|
||||
const DraftTemplate = lazy(() => import("./pages/DraftTemplate"));
|
||||
const Preferences = lazy(() => import("./pages/Preferences"));
|
||||
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
|
||||
const AppLoader = () => {
|
||||
@@ -199,6 +200,10 @@ function App() {
|
||||
</>
|
||||
)}
|
||||
<Route path="/users" element={<UserList />} />
|
||||
<Route
|
||||
path="/preferences"
|
||||
element={<LazyPage Page={Preferences} />}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="/sso" element={<SSOVerify />} />
|
||||
<Route
|
||||
|
||||
@@ -258,7 +258,11 @@ const BulkSendUi = (props) => {
|
||||
: [...existSigner]
|
||||
});
|
||||
} else {
|
||||
Documents.push({ ...props.item, Placeholders: updatedPlaceholders });
|
||||
Documents.push({
|
||||
...props.item,
|
||||
Placeholders: updatedPlaceholders,
|
||||
SignatureType: props.signatureType
|
||||
});
|
||||
}
|
||||
});
|
||||
await batchQuery(Documents);
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
function DefaultSignature({ defaultSignImg, xyPostion, setDefaultSignAlert }) {
|
||||
function DefaultSignature(props) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const confirmToaddDefaultSign = () => {
|
||||
if (xyPostion.length > 0) {
|
||||
setDefaultSignAlert({
|
||||
if (props?.xyPostion.length > 0) {
|
||||
props?.setDefaultSignAlert({
|
||||
isShow: true,
|
||||
alertMessage: t("default-sign-alert")
|
||||
});
|
||||
} else {
|
||||
setDefaultSignAlert({
|
||||
props?.setDefaultSignAlert({
|
||||
isShow: true,
|
||||
alertMessage: t("please-select-position!")
|
||||
});
|
||||
@@ -22,22 +22,32 @@ function DefaultSignature({ defaultSignImg, xyPostion, setDefaultSignAlert }) {
|
||||
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
|
||||
{t("signature")}
|
||||
</div>
|
||||
<div className="flex flex-col items-center mt-[10px] font-semibold">
|
||||
<div
|
||||
className={`${
|
||||
props?.isDefault ? "" : "bg-black/70"
|
||||
} flex flex-col items-center mt-[10px] font-semibold relative`}
|
||||
>
|
||||
<p className="text-base-content">{t("Your-Signature")}</p>
|
||||
<div className="op-card shadow-md h-[111px] w-[90%] p-2">
|
||||
<img
|
||||
alt="signature"
|
||||
className="w-full h-full object-contain"
|
||||
src={defaultSignImg}
|
||||
src={props?.defaultSignImg}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-primary op-btn-sm mt-[10px]"
|
||||
onClick={() => confirmToaddDefaultSign()}
|
||||
disabled={!props?.isDefault}
|
||||
>
|
||||
{t("auto-sign-all")}
|
||||
</button>
|
||||
{!props.isDefault && (
|
||||
<div className="absolute text-white w-full h-full flex items-center justify-center -rotate-45 text-[11px] cursor-default">
|
||||
Document creator has disabled this option
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -445,17 +445,13 @@ function Placeholder(props) {
|
||||
handleOnClickSettingIcon();
|
||||
}}
|
||||
className="fa-light fa-gear icon"
|
||||
style={{
|
||||
color: "#188ae2",
|
||||
right: "29px",
|
||||
top: "-19px"
|
||||
}}
|
||||
style={{ color: "#188ae2", right: "29px", top: "-19px" }}
|
||||
></i>
|
||||
) : (
|
||||
/* condition to add setting icon for placeholder & template flow for all widgets except signature and date */
|
||||
((!props?.pos?.type && props.pos.isStamp) ||
|
||||
(props?.pos?.type &&
|
||||
!["date", "signature"].includes(props.pos.type) &&
|
||||
!["date"].includes(props.pos.type) &&
|
||||
!props.isSignYourself)) && (
|
||||
<i
|
||||
onClick={(e) => {
|
||||
@@ -469,7 +465,7 @@ function Placeholder(props) {
|
||||
className="fa-light fa-gear icon"
|
||||
style={{
|
||||
color: "#188ae2",
|
||||
right: props?.pos?.type === textWidget ? "32px" : "47px",
|
||||
right: props?.pos?.type === textWidget ? "32px" : "51px",
|
||||
top: "-19px"
|
||||
}}
|
||||
></i>
|
||||
|
||||
@@ -1,39 +1,20 @@
|
||||
import React, { useRef, useState, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import SignatureCanvas from "react-signature-canvas";
|
||||
function SignPad({
|
||||
isSignPad,
|
||||
isStamp,
|
||||
setIsImageSelect,
|
||||
onSaveSign,
|
||||
setIsSignPad,
|
||||
setImage,
|
||||
isImageSelect,
|
||||
imageRef,
|
||||
onImageChange,
|
||||
onSaveImage,
|
||||
image,
|
||||
defaultSign,
|
||||
setSignature,
|
||||
myInitial,
|
||||
isInitial,
|
||||
setIsInitial,
|
||||
setIsStamp,
|
||||
widgetType,
|
||||
currWidgetsDetails,
|
||||
setCurrWidgetsDetails
|
||||
}) {
|
||||
|
||||
function SignPad(props) {
|
||||
const { t } = useTranslation();
|
||||
const [penColor, setPenColor] = useState("blue");
|
||||
const allColor = ["blue", "red", "black"];
|
||||
const canvasRef = useRef(null);
|
||||
const [isDefaultSign, setIsDefaultSign] = useState(false);
|
||||
const [isTab, setIsTab] = useState("draw");
|
||||
const [isTab, setIsTab] = useState("");
|
||||
const [isSignImg, setIsSignImg] = useState("");
|
||||
const [signValue, setSignValue] = useState("");
|
||||
const [textWidth, setTextWidth] = useState(0);
|
||||
const [textHeight, setTextHeight] = useState(0);
|
||||
const [signatureType, setSignatureType] = useState("draw");
|
||||
const [signatureType, setSignatureType] = useState("");
|
||||
const [isSignTypes, setIsSignTypes] = useState(true);
|
||||
const fontOptions = [
|
||||
{ value: "Fasthand" },
|
||||
{ value: "Dancing Script" },
|
||||
@@ -53,24 +34,56 @@ function SignPad({
|
||||
const jsonSender = JSON.parse(senderUser);
|
||||
const currentUserName = jsonSender && jsonSender?.name;
|
||||
|
||||
useEffect(() => {
|
||||
handleTab();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
function handleTab() {
|
||||
const signtypes = props?.signatureTypes || [];
|
||||
const index = signtypes?.findIndex((x) => x.enabled === true);
|
||||
if (index !== -1) {
|
||||
const tab = props?.signatureTypes[index].name;
|
||||
if (tab === "draw") {
|
||||
setIsTab("draw");
|
||||
setSignatureType("draw");
|
||||
} else if (tab === "upload") {
|
||||
props?.setIsImageSelect(true);
|
||||
setIsTab("uploadImage");
|
||||
} else if (tab === "typed") {
|
||||
setIsTab("type");
|
||||
} else if (tab === "default") {
|
||||
setIsTab("mysignature");
|
||||
} else {
|
||||
setIsTab(true);
|
||||
}
|
||||
} else {
|
||||
setIsSignTypes(false);
|
||||
}
|
||||
}
|
||||
function isTabEnabled(tabName) {
|
||||
const isEnabled = props?.signatureTypes.find(
|
||||
(x) => x.name === tabName
|
||||
)?.enabled;
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
//function for clear signature image
|
||||
const handleClear = () => {
|
||||
setCurrWidgetsDetails({});
|
||||
props?.setCurrWidgetsDetails({});
|
||||
if (isTab === "draw") {
|
||||
if (canvasRef.current) {
|
||||
canvasRef.current.clear();
|
||||
} else if (isStamp) {
|
||||
setImage("");
|
||||
} else if (props?.isStamp) {
|
||||
props?.setImage("");
|
||||
}
|
||||
setIsSignImg("");
|
||||
} else if (isTab === "uploadImage") {
|
||||
setImage("");
|
||||
props?.setImage("");
|
||||
}
|
||||
// setIsInitial(false);
|
||||
};
|
||||
//function for set signature url
|
||||
const handleSignatureChange = (data) => {
|
||||
setSignature(data);
|
||||
props?.setSignature(data);
|
||||
setIsSignImg(data);
|
||||
};
|
||||
//save button component
|
||||
@@ -88,58 +101,58 @@ function SignPad({
|
||||
)}
|
||||
<button
|
||||
onClick={() => {
|
||||
setCurrWidgetsDetails({});
|
||||
if (!image) {
|
||||
props?.setCurrWidgetsDetails({});
|
||||
if (!props?.image) {
|
||||
if (isTab === "mysignature") {
|
||||
setIsSignImg("");
|
||||
if (isInitial) {
|
||||
onSaveSign(signatureType, "initials");
|
||||
if (props?.isInitial) {
|
||||
props?.onSaveSign(signatureType, "initials");
|
||||
} else {
|
||||
onSaveSign(null, "default");
|
||||
props?.onSaveSign(null, "default");
|
||||
}
|
||||
} else {
|
||||
if (isTab === "type") {
|
||||
setIsSignImg("");
|
||||
onSaveSign(
|
||||
props?.onSaveSign(
|
||||
null,
|
||||
false,
|
||||
!isInitial && textWidth > 150 ? 150 : textWidth,
|
||||
!isInitial && textHeight > 35 ? 35 : textHeight
|
||||
!props?.isInitial && textWidth > 150 ? 150 : textWidth,
|
||||
!props?.isInitial && textHeight > 35 ? 35 : textHeight
|
||||
);
|
||||
} else {
|
||||
setIsSignImg("");
|
||||
canvasRef.current.clear();
|
||||
onSaveSign(signatureType);
|
||||
props?.onSaveSign(signatureType);
|
||||
}
|
||||
}
|
||||
|
||||
setPenColor("blue");
|
||||
} else {
|
||||
setIsSignImg("");
|
||||
onSaveImage(signatureType);
|
||||
props?.onSaveImage(signatureType);
|
||||
}
|
||||
setIsSignPad(false);
|
||||
setIsInitial(false);
|
||||
setIsImageSelect(false);
|
||||
props?.setIsSignPad(false);
|
||||
props?.setIsInitial(false);
|
||||
props?.setIsImageSelect(false);
|
||||
setIsDefaultSign(false);
|
||||
setImage();
|
||||
props?.setImage();
|
||||
setIsTab("draw");
|
||||
setSignValue("");
|
||||
setIsStamp(false);
|
||||
props?.setIsStamp(false);
|
||||
}}
|
||||
type="button"
|
||||
className={`${
|
||||
isSignImg || image || isDefaultSign || textWidth
|
||||
isSignImg || props?.image || isDefaultSign || textWidth
|
||||
? ""
|
||||
: "pointer-events-none"
|
||||
} op-btn op-btn-primary shadow-lg`}
|
||||
disabled={
|
||||
(isTab === "draw" && isSignImg) ||
|
||||
(isTab === "image" && image) ||
|
||||
(isTab === "image" && props?.image) ||
|
||||
(isTab === "mysignature" && isDefaultSign) ||
|
||||
(isTab === "type" && signValue)
|
||||
? false
|
||||
: image
|
||||
: props?.image
|
||||
? false
|
||||
: true
|
||||
}
|
||||
@@ -151,12 +164,12 @@ function SignPad({
|
||||
};
|
||||
//useEffect for set already draw or save signature url/text url of signature text type and draw type for initial type and signature type widgets
|
||||
useEffect(() => {
|
||||
if (currWidgetsDetails && canvasRef.current) {
|
||||
const isWidgetType = currWidgetsDetails?.type;
|
||||
const signatureType = currWidgetsDetails?.signatureType;
|
||||
const url = currWidgetsDetails?.SignUrl;
|
||||
if (props?.currWidgetsDetails && canvasRef.current) {
|
||||
const isWidgetType = props?.currWidgetsDetails?.type;
|
||||
const signatureType = props?.currWidgetsDetails?.signatureType;
|
||||
const url = props?.currWidgetsDetails?.SignUrl;
|
||||
//checking widget type and draw type signature url
|
||||
if (isInitial) {
|
||||
if (props?.isInitial) {
|
||||
if (isWidgetType === "initials" && signatureType === "draw" && url) {
|
||||
canvasRef.current.fromDataURL(url);
|
||||
}
|
||||
@@ -171,12 +184,12 @@ function SignPad({
|
||||
|
||||
const trimmedName = currentUserName && currentUserName?.trim();
|
||||
const firstCharacter = trimmedName?.charAt(0);
|
||||
const userName = isInitial ? firstCharacter : currentUserName;
|
||||
const userName = props?.isInitial ? firstCharacter : currentUserName;
|
||||
setSignValue(userName || "");
|
||||
setFontSelect("Fasthand");
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isSignPad]);
|
||||
}, [props.isSignPad]);
|
||||
useEffect(() => {
|
||||
const loadFont = async () => {
|
||||
try {
|
||||
@@ -204,7 +217,7 @@ function SignPad({
|
||||
? signValue?.trim()
|
||||
: currentUserName?.trim();
|
||||
const firstCharacter = trimmedName?.charAt(0);
|
||||
const userName = isInitial ? firstCharacter : signValue;
|
||||
const userName = props?.isInitial ? firstCharacter : signValue;
|
||||
setSignValue(userName);
|
||||
convertToImg(fontSelect, userName);
|
||||
}
|
||||
@@ -233,7 +246,7 @@ function SignPad({
|
||||
// Draw the text content on the canvas
|
||||
const ctx = canvasElement.getContext("2d");
|
||||
const pixelRatio = window.devicePixelRatio || 1;
|
||||
const addExtraWidth = isInitial ? 10 : 50;
|
||||
const addExtraWidth = props?.isInitial ? 10 : 50;
|
||||
const width = span.offsetWidth + addExtraWidth;
|
||||
const height = span.offsetHeight;
|
||||
setTextWidth(width);
|
||||
@@ -255,7 +268,7 @@ function SignPad({
|
||||
document.body.removeChild(span);
|
||||
// Convert the canvas to image data
|
||||
const dataUrl = canvasElement.toDataURL("image/png");
|
||||
setSignature(dataUrl);
|
||||
props?.setSignature(dataUrl);
|
||||
};
|
||||
|
||||
const PenColorComponent = (props) => {
|
||||
@@ -299,317 +312,372 @@ function SignPad({
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
{isSignPad && (
|
||||
{props?.isSignPad && (
|
||||
<div className="op-modal op-modal-open">
|
||||
<div className="op-modal-box px-[13px] pt-2 pb-0">
|
||||
<div className="flex justify-between text-base-content items-center">
|
||||
<div className="text-[1.2rem]">
|
||||
<div className="flex flex-row justify-between mt-[3px]">
|
||||
<div className="flex flex-row justify-between gap-[5px] md:gap-[8px] text-[11px] md:text-base">
|
||||
{isStamp ? (
|
||||
<span className="text-base-content font-bold text-lg">
|
||||
{widgetType === "image" ||
|
||||
currWidgetsDetails?.type === "image"
|
||||
? t("upload-image")
|
||||
: t("upload-stamp-image")}
|
||||
</span>
|
||||
) : (
|
||||
<>
|
||||
<div>
|
||||
<span
|
||||
onClick={() => {
|
||||
setIsDefaultSign(false);
|
||||
setIsImageSelect(false);
|
||||
setIsTab("draw");
|
||||
setImage();
|
||||
if (isSignImg) {
|
||||
setSignature(isSignImg);
|
||||
}
|
||||
}}
|
||||
className={`${
|
||||
isTab === "draw"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
{t("draw")}
|
||||
{isSignTypes ? (
|
||||
<>
|
||||
<div className="flex justify-between text-base-content items-center">
|
||||
<div className="text-[1.2rem]">
|
||||
<div className="flex flex-row justify-between mt-[3px]">
|
||||
<div className="flex flex-row justify-between gap-[5px] md:gap-[8px] text-[11px] md:text-base">
|
||||
{props?.isStamp ? (
|
||||
<span className="text-base-content font-bold text-lg">
|
||||
{props?.widgetType === "image" ||
|
||||
props?.currWidgetsDetails?.type === "image"
|
||||
? t("upload-image")
|
||||
: t("upload-stamp-image")}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
onClick={() => {
|
||||
setIsDefaultSign(false);
|
||||
setIsImageSelect(true);
|
||||
setIsTab("uploadImage");
|
||||
setSignatureType("");
|
||||
}}
|
||||
className={`${
|
||||
isTab === "uploadImage"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
{t("upload-image")}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
onClick={() => {
|
||||
setIsDefaultSign(false);
|
||||
setIsImageSelect(false);
|
||||
setIsTab("type");
|
||||
setSignatureType("");
|
||||
setImage();
|
||||
}}
|
||||
className={`${
|
||||
isTab === "type"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
{t("type")}
|
||||
</span>
|
||||
</div>
|
||||
{!isInitial && defaultSign ? (
|
||||
<div>
|
||||
<span
|
||||
onClick={() => {
|
||||
setIsDefaultSign(true);
|
||||
setIsImageSelect(true);
|
||||
setIsTab("mysignature");
|
||||
setSignatureType("");
|
||||
setImage();
|
||||
}}
|
||||
className={`${
|
||||
isTab === "mysignature"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
{t("my-signature")}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
isInitial &&
|
||||
myInitial && (
|
||||
<div>
|
||||
<span
|
||||
onClick={() => {
|
||||
setIsDefaultSign(true);
|
||||
setIsImageSelect(true);
|
||||
setIsTab("mysignature");
|
||||
setSignatureType("");
|
||||
setImage();
|
||||
}}
|
||||
className={`${
|
||||
isTab === "mysignature"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
{t("my-initials")}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
<>
|
||||
{isTabEnabled("draw") && (
|
||||
<div>
|
||||
<span
|
||||
onClick={() => {
|
||||
setIsDefaultSign(false);
|
||||
props?.setIsImageSelect(false);
|
||||
setIsTab("draw");
|
||||
props?.setImage();
|
||||
if (isSignImg) {
|
||||
props?.setSignature(isSignImg);
|
||||
}
|
||||
}}
|
||||
className={`${
|
||||
isTab === "draw"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
{t("draw")}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{isTabEnabled("upload") && (
|
||||
<div>
|
||||
<span
|
||||
onClick={() => {
|
||||
setIsDefaultSign(false);
|
||||
props?.setIsImageSelect(true);
|
||||
setIsTab("uploadImage");
|
||||
setSignatureType("");
|
||||
}}
|
||||
className={`${
|
||||
isTab === "uploadImage"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
{t("upload-image")}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{isTabEnabled("typed") && (
|
||||
<div>
|
||||
<span
|
||||
onClick={() => {
|
||||
setIsDefaultSign(false);
|
||||
props?.setIsImageSelect(false);
|
||||
setIsTab("type");
|
||||
setSignatureType("");
|
||||
props?.setImage();
|
||||
}}
|
||||
className={`${
|
||||
isTab === "type"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
{t("type")}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{!props?.isInitial &&
|
||||
props?.defaultSign &&
|
||||
isTabEnabled("default") ? (
|
||||
<div>
|
||||
<span
|
||||
onClick={() => {
|
||||
setIsDefaultSign(true);
|
||||
props?.setIsImageSelect(true);
|
||||
setIsTab("mysignature");
|
||||
setSignatureType("");
|
||||
props?.setImage();
|
||||
}}
|
||||
className={`${
|
||||
isTab === "mysignature"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
{t("my-signature")}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
props?.isInitial &&
|
||||
props?.myInitial &&
|
||||
isTabEnabled("default") && (
|
||||
<div>
|
||||
<span
|
||||
onClick={() => {
|
||||
setIsDefaultSign(true);
|
||||
props?.setIsImageSelect(true);
|
||||
setIsTab("mysignature");
|
||||
setSignatureType("");
|
||||
props?.setImage();
|
||||
}}
|
||||
className={`${
|
||||
isTab === "mysignature"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
{t("my-initials")}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="text-[1.5rem] cursor-pointer"
|
||||
onClick={() => {
|
||||
setPenColor("blue");
|
||||
setIsSignPad(false);
|
||||
setIsInitial(false);
|
||||
setIsImageSelect(false);
|
||||
setIsDefaultSign(false);
|
||||
setImage();
|
||||
setIsTab("draw");
|
||||
setSignatureType("draw");
|
||||
setSignValue("");
|
||||
setIsStamp(false);
|
||||
}}
|
||||
>
|
||||
×
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-[20px] h-full">
|
||||
{isDefaultSign ? (
|
||||
<>
|
||||
<div className="flex justify-center">
|
||||
<div
|
||||
style={{
|
||||
border: "1.3px solid #007bff",
|
||||
borderRadius: "2px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginBottom: 6,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
className={
|
||||
isInitial ? "intialSignatureCanvas" : "signatureCanvas"
|
||||
}
|
||||
>
|
||||
<img
|
||||
alt="stamp img"
|
||||
className="w-full h-full object-contain bg-white"
|
||||
draggable="false"
|
||||
src={isInitial ? myInitial : defaultSign}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</>
|
||||
) : isImageSelect || isStamp ? (
|
||||
!image ? (
|
||||
<div className="flex justify-center">
|
||||
<div
|
||||
style={{
|
||||
border: "1.3px solid #007bff",
|
||||
borderRadius: "2px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginBottom: 6,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
className={
|
||||
isInitial ? "intialSignatureCanvas" : "signatureCanvas"
|
||||
}
|
||||
onClick={() => imageRef.current.click()}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
onChange={onImageChange}
|
||||
className="filetype"
|
||||
accept="image/png,image/jpeg"
|
||||
ref={imageRef}
|
||||
hidden
|
||||
/>
|
||||
<i className="fa-light fa-cloud-upload-alt uploadImgLogo"></i>
|
||||
<div className="text-[10px]">{t("upload")}</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex justify-center">
|
||||
<div
|
||||
style={{
|
||||
border: "1.3px solid #007bff",
|
||||
borderRadius: "2px",
|
||||
marginBottom: 6,
|
||||
overflow: "hidden"
|
||||
}}
|
||||
className={
|
||||
isInitial
|
||||
? "intialSignatureCanvas"
|
||||
: "signatureCanvas"
|
||||
}
|
||||
>
|
||||
<img
|
||||
alt="print img"
|
||||
ref={imageRef}
|
||||
src={image.src}
|
||||
draggable="false"
|
||||
className=" object-contain h-full w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
) : isTab === "type" ? (
|
||||
<div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="mr-[5px] text-[12px]">
|
||||
{isInitial ? t("initial-teb") : t("signature-tab")}:
|
||||
</span>
|
||||
<input
|
||||
maxLength={isInitial ? 3 : 30}
|
||||
style={{ fontFamily: fontSelect, color: penColor }}
|
||||
type="text"
|
||||
className="ml-1 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-[20px]"
|
||||
placeholder="Your signature"
|
||||
value={signValue}
|
||||
onChange={(e) => {
|
||||
setSignValue(e.target.value);
|
||||
convertToImg(fontSelect, e.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="border-[1px] border-[#d6d3d3] mt-[10px] ml-[5px]">
|
||||
{fontOptions.map((font, ind) => {
|
||||
return (
|
||||
<div
|
||||
key={ind}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
fontFamily: font.value,
|
||||
backgroundColor:
|
||||
fontSelect === font.value && "rgb(206 225 247)"
|
||||
}}
|
||||
onClick={() => {
|
||||
setFontSelect(font.value);
|
||||
convertToImg(font.value, signValue);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
padding: "5px 10px 5px 10px",
|
||||
fontSize: "20px",
|
||||
color: penColor
|
||||
}}
|
||||
>
|
||||
{signValue ? signValue : "Your signature"}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row justify-between mt-[10px]">
|
||||
<PenColorComponent convertToImg={convertToImg} />
|
||||
<SaveBtn />
|
||||
<div
|
||||
className="text-[1.5rem] cursor-pointer"
|
||||
onClick={() => {
|
||||
setPenColor("blue");
|
||||
props?.setIsSignPad(false);
|
||||
props?.setIsInitial(false);
|
||||
props?.setIsImageSelect(false);
|
||||
setIsDefaultSign(false);
|
||||
props?.setImage();
|
||||
setIsTab("draw");
|
||||
setSignatureType("draw");
|
||||
setSignValue("");
|
||||
props?.setIsStamp(false);
|
||||
}}
|
||||
>
|
||||
×
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex justify-center">
|
||||
<SignatureCanvas
|
||||
ref={canvasRef}
|
||||
penColor={penColor}
|
||||
canvasProps={{
|
||||
className: isInitial
|
||||
? "intialSignatureCanvas"
|
||||
: "signatureCanvas",
|
||||
style: {
|
||||
border: "1.6px solid #007bff",
|
||||
borderRadius: "2px"
|
||||
}
|
||||
}}
|
||||
// backgroundColor="rgb(255, 255, 255)"
|
||||
onEnd={() =>
|
||||
handleSignatureChange(canvasRef.current?.toDataURL())
|
||||
}
|
||||
dotSize={1}
|
||||
/>
|
||||
<div className="p-[20px] h-full">
|
||||
{isDefaultSign ? (
|
||||
<>
|
||||
<div className="flex justify-center">
|
||||
<div
|
||||
style={{
|
||||
border: "1.3px solid #007bff",
|
||||
borderRadius: "2px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginBottom: 6,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
className={
|
||||
props?.isInitial
|
||||
? "intialSignatureCanvas"
|
||||
: "signatureCanvas"
|
||||
}
|
||||
>
|
||||
<img
|
||||
alt="stamp img"
|
||||
className="w-full h-full object-contain bg-white"
|
||||
draggable="false"
|
||||
src={
|
||||
props?.isInitial
|
||||
? props?.myInitial
|
||||
: props?.defaultSign
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</>
|
||||
) : props?.isImageSelect || props?.isStamp ? (
|
||||
!props?.image ? (
|
||||
<div className="flex justify-center">
|
||||
<div
|
||||
style={{
|
||||
border: "1.3px solid #007bff",
|
||||
borderRadius: "2px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginBottom: 6,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
className={
|
||||
props?.isInitial
|
||||
? "intialSignatureCanvas"
|
||||
: "signatureCanvas"
|
||||
}
|
||||
onClick={() => props?.imageRef.current.click()}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
onChange={props?.onImageChange}
|
||||
className="filetype"
|
||||
accept="image/png,image/jpeg"
|
||||
ref={props?.imageRef}
|
||||
hidden
|
||||
/>
|
||||
<i className="fa-light fa-cloud-upload-alt uploadImgLogo"></i>
|
||||
<div className="text-[10px]">{t("upload")}</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex justify-center">
|
||||
<div
|
||||
style={{
|
||||
border: "1.3px solid #007bff",
|
||||
borderRadius: "2px",
|
||||
marginBottom: 6,
|
||||
overflow: "hidden"
|
||||
}}
|
||||
className={
|
||||
props?.isInitial
|
||||
? "intialSignatureCanvas"
|
||||
: "signatureCanvas"
|
||||
}
|
||||
>
|
||||
<img
|
||||
alt="print img"
|
||||
ref={props?.imageRef}
|
||||
src={props?.image.src}
|
||||
draggable="false"
|
||||
className=" object-contain h-full w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
) : isTab === "type" ? (
|
||||
<div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="mr-[5px] text-[12px]">
|
||||
{props?.isInitial
|
||||
? t("initial-teb")
|
||||
: t("signature-tab")}
|
||||
:
|
||||
</span>
|
||||
<input
|
||||
maxLength={props?.isInitial ? 3 : 30}
|
||||
style={{ fontFamily: fontSelect, color: penColor }}
|
||||
type="text"
|
||||
className="ml-1 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-[20px]"
|
||||
placeholder="Your signature"
|
||||
value={signValue}
|
||||
onChange={(e) => {
|
||||
setSignValue(e.target.value);
|
||||
convertToImg(fontSelect, e.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="border-[1px] border-[#d6d3d3] mt-[10px] ml-[5px]">
|
||||
{fontOptions.map((font, ind) => {
|
||||
return (
|
||||
<div
|
||||
key={ind}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
fontFamily: font.value,
|
||||
backgroundColor:
|
||||
fontSelect === font.value &&
|
||||
"rgb(206 225 247)"
|
||||
}}
|
||||
onClick={() => {
|
||||
setFontSelect(font.value);
|
||||
convertToImg(font.value, signValue);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
padding: "5px 10px 5px 10px",
|
||||
fontSize: "20px",
|
||||
color: penColor
|
||||
}}
|
||||
>
|
||||
{signValue ? signValue : "Your signature"}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row justify-between mt-[10px]">
|
||||
<PenColorComponent convertToImg={convertToImg} />
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex justify-center">
|
||||
<SignatureCanvas
|
||||
ref={canvasRef}
|
||||
penColor={penColor}
|
||||
canvasProps={{
|
||||
className: props?.isInitial
|
||||
? "intialSignatureCanvas"
|
||||
: "signatureCanvas",
|
||||
style: {
|
||||
border: "1.6px solid #007bff",
|
||||
borderRadius: "2px"
|
||||
}
|
||||
}}
|
||||
// backgroundColor="rgb(255, 255, 255)"
|
||||
onEnd={() =>
|
||||
handleSignatureChange(
|
||||
canvasRef.current?.toDataURL()
|
||||
)
|
||||
}
|
||||
dotSize={1}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row justify-between mt-[10px]">
|
||||
<PenColorComponent />
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="">
|
||||
<div className="relative flex flex-row items-center justify-between">
|
||||
<div className="text-base-content font-bold text-lg">
|
||||
Signature
|
||||
</div>
|
||||
<div className="flex flex-row justify-between mt-[10px]">
|
||||
<PenColorComponent />
|
||||
<SaveBtn />
|
||||
<div
|
||||
className="text-[1.5rem] cursor-pointer"
|
||||
onClick={() => {
|
||||
setPenColor("blue");
|
||||
props?.setIsSignPad(false);
|
||||
props?.setIsInitial(false);
|
||||
props?.setIsImageSelect(false);
|
||||
setIsDefaultSign(false);
|
||||
props?.setImage();
|
||||
setIsTab("draw");
|
||||
setSignatureType("draw");
|
||||
setSignValue("");
|
||||
props?.setIsStamp(false);
|
||||
}}
|
||||
>
|
||||
×
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx-3 mb-6 mt-3">
|
||||
<p>{t("at-least-one-signature-type")}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -2,7 +2,11 @@ import React, { useEffect, useState } from "react";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
import "../../styles/AddUser.css";
|
||||
import RegexParser from "regex-parser";
|
||||
import { textInputWidget, textWidget } from "../../constant/Utils";
|
||||
import {
|
||||
signatureTypes,
|
||||
textInputWidget,
|
||||
textWidget
|
||||
} from "../../constant/Utils";
|
||||
import Upgrade from "../../primitives/Upgrade";
|
||||
import { isEnableSubscription } from "../../constant/const";
|
||||
import Tooltip from "../../primitives/Tooltip";
|
||||
@@ -11,6 +15,7 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
const WidgetNameModal = (props) => {
|
||||
const { t } = useTranslation();
|
||||
const signTypes = props?.signatureType || signatureTypes;
|
||||
const [formdata, setFormdata] = useState({
|
||||
name: "",
|
||||
defaultValue: "",
|
||||
@@ -21,6 +26,7 @@ const WidgetNameModal = (props) => {
|
||||
const [isValid, setIsValid] = useState(true);
|
||||
const statusArr = ["Required", "Optional"];
|
||||
const inputOpt = ["text", "email", "number"];
|
||||
const [signatureType, setSignatureType] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.defaultdata) {
|
||||
@@ -40,12 +46,22 @@ const WidgetNameModal = (props) => {
|
||||
name: props.defaultdata?.options?.name || ""
|
||||
});
|
||||
}
|
||||
|
||||
if (signTypes.length > 0) {
|
||||
const defaultSignatureType = signTypes || [];
|
||||
setSignatureType(defaultSignatureType);
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, [props.defaultdata]);
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
if (props.handleData) {
|
||||
props.handleData(formdata);
|
||||
if (["signature", "initials"].includes(props.defaultdata?.type)) {
|
||||
const data = { ...formdata, signatureType };
|
||||
props.handleData(data, props.defaultdata?.type);
|
||||
} else {
|
||||
props.handleData(formdata);
|
||||
}
|
||||
setFormdata({
|
||||
name: "",
|
||||
defaultValue: "",
|
||||
@@ -53,6 +69,7 @@ const WidgetNameModal = (props) => {
|
||||
hint: "",
|
||||
textvalidate: ""
|
||||
});
|
||||
setSignatureType(signTypes);
|
||||
}
|
||||
};
|
||||
const handleChange = (e) => {
|
||||
@@ -102,6 +119,15 @@ const WidgetNameModal = (props) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleCheckboxChange = (index) => {
|
||||
// Create a copy of the signatureType array
|
||||
const updatedSignatureType = [...signatureType];
|
||||
// Toggle the enabled value for the clicked item
|
||||
updatedSignatureType[index].enabled = !updatedSignatureType[index].enabled;
|
||||
// Update the state with the modified array
|
||||
setSignatureType(updatedSignatureType);
|
||||
};
|
||||
return (
|
||||
<ModalUi
|
||||
isOpen={props.isOpen}
|
||||
@@ -111,24 +137,30 @@ const WidgetNameModal = (props) => {
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className={`${
|
||||
props.defaultdata?.type === textInputWidget ? "pt-0" : ""
|
||||
props.defaultdata?.type === textInputWidget
|
||||
? "pt-0"
|
||||
: ["signature", "initials"].includes(props.defaultdata?.type)
|
||||
? "pt-2"
|
||||
: ""
|
||||
} p-[20px] text-base-content`}
|
||||
>
|
||||
<div className="mb-[0.75rem] text-[13px]">
|
||||
<label htmlFor="name">
|
||||
{t("name")}
|
||||
<span className="text-[red]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
name="name"
|
||||
value={formdata.name}
|
||||
onChange={(e) => handleChange(e)}
|
||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
{!["signature", "initials"].includes(props.defaultdata?.type) && (
|
||||
<div className="mb-[0.75rem] text-[13px]">
|
||||
<label htmlFor="name">
|
||||
{t("name")}
|
||||
<span className="text-[red]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
name="name"
|
||||
value={formdata.name}
|
||||
onChange={(e) => handleChange(e)}
|
||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
||||
onInput={(e) => e.target.setCustomValidity("")}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{props.defaultdata?.type === textInputWidget && (
|
||||
<>
|
||||
{isEnableSubscription && (
|
||||
@@ -226,30 +258,63 @@ const WidgetNameModal = (props) => {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className="mb-[0.75rem]">
|
||||
<div className="flex flex-row gap-[10px] mb-[0.5rem]">
|
||||
{statusArr.map((data, ind) => {
|
||||
return (
|
||||
<div key={ind} className="flex flex-row gap-[5px] items-center">
|
||||
<input
|
||||
className="mr-[2px] op-radio op-radio-xs"
|
||||
type="radio"
|
||||
name="status"
|
||||
onChange={() =>
|
||||
setFormdata({ ...formdata, status: data.toLowerCase() })
|
||||
}
|
||||
checked={
|
||||
formdata.status.toLowerCase() === data.toLowerCase()
|
||||
}
|
||||
/>
|
||||
<div className="text-[13px] font-medium">
|
||||
{t(`widget-status.${data}`)}
|
||||
{!["signature", "initials"].includes(props.defaultdata?.type) && (
|
||||
<div className="mb-[0.75rem]">
|
||||
<div className="flex flex-row gap-[10px] mb-[0.5rem]">
|
||||
{statusArr.map((data, ind) => {
|
||||
return (
|
||||
<div
|
||||
key={ind}
|
||||
className="flex flex-row gap-[5px] items-center"
|
||||
>
|
||||
<input
|
||||
className="mr-[2px] op-radio op-radio-xs"
|
||||
type="radio"
|
||||
name="status"
|
||||
onChange={() =>
|
||||
setFormdata({ ...formdata, status: data.toLowerCase() })
|
||||
}
|
||||
checked={
|
||||
formdata.status.toLowerCase() === data.toLowerCase()
|
||||
}
|
||||
/>
|
||||
<div className="text-[13px] font-medium">
|
||||
{t(`widget-status.${data}`)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{props.defaultdata?.type === "signature" && (
|
||||
<div className="mb-[0.75rem]">
|
||||
<label htmlFor="signaturetype" className="text-[14px] mb-[0.7rem]">
|
||||
{t("allowed-signature-types")}
|
||||
</label>
|
||||
<div className=" ml-[7px] flex flex-col md:flex-row gap-[10px] mb-[0.7rem]">
|
||||
{signatureType.map((type, i) => {
|
||||
return (
|
||||
<div key={i} className="flex flex-row gap-[5px] items-center">
|
||||
<input
|
||||
className="mr-[2px] op-checkbox op-checkbox-xs"
|
||||
type="checkbox"
|
||||
name="signaturetype"
|
||||
onChange={() => handleCheckboxChange(i)}
|
||||
checked={type.enabled}
|
||||
/>
|
||||
<div
|
||||
className="text-[13px] font-medium hover:underline underline-offset-2 cursor-default"
|
||||
title={`Enabling this allow signers to ${type.name} signature`}
|
||||
>
|
||||
{type.name}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{props.defaultdata?.type === textInputWidget && (
|
||||
<div className="mb-[0.75rem]">
|
||||
<label htmlFor="hint" className="text-[13px]">
|
||||
|
||||
@@ -685,7 +685,6 @@ export const createDocument = async (
|
||||
) => {
|
||||
if (template && template.length > 0) {
|
||||
const Doc = template[0];
|
||||
|
||||
let placeholdersArr = [];
|
||||
if (placeholders?.length > 0) {
|
||||
placeholdersArr = placeholders;
|
||||
@@ -703,6 +702,9 @@ export const createDocument = async (
|
||||
}
|
||||
});
|
||||
}
|
||||
const SignatureType = Doc?.SignatureType
|
||||
? { SignatureType: Doc?.SignatureType }
|
||||
: {};
|
||||
const data = {
|
||||
Name: Doc.Name,
|
||||
URL: pdfUrl,
|
||||
@@ -727,7 +729,8 @@ export const createDocument = async (
|
||||
RemindOnceInEvery: parseInt(Doc?.RemindOnceInEvery || 5),
|
||||
IsEnableOTP: Doc?.IsEnableOTP || false,
|
||||
IsTourEnabled: Doc?.IsTourEnabled || false,
|
||||
FileAdapterId: Doc?.FileAdapterId || ""
|
||||
FileAdapterId: Doc?.FileAdapterId || "",
|
||||
...SignatureType
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -2592,3 +2595,23 @@ export function generateTitleFromFilename(filename) {
|
||||
return "Untitled Document";
|
||||
}
|
||||
}
|
||||
|
||||
export const signatureTypes = [
|
||||
{ name: "draw", enabled: true },
|
||||
{ name: "typed", enabled: true },
|
||||
{ name: "upload", enabled: true },
|
||||
{ name: "default", enabled: true }
|
||||
];
|
||||
|
||||
// `handleSignatureType` is used to return update signature types as per tenant or user
|
||||
export async function handleSignatureType(tenantSignTypes, signatureType) {
|
||||
const docSignTypes = signatureType || signatureTypes;
|
||||
let updatedSignatureType = signatureType || signatureTypes;
|
||||
if (tenantSignTypes?.length > 0) {
|
||||
updatedSignatureType = tenantSignTypes?.map((item) => {
|
||||
const match = docSignTypes.find((data) => data.name === item.name);
|
||||
return match ? { ...item, enabled: match.enabled } : item;
|
||||
});
|
||||
}
|
||||
return updatedSignatureType;
|
||||
}
|
||||
|
||||
@@ -154,6 +154,14 @@ const sidebarList = [
|
||||
pageType: "",
|
||||
description: "",
|
||||
objectId: "webhook"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-pen-fancy",
|
||||
title: "Preferences",
|
||||
target: "_self",
|
||||
pageType: "",
|
||||
description: "",
|
||||
objectId: "preferences"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -30,7 +30,10 @@ import {
|
||||
handleRemoveWidgets,
|
||||
handleRotateWarning,
|
||||
color,
|
||||
copytoData
|
||||
copytoData,
|
||||
getTenantDetails,
|
||||
signatureTypes,
|
||||
handleSignatureType
|
||||
} from "../constant/Utils";
|
||||
import RenderPdf from "../components/pdf/RenderPdf";
|
||||
import "../styles/AddUser.css";
|
||||
@@ -125,6 +128,7 @@ const DraftTemplate = () => {
|
||||
const [isPublic, setIsPublic] = useState("");
|
||||
const [isPublicErr, setIsPublicError] = useState("");
|
||||
const [isAllRoleLinked, setIsAllRolelinked] = useState(false);
|
||||
const [signatureType, setSignatureType] = useState([]);
|
||||
const [, drop] = useDrop({
|
||||
accept: "BOX",
|
||||
drop: (item, monitor) => addPositionOfSignature(item, monitor),
|
||||
@@ -189,9 +193,36 @@ const DraftTemplate = () => {
|
||||
handleNavigation(plan);
|
||||
}
|
||||
}
|
||||
//function to fetch tenant Details
|
||||
const fetchTenantDetails = async () => {
|
||||
const user = JSON.parse(
|
||||
localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
)
|
||||
);
|
||||
if (user) {
|
||||
try {
|
||||
const tenantDetails = await getTenantDetails(user?.objectId);
|
||||
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||
alert(t("user-not-exist"));
|
||||
} else if (tenantDetails) {
|
||||
const signatureType = tenantDetails?.SignatureType || [];
|
||||
const filterSignTypes = signatureType?.filter(
|
||||
(x) => x.enabled === true
|
||||
);
|
||||
return filterSignTypes;
|
||||
}
|
||||
} catch (e) {
|
||||
alert(t("user-not-exist"));
|
||||
}
|
||||
} else {
|
||||
alert(t("user-not-exist"));
|
||||
}
|
||||
};
|
||||
// `fetchTemplate` function in used to get Template from server and setPlaceholder ,setSigner if present
|
||||
const fetchTemplate = async () => {
|
||||
try {
|
||||
const tenantSignTypes = await fetchTenantDetails();
|
||||
const params = { templateId: templateId };
|
||||
const token = jwttoken
|
||||
? { jwttoken: jwttoken }
|
||||
@@ -222,6 +253,12 @@ const DraftTemplate = () => {
|
||||
}
|
||||
|
||||
if (documentData && documentData.length > 0) {
|
||||
const docSignTypes = documentData?.[0]?.SignatureType || signatureTypes;
|
||||
const updatedSignatureType = await handleSignatureType(
|
||||
tenantSignTypes,
|
||||
docSignTypes
|
||||
);
|
||||
setSignatureType(updatedSignatureType);
|
||||
if (isEnableSubscription) {
|
||||
checkIsSubscribed(documentData[0]?.ExtUserPtr?.Email);
|
||||
}
|
||||
@@ -290,6 +327,36 @@ const DraftTemplate = () => {
|
||||
setHandleError(t("no-data-avaliable"));
|
||||
setIsLoading({ isLoad: false });
|
||||
}
|
||||
|
||||
const res = await contractUsers(jwttoken);
|
||||
if (res[0] && res.length) {
|
||||
const userSignatureType = res[0]?.SignatureType || signatureTypes;
|
||||
const docSignTypes =
|
||||
documentData?.[0]?.SignatureType || userSignatureType;
|
||||
const updatedSignatureType = await handleSignatureType(
|
||||
tenantSignTypes,
|
||||
docSignTypes
|
||||
);
|
||||
setSignatureType(updatedSignatureType);
|
||||
setSignerUserId(res[0].objectId);
|
||||
const tourstatus = res[0].TourStatus && res[0].TourStatus;
|
||||
if (tourstatus && tourstatus.length > 0) {
|
||||
setTourStatus(tourstatus);
|
||||
const checkTourRecipients = tourstatus.filter(
|
||||
(data) => data.templateTour
|
||||
);
|
||||
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
||||
setCheckTourStatus(checkTourRecipients[0].templateTour);
|
||||
}
|
||||
}
|
||||
setIsLoading({ isLoad: false });
|
||||
} else if (res === "Error: Something went wrong!") {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
setIsLoading({ isLoad: false });
|
||||
} else if (res.length === 0) {
|
||||
setHandleError(t("no-data-avaliable"));
|
||||
setIsLoading({ isLoad: false });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err ", err);
|
||||
if (err?.response?.data?.code === 101) {
|
||||
@@ -298,27 +365,6 @@ const DraftTemplate = () => {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
}
|
||||
}
|
||||
const res = await contractUsers(jwttoken);
|
||||
if (res[0] && res.length) {
|
||||
setSignerUserId(res[0].objectId);
|
||||
const tourstatus = res[0].TourStatus && res[0].TourStatus;
|
||||
if (tourstatus && tourstatus.length > 0) {
|
||||
setTourStatus(tourstatus);
|
||||
const checkTourRecipients = tourstatus.filter(
|
||||
(data) => data.templateTour
|
||||
);
|
||||
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
||||
setCheckTourStatus(checkTourRecipients[0].templateTour);
|
||||
}
|
||||
}
|
||||
setIsLoading({ isLoad: false });
|
||||
} else if (res === "Error: Something went wrong!") {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
setIsLoading({ isLoad: false });
|
||||
} else if (res.length === 0) {
|
||||
setHandleError(t("no-data-avaliable"));
|
||||
setIsLoading({ isLoad: false });
|
||||
}
|
||||
};
|
||||
//function for setting position after drop signature button over pdf
|
||||
const addPositionOfSignature = (item, monitor) => {
|
||||
@@ -694,7 +740,8 @@ const DraftTemplate = () => {
|
||||
RemindOnceInEvery: parseInt(pdfDetails[0]?.RemindOnceInEvery),
|
||||
NextReminderDate: pdfDetails[0]?.NextReminderDate,
|
||||
IsEnableOTP: pdfDetails[0]?.IsEnableOTP === true ? true : false,
|
||||
IsTourEnabled: pdfDetails[0]?.IsTourEnabled === true ? true : false
|
||||
IsTourEnabled: pdfDetails[0]?.IsTourEnabled === true ? true : false,
|
||||
SignatureType: signatureType
|
||||
};
|
||||
const baseURL = localStorage.getItem("baseUrl");
|
||||
const url = `${baseURL}functions/savetemplate`;
|
||||
@@ -1121,7 +1168,15 @@ const DraftTemplate = () => {
|
||||
setFontColor();
|
||||
};
|
||||
|
||||
const handleWidgetdefaultdata = (defaultdata) => {
|
||||
const handleWidgetdefaultdata = (defaultdata, isSignWidget) => {
|
||||
if (isSignWidget) {
|
||||
const updatedPdfDetails = [...pdfDetails];
|
||||
const signtypes = defaultdata.signatureType || signatureType;
|
||||
updatedPdfDetails[0].SignatureType = signtypes;
|
||||
// Update the SignatureType with the modified array
|
||||
setPdfDetails(updatedPdfDetails);
|
||||
setSignatureType(signtypes);
|
||||
}
|
||||
const options = ["email", "number", "text"];
|
||||
let inputype;
|
||||
if (defaultdata.textvalidate) {
|
||||
@@ -1321,6 +1376,7 @@ const DraftTemplate = () => {
|
||||
template.URL = pdfUrl;
|
||||
template.Signers = signers;
|
||||
template.Placeholders = signerPos;
|
||||
template.SignatureType = signatureType;
|
||||
const Documents = [template];
|
||||
const token = jwttoken
|
||||
? { jwttoken: jwttoken }
|
||||
@@ -1495,6 +1551,7 @@ const DraftTemplate = () => {
|
||||
) : (
|
||||
<>
|
||||
<BulkSendUi
|
||||
signatureType={signatureType}
|
||||
Placeholders={signerPos}
|
||||
item={pdfDetails?.[0]}
|
||||
handleClose={handleQuickSendClose}
|
||||
@@ -1822,6 +1879,7 @@ const DraftTemplate = () => {
|
||||
/>
|
||||
</ModalUi>
|
||||
<WidgetNameModal
|
||||
signatureType={signatureType}
|
||||
widgetName={widgetName}
|
||||
defaultdata={currWidgetsDetails}
|
||||
isOpen={isNameModal}
|
||||
|
||||
@@ -33,7 +33,10 @@ import {
|
||||
getDefaultSignature,
|
||||
onClickZoomIn,
|
||||
onClickZoomOut,
|
||||
fetchUrl
|
||||
fetchUrl,
|
||||
signatureTypes,
|
||||
handleSignatureType,
|
||||
getTenantDetails
|
||||
} from "../constant/Utils";
|
||||
import Header from "../components/pdf/PdfHeader";
|
||||
import RenderPdf from "../components/pdf/RenderPdf";
|
||||
@@ -136,6 +139,7 @@ function PdfRequestFiles(props) {
|
||||
const isHeader = useSelector((state) => state.showHeader);
|
||||
const divRef = useRef(null);
|
||||
const [isDownloadModal, setIsDownloadModal] = useState(false);
|
||||
const [signatureType, setSignatureType] = useState([]);
|
||||
const isMobile = window.innerWidth < 767;
|
||||
|
||||
let isGuestSignFlow = false;
|
||||
@@ -302,17 +306,13 @@ function PdfRequestFiles(props) {
|
||||
: [];
|
||||
if (documentData && documentData[0]?.error) {
|
||||
props?.setTemplateStatus &&
|
||||
props?.setTemplateStatus({
|
||||
status: "Invalid"
|
||||
});
|
||||
props?.setTemplateStatus({ status: "Invalid" });
|
||||
throw new Error("error: Invalid TemplateId");
|
||||
} else if (documentData && documentData.length > 0) {
|
||||
if (documentData[0]?.IsPublic) {
|
||||
//handle condition when someone use plan js then setTemplateStatus is not supporting
|
||||
props?.setTemplateStatus &&
|
||||
props?.setTemplateStatus({
|
||||
status: "Success"
|
||||
});
|
||||
props?.setTemplateStatus({ status: "Success" });
|
||||
const url =
|
||||
documentData[0] &&
|
||||
(documentData[0]?.SignedUrl || documentData[0]?.URL);
|
||||
@@ -350,24 +350,18 @@ function PdfRequestFiles(props) {
|
||||
}
|
||||
setUnSignedSigners(placeholdersOrSigners);
|
||||
setPdfDetails(documentData);
|
||||
setIsLoading({
|
||||
isLoad: false
|
||||
});
|
||||
setIsLoading({ isLoad: false });
|
||||
} else {
|
||||
props?.setTemplateStatus &&
|
||||
props?.setTemplateStatus({
|
||||
status: "Private"
|
||||
});
|
||||
setIsLoading(false);
|
||||
props?.setTemplateStatus({ status: "Private" });
|
||||
setIsLoading({ isLoad: false });
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
console.error("error: TemplateId is not public");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
props?.setTemplateStatus &&
|
||||
props?.setTemplateStatus({
|
||||
status: "Invalid"
|
||||
});
|
||||
props?.setTemplateStatus({ status: "Invalid" });
|
||||
setIsLoading(false);
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
console.error("error: Invalid TemplateId");
|
||||
@@ -384,6 +378,33 @@ function PdfRequestFiles(props) {
|
||||
return;
|
||||
}
|
||||
};
|
||||
const fetchTenantDetails = async () => {
|
||||
const user = JSON.parse(
|
||||
localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
)
|
||||
);
|
||||
if (user) {
|
||||
try {
|
||||
const tenantDetails = await getTenantDetails(user?.objectId);
|
||||
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||
alert(t("user-not-exist"));
|
||||
} else if (tenantDetails) {
|
||||
const signatureType = tenantDetails?.SignatureType || [];
|
||||
const filterSignTypes = signatureType?.filter(
|
||||
(x) => x.enabled === true
|
||||
);
|
||||
|
||||
return filterSignTypes;
|
||||
}
|
||||
} catch (e) {
|
||||
alert(t("user-not-exist"));
|
||||
}
|
||||
} else {
|
||||
alert(t("user-not-exist"));
|
||||
}
|
||||
};
|
||||
|
||||
//function for get document details for perticular signer with signer'object id
|
||||
const getDocumentDetails = async (docId, isNextUser) => {
|
||||
try {
|
||||
@@ -391,11 +412,18 @@ function PdfRequestFiles(props) {
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
);
|
||||
const jsonSender = JSON.parse(senderUser);
|
||||
const tenantSignTypes = await fetchTenantDetails();
|
||||
// `currUserId` will be contactId or extUserId
|
||||
let currUserId;
|
||||
//getting document details
|
||||
const documentData = await contractDocument(docId);
|
||||
if (documentData && documentData.length > 0) {
|
||||
const docSignTypes = documentData?.[0]?.SignatureType || signatureTypes;
|
||||
const updatedSignatureType = await handleSignatureType(
|
||||
tenantSignTypes,
|
||||
docSignTypes
|
||||
);
|
||||
setSignatureType(updatedSignatureType);
|
||||
const url =
|
||||
documentData[0] &&
|
||||
(documentData[0]?.SignedUrl || documentData[0]?.URL);
|
||||
@@ -968,11 +996,7 @@ function PdfRequestFiles(props) {
|
||||
const newDate = new Date(expireDate);
|
||||
const localExpireDate = newDate.toLocaleDateString(
|
||||
"en-US",
|
||||
{
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric"
|
||||
}
|
||||
{ day: "numeric", month: "long", year: "numeric" }
|
||||
);
|
||||
let senderEmail = pdfDetails?.[0].ExtUserPtr.Email;
|
||||
let senderPhone = pdfDetails?.[0]?.ExtUserPtr?.Phone;
|
||||
@@ -1381,9 +1405,7 @@ function PdfRequestFiles(props) {
|
||||
try {
|
||||
await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}functions/updatecontacttour`,
|
||||
{
|
||||
contactId: signerObjectId
|
||||
},
|
||||
{ contactId: signerObjectId },
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -2108,6 +2130,7 @@ function PdfRequestFiles(props) {
|
||||
</ModalUi>
|
||||
{/* this component is used for signature pad modal */}
|
||||
<SignPad
|
||||
signatureTypes={signatureType}
|
||||
isSignPad={isSignPad}
|
||||
isStamp={isStamp}
|
||||
setIsImageSelect={setIsImageSelect}
|
||||
@@ -2256,6 +2279,10 @@ function PdfRequestFiles(props) {
|
||||
setIsLoading={setIsLoading}
|
||||
xyPostion={signerPos}
|
||||
setDefaultSignAlert={setDefaultSignAlert}
|
||||
isDefault={
|
||||
signatureType?.find((x) => x.name === "default")
|
||||
?.enabled || false
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -38,7 +38,9 @@ import {
|
||||
onClickZoomOut,
|
||||
rotatePdfPage,
|
||||
handleRemoveWidgets,
|
||||
handleRotateWarning
|
||||
handleRotateWarning,
|
||||
signatureTypes,
|
||||
handleSignatureType
|
||||
} from "../constant/Utils";
|
||||
import RenderPdf from "../components/pdf/RenderPdf";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
@@ -152,28 +154,22 @@ function PlaceHolderSign() {
|
||||
const [pdfRotateBase64, setPdfRotatese64] = useState("");
|
||||
const [planCode, setPlanCode] = useState("");
|
||||
const [unSignedWidgetId, setUnSignedWidgetId] = useState("");
|
||||
const [signatureType, setSignatureType] = useState(signatureTypes);
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const [, drop] = useDrop({
|
||||
accept: "BOX",
|
||||
drop: (item, monitor) => addPositionOfSignature(item, monitor),
|
||||
collect: (monitor) => ({
|
||||
isOver: !!monitor.isOver()
|
||||
})
|
||||
collect: (monitor) => ({ isOver: !!monitor.isOver() })
|
||||
});
|
||||
|
||||
const [{ isDragSign }, dragSignature] = useDrag({
|
||||
type: "BOX",
|
||||
item: { type: "BOX", id: 1, text: "signature" },
|
||||
collect: (monitor) => ({
|
||||
isDragSign: !!monitor.isDragging()
|
||||
})
|
||||
collect: (monitor) => ({ isDragSign: !!monitor.isDragging() })
|
||||
});
|
||||
const [{ isDragStamp }, dragStamp] = useDrag({
|
||||
type: "BOX",
|
||||
item: { type: "BOX", id: 2, text: "stamp" },
|
||||
collect: (monitor) => ({
|
||||
isDragStamp: !!monitor.isDragging()
|
||||
})
|
||||
collect: (monitor) => ({ isDragStamp: !!monitor.isDragging() })
|
||||
});
|
||||
const documentId = docId;
|
||||
useEffect(() => {
|
||||
@@ -202,10 +198,15 @@ function PlaceHolderSign() {
|
||||
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||
alert(t("user-not-exist"));
|
||||
} else if (tenantDetails) {
|
||||
const signatureType = tenantDetails?.SignatureType || [];
|
||||
const filterSignTypes = signatureType?.filter(
|
||||
(x) => x.enabled === true
|
||||
);
|
||||
if (tenantDetails?.RequestBody) {
|
||||
setRequestBody(tenantDetails?.RequestBody);
|
||||
setRequestSubject(tenantDetails?.RequestSubject);
|
||||
}
|
||||
return filterSignTypes;
|
||||
}
|
||||
} catch (e) {
|
||||
alert(t("user-not-exist"));
|
||||
@@ -256,11 +257,17 @@ function PlaceHolderSign() {
|
||||
}
|
||||
//function for get document details
|
||||
const getDocumentDetails = async () => {
|
||||
fetchTenantDetails();
|
||||
const tenantSignTypes = await fetchTenantDetails();
|
||||
//getting document details
|
||||
const documentData = await contractDocument(documentId);
|
||||
if (documentData && documentData.length > 0) {
|
||||
const url = documentData[0] && documentData[0]?.URL;
|
||||
const docSignTypes = documentData?.[0]?.SignatureType || signatureTypes;
|
||||
const updatedSignatureType = await handleSignatureType(
|
||||
tenantSignTypes,
|
||||
docSignTypes
|
||||
);
|
||||
setSignatureType(updatedSignatureType);
|
||||
//convert document url in array buffer format to use embed widgets in pdf using pdf-lib
|
||||
const arrayBuffer = await convertPdfArrayBuffer(url);
|
||||
if (arrayBuffer === "Error") {
|
||||
@@ -436,6 +443,14 @@ function PlaceHolderSign() {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
setIsLoading({ isLoad: false });
|
||||
} else if (res.length && res[0]?.objectId) {
|
||||
const userSignatureType = res[0]?.SignatureType || signatureTypes;
|
||||
const docSignTypes =
|
||||
documentData?.[0]?.SignatureType || userSignatureType;
|
||||
const updatedSignatureType = await handleSignatureType(
|
||||
tenantSignTypes,
|
||||
docSignTypes
|
||||
);
|
||||
setSignatureType(updatedSignatureType);
|
||||
setActiveMailAdapter(res[0]?.active_mail_adapter);
|
||||
setSignerUserId(res[0].objectId);
|
||||
const tourstatus = res[0].TourStatus && res[0].TourStatus;
|
||||
@@ -920,15 +935,16 @@ function PlaceHolderSign() {
|
||||
|
||||
// `autosavedetails` is used to save doc details after every 2 sec when changes are happern in placeholder like drag-drop widgets, remove signers
|
||||
const autosavedetails = async () => {
|
||||
const signers = signersdata?.filter(
|
||||
(x) =>
|
||||
x?.Role !== "prefill" &&
|
||||
x.objectId && {
|
||||
const signers = signersdata?.reduce((acc, x) => {
|
||||
if (x.objectId) {
|
||||
acc.push({
|
||||
__type: "Pointer",
|
||||
className: "contracts_Contactbook",
|
||||
objectId: x.objectId
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
try {
|
||||
const docCls = new Parse.Object("contracts_Document");
|
||||
docCls.id = documentId;
|
||||
@@ -973,21 +989,15 @@ function PlaceHolderSign() {
|
||||
//filter label widgets after add label widgets data on pdf
|
||||
const filterPrefill = signerPos.filter((data) => data.Role !== "prefill");
|
||||
try {
|
||||
data = {
|
||||
Placeholders: filterPrefill,
|
||||
SignedUrl: pdfUrl,
|
||||
Signers: signers,
|
||||
SentToOthers: true,
|
||||
SignatureType: pdfDetails?.[0]?.SignatureType
|
||||
};
|
||||
if (updateExpiryDate) {
|
||||
data = {
|
||||
Placeholders: filterPrefill,
|
||||
SignedUrl: pdfUrl,
|
||||
Signers: signers,
|
||||
SentToOthers: true,
|
||||
ExpiryDate: { iso: updateExpiryDate, __type: "Date" }
|
||||
};
|
||||
} else {
|
||||
data = {
|
||||
Placeholders: filterPrefill,
|
||||
SignedUrl: pdfUrl,
|
||||
Signers: signers,
|
||||
SentToOthers: true
|
||||
};
|
||||
data["ExpiryDate"] = { iso: updateExpiryDate, __type: "Date" };
|
||||
}
|
||||
await axios
|
||||
.put(
|
||||
@@ -1429,7 +1439,15 @@ function PlaceHolderSign() {
|
||||
setFontSize();
|
||||
setFontColor();
|
||||
};
|
||||
const handleWidgetdefaultdata = (defaultdata) => {
|
||||
const handleWidgetdefaultdata = (defaultdata, isSignWidget) => {
|
||||
if (isSignWidget) {
|
||||
const updatedPdfDetails = [...pdfDetails];
|
||||
const signtypes = defaultdata.signatureType || signatureType;
|
||||
updatedPdfDetails[0].SignatureType = signtypes;
|
||||
// Update the SignatureType with the modified array
|
||||
setPdfDetails(updatedPdfDetails);
|
||||
setSignatureType(signtypes);
|
||||
}
|
||||
const options = ["email", "number", "text"];
|
||||
let inputype;
|
||||
if (defaultdata.textvalidate) {
|
||||
@@ -1550,14 +1568,12 @@ function PlaceHolderSign() {
|
||||
} else {
|
||||
updatedTourStatus = [{ placeholder: true }];
|
||||
}
|
||||
await axios
|
||||
.put(
|
||||
try {
|
||||
await axios.put(
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/contracts_Users/${signerUserId}`,
|
||||
{
|
||||
TourStatus: updatedTourStatus
|
||||
},
|
||||
{ TourStatus: updatedTourStatus },
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -1565,14 +1581,10 @@ function PlaceHolderSign() {
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
// const json = Listdata.data;
|
||||
// const res = json.results;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("axois err ", err);
|
||||
});
|
||||
);
|
||||
} catch (err) {
|
||||
console.log("axois err ", err);
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleRecipientSign = () => {
|
||||
@@ -2231,6 +2243,7 @@ function PlaceHolderSign() {
|
||||
signersData={signersdata}
|
||||
/>
|
||||
<WidgetNameModal
|
||||
signatureType={signatureType}
|
||||
widgetName={widgetName}
|
||||
defaultdata={currWidgetsDetails}
|
||||
isOpen={isNameModal}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Title from "../components/Title";
|
||||
import Alert from "../primitives/Alert";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Loader from "../primitives/Loader";
|
||||
import Tooltip from "../primitives/Tooltip";
|
||||
import {
|
||||
getTenantDetails,
|
||||
handleSignatureType,
|
||||
signatureTypes
|
||||
} from "../constant/Utils";
|
||||
import Parse from "parse";
|
||||
|
||||
const Preferences = () => {
|
||||
const { t } = useTranslation();
|
||||
const [isalert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||
const [isTopLoader, setIsTopLoader] = useState(false);
|
||||
const [isLoader, setIsLoader] = useState(false);
|
||||
const [signatureType, setSignatureType] = useState([]);
|
||||
const [errMsg, setErrMsg] = useState("");
|
||||
useEffect(() => {
|
||||
fetchSignType();
|
||||
}, []);
|
||||
|
||||
const fetchSignType = async () => {
|
||||
setIsTopLoader(true);
|
||||
try {
|
||||
const user = JSON.parse(
|
||||
localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
)
|
||||
);
|
||||
const tenantDetails = await getTenantDetails(user?.objectId);
|
||||
const signatureType = tenantDetails?.SignatureType || [];
|
||||
const tenantSignTypes = signatureType?.filter((x) => x.enabled === true);
|
||||
const getUser = await Parse.Cloud.run("getUserDetails");
|
||||
if (getUser) {
|
||||
const _getUser = JSON.parse(JSON.stringify(getUser));
|
||||
if (tenantSignTypes?.length > 0) {
|
||||
const signatureType = _getUser?.SignatureType || signatureTypes;
|
||||
const updatedSignatureType = await handleSignatureType(
|
||||
tenantSignTypes,
|
||||
signatureType
|
||||
);
|
||||
setSignatureType(updatedSignatureType);
|
||||
} else {
|
||||
const SignatureType = _getUser?.SignatureType || signatureTypes;
|
||||
setSignatureType(SignatureType);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err while getting user details", err);
|
||||
setErrMsg("Something went wrong");
|
||||
} finally {
|
||||
setIsTopLoader(false);
|
||||
}
|
||||
};
|
||||
console.log("sign", signatureType);
|
||||
const handleCheckboxChange = (index) => {
|
||||
// Create a copy of the signatureType array
|
||||
const updatedSignatureType = [...signatureType];
|
||||
// Toggle the enabled value for the clicked item
|
||||
updatedSignatureType[index].enabled = !updatedSignatureType[index].enabled;
|
||||
// Update the state with the modified array
|
||||
setSignatureType(updatedSignatureType);
|
||||
};
|
||||
const handleSave = async () => {
|
||||
console.log("submit", signatureType);
|
||||
setIsLoader(true);
|
||||
const isEnabled = signatureType.some((x) => x.enabled === true);
|
||||
if (isEnabled) {
|
||||
try {
|
||||
const params = { SignatureType: signatureType };
|
||||
const updateRes = await Parse.Cloud.run("updatesignaturetype", params);
|
||||
if (updateRes) {
|
||||
setIsAlert({ type: "danger", msg: "Saved successfully." });
|
||||
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err while updating signtype", err);
|
||||
} finally {
|
||||
setIsLoader(false);
|
||||
}
|
||||
} else {
|
||||
setIsAlert({
|
||||
type: "danger",
|
||||
msg: "please enable at least one signature type"
|
||||
});
|
||||
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
|
||||
setIsLoader(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Title title={"API Token"} />
|
||||
{isalert.msg && <Alert type={isalert.type}>{isalert.msg}</Alert>}
|
||||
{isTopLoader ? (
|
||||
<div className="flex justify-center items-center h-screen">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{errMsg ? (
|
||||
<div className="flex justify-center items-center h-screen">
|
||||
{errMsg}
|
||||
</div>
|
||||
) : (
|
||||
<div className="relative bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box mb-3">
|
||||
{isLoader && (
|
||||
<div className="flex justify-center items-center absolute w-full h-full rounded-box bg-black/30">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<h1 className="ml-4 mt-3 mb-2 font-semibold">
|
||||
OpenSign™ {t("Preferences")}{" "}
|
||||
<span>
|
||||
<Tooltip
|
||||
message={`OpenSign™ ${t("Preferences")}`}
|
||||
isSubscribe={true}
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
<div className="ml-4 mt-1 mb-2 flex flex-col">
|
||||
<div className="mb-[0.75rem]">
|
||||
<label
|
||||
htmlFor="signaturetype"
|
||||
className="text-[14px] mb-[0.7rem] font-medium"
|
||||
>
|
||||
Allowed signature types
|
||||
</label>
|
||||
<div className=" ml-[7px] flex flex-col md:flex-row gap-[10px] mb-[0.7rem]">
|
||||
{signatureType.map((type, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex flex-row gap-[5px] items-center"
|
||||
>
|
||||
<input
|
||||
className="mr-[2px] op-checkbox op-checkbox-xs"
|
||||
type="checkbox"
|
||||
name="signaturetype"
|
||||
onChange={() => handleCheckboxChange(i)}
|
||||
checked={type.enabled}
|
||||
/>
|
||||
<div
|
||||
className="text-[13px] font-medium hover:underline underline-offset-2 cursor-default"
|
||||
title={`Enabling this allow signers to ${type.name} signature`}
|
||||
>
|
||||
{/* {t(`widget-status.${data}`)} */}
|
||||
{type.name}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
className="op-btn op-btn-primary"
|
||||
onClick={handleSave}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
export default Preferences;
|
||||
@@ -36,7 +36,8 @@ import {
|
||||
getDefaultSignature,
|
||||
onClickZoomIn,
|
||||
onClickZoomOut,
|
||||
rotatePdfPage
|
||||
rotatePdfPage,
|
||||
signatureTypes
|
||||
} from "../constant/Utils";
|
||||
import { useParams } from "react-router-dom";
|
||||
import Tour from "reactour";
|
||||
@@ -1302,6 +1303,7 @@ function SignYourSelf() {
|
||||
/>
|
||||
{/* this is modal of signature pad */}
|
||||
<SignPad
|
||||
signatureTypes={signatureTypes}
|
||||
isSignPad={isSignPad}
|
||||
isStamp={isStamp}
|
||||
setIsImageSelect={setIsImageSelect}
|
||||
|
||||
@@ -30,7 +30,10 @@ import {
|
||||
onClickZoomIn,
|
||||
handleRemoveWidgets,
|
||||
handleRotateWarning,
|
||||
color
|
||||
color,
|
||||
signatureTypes,
|
||||
getTenantDetails,
|
||||
handleSignatureType
|
||||
} from "../constant/Utils";
|
||||
import RenderPdf from "../components/pdf/RenderPdf";
|
||||
import "../styles/AddUser.css";
|
||||
@@ -69,10 +72,7 @@ const TemplatePlaceholder = () => {
|
||||
const [isSendAlert, setIsSendAlert] = useState(false);
|
||||
const [isCreateDocModal, setIsCreateDocModal] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
const [isRotate, setIsRotate] = useState({
|
||||
status: false,
|
||||
degree: 0
|
||||
});
|
||||
const [isRotate, setIsRotate] = useState({ status: false, degree: 0 });
|
||||
const [isLoading, setIsLoading] = useState({
|
||||
isLoad: true,
|
||||
message: t("loading-mssg")
|
||||
@@ -107,32 +107,17 @@ const TemplatePlaceholder = () => {
|
||||
const [, drop] = useDrop({
|
||||
accept: "BOX",
|
||||
drop: (item, monitor) => addPositionOfSignature(item, monitor),
|
||||
collect: (monitor) => ({
|
||||
isOver: !!monitor.isOver()
|
||||
})
|
||||
collect: (monitor) => ({ isOver: !!monitor.isOver() })
|
||||
});
|
||||
const [{ isDragSign }, dragSignature] = useDrag({
|
||||
type: "BOX",
|
||||
item: {
|
||||
type: "BOX",
|
||||
id: 1,
|
||||
text: "signature"
|
||||
},
|
||||
collect: (monitor) => ({
|
||||
isDragSign: !!monitor.isDragging()
|
||||
})
|
||||
item: { type: "BOX", id: 1, text: "signature" },
|
||||
collect: (monitor) => ({ isDragSign: !!monitor.isDragging() })
|
||||
});
|
||||
const [{ isDragStamp }, dragStamp] = useDrag({
|
||||
type: "BOX",
|
||||
|
||||
item: {
|
||||
type: "BOX",
|
||||
id: 2,
|
||||
text: "stamp"
|
||||
},
|
||||
collect: (monitor) => ({
|
||||
isDragStamp: !!monitor.isDragging()
|
||||
})
|
||||
item: { type: "BOX", id: 2, text: "stamp" },
|
||||
collect: (monitor) => ({ isDragStamp: !!monitor.isDragging() })
|
||||
});
|
||||
const [uniqueId, setUniqueId] = useState("");
|
||||
const [isModalRole, setIsModalRole] = useState(false);
|
||||
@@ -153,6 +138,7 @@ const TemplatePlaceholder = () => {
|
||||
const [fontColor, setFontColor] = useState();
|
||||
const [zoomPercent, setZoomPercent] = useState(0);
|
||||
const [scale, setScale] = useState(1);
|
||||
const [signatureType, setSignatureType] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchTemplate();
|
||||
@@ -200,9 +186,38 @@ const TemplatePlaceholder = () => {
|
||||
handleNavigation(plan);
|
||||
}
|
||||
}
|
||||
|
||||
//function to fetch tenant Details
|
||||
const fetchTenantDetails = async () => {
|
||||
const user = JSON.parse(
|
||||
localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
)
|
||||
);
|
||||
if (user) {
|
||||
try {
|
||||
const tenantDetails = await getTenantDetails(user?.objectId);
|
||||
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||
alert(t("user-not-exist"));
|
||||
} else if (tenantDetails) {
|
||||
const signatureType = tenantDetails?.SignatureType || [];
|
||||
const filterSignTypes = signatureType?.filter(
|
||||
(x) => x.enabled === true
|
||||
);
|
||||
return filterSignTypes;
|
||||
}
|
||||
} catch (e) {
|
||||
alert(t("user-not-exist"));
|
||||
}
|
||||
} else {
|
||||
alert(t("user-not-exist"));
|
||||
}
|
||||
};
|
||||
|
||||
// `fetchTemplate` function in used to get Template from server and setPlaceholder ,setSigner if present
|
||||
const fetchTemplate = async () => {
|
||||
try {
|
||||
const tenantSignTypes = await fetchTenantDetails();
|
||||
const params = { templateId: templateId };
|
||||
const templateDeatils = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}functions/getTemplate`,
|
||||
@@ -221,6 +236,12 @@ const TemplatePlaceholder = () => {
|
||||
: [];
|
||||
|
||||
if (documentData && documentData.length > 0) {
|
||||
const docSignTypes = documentData?.[0]?.SignatureType || signatureTypes;
|
||||
const updatedSignatureType = await handleSignatureType(
|
||||
tenantSignTypes,
|
||||
docSignTypes
|
||||
);
|
||||
setSignatureType(updatedSignatureType);
|
||||
if (isEnableSubscription) {
|
||||
checkIsSubscribed(documentData[0]?.ExtUserPtr?.Email);
|
||||
}
|
||||
@@ -247,11 +268,7 @@ const TemplatePlaceholder = () => {
|
||||
blockColor: x.blockColor
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
Role: x.Role,
|
||||
Id: x.Id,
|
||||
blockColor: x.blockColor
|
||||
};
|
||||
return { Role: x.Role, Id: x.Id, blockColor: x.blockColor };
|
||||
}
|
||||
});
|
||||
setSignersData(updatedSigners);
|
||||
@@ -274,11 +291,7 @@ const TemplatePlaceholder = () => {
|
||||
documentData[0].Placeholders.length > 0
|
||||
) {
|
||||
let updatedSigners = documentData[0].Placeholders.map((x) => {
|
||||
return {
|
||||
Role: x.Role,
|
||||
Id: x.Id,
|
||||
blockColor: x.blockColor
|
||||
};
|
||||
return { Role: x.Role, Id: x.Id, blockColor: x.blockColor };
|
||||
});
|
||||
setSignerPos(documentData[0].Placeholders);
|
||||
setUniqueId(updatedSigners[0].Id);
|
||||
@@ -291,17 +304,41 @@ const TemplatePlaceholder = () => {
|
||||
documentData === "Error: Something went wrong!" ||
|
||||
(documentData.result && documentData.result.error)
|
||||
) {
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
setIsLoading(loadObj);
|
||||
setIsLoading({ isLoad: false });
|
||||
} else {
|
||||
setHandleError(t("no-data-avaliable"));
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
setIsLoading({ isLoad: false });
|
||||
}
|
||||
const res = await contractUsers();
|
||||
if (res[0] && res.length) {
|
||||
const userSignatureType = res[0]?.SignatureType || signatureTypes;
|
||||
const docSignTypes =
|
||||
documentData?.[0]?.SignatureType || userSignatureType;
|
||||
const updatedSignatureType = await handleSignatureType(
|
||||
tenantSignTypes,
|
||||
docSignTypes
|
||||
);
|
||||
setSignatureType(updatedSignatureType);
|
||||
setSignerUserId(res[0].objectId);
|
||||
setCurrentEmail(res[0].Email);
|
||||
const tourstatus = res[0].TourStatus && res[0].TourStatus;
|
||||
if (tourstatus && tourstatus.length > 0) {
|
||||
setTourStatus(tourstatus);
|
||||
const checkTourRecipients = tourstatus.filter(
|
||||
(data) => data.templateTour
|
||||
);
|
||||
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
||||
setCheckTourStatus(checkTourRecipients[0].templateTour);
|
||||
}
|
||||
}
|
||||
setIsLoading({ isLoad: false });
|
||||
} else if (res === "Error: Something went wrong!") {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
setIsLoading({ isLoad: false });
|
||||
} else if (res.length === 0) {
|
||||
setHandleError(t("no-data-avaliable"));
|
||||
setIsLoading({ isLoad: false });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err ", err);
|
||||
@@ -311,37 +348,6 @@ const TemplatePlaceholder = () => {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
}
|
||||
}
|
||||
const res = await contractUsers();
|
||||
if (res[0] && res.length) {
|
||||
setSignerUserId(res[0].objectId);
|
||||
setCurrentEmail(res[0].Email);
|
||||
const tourstatus = res[0].TourStatus && res[0].TourStatus;
|
||||
if (tourstatus && tourstatus.length > 0) {
|
||||
setTourStatus(tourstatus);
|
||||
const checkTourRecipients = tourstatus.filter(
|
||||
(data) => data.templateTour
|
||||
);
|
||||
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
||||
setCheckTourStatus(checkTourRecipients[0].templateTour);
|
||||
}
|
||||
}
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
} else if (res === "Error: Something went wrong!") {
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
setIsLoading(loadObj);
|
||||
} else if (res.length === 0) {
|
||||
setHandleError(t("no-data-avaliable"));
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
}
|
||||
};
|
||||
|
||||
//function for setting position after drop signature button over pdf
|
||||
@@ -389,10 +395,7 @@ const TemplatePlaceholder = () => {
|
||||
Height: widgetHeight / (containerScale * scale)
|
||||
};
|
||||
dropData.push(dropObj);
|
||||
placeHolder = {
|
||||
pageNumber: pageNumber,
|
||||
pos: dropData
|
||||
};
|
||||
placeHolder = { pageNumber: pageNumber, pos: dropData };
|
||||
} else {
|
||||
const offset = monitor.getClientOffset();
|
||||
//adding and updating drop position in array when user drop signature button in div
|
||||
@@ -423,10 +426,7 @@ const TemplatePlaceholder = () => {
|
||||
};
|
||||
|
||||
dropData.push(dropObj);
|
||||
placeHolder = {
|
||||
pageNumber: pageNumber,
|
||||
pos: dropData
|
||||
};
|
||||
placeHolder = { pageNumber: pageNumber, pos: dropData };
|
||||
}
|
||||
let filterSignerPos = signerPos.find((data) => data.Id === uniqueId);
|
||||
const getPlaceHolder = filterSignerPos?.placeHolder;
|
||||
@@ -443,10 +443,7 @@ const TemplatePlaceholder = () => {
|
||||
);
|
||||
const getPos = currentPagePosition?.pos;
|
||||
const newSignPos = getPos.concat(dropData);
|
||||
let xyPos = {
|
||||
pageNumber: pageNumber,
|
||||
pos: newSignPos
|
||||
};
|
||||
let xyPos = { pageNumber: pageNumber, pos: newSignPos };
|
||||
updatePlace.push(xyPos);
|
||||
const updatesignerPos = signerPos.map((x) =>
|
||||
x.Id === uniqueId ? { ...x, placeHolder: updatePlace } : x
|
||||
@@ -482,7 +479,6 @@ const TemplatePlaceholder = () => {
|
||||
setWidgetType(dragTypeValue);
|
||||
setSignKey(key);
|
||||
setSelectWidgetId(key);
|
||||
|
||||
setIsMailSend(false);
|
||||
} else {
|
||||
setIsReceipent(false);
|
||||
@@ -581,9 +577,7 @@ const TemplatePlaceholder = () => {
|
||||
}
|
||||
}
|
||||
setIsMailSend(false);
|
||||
setTimeout(() => {
|
||||
setIsDragging(false);
|
||||
}, 200);
|
||||
setTimeout(() => setIsDragging(false), 200);
|
||||
};
|
||||
//function for delete signature block
|
||||
const handleDeleteSign = (key, Id) => {
|
||||
@@ -729,8 +723,7 @@ const TemplatePlaceholder = () => {
|
||||
|
||||
const handleSaveTemplate = async () => {
|
||||
if (signersdata?.length) {
|
||||
const loadObj = { isLoad: true, message: t("loading-mssg") };
|
||||
setIsLoading(loadObj);
|
||||
setIsLoading({ isLoad: true, message: t("loading-mssg") });
|
||||
setIsSendAlert(false);
|
||||
let signers = [];
|
||||
if (signersdata?.length > 0) {
|
||||
@@ -769,7 +762,8 @@ const TemplatePlaceholder = () => {
|
||||
NextReminderDate: pdfDetails[0]?.NextReminderDate,
|
||||
IsEnableOTP: pdfDetails[0]?.IsEnableOTP === true ? true : false,
|
||||
IsTourEnabled: pdfDetails[0]?.IsTourEnabled === true ? true : false,
|
||||
URL: pdfUrl
|
||||
URL: pdfUrl,
|
||||
SignatureType: signatureType
|
||||
};
|
||||
const updateTemplate = new Parse.Object("contracts_Template");
|
||||
updateTemplate.id = templateId;
|
||||
@@ -878,9 +872,7 @@ const TemplatePlaceholder = () => {
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/contracts_Users/${signerUserId}`,
|
||||
{
|
||||
TourStatus: updatedTourStatus
|
||||
},
|
||||
{ TourStatus: updatedTourStatus },
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -1214,7 +1206,15 @@ const TemplatePlaceholder = () => {
|
||||
setFontColor();
|
||||
};
|
||||
|
||||
const handleWidgetdefaultdata = (defaultdata) => {
|
||||
const handleWidgetdefaultdata = (defaultdata, isSignWidget) => {
|
||||
if (isSignWidget) {
|
||||
const updatedPdfDetails = [...pdfDetails];
|
||||
const signtypes = defaultdata.signatureType || signatureType;
|
||||
updatedPdfDetails[0].SignatureType = signtypes;
|
||||
// Update the SignatureType with the modified array
|
||||
setPdfDetails(updatedPdfDetails);
|
||||
setSignatureType(signtypes);
|
||||
}
|
||||
const options = ["email", "number", "text"];
|
||||
let inputype;
|
||||
if (defaultdata.textvalidate) {
|
||||
@@ -1710,6 +1710,7 @@ const TemplatePlaceholder = () => {
|
||||
/>
|
||||
</ModalUi>
|
||||
<WidgetNameModal
|
||||
signatureType={signatureType}
|
||||
widgetName={widgetName}
|
||||
defaultdata={currWidgetsDetails}
|
||||
isOpen={isNameModal}
|
||||
|
||||
@@ -15,7 +15,10 @@ import {
|
||||
copytoData,
|
||||
fetchUrl,
|
||||
getSignedUrl,
|
||||
replaceMailVaribles
|
||||
getTenantDetails,
|
||||
handleSignatureType,
|
||||
replaceMailVaribles,
|
||||
signatureTypes
|
||||
} from "../constant/Utils";
|
||||
import Confetti from "react-confetti";
|
||||
import EditorToolbar, {
|
||||
@@ -77,6 +80,7 @@ const ReportTable = (props) => {
|
||||
const [isDownloadModal, setIsDownloadModal] = useState(false);
|
||||
const [isEmbed, setIsEmbed] = useState(false);
|
||||
const [isPublicTour, setIsPublicTour] = useState();
|
||||
const [signatureType, setSignatureType] = useState([]);
|
||||
const Extand_Class = localStorage.getItem("Extand_Class");
|
||||
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
||||
const startIndex = (currentPage - 1) * props.docPerPage;
|
||||
@@ -195,6 +199,33 @@ const ReportTable = (props) => {
|
||||
}
|
||||
}, [isMoreDocs, pageNumbers, currentPage, setIsNextRecord]);
|
||||
|
||||
//function to fetch tenant Details
|
||||
const fetchTenantDetails = async () => {
|
||||
const user = JSON.parse(
|
||||
localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
)
|
||||
);
|
||||
if (user) {
|
||||
try {
|
||||
const tenantDetails = await getTenantDetails(user?.objectId);
|
||||
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||
alert(t("user-not-exist"));
|
||||
} else if (tenantDetails) {
|
||||
const signatureType = tenantDetails?.SignatureType || [];
|
||||
const filterSignTypes = signatureType?.filter(
|
||||
(x) => x.enabled === true
|
||||
);
|
||||
return filterSignTypes;
|
||||
}
|
||||
} catch (e) {
|
||||
alert(t("user-not-exist"));
|
||||
}
|
||||
} else {
|
||||
alert(t("user-not-exist"));
|
||||
}
|
||||
};
|
||||
|
||||
// `handleURL` is used to open microapp
|
||||
const handleURL = async (item, act) => {
|
||||
if (props.ReportName === "Templates") {
|
||||
@@ -203,9 +234,7 @@ const ReportTable = (props) => {
|
||||
} else {
|
||||
setActLoader({ [`${item.objectId}_${act.btnId}`]: true });
|
||||
try {
|
||||
const params = {
|
||||
templateId: item.objectId
|
||||
};
|
||||
const params = { templateId: item.objectId };
|
||||
const templateDeatils = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}functions/getTemplate`,
|
||||
params,
|
||||
@@ -249,6 +278,16 @@ const ReportTable = (props) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
const tenantSignTypes = await fetchTenantDetails();
|
||||
const docSignTypes = Doc?.SignatureType || signatureTypes;
|
||||
const updatedSignatureType = await handleSignatureType(
|
||||
tenantSignTypes,
|
||||
docSignTypes
|
||||
);
|
||||
const SignatureType =
|
||||
updatedSignatureType.length > 0
|
||||
? { SignatureType: updatedSignatureType }
|
||||
: {};
|
||||
let placeholdersArr = [];
|
||||
if (Doc.Placeholders?.length > 0) {
|
||||
placeholdersArr = Doc.Placeholders;
|
||||
@@ -275,7 +314,8 @@ const ReportTable = (props) => {
|
||||
AutomaticReminders: Doc?.AutomaticReminders || false,
|
||||
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5,
|
||||
IsEnableOTP: Doc?.IsEnableOTP || false,
|
||||
FileAdapterId: Doc?.FileAdapterId || ""
|
||||
FileAdapterId: Doc?.FileAdapterId || "",
|
||||
...SignatureType
|
||||
};
|
||||
try {
|
||||
const res = await axios.post(
|
||||
@@ -910,6 +950,13 @@ const ReportTable = (props) => {
|
||||
}
|
||||
);
|
||||
const templateRes = axiosRes.data && axiosRes.data.result;
|
||||
const tenantSignTypes = await fetchTenantDetails();
|
||||
const docSignTypes = templateRes?.SignatureType || signatureTypes;
|
||||
const updatedSignatureType = await handleSignatureType(
|
||||
tenantSignTypes,
|
||||
docSignTypes
|
||||
);
|
||||
setSignatureType(updatedSignatureType);
|
||||
setPlaceholders(templateRes?.Placeholders);
|
||||
setTemplateDetails(templateRes);
|
||||
setIsLoader({});
|
||||
@@ -1933,6 +1980,7 @@ const ReportTable = (props) => {
|
||||
Placeholders={placeholders}
|
||||
item={templateDeatils}
|
||||
handleClose={handleQuickSendClose}
|
||||
signatureType={signatureType}
|
||||
/>
|
||||
)}
|
||||
</ModalUi>
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
"My Signature": "My Signature",
|
||||
"API Token": "API Token",
|
||||
"Webhook": "Webhook",
|
||||
"Preferences": "Preferences",
|
||||
"Teams": "Teams",
|
||||
"Team-update-successfully": "Team Updated successfully.",
|
||||
"Users": "Users"
|
||||
@@ -683,7 +684,8 @@
|
||||
"public-tour-message": "The template needs to be public before you can generate a shareable link.",
|
||||
"add-user-template": "You need to add a role before you can add fields for it.",
|
||||
"pdf-uncompatible": "This pdf is not compatible with opensign, please contact <support@opensignlabs.com>",
|
||||
"text-field-tour":"Fields of type 'Text' must be filled in advance before the document is sent. If you need the signers to provide input, use the 'Text Input' field instead.",
|
||||
"attach-signer-tour":"You need to attach a Signer to every role. You can do that by clicking this icon. Once you select a Signer it will be attached to all the fields associated with that role which appear in the same colour."
|
||||
|
||||
"text-field-tour": "Fields of type 'Text' must be filled in advance before the document is sent. If you need the signers to provide input, use the 'Text Input' field instead.",
|
||||
"attach-signer-tour": "You need to attach a Signer to every role. You can do that by clicking this icon. Once you select a Signer it will be attached to all the fields associated with that role which appear in the same colour.",
|
||||
"allowed-signature-types": "Allowed signature types",
|
||||
"at-least-one-signature-type": "At least one signature type should be enabled."
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
"My Signature": "Mi firma",
|
||||
"API Token": "Token API",
|
||||
"Webhook": "Webhook",
|
||||
"Preferences": "Preferencias",
|
||||
"Teams": "Equipos",
|
||||
"Team-update-successfully": "Equipo actualizado correctamente.",
|
||||
"Users": "Usuarios"
|
||||
@@ -676,13 +677,15 @@
|
||||
"add-user-template": "Es necesario agregar un rol antes de poder agregarle campos.",
|
||||
"pdf-uncompatible": "Este pdf no es compatible con opensign, comuníquese con <support@opensignlabs.com>",
|
||||
"enable-tour": "Habilitar recorrido",
|
||||
"istourenabled-help":{
|
||||
"istourenabled-help": {
|
||||
"p1": "Esto permitirá realizar una visita guiada para los firmantes, brindando instrucciones durante el proceso de firma.",
|
||||
"p2": "Esto desactivará la visita guiada, lo que garantizará una experiencia de firma más rápida e ininterrumpida.",
|
||||
"p3": "Consejo: si sus firmantes están familiarizados con OpenSign y lo utilizan con frecuencia, es posible que desee desactivar la visita guiada para disfrutar de una experiencia más fluida. Elija la opción que mejor se adapte a sus necesidades de firma de documentos"
|
||||
},
|
||||
"form-title-1": "Configuración del flujo de documentos",
|
||||
"form-title-2": "Configuración de seguridad",
|
||||
"text-field-tour":"Los campos de tipo 'Texto' deben completarse con anticipación antes de enviar el documento. Si necesita que los firmantes proporcionen información, utilice el campo 'Entrada de texto'",
|
||||
"attach-signer-tour" :"Debe adjuntar un firmante a cada función. Puede hacerlo haciendo clic en este icono. Una vez que seleccione un Firmante, se adjuntará a todos los campos asociados con ese rol que aparecen en el mismo color."
|
||||
"text-field-tour": "Los campos de tipo 'Texto' deben completarse con anticipación antes de enviar el documento. Si necesita que los firmantes proporcionen información, utilice el campo 'Entrada de texto'",
|
||||
"attach-signer-tour": "Debe adjuntar un firmante a cada función. Puede hacerlo haciendo clic en este icono. Una vez que seleccione un Firmante, se adjuntará a todos los campos asociados con ese rol que aparecen en el mismo color.",
|
||||
"allowed-signature-types": "Tipos de firma permitidos",
|
||||
"at-least-one-signature-type": "Se debe habilitar al menos un tipo de firma."
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
"My Signature": "Ma signature",
|
||||
"API Token": "Jeton API",
|
||||
"Webhook": "Webhook",
|
||||
"Preferences": "Préférences",
|
||||
"Teams": "Équipe",
|
||||
"Team-update-successfully": "Équipe mise à jour avec succès.",
|
||||
"Users": "Utilisateurs"
|
||||
@@ -672,16 +673,18 @@
|
||||
"server-down": "Impossible de se connecter au serveur OpenSign. Si vous hébergez vous-même OpenSign, veuillez vous assurer que toutes les étapes de la documentation ont été correctement suivies. Si vous exécutez OpenSign localement, vous y accédez peut-être via un numéro de port incorrect.",
|
||||
"admin-exists": "L'administrateur existe déjà. Veuillez vous connecter à l'application en utilisant les informations d'identification de l'administrateur afin de gérer les utilisateurs.",
|
||||
"enable-tour": "Activer la visite",
|
||||
"istourenabled-otp-help":{
|
||||
"istourenabled-otp-help": {
|
||||
"p1": "Cela permettra une visite guidée pour les signataires, fournissant des instructions pendant le processus de signature.",
|
||||
"p2": "Cela désactivera la visite guidée, garantissant ainsi une expérience de signature plus rapide et ininterrompue.",
|
||||
"p3": "Conseil : si vos signataires connaissent OpenSign et l'utilisent fréquemment, vous souhaiterez peut-être désactiver la visite guidée pour une expérience plus fluide. Choisissez l'option qui correspond le mieux à vos besoins en matière de signature de documents."
|
||||
"p3": "Conseil : si vos signataires connaissent OpenSign et l'utilisent fréquemment, vous souhaiterez peut-être désactiver la visite guidée pour une expérience plus fluide. Choisissez l'option qui correspond le mieux à vos besoins en matière de signature de documents."
|
||||
},
|
||||
"form-title-1": "Paramètre du flux de documents",
|
||||
"form-title-2": "Paramètre de sécurité",
|
||||
"public-tour-message": "Le modèle doit être public avant que vous puissiez générer un lien partageable.",
|
||||
"add-user-template": "Vous devez ajouter un rôle avant de pouvoir lui ajouter des champs. ",
|
||||
"pdf-uncompatible": "Ce pdf n'est pas compatible avec opensign, veuillez contacter <support@opensignlabs.com>",
|
||||
"text-field-tour" :"Les champs de type 'Texte' doivent être remplis à l'avance avant l'envoi du document. Si vous avez besoin que les signataires fournissent des informations, utilisez plutôt le champ 'Saisie de texte'.",
|
||||
"attach-signer-tour" :"Vous devez associer un signataire à chaque rôle. Vous pouvez le faire en cliquant sur cette icône. Une fois que vous avez sélectionné un signataire, il sera attaché à tous les champs associés à ce rôle qui apparaissent dans la même couleur."
|
||||
"text-field-tour": "Les champs de type 'Texte' doivent être remplis à l'avance avant l'envoi du document. Si vous avez besoin que les signataires fournissent des informations, utilisez plutôt le champ 'Saisie de texte'.",
|
||||
"attach-signer-tour": "Vous devez associer un signataire à chaque rôle. Vous pouvez le faire en cliquant sur cette icône. Une fois que vous avez sélectionné un signataire, il sera attaché à tous les champs associés à ce rôle qui apparaissent dans la même couleur.",
|
||||
"allowed-signature-types": "Types de signature autorisés",
|
||||
"at-least-one-signature-type": "Au moins un type de signature doit être activé."
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ import isUserInContactBook from './parsefunction/isUserInContactBook.js';
|
||||
import updateTourStatus from './parsefunction/updateTourStatus.js';
|
||||
import saveTemplate from './parsefunction/saveTemplate.js';
|
||||
import updateToPublicTemplate from './parsefunction/updateToPublicTemplate.js';
|
||||
import updateSignatureType from './parsefunction/updatesignaturetype.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);
|
||||
@@ -178,3 +179,4 @@ Parse.Cloud.define('savecontact', savecontact);
|
||||
Parse.Cloud.define('isuserincontactbook', isUserInContactBook);
|
||||
Parse.Cloud.define('updatetourstatus', updateTourStatus);
|
||||
Parse.Cloud.define('updatetopublictemplate', updateToPublicTemplate);
|
||||
Parse.Cloud.define('updatesignaturetype', updateSignatureType);
|
||||
|
||||
@@ -82,6 +82,7 @@ export default async function GetTemplate(request) {
|
||||
template.include('Signers');
|
||||
template.include('CreatedBy');
|
||||
template.include('ExtUserPtr.TenantId');
|
||||
template.include('Placeholders.signerPtr');
|
||||
}
|
||||
}
|
||||
const res = await template.first({ useMasterKey: true });
|
||||
|
||||
@@ -251,6 +251,7 @@ async function batchQuery(userId, Documents, Ip, parseConfig) {
|
||||
IsEnableOTP: x?.IsEnableOTP || false,
|
||||
IsTourEnabled: x?.IsTourEnabled || false,
|
||||
FileAdapterId: x?.FileAdapterId || '',
|
||||
...(x?.SignatureType ? { SignatureType: x?.SignatureType } : {}),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
export default async function updateSignatureType(request) {
|
||||
if (!request?.user) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||
}
|
||||
const SignatureType = request.params.SignatureType || [];
|
||||
if (SignatureType.length > 0) {
|
||||
const isEnabled = SignatureType.some(x => x.enabled === true);
|
||||
if (isEnabled) {
|
||||
try {
|
||||
const orgQuery = new Parse.Query('contracts_Users');
|
||||
orgQuery.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: request.user.id,
|
||||
});
|
||||
const resUser = await orgQuery.first({ useMasterKey: true });
|
||||
if (resUser) {
|
||||
const newOrg = new Parse.Object('contracts_Users');
|
||||
newOrg.id = resUser.id;
|
||||
newOrg.set('SignatureType', SignatureType);
|
||||
const updateUserRes = await newOrg.save(null, { useMasterKey: true });
|
||||
if (updateUserRes) {
|
||||
const _updateUserRes = JSON.parse(JSON.stringify(updateUserRes));
|
||||
return _updateUserRes;
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Premission denied.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in addorganization', err);
|
||||
const code = err?.code || 400;
|
||||
const msg = err?.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_QUERY,
|
||||
'At least one signature type should be enabled.'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide signature types.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
*
|
||||
* @param {Parse} Parse
|
||||
*/
|
||||
exports.up = async Parse => {
|
||||
const docSchema = new Parse.Schema('contracts_Document');
|
||||
docSchema.addArray('SignatureType');
|
||||
await docSchema.update();
|
||||
|
||||
const templateSchema = new Parse.Schema('contracts_Template');
|
||||
templateSchema.addArray('SignatureType');
|
||||
await templateSchema.update();
|
||||
|
||||
const extUserSchema = new Parse.Schema('contracts_Users');
|
||||
extUserSchema.addArray('SignatureType');
|
||||
await extUserSchema.update();
|
||||
|
||||
const tenantSchema = new Parse.Schema('partners_Tenant');
|
||||
tenantSchema.addArray('SignatureType');
|
||||
return tenantSchema.update();
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Parse} Parse
|
||||
*/
|
||||
exports.down = async Parse => {
|
||||
const docSchema = new Parse.Schema('contracts_Document');
|
||||
docSchema.deleteField('SignatureType');
|
||||
await docSchema.update();
|
||||
|
||||
const templateSchema = new Parse.Schema('contracts_Template');
|
||||
docSchema.deleteField('SignatureType');
|
||||
await templateSchema.update();
|
||||
|
||||
const extUserSchema = new Parse.Schema('contracts_Users');
|
||||
docSchema.deleteField('SignatureType');
|
||||
await extUserSchema.update();
|
||||
|
||||
const tenantSchema = new Parse.Schema('partners_Tenant');
|
||||
docSchema.deleteField('SignatureType');
|
||||
return tenantSchema.update();
|
||||
};
|
||||
Reference in New Issue
Block a user