diff --git a/apps/OpenSign/public/locales/en/translation.json b/apps/OpenSign/public/locales/en/translation.json index c07cdedda..40d56f9f4 100644 --- a/apps/OpenSign/public/locales/en/translation.json +++ b/apps/OpenSign/public/locales/en/translation.json @@ -515,7 +515,7 @@ "error": "Error", "invalid-document": "Error: invalid document!", "document-not-found": "Document not Found!", - "document-signed-alert-1": "You have successfully signed the document. You can download or print a copy of the partially signed document. A copy of the digitally signed document will be sent to the owner over email once it is signed by all signers.", + "document-signed-alert-1": "You have successfully signed the document. You can download or print a copy of the partially signed document. A copy of the digitally signed document & completion certificate will be sent to the owner & all signers over email once it is signed by all signers.", "encrypted-pdf-not-support": "Currently encrypted pdf files are not supported.", "document-signed-alert-4": " Congratulations! 🎉 This document has been successfully signed by all participants!", "document-signed-alert-5": "This document has been signed by all Signers.", @@ -655,6 +655,7 @@ "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-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 by manually sharing the signing request links.", "quota-mail-head":"Quota Reached", diff --git a/apps/OpenSign/public/locales/es/translation.json b/apps/OpenSign/public/locales/es/translation.json index d2cc76701..bb0ed8987 100644 --- a/apps/OpenSign/public/locales/es/translation.json +++ b/apps/OpenSign/public/locales/es/translation.json @@ -515,7 +515,7 @@ "error": "Error", "invalid-document": "Error: ¡Documento inválido!", "document-not-found": "¡Documento no encontrado!", - "document-signed-alert-1": "Has firmado el documento exitosamente. Puedes descargar o imprimir una copia del documento parcialmente firmado. Una copia del documento firmado digitalmente será enviada al propietario mediante correo electrónico una vez haya sido firmado por todos los firmantes.", + "document-signed-alert-1": "Ha firmado exitosamente el documento. Puede descargar o imprimir una copia del documento parcialmente firmado. Se enviará una copia del documento firmado digitalmente y del certificado de finalización al propietario y a todos los firmantes por correo electrónico una vez que todos los firmantes lo hayan firmado.", "encrypted-pdf-not-support": "Los archivos PDF encriptados no están soportados actualmente.", "document-signed-alert-4": " ¡Felicitaciones! 🎉 ¡Este documento ha sido firmado exitosamente por todos los participantes!", "document-signed-alert-5": "Este documento ha sido firmado por todos los firmantes.", @@ -655,6 +655,7 @@ "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-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 compartiendo manualmente los enlaces de solicitud de firma.", "quota-mail-head": "Cuota alcanzada", diff --git a/apps/OpenSign/public/locales/fr/translation.json b/apps/OpenSign/public/locales/fr/translation.json index 3aa1ebc05..eb515ef3e 100644 --- a/apps/OpenSign/public/locales/fr/translation.json +++ b/apps/OpenSign/public/locales/fr/translation.json @@ -514,7 +514,7 @@ "error": "Erreur", "invalid-document": "Erreur : document invalide !", "document-not-found": "Document introuvable !", - "document-signed-alert-1": "Vous avez signé le document avec succès. Vous pouvez télécharger ou imprimer une copie du document partiellement signé. Une copie du document signé numériquement sera envoyée au propriétaire par e-mail une fois qu'il sera signé par tous les signataires.", + "document-signed-alert-1": "Vous avez signé le document avec succès. Vous pouvez télécharger ou imprimer une copie du document partiellement signé. Une copie du document signé numériquement et du certificat d'achèvement sera envoyée au propriétaire et à tous les signataires par e-mail une fois qu'il aura été signé par tous les signataires.", "encrypted-pdf-not-support": "Les fichiers PDF actuellement cryptés ne sont pas pris en charge. ", "document-signed-alert-4": "Toutes nos félicitations! 🎉 Ce document a été signé avec succès par tous les participants !", "document-signed-alert-5": "Ce document a été signé par tous les signataires.", @@ -654,6 +654,7 @@ "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-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 en partageant manuellement les liens de demande de signature.", "quota-mail-head":"Quota atteint", diff --git a/apps/OpenSign/src/components/Header.js b/apps/OpenSign/src/components/Header.js index 2b9867240..2b8118b9b 100644 --- a/apps/OpenSign/src/components/Header.js +++ b/apps/OpenSign/src/components/Header.js @@ -6,6 +6,7 @@ import Parse from "parse"; import { useWindowSize } from "../hook/useWindowSize"; import { checkIsSubscribed, + formatDate, getAppLogo, openInNewTab, saveLanguageInLocal @@ -33,6 +34,7 @@ const Header = ({ showSidebar, setIsMenu }) => { ); const [emailUsed, setEmailUsed] = useState(0); const [isModal, setIsModal] = useState(false); + const [emailResetDate, setEmailResetDate] = useState(""); const [showNotification, setShowNotification] = useState( (!dismissedVersion || dismissedVersion !== current_notification_version) && true @@ -66,6 +68,10 @@ const Header = ({ showSidebar, setIsMenu }) => { setEmailUsed(MonthlyFreeEmails); if (extUser) { const _extUser = JSON.parse(JSON.stringify(extUser)); + if (_extUser?.LastEmailCountReset?.iso) { + const resetDate = formatDate(_extUser?.LastEmailCountReset?.iso); + setEmailResetDate(resetDate); + } localStorage.setItem("Extand_Class", JSON.stringify([_extUser])); } } catch (err) { @@ -302,7 +308,11 @@ const Header = ({ showSidebar, setIsMenu }) => { - + ); diff --git a/apps/OpenSign/src/constant/Utils.js b/apps/OpenSign/src/constant/Utils.js index 5ce9f7d7c..808d6c633 100644 --- a/apps/OpenSign/src/constant/Utils.js +++ b/apps/OpenSign/src/constant/Utils.js @@ -2596,3 +2596,17 @@ export async function handleSignatureType(tenantSignTypes, signatureType) { } return updatedSignatureType; } + +// `formatDate` is used to format date to dd-mmm-yyy +export const formatDate = (date) => { + // Create a Date object + const newDate = new Date(date); + // Format the date + const formattedDate = newDate.toLocaleDateString("en-GB", { + day: "2-digit", + month: "short", + year: "numeric" + }); + const format = formattedDate.replaceAll(/ /g, "-"); + return format; +}; diff --git a/apps/OpenSign/src/json/ReportJson.js b/apps/OpenSign/src/json/ReportJson.js index ed8aac236..025ed065d 100644 --- a/apps/OpenSign/src/json/ReportJson.js +++ b/apps/OpenSign/src/json/ReportJson.js @@ -2,29 +2,12 @@ import { isEnableSubscription } from "../constant/const"; export default function reportJson(id) { // console.log("json ", json); - const head = ["Sr.No", "Title", "Note", "Folder", "File", "Owner", "Signers"]; - const declineHead = [ - "Sr.No", - "Title", - "Reason", - "Folder", - "File", - "Owner", - "Signers" - ]; - const iphead = [ - "Sr.No", - "Title", - "Note", - "Folder", - "File", - "Status", - "Signers", - "Expiry-date" - ]; - const contactbook = ["Sr.No", "Name", "Email", "Phone"]; + const head = ["Title", "Note", "Folder", "File", "Owner", "Signers"]; + const declineHead = ["Title", "Reason", "Folder", "File", "Owner", "Signers"]; + const iphead = ["Title", "Note", "Folder", "File", "Signers"]; + const contactbook = ["Name", "Email", "Phone"]; const dashboardReportHead = ["Title", "File", "Owner", "Signers"]; - const templateReport = ["Sr.No", "Title", "File", "Owner", "Signers"]; + const templateReport = ["Title", "File", "Owner", "Signers"]; const templateSubAction = isEnableSubscription ? [ { @@ -212,7 +195,7 @@ export default function reportJson(id) { case "zNqBHXHsYH": return { reportName: "Expired Documents", - heading: [...head, "Expiry-date"], + heading: head, actions: [ { btnId: "1898", @@ -257,7 +240,7 @@ export default function reportJson(id) { case "d9k3UfYHBc": return { reportName: "Recently sent for signatures", - heading: [...dashboardReportHead, "Expiry-date"], + heading: dashboardReportHead, actions: [ { btnId: "1999", diff --git a/apps/OpenSign/src/pages/PlaceHolderSign.js b/apps/OpenSign/src/pages/PlaceHolderSign.js index b336b040a..3018953cb 100644 --- a/apps/OpenSign/src/pages/PlaceHolderSign.js +++ b/apps/OpenSign/src/pages/PlaceHolderSign.js @@ -40,7 +40,8 @@ import { handleRemoveWidgets, handleRotateWarning, signatureTypes, - handleSignatureType + handleSignatureType, + formatDate } from "../constant/Utils"; import RenderPdf from "../components/pdf/RenderPdf"; import { useNavigate } from "react-router-dom"; @@ -155,6 +156,7 @@ function PlaceHolderSign() { const [planCode, setPlanCode] = useState(""); const [unSignedWidgetId, setUnSignedWidgetId] = useState(""); const [signatureType, setSignatureType] = useState(signatureTypes); + const [emailResetDate, setEmailResetDate] = useState(""); const isMobile = window.innerWidth < 767; const [, drop] = useDrop({ accept: "BOX", @@ -269,6 +271,12 @@ function PlaceHolderSign() { } else { setPdfArrayBuffer(arrayBuffer); } + if (documentData[0]?.ExtUserPtr?.LastEmailCountReset?.iso) { + const resetDate = formatDate( + documentData[0]?.ExtUserPtr?.LastEmailCountReset?.iso + ); + setEmailResetDate(resetDate); + } setExtUserId(documentData[0]?.ExtUserPtr?.objectId); if (isEnableSubscription) { checkIsSubscribed(documentData[0]?.ExtUserPtr?.Email); @@ -602,7 +610,7 @@ function PlaceHolderSign() { Role: "prefill", Id: key }; - setSignerPos((prev)=>[...prev,prefillTextWidget]); + setSignerPos((prev) => [...prev, prefillTextWidget]); } } else { //else condition to add placeholder widgets on multiple page first time @@ -1939,6 +1947,7 @@ function PlaceHolderSign() { ) : mailStatus === "quotareached" ? (
{ setIsSend(false); setSignerPos([]); diff --git a/apps/OpenSign/src/primitives/GetReportDisplay.js b/apps/OpenSign/src/primitives/GetReportDisplay.js index 6ef484120..ecc4164ab 100644 --- a/apps/OpenSign/src/primitives/GetReportDisplay.js +++ b/apps/OpenSign/src/primitives/GetReportDisplay.js @@ -14,6 +14,7 @@ import { checkIsSubscribed, copytoData, fetchUrl, + formatDate, getSignedUrl, getTenantDetails, handleSignatureType, @@ -666,15 +667,12 @@ const ReportTable = (props) => { } const closeTour = async () => { - // console.log("closeTour"); setIsTour(false); if (props.isDontShow) { const serverUrl = localStorage.getItem("baseUrl"); const appId = localStorage.getItem("parseAppId"); const json = JSON.parse(localStorage.getItem("Extand_Class")); const extUserId = json && json.length > 0 && json[0].objectId; - // console.log("extUserId ", extUserId) - let updatedTourStatus = []; if (tourStatusArr.length > 0) { updatedTourStatus = [...tourStatusArr]; @@ -692,14 +690,8 @@ const ReportTable = (props) => { await axios.put( serverUrl + "classes/contracts_Users/" + extUserId, - { - TourStatus: updatedTourStatus - }, - { - headers: { - "X-Parse-Application-Id": appId - } - } + { TourStatus: updatedTourStatus }, + { headers: { "X-Parse-Application-Id": appId } } ); } }; @@ -1274,6 +1266,68 @@ const ReportTable = (props) => { setTimeout(() => setIsAlert(false), 2000); } }; + // `formatStatusRow` is used to format status row + const formatStatusRow = (item) => { + const signers = item?.Placeholders?.map((x, i) => { + const matchSigner = item?.AuditTrail?.find( + (audit) => audit.UserPtr.objectId === x.signerObjId + ); + if (matchSigner) { + return { + id: i, + Email: matchSigner.UserPtr.Email, + Activity: matchSigner?.Activity?.toUpperCase() || "-", + SignedOn: matchSigner?.SignedOn + ? new Date(matchSigner?.SignedOn)?.toUTCString() + : "-", + ViewedOn: matchSigner?.ViewedOn + ? new Date(matchSigner?.ViewedOn)?.toUTCString() + : "-" + }; + } else { + return { + id: i, + Email: x?.signerPtr?.Email || x?.email, + Activity: "SENT", + SignedOn: "-", + ViewedOn: "-" + }; + } + }); + return signers?.map((x, i) => ( +
+ +
{x?.Email || "-"}
+ {isModal[`${item.objectId}_${i}`] && ( + setIsModal({})} + > +
+

{x?.Email}

+

Viewed on: {x?.ViewedOn}

+

Signed on: {x?.SignedOn}

+
+
+ )} +
+ )); + }; return (
{Object.keys(actLoader)?.length > 0 && ( @@ -1353,18 +1407,18 @@ const ReportTable = (props) => { }`} > - + {props.heading?.map((item, index) => ( - + ))} {props.ReportName === "Templates" && isEnableSubscription && ( - + )} {props.actions?.length > 0 && ( - )} @@ -1377,15 +1431,17 @@ const ReportTable = (props) => { props.ReportName === "Contactbook" ? ( {props.heading.includes("Sr.No") && ( - + )} - - + + )} - {props?.heading?.includes("Reason") && ( - )} {props.heading.includes("Note") && ( - )} {props.heading.includes("Folder") && ( - )} - - {props.ReportName === "In-progress documents" ? ( - + )} + {props.heading.includes("Signers") && + ["In-progress documents", "Need your sign"].includes( + props.ReportName + ) ? ( + ) : ( - )} - - {props.heading.includes("Expiry-date") && - item?.ExpiryDate?.iso && ( - - )} {props.ReportName === "Templates" && isEnableSubscription && (
{t(`report-heading.${item}`)}{t(`report-heading.${item}`)} {t("public")}{t("public")} + {t("action")}
- {startIndex + index + 1} - {startIndex + index + 1} {item?.Name}{" "} {item?.Email || "-"}{item?.Phone || "-"} + {item?.Email || "-"} + + {item?.Phone || "-"} +
{props.actions?.length > 0 && @@ -1442,34 +1498,39 @@ const ReportTable = (props) => { key={index} > {props.heading.includes("Sr.No") && ( -
+ {startIndex + index + 1} - {item?.Name}{" "} + +
{item?.Name}
+ {item?.ExpiryDate?.iso && ( +
+ Expire: {formatDate(item?.ExpiryDate?.iso)} +
+ )}
+ {item?.DeclineReason?.length > 25 ? item?.DeclineReason?.slice(0, 25) + "..." : item?.DeclineReason || "-"} - {item?.Note?.length > 25 - ? item?.Note?.slice(0, 25) + "..." - : item?.Note || "-"} + +

+ {item?.Note || "-"} +

+ {item?.Folder?.Name || t("sidebar.OpenSign™ Drive")} + - - {isModal[item.objectId] && ( - setIsModal({})} - > - {item?.AuditTrail?.map((x, i) => ( -
-
- {x?.UserPtr?.Email || "-"} -
- -
- {x?.Activity === "Signed" - ? new Date(x?.SignedOn)?.toUTCString() - : new Date( - x?.ViewedOn - )?.toUTCString() || "-"} -
-
- ))} -
+ {props.heading.includes("Owner") && ( +
+ {formatRow(item?.ExtUserPtr)} + + {!item?.IsSignyourself && item?.Placeholders && ( + <>{formatStatusRow(item)} )} - {formatRow(item?.ExtUserPtr)} + + {!item?.IsSignyourself && item?.Placeholders ? ( + + ) : ( + "-" + )} - {!item?.IsSignyourself && item?.Placeholders ? ( - - ) : ( - "-" - )} - - - {new Date( - item?.ExpiryDate?.iso - )?.toLocaleDateString()} - - diff --git a/apps/OpenSign/src/primitives/QuotaCard.js b/apps/OpenSign/src/primitives/QuotaCard.js index 68d29be9f..769bf0eba 100644 --- a/apps/OpenSign/src/primitives/QuotaCard.js +++ b/apps/OpenSign/src/primitives/QuotaCard.js @@ -2,7 +2,7 @@ import React from "react"; import { Trans, useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; -const QuotaCard = ({ isPaidInfo, handlClose }) => { +const QuotaCard = ({ isPaidInfo, handlClose, emailResetDate }) => { const { t } = useTranslation(); const navigate = useNavigate(); return isPaidInfo ? ( @@ -17,6 +17,11 @@ const QuotaCard = ({ isPaidInfo, handlClose }) => {

{t("quota-mail-info-head")}

{t("quota-mail-info")}

+ {emailResetDate && ( +

+ {t("quota-mail-reset")} {emailResetDate} +

+ )}

Tip: You can still sign unlimited documents by @@ -39,7 +44,17 @@ const QuotaCard = ({ isPaidInfo, handlClose }) => {

{t("quota-mail")}

-

{t("quota-mail-tip")}

+ {emailResetDate && ( +

+ {t("quota-mail-reset")} {emailResetDate} +

+ )} +
+ + Tip: You can still sign unlimited documents by + manually sharing the signing request links. + +