Merge pull request #1573 from OpenSignLabs/updates-13306452314

v2.13.0
This commit is contained in:
prafull-opensignlabs
2025-02-13 16:54:14 +05:30
committed by GitHub
17 changed files with 1375 additions and 581 deletions
+1228 -442
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -10,6 +10,7 @@
"@react-pdf/renderer": "^4.1.6",
"@reduxjs/toolkit": "^2.5.1",
"axios": "^1.7.9",
"css-minimizer-webpack-plugin": "^7.0.0",
"file-saver": "^2.0.5",
"i18next": "^23.16.8",
"i18next-browser-languagedetector": "^8.0.2",
@@ -101,7 +102,6 @@
"@babel/runtime-corejs2": "^7.26.7",
"autoprefixer": "^10.4.20",
"babel-loader": "^9.2.1",
"clean-webpack-plugin": "^4.0.0",
"commitizen": "^4.3.1",
"concurrently": "^9.1.2",
"css-loader": "^7.1.2",
@@ -666,11 +666,11 @@
"insufficient-credits": "Nicht genügend Signatur-Credits",
"insufficient-credits-mssg": "Der Besitzer dieses Dokuments verfügt derzeit nicht über die notwendigen OpenSign-Credits, damit Sie unterzeichnen können. Bitte wenden Sie sich an den Besitzer, wenn Sie weitere Informationen benötigen.",
"angular-npm-mssg-1": "Um OpenSign in Ihr Angular-Projekt zu integrieren, führen Sie einfach den folgenden Befehl aus:",
"quota-mail-info-head": "Monatliches Limit für Signaturanfragen per E-Mail",
"quota-mail-info": "Sie können bis zu 15 Signaturanfragen per E-Mail pro Monat senden. Jetzt upgraden, um unbegrenzt Signaturanfragen direkt zu senden.",
"quota-mail-info-head": "Monatliches E-Mail-Limit",
"quota-mail-info": "Um die Servicequalität aufrechtzuerhalten und Spam zu verhindern, erlaubt OpenSign bis zu 15 E-Mails pro Monat im kostenlosen Plan. Upgraden Sie jetzt für unbegrenzten E-Mail-Versand.",
"quota-mail-reset": "Ihre Credits für Signaturanfragen per E-Mail werden zurückgesetzt am",
"quota-mail": "Sie haben Ihr monatliches Limit von 15 Signaturanfragen per E-Mail erreicht. Jetzt upgraden, um weiter E-Mails direkt zu senden.",
"quota-mail-tip": "Tipp: Sie können weiterhin <1>unbegrenzt Dokumente</1> signieren, indem Sie die Signaturanfragelinks manuell teilen.",
"quota-mail-tip": "Tipp: Sie können weiterhin <1>unbegrenzt Dokumente</1> signieren, indem Sie den Signaturanfragelink manuell teilen.",
"quota-mail-head": "Kontingent erreicht",
"unauthorized-modal": "Sie haben keine Berechtigung, diese Aktion auszuführen. Bitte kontaktieren Sie {{adminEmail}}.",
"sent-this-month": "Diesen Monat gesendet",
@@ -667,11 +667,11 @@
"insufficient-credits": "Insufficient signing credits",
"insufficient-credits-mssg": "The owner of this document currently lacks the necessary OpenSign credits for you to sign. Please reach out to the owner if you require further details.",
"angular-npm-mssg-1": "To integrate OpenSign into your Angular project, simply run the following command:",
"quota-mail-info-head": "Monthly request signatures email limit",
"quota-mail-info": "You can send upto 15 signature request emails every month. Upgrade now to send unlimited signing requests directly.",
"quota-mail-info-head": "Monthly Email Limit",
"quota-mail-info": "To maintain service quality and prevent spam, OpenSign allows up to 15 emails per month on the free plan. Upgrade now for unlimited email sending.",
"quota-mail-reset": "Your signature request email credits will be reset on",
"quota-mail": "You've reached your limit of 15 signature request emails for this month. Upgrade now to continue sending emails directly.",
"quota-mail-tip": "Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.",
"quota-mail-tip": "Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request link.",
"quota-mail-head": "Quota reached",
"unauthorized-modal": "You don't have permission to perform this action, please contact {{adminEmail}}.",
"sent-this-month": "Sent this month",
@@ -667,11 +667,11 @@
"insufficient-credits": "Créditos de firma insuficientes",
"insufficient-credits-mssg": "El propietario de este documento actualmente carece de los créditos OpenSign necesarios para que puedas firmarlo. Por favor, contacta al propietario si necesitas más detalles.",
"angular-npm-mssg-1": "Para integrar OpenSign a tu proyecto Angular, simplemente ejecuta los siguientes comandos:",
"quota-mail-info-head": "Límite mensual de solicitudes de firma por correo",
"quota-mail-info": "Puedes enviar hasta 15 solicitudes de firma por correo cada mes. Mejora ahora para enviar solicitudes de firma sin límite.",
"quota-mail-info-head": "Límite mensual de correos electrónicos",
"quota-mail-info": "Para mantener la calidad del servicio y prevenir el spam, OpenSign permite hasta 15 correos electrónicos por mes en el plan gratuito. Mejora tu plan ahora para envíos ilimitados de correos electrónicos.",
"quota-mail-reset": "Los créditos de tu correo electrónico de solicitud de firma se restablecerán el",
"quota-mail": "Has alcanzado tu límite de 15 solicitudes de firma por correo para este mes. Mejora ahora para continuar enviando correos.",
"quota-mail-tip": "Consejo: Todavía puedes solciitar la firma de <1>documentos ilimitados</1> compartiendo manualmente los enlaces de solicitud de firma.",
"quota-mail-tip": "Consejo: Aún puedes firmar <1>documentos ilimitados</1> compartiendo manualmente el enlace de solicitud de firma.",
"quota-mail-head": "Cuota alcanzada",
"unauthorized-modal": "No tienes permisos para realizar esta acción, por favor, contacta a {{adminEmail}}.",
"sent-this-month": "Enviados este mes",
@@ -666,11 +666,11 @@
"insufficient-credits": "Crédits de signature insuffisants",
"insufficient-credits-mssg": "Le propriétaire de ce document ne dispose actuellement pas des crédits OpenSign nécessaires pour que vous puissiez le signer. Veuillez contacter le propriétaire si vous avez besoin de plus de détails.",
"angular-npm-mssg-1": "Pour intégrer OpenSign dans votre projet Angular, exécutez simplement la commande suivante :",
"quota-mail-info-head": "Limite mensuelle d'e-mails de signatures de demandes",
"quota-mail-info": "Vous pouvez envoyer jusqu'à 15 e-mails de demande de signature chaque mois. Mettez à niveau maintenant pour envoyer directement des demandes de signature illimitées.",
"quota-mail-info-head": "Limite mensuelle d'e-mails",
"quota-mail-info": "Pour maintenir la qualité du service et prévenir le spam, OpenSign permet jusqu'à 15 e-mails par mois avec le plan gratuit. Passez à l'offre supérieure pour un envoi illimité d'e-mails.",
"quota-mail-reset": "Les crédits de votre email de demande de signature seront réinitialisés le",
"quota-mail": "Vous avez atteint votre limite de 15 e-mails de demande de signature pour ce mois. Mettez à niveau maintenant pour continuer à envoyer des e-mails directement.",
"quota-mail-tip-tip": "Astuce : Vous pouvez toujours signer un nombre <1>illimité de documents</1> en partageant manuellement les liens de demande de signature.",
"quota-mail-tip-tip": "Astuce: Vous pouvez toujours signer un nombre <1>illimité de documents</1> en partageant manuellement le lien de demande de signature.",
"quota-mail-head": "Quota atteint",
"unauthorized-modal": "Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminEmail}}.",
"sent-this-month": "envoyé ce mois-ci",
@@ -666,11 +666,11 @@
"insufficient-credits": "Crediti di firma insufficienti",
"insufficient-credits-mssg": "Il proprietario di questo documento non dispone attualmente dei crediti OpenSign necessari affinché tu possa firmare. Contatta il proprietario per ulteriori dettagli.",
"angular-npm-mssg-1": "Per integrare OpenSign nel tuo progetto Angular, esegui semplicemente il seguente comando:",
"quota-mail-info-head": "Limite mensile email per richieste di firma",
"quota-mail-info": "Puoi inviare fino a 15 email di richiesta di firma ogni mese. Passa al piano superiore per inviare richieste di firma illimitate direttamente.",
"quota-mail-info-head": "Limite mensile di email",
"quota-mail-info": "Per mantenere la qualità del servizio e prevenire lo spam, OpenSign consente fino a 15 email al mese con il piano gratuito. Esegui l'upgrade ora per l'invio illimitato di email.",
"quota-mail-reset": "I tuoi crediti email per richieste di firma saranno ripristinati il",
"quota-mail": "Hai raggiunto il limite di 15 email di richiesta di firma per questo mese. Passa al piano superiore per continuare a inviare email direttamente.",
"quota-mail-tip": "Suggerimento: Puoi comunque firmare <1>documenti illimitati</1> condividendo manualmente i link per le richieste di firma.",
"quota-mail-tip": "Suggerimento: Puoi ancora firmare un numero <1>illimitato de documenti</1> condividendo manualmente il link della richiesta di firma.",
"quota-mail-head": "Quota Raggiunta",
"unauthorized-modal": "Non hai l'autorizzazione per eseguire questa azione, contatta {{adminEmail}}.",
"sent-this-month": "Inviati questo mese",
+65 -65
View File
@@ -13,7 +13,7 @@ const BulkSendUi = (props) => {
const [scrollOnNextUpdate, setScrollOnNextUpdate] = useState(false);
const [isSubmit, setIsSubmit] = useState(false);
const [isSignatureExist, setIsSignatureExist] = useState();
const [isBulkAvailable, setIsBulkAvailable] = useState(false);
const [isDisableBulkSend, setIsDisableBulkSend] = useState(false);
const [isLoader, setIsLoader] = useState(false);
useEffect(() => {
signatureExist();
@@ -22,7 +22,7 @@ const BulkSendUi = (props) => {
//function to check atleast one signature field exist
const signatureExist = async () => {
setIsBulkAvailable(true);
setIsDisableBulkSend(false);
const getPlaceholder = props?.Placeholders;
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
placeholderObj?.placeHolder?.some((holder) =>
@@ -95,70 +95,70 @@ const BulkSendUi = (props) => {
const handleSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
setIsSubmit(true);
if (validateEmails(forms)) {
// Create a copy of Placeholders array from props.item
let Placeholders = [...props.Placeholders];
// Initialize an empty array to store updated documents
let Documents = [];
// Loop through each form
forms.forEach((form) => {
//checking if user enter email which already exist as a signer then add user in a signers array
let existSigner = [];
form.fields.map((data) => {
if (data.signer) {
existSigner.push(data.signer);
}
});
// Map through the copied Placeholders array to update email values
const updatedPlaceholders = Placeholders.map((placeholder) => {
// Find the field in the current form that matches the placeholder Id
const field = form.fields.find(
(element) => parseInt(element.fieldId) === placeholder.Id
);
// If a matching field is found, update the email value in the placeholder
const signer = field?.signer?.objectId ? field.signer : "";
if (field) {
if (signer) {
return {
...placeholder,
signerObjId: field?.signer?.objectId || "",
signerPtr: signer
};
} else {
return {
...placeholder,
email: field.email,
signerObjId: field?.signer?.objectId || "",
signerPtr: signer
};
setIsSubmit(true);
if (validateEmails(forms)) {
// Create a copy of Placeholders array from props.item
let Placeholders = [...props.Placeholders];
// Initialize an empty array to store updated documents
let Documents = [];
// Loop through each form
forms.forEach((form) => {
//checking if user enter email which already exist as a signer then add user in a signers array
let existSigner = [];
form.fields.map((data) => {
if (data.signer) {
existSigner.push(data.signer);
}
}
// If no matching field is found, keep the placeholder as is
return placeholder;
});
});
// Map through the copied Placeholders array to update email values
const updatedPlaceholders = Placeholders.map((placeholder) => {
// Find the field in the current form that matches the placeholder Id
const field = form.fields.find(
(element) => parseInt(element.fieldId) === placeholder.Id
);
// If a matching field is found, update the email value in the placeholder
const signer = field?.signer?.objectId ? field.signer : "";
if (field) {
if (signer) {
return {
...placeholder,
signerObjId: field?.signer?.objectId || "",
signerPtr: signer
};
} else {
return {
...placeholder,
email: field.email,
signerObjId: field?.signer?.objectId || "",
signerPtr: signer
};
}
}
// If no matching field is found, keep the placeholder as is
return placeholder;
});
// Push a new document object with updated Placeholders into the Documents array
if (existSigner?.length > 0) {
Documents.push({
...props.item,
Placeholders: updatedPlaceholders,
Signers: props.item.Signers
? [...props.item.Signers, ...existSigner]
: [...existSigner]
});
} else {
Documents.push({
...props.item,
Placeholders: updatedPlaceholders,
SignatureType: props.signatureType
});
}
});
await batchQuery(Documents);
} else {
setIsSubmit(false);
}
// Push a new document object with updated Placeholders into the Documents array
if (existSigner?.length > 0) {
Documents.push({
...props.item,
Placeholders: updatedPlaceholders,
Signers: props.item.Signers
? [...props.item.Signers, ...existSigner]
: [...existSigner]
});
} else {
Documents.push({
...props.item,
Placeholders: updatedPlaceholders,
SignatureType: props.signatureType
});
}
});
await batchQuery(Documents);
} else {
setIsSubmit(false);
}
};
const batchQuery = async (Documents) => {
@@ -199,7 +199,7 @@ const BulkSendUi = (props) => {
<Loader />
</div>
)}
{isBulkAvailable ? (
{!isDisableBulkSend ? (
<>
{props.Placeholders?.length > 0 ? (
isSignatureExist ? (
@@ -30,7 +30,8 @@ const EditTemplate = ({
: false,
Bcc: template?.Bcc,
RedirectUrl: template?.RedirectUrl || "",
AllowModifications: template?.AllowModifications || false
AllowModifications: template?.AllowModifications || false,
TimeToCompleteDays: template?.TimeToCompleteDays || 15
});
// `isValidURL` is used to check valid webhook url
@@ -228,14 +229,13 @@ const EditTemplate = ({
</div>
</div>
<div className="text-xs mt-3">
<label
>
<label>
{t("notify-on-signatures")}
<a data-tooltip-id="nos-tooltip" className="ml-1">
<sup>
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
</sup>
</a>
</a>{" "}
<Tooltip id="nos-tooltip" className="z-[999]">
<div className="max-w-[200px] md:max-w-[450px] text-[11px]">
<p className="font-bold">{t("notify-on-signatures")}</p>
@@ -247,7 +247,7 @@ const EditTemplate = ({
<div className="flex flex-col md:flex-row md:gap-4">
<div
className={
"flex items-center gap-2 ml-2 mb-1"
`flex items-center gap-2 ml-2 mb-1`
}
>
<input
@@ -260,7 +260,7 @@ const EditTemplate = ({
</div>
<div
className={
"flex items-center gap-2 ml-2 mb-1"
`flex items-center gap-2 ml-2 mb-1`
}
>
<input
@@ -294,6 +294,22 @@ const EditTemplate = ({
onInput={(e) => e.target.setCustomValidity("")}
/>
</div>
<div className="text-xs mt-2">
<label className="block">
{t("time-to-complete")}
<span className="text-red-500 text-[13px]">*</span>
</label>
<input
type="number"
name="TimeToCompleteDays"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={formData.TimeToCompleteDays}
onChange={(e) => handleStrInput(e)}
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
onInput={(e) => e.target.setCustomValidity("")}
required
/>
</div>
<div className="mt-[1rem] flex justify-start">
<button type="submit" className="op-btn op-btn-primary">
{t("submit")}
+2 -1
View File
@@ -491,7 +491,7 @@ export const signPdfFun = async (
documentId,
signerObjectId,
objectId,
widgets
widgets,
) => {
let isCustomCompletionMail = false;
try {
@@ -632,6 +632,7 @@ export const createDocument = async (
IsEnableOTP: Doc?.IsEnableOTP || false,
IsTourEnabled: Doc?.IsTourEnabled || false,
AllowModifications: Doc?.AllowModifications || false,
TimeToCompleteDays: parseInt(Doc?.TimeToCompleteDays) || 15,
...SignatureType,
...NotifyOnSignatures,
...Bcc,
+9 -13
View File
@@ -360,10 +360,6 @@ const Forms = (props) => {
object.set("Description", formData?.Description);
object.set("Note", formData?.Note);
if (props.title === "Request Signatures") {
object.set(
"TimeToCompleteDays",
parseInt(formData?.TimeToCompleteDays)
);
if (
extUserData?.TenantId?.RequestBody &&
extUserData?.TenantId?.RequestSubject
@@ -380,6 +376,10 @@ const Forms = (props) => {
object.set("AutomaticReminders", formData.autoreminder);
object.set("RemindOnceInEvery", parseInt(formData.remindOnceInEvery));
object.set("IsTourEnabled", isTourEnabled);
object.set(
"TimeToCompleteDays",
parseInt(formData?.TimeToCompleteDays)
);
object.set("AllowModifications", false);
object.set("IsEnableOTP", false);
if (formData.NotifyOnSignatures !== undefined) {
@@ -448,12 +448,12 @@ const Forms = (props) => {
});
setFileUpload("");
setpercentage(0);
navigate(`/${props?.redirectRoute}/${res.id}`);
setIsAlert((obj) => ({
...obj,
type: "success",
message: `${props.msgVar} created successfully!`
}));
navigate(`/${props?.redirectRoute}/${res.id}`);
}
} catch (err) {
console.log("err ", err);
@@ -991,7 +991,7 @@ const Forms = (props) => {
</>
)}
<div className="overflow-y-auto z-[40] transition-all">
{props.title === "Request Signatures" && (
{props.title !== "Sign yourself" && (
<div className="text-xs mt-2">
<label className="block">
{t("time-to-complete")}
@@ -1123,11 +1123,7 @@ const Forms = (props) => {
</div>
</div>
<div className="text-xs mt-3">
<label
className={
"block"
}
>
<label className="block">
{t("notify-on-signatures")}
<a data-tooltip-id="nos-tooltip" className="ml-1">
<sup>
@@ -1147,7 +1143,7 @@ const Forms = (props) => {
<div className="flex flex-col md:flex-row md:gap-4">
<div
className={
"flex items-center gap-2 ml-2 mb-1"
`flex items-center gap-2 ml-2 mb-1`
}
>
<input
@@ -1160,7 +1156,7 @@ const Forms = (props) => {
</div>
<div
className={
"flex items-center gap-2 ml-2 mb-1"
`flex items-center gap-2 ml-2 mb-1`
}
>
<input
+18 -25
View File
@@ -1003,7 +1003,7 @@ function PlaceHolderSign() {
docCls.set("URL", pdfUrl);
}
const res = await docCls.save();
if (res) {
if (res && pdfUrl) {
pdfDetails[0] = { ...pdfDetails[0], URL: pdfUrl };
}
} catch (e) {
@@ -1058,31 +1058,24 @@ function PlaceHolderSign() {
if (updateExpiryDate) {
data["ExpiryDate"] = { iso: updateExpiryDate, __type: "Date" };
}
await axios
.put(
`${localStorage.getItem(
"baseUrl"
)}classes/contracts_Document/${documentId}`,
data,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
await axios.put(
`${localStorage.getItem(
"baseUrl"
)}classes/contracts_Document/${documentId}`,
data,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
)
.then(() => {
setIsMailSend(true);
setIsLoading({ isLoad: false });
setIsUiLoading(false);
setSignerPos([]);
setIsSendAlert({ mssg: "confirm", alert: true });
})
.catch((err) => {
console.log("axois err ", err);
alert(t("something-went-wrong-mssg"));
});
}
);
setIsMailSend(true);
setIsLoading({ isLoad: false });
setIsUiLoading(false);
setSignerPos([]);
setIsSendAlert({ mssg: "confirm", alert: true });
} catch (e) {
console.log("error", e);
alert(t("something-went-wrong-mssg"));
+1 -5
View File
@@ -410,11 +410,7 @@ const Preferences = () => {
</div>
</div>
<div className="mb-[0.75rem]">
<label
className={
"text-[14px] mb-[0.7rem] font-medium"
}
>
<label className="text-[14px] mb-[0.7rem] font-medium">
{t("notify-on-signatures")}
<a data-tooltip-id="nos-tooltip" className="ml-1">
<sup>
@@ -710,6 +710,10 @@ const TemplatePlaceholder = () => {
if (pdfUrl) {
templateCls.set("URL", pdfUrl);
}
templateCls.set(
"TimeToCompleteDays",
parseInt(pdfDetails?.[0]?.TimeToCompleteDays) || 15
);
if (pdfDetails[0]?.Bcc?.length) {
const Bcc = pdfDetails[0]?.Bcc.map((x) => ({
__type: "Pointer",
@@ -789,6 +793,8 @@ const TemplatePlaceholder = () => {
pdfDetails[0]?.NotifyOnSignatures !== undefined
? pdfDetails[0]?.NotifyOnSignatures
: false,
TimeToCompleteDays:
parseInt(pdfDetails?.[0]?.TimeToCompleteDays) || 15,
...Bcc,
...RedirectUrl
};
@@ -1126,6 +1132,8 @@ const TemplatePlaceholder = () => {
updateTemplate?.[0]?.NotifyOnSignatures !== undefined
? updateTemplate?.[0]?.NotifyOnSignatures
: false,
TimeToCompleteDays:
parseInt(updateTemplate?.[0]?.TimeToCompleteDays) || 15,
...Bcc,
...RedirectUrl
};
@@ -312,6 +312,7 @@ const ReportTable = (props) => {
AutomaticReminders: Doc?.AutomaticReminders || false,
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5,
IsEnableOTP: Doc?.IsEnableOTP || false,
TimeToCompleteDays: parseInt(Doc?.TimeToCompleteDays) || 15,
AllowModifications: Doc?.AllowModifications || false,
...SignatureType,
...NotifyOnSignatures,
@@ -71,12 +71,6 @@ export default async function createDuplicate(request) {
if (_templateRes?.SharedWith?.length > 0) {
newTemplate.set('SharedWith', _templateRes.SharedWith);
}
if (_templateRes?.IsPublic) {
newTemplate.set('IsPublic', _templateRes?.IsPublic);
}
if (_templateRes?.PublicRole?.length > 0) {
newTemplate.set('PublicRole', _templateRes?.PublicRole);
}
if (_templateRes?.IsTourEnabled) {
newTemplate.set('IsTourEnabled', _templateRes?.IsTourEnabled);
}
@@ -91,6 +85,9 @@ export default async function createDuplicate(request) {
if (_templateRes?.RedirectUrl) {
newTemplate.set('RedirectUrl', _templateRes?.RedirectUrl);
}
if (_templateRes?.TimeToCompleteDays) {
newTemplate.set('TimeToCompleteDays', parseInt(_templateRes?.TimeToCompleteDays));
}
const acl = templateRes.getACL();
if (acl) {
newTemplate.setACL(acl);
@@ -246,7 +246,7 @@ async function sendMailsaveCertifcate(
P12Buffer,
isCustomMail,
mailProvider,
filename
filename,
) {
const certificate = await GenerateCertificate(doc);
const certificatePdf = await PDFDocument.load(certificate);
@@ -440,7 +440,7 @@ async function PDF(req) {
P12Buffer,
isCustomMail,
mailProvider,
name
name,
);
}
// `fs.unlinkSync` is used to remove exported signed pdf file from exports folder