From d4d53623efe07a24a24aecc321547a2c3d7cd326 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs Date: Mon, 2 Sep 2024 13:03:47 +0530 Subject: [PATCH 1/3] refactor: add logout btn --- apps/OpenSign/src/components/BulkSendUi.js | 2 +- apps/OpenSign/src/pages/PlanSubscriptions.js | 40 ++++++++++++++++++- .../cloud/parsefunction/BuyCredits.js | 2 +- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/apps/OpenSign/src/components/BulkSendUi.js b/apps/OpenSign/src/components/BulkSendUi.js index b46584235..4491a08d3 100644 --- a/apps/OpenSign/src/components/BulkSendUi.js +++ b/apps/OpenSign/src/components/BulkSendUi.js @@ -262,7 +262,7 @@ const BulkSendUi = (props) => { quantity: 500, priceperbulksend: 0.15, price: (75.0).toFixed(2), - totalcredits: _resAddon.addon + totalcredits: obj?.totalcredits + _resAddon.addon })); } } diff --git a/apps/OpenSign/src/pages/PlanSubscriptions.js b/apps/OpenSign/src/pages/PlanSubscriptions.js index bc9b9526a..8428487ef 100644 --- a/apps/OpenSign/src/pages/PlanSubscriptions.js +++ b/apps/OpenSign/src/pages/PlanSubscriptions.js @@ -4,7 +4,7 @@ import checkmark from "../assets/images/checkmark.png"; import plansArr from "../json/plansArr"; import Title from "../components/Title"; import Parse from "parse"; -import { openInNewTab } from "../constant/Utils"; +import { openInNewTab, saveLanguageInLocal } from "../constant/Utils"; import Loader from "../primitives/Loader"; import { useTranslation } from "react-i18next"; const listItemStyle = { @@ -119,6 +119,30 @@ const PlanSubscriptions = () => { } } }; + const handleLogout = async () => { + try { + Parse?.User?.logOut(); + } catch (err) { + console.log("Err", err); + } + let appdata = localStorage.getItem("userSettings"); + let applogo = localStorage.getItem("appLogo"); + let defaultmenuid = localStorage.getItem("defaultmenuid"); + let PageLanding = localStorage.getItem("PageLanding"); + let baseUrl = localStorage.getItem("baseUrl"); + let appid = localStorage.getItem("parseAppId"); + + localStorage.clear(); + saveLanguageInLocal(i18n); + localStorage.setItem("appLogo", applogo); + localStorage.setItem("defaultmenuid", defaultmenuid); + localStorage.setItem("PageLanding", PageLanding); + localStorage.setItem("userSettings", appdata); + localStorage.setItem("baseUrl", baseUrl); + localStorage.setItem("parseAppId", appid); + + navigate("/"); + }; return ( <> @@ -129,7 +153,13 @@ const PlanSubscriptions = () => { ) : ( <div className="overflow-y-auto max-h-full"> <div className="block my-2"> - <div className="flex flex-col justify-center items-center w-full"> + <div className="flex flex-col justify-center items-center w-full relative"> + <button + className="md:hidden op-btn op-btn-primary op-btn-sm h-[40px] w-[250px] shadow-lg" + onClick={() => handleLogout()} + > + Log out + </button> <div role="tablist" className="op-tabs op-tabs-boxed bg-base-100 my-2 shadow-lg transition-all" @@ -150,6 +180,12 @@ const PlanSubscriptions = () => { </a> </div> <ul className="op-card flex flex-col md:flex-row h-full bg-base-100 justify-center shadow-lg"> + <button + className="hidden md:block -top-12 right-1 absolute w-[150px] h-[40px] op-btn op-btn-primary op-btn-sm shadow-lg" + onClick={() => handleLogout()} + > + {t("log-out")} + </button> {plansArr.map((item) => ( <li className="flex flex-col text-center border-collapse border-[1px] border-gray-300 max-w-[250px]" diff --git a/apps/OpenSignServer/cloud/parsefunction/BuyCredits.js b/apps/OpenSignServer/cloud/parsefunction/BuyCredits.js index 0e0e99827..c33134cc2 100644 --- a/apps/OpenSignServer/cloud/parsefunction/BuyCredits.js +++ b/apps/OpenSignServer/cloud/parsefunction/BuyCredits.js @@ -67,7 +67,7 @@ export default async function BuyCredits(request) { updateSub.set('AddonCredits', addonCredits); const resupdateSub = await updateSub.save(null, { useMasterKey: true }); // console.log('resupdateSub ', resupdateSub); - return { status: 'success', addon: addonCredits }; + return { status: 'success', addon: quantity }; } } else { throw new Parse.Error('400', 'Invalid access token.'); From da053658e8eae37a27ab73a74c0ea5a338029703 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Mon, 2 Sep 2024 19:29:36 +0530 Subject: [PATCH 2/3] refactor: handle uncuaght err in send mail --- .../public/locales/en/translation.json | 8 +- .../public/locales/fr/translation.json | 8 +- .../src/components/pdf/EmailComponent.js | 19 ++- apps/OpenSign/src/pages/PdfRequestFiles.js | 3 + apps/OpenSign/src/pages/PlaceHolderSign.js | 109 ++++++++++-------- apps/OpenSign/src/pages/SignyourselfPdf.js | 73 ++++++------ apps/OpenSign/src/pages/Webhook.js | 7 +- apps/OpenSign/src/primitives/ModalUi.js | 8 +- apps/OpenSign/src/primitives/QuotaCard.js | 53 +++++++++ apps/OpenSignServer/Utils.js | 24 ++-- .../parsefunction/sendMailGmailProvider.js | 3 +- .../cloud/parsefunction/sendMailv3.js | 103 +++++++++++------ 12 files changed, 275 insertions(+), 143 deletions(-) create mode 100644 apps/OpenSign/src/primitives/QuotaCard.js diff --git a/apps/OpenSign/public/locales/en/translation.json b/apps/OpenSign/public/locales/en/translation.json index ee282f354..02df68661 100644 --- a/apps/OpenSign/public/locales/en/translation.json +++ b/apps/OpenSign/public/locales/en/translation.json @@ -623,5 +623,11 @@ "generate-test-token":"Generate Test Token", "regenerate-test-token":"Regenerate Test Token", "help-test-token":"This token can be used to test the APIs at the https://sandbox.opensignlabs.com/api/v1 endpoint, allowing you to conduct unlimited document signatures. Please note that the sandbox API will sign your documents with self-signed certificates, which may not be recognized as valid by Adobe. Once you’ve completed your testing, you can upgrade to one of our paid plans to generate a production token.", - "help-api-token":"This token can be used to access the production APIs at the {{origin}}/api/v1 endpoint. It can only be generated on one of our paid plans." + "help-api-token":"This token can be used to access the production APIs at the {{origin}}/api/v1 endpoint. It can only be generated on one of our paid plans.", + "Add-Webhook":"Add Webhook", + "quotamailselfsign": "You've reached your limit of 20 emails for this month. Upgrade now to continue sending emails directly.", + "quotamail": "You've reached your limit of 20 signature request emails for this month. Upgrade now to continue sending emails directly.", + "quotamailTip":"Tip: You can still sign unlimited documents by manually sharing the signing request links below.", + "quotamailhead":"Quota Reached" + } diff --git a/apps/OpenSign/public/locales/fr/translation.json b/apps/OpenSign/public/locales/fr/translation.json index 72a30b619..4faac0193 100644 --- a/apps/OpenSign/public/locales/fr/translation.json +++ b/apps/OpenSign/public/locales/fr/translation.json @@ -624,5 +624,11 @@ "generate-test-token": "Générer jeton de test", "regenerate-test-token":"Régénérer le jeton de test", "help-test-token":"Ce jeton peut être utilisé pour tester les API au niveau du point de terminaison https://sandbox.opensignlabs.com/api/v1, vous permettant ainsi d'effectuer un nombre illimité de signatures de documents. Veuillez noter que l'API sandbox signera vos documents avec des certificats auto-signés, qui peuvent ne pas être reconnus comme valides par Adobe. Une fois vos tests terminés, vous pouvez passer à l’un de nos forfaits payants pour générer un jeton de production.", - "help-api-token":"Ce jeton peut être utilisé pour accéder aux API de production au point de terminaison {{origin}}/api/v1. Il ne peut être généré que sur l'un de nos forfaits payants." + "help-api-token":"Ce jeton peut être utilisé pour accéder aux API de production au point de terminaison {{origin}}/api/v1. Il ne peut être généré que sur l'un de nos forfaits payants.", + "Add-Webhook":"Ajouter Webhook", + "quotamailselfsign": "Vous avez atteint votre limite de 20 e-mails pour ce mois. Mettez à niveau maintenant pour continuer à envoyer des e-mails directement.", + "quotamail": "Vous avez atteint votre limite de 20 e-mails de demande de signature pour ce mois. Mettez à niveau maintenant pour continuer à envoyer des e-mails directement.", + "quotamailTip":"Astuce : Vous pouvez toujours signer un nombre illimité de documents en partageant manuellement les liens de demande de signature ci-dessous.", + "quotamailhead":"Quota atteint" + } diff --git a/apps/OpenSign/src/components/pdf/EmailComponent.js b/apps/OpenSign/src/components/pdf/EmailComponent.js index 948f58994..f0404439c 100644 --- a/apps/OpenSign/src/components/pdf/EmailComponent.js +++ b/apps/OpenSign/src/components/pdf/EmailComponent.js @@ -15,7 +15,8 @@ function EmailComponent({ sender, setIsAlert, extUserId, - activeMailAdapter + activeMailAdapter, + planCode }) { const { t } = useTranslation(); const [emailList, setEmailList] = useState([]); @@ -34,7 +35,7 @@ function EmailComponent({ const imgPng = "https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"; - let url = `${localStorage.getItem("baseUrl")}functions/sendmailv3/`; + let url = `${localStorage.getItem("baseUrl")}functions/sendmailv3`; const headers = { "Content-Type": "application/json", "X-Parse-Application-Id": localStorage.getItem("parseAppId"), @@ -50,6 +51,7 @@ function EmailComponent({ recipient: emailList[i], subject: `${sender.name} has signed the doc - ${pdfName}`, from: sender.email, + plan: planCode, html: "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=" + imgPng + @@ -74,24 +76,19 @@ function EmailComponent({ }); } } - - if (sendMail && sendMail.data.result.status === "success") { + if (sendMail?.data?.result?.status === "success") { setSuccessEmail(true); + setIsEmail(false); setTimeout(() => { setSuccessEmail(false); - setIsEmail(false); setEmailValue(""); setEmailList([]); }, 1500); - setIsLoading(false); - } else if (sendMail && sendMail.data.result.status === "error") { + } else if (sendMail?.data?.result?.status === "quota-reached") { setIsLoading(false); setIsEmail(false); - setIsAlert({ - isShow: true, - alertMessage: t("something-went-wrong-mssg") - }); + setIsAlert({ isShow: true, alertMessage: "quotareached" }); setEmailValue(""); setEmailList([]); } else { diff --git a/apps/OpenSign/src/pages/PdfRequestFiles.js b/apps/OpenSign/src/pages/PdfRequestFiles.js index 3dacc088e..e7c0e3230 100644 --- a/apps/OpenSign/src/pages/PdfRequestFiles.js +++ b/apps/OpenSign/src/pages/PdfRequestFiles.js @@ -133,6 +133,7 @@ function PdfRequestFiles(props) { const [documentId, setDocumentId] = useState(""); const [isPublicContact, setIsPublicContact] = useState(false); const [pdfArrayBuffer, setPdfArrayBuffer] = useState(""); + const [plancode, setPlanCode] = useState(""); const isHeader = useSelector((state) => state.showHeader); const divRef = useRef(null); @@ -246,6 +247,7 @@ function PdfRequestFiles(props) { const plan = res.plan; const billingDate = res?.billingDate; const status = res?.status; + setPlanCode(plan); if (plan === "freeplan") { return true; } else if (billingDate) { @@ -986,6 +988,7 @@ function PdfRequestFiles(props) { ? replaceVar?.subject : `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign "${pdfDetails?.[0].Name}"`, from: senderEmail, + plan: plancode, html: requestBody ? replaceVar?.body : "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'=> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" + diff --git a/apps/OpenSign/src/pages/PlaceHolderSign.js b/apps/OpenSign/src/pages/PlaceHolderSign.js index 7b28d007a..7c0e11a8d 100644 --- a/apps/OpenSign/src/pages/PlaceHolderSign.js +++ b/apps/OpenSign/src/pages/PlaceHolderSign.js @@ -61,6 +61,7 @@ import PdfZoom from "../components/pdf/PdfZoom"; import LottieWithLoader from "../primitives/DotLottieReact"; import { useTranslation } from "react-i18next"; import RotateAlert from "../components/RotateAlert"; +import QuotaCard from "../primitives/QuotaCard"; function PlaceHolderSign() { const { t } = useTranslation(); @@ -150,8 +151,8 @@ function PlaceHolderSign() { const [isCustomize, setIsCustomize] = useState(false); const [zoomPercent, setZoomPercent] = useState(0); const [scale, setScale] = useState(1); - const [pdfRotateBase64, setPdfRotatese64] = useState(""); + const [planCode, setPlanCode] = useState(""); const isMobile = window.innerWidth < 767; const [, drop] = useDrop({ accept: "BOX", @@ -240,6 +241,7 @@ function PlaceHolderSign() { const res = await fetchSubscription(); const plan = res.plan; const billingDate = res.billingDate; + setPlanCode(plan); if (plan === "freeplan") { return true; } else if (billingDate) { @@ -1058,7 +1060,7 @@ function PlaceHolderSign() { try { const imgPng = "https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"; - let url = `${localStorage.getItem("baseUrl")}functions/sendmailv3/`; + let url = `${localStorage.getItem("baseUrl")}functions/sendmailv3`; const headers = { "Content-Type": "application/json", "X-Parse-Application-Id": localStorage.getItem("parseAppId"), @@ -1113,6 +1115,7 @@ function PlaceHolderSign() { ? replaceVar?.subject : `${senderName} has requested you to sign "${documentName}"`, from: senderEmail, + plan: planCode, html: isCustomize ? replaceVar?.body : "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'=> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" + @@ -1143,7 +1146,7 @@ function PlaceHolderSign() { console.log("error", error); } } - if (sendMail.data.result.status === "success") { + if (sendMail?.data?.result?.status === "success") { setMailStatus("success"); try { let data; @@ -1156,9 +1159,8 @@ function PlaceHolderSign() { } else { data = { SendMail: true }; } - - await axios - .put( + try { + await axios.put( `${localStorage.getItem( "baseUrl" )}classes/contracts_Document/${documentId}`, @@ -1170,21 +1172,21 @@ function PlaceHolderSign() { "X-Parse-Session-Token": localStorage.getItem("accesstoken") } } - ) - .then(() => {}) - .catch((err) => { - console.log("axois err ", err); - }); + ); + } catch (err) { + console.log("axois err ", err); + } } catch (e) { console.log("error", e); } - setIsSend(true); setIsMailSend(true); - const loadObj = { - isLoad: false - }; - setIsLoading(loadObj); + setIsLoading({ isLoad: false }); + setIsUiLoading(false); + } else if (sendMail?.data?.result?.status === "quota-reached") { + setMailStatus("quotareached"); + setIsSend(true); + setIsMailSend(true); setIsUiLoading(false); } else { setMailStatus("failed"); @@ -1829,7 +1831,7 @@ function PlaceHolderSign() { <span className="ml-[5px] mr-[5px]">{t("or")}</span> <span className="h-[1px] w-[20%] bg-[#ccc]"></span> </div> - <div className="mt-3 mb-3">{handleShareList()}</div> + <div className="my-3">{handleShareList()}</div> </> )} </div> @@ -1838,7 +1840,11 @@ function PlaceHolderSign() { {/* this modal is used show send mail message and after send mail success message */} <ModalUi isOpen={isSend} - title={t("Mails Sent")} + title={ + mailStatus === "quotareached" + ? t("quotamailhead") + : t("Mails Sent") + } handleClose={() => { setIsSend(false); setSignerPos([]); @@ -1852,40 +1858,53 @@ function PlaceHolderSign() { <p>{t("placeholder-alert-4")}</p> {isCurrUser && <p>{t("placeholder-alert-5")}</p>} </div> + ) : mailStatus === "quotareached" ? ( + <div className="flex flex-col gap-y-3"> + <QuotaCard + handleClose={() => { + setIsSend(false); + setSignerPos([]); + navigate("/report/1MwEuxLEkF"); + }} + /> + <div className="my-3">{handleShareList()}</div> + </div> ) : ( <p>{t("placeholder-alert-6")}</p> )} {!mailStatus && ( <div className="w-full h-[1px] bg-[#9f9f9f] my-[15px]"></div> )} - <div - className={ - mailStatus === "success" - ? "flex justify-center mt-1" - : "" - } - > - {isCurrUser && ( - <button - onClick={() => handleRecipientSign()} - type="button" - className="op-btn op-btn-primary mr-1" - > - {t("yes")} - </button> - )} - <button - onClick={() => { - setIsSend(false); - setSignerPos([]); - navigate("/report/1MwEuxLEkF"); - }} - type="button" - className="op-btn op-btn-ghost" + {mailStatus !== "quotareached" && ( + <div + className={ + mailStatus === "success" + ? "flex justify-center mt-1" + : "" + } > - {isCurrUser ? t("no") : t("close")} - </button> - </div> + {isCurrUser && ( + <button + onClick={() => handleRecipientSign()} + type="button" + className="op-btn op-btn-primary mr-1" + > + {t("yes")} + </button> + )} + <button + onClick={() => { + setIsSend(false); + setSignerPos([]); + navigate("/report/1MwEuxLEkF"); + }} + type="button" + className="op-btn op-btn-ghost" + > + {isCurrUser ? t("no") : t("close")} + </button> + </div> + )} </div> </ModalUi> <ModalUi diff --git a/apps/OpenSign/src/pages/SignyourselfPdf.js b/apps/OpenSign/src/pages/SignyourselfPdf.js index f4dc4cf56..da31e5214 100644 --- a/apps/OpenSign/src/pages/SignyourselfPdf.js +++ b/apps/OpenSign/src/pages/SignyourselfPdf.js @@ -57,6 +57,7 @@ import PdfZoom from "../components/pdf/PdfZoom"; import Loader from "../primitives/Loader"; import { useTranslation } from "react-i18next"; import RotateAlert from "../components/RotateAlert"; +import QuotaCard from "../primitives/QuotaCard"; //For signYourself inProgress section signer can add sign and complete doc sign. function SignYourSelf() { const { t } = useTranslation(); @@ -128,56 +129,37 @@ function SignYourSelf() { const isHeader = useSelector((state) => state.showHeader); const [scale, setScale] = useState(1); const [pdfRotateBase64, setPdfRotatese64] = useState(""); - const [isRotate, setIsRotate] = useState({ - status: false, - degree: 0 - }); + const [isRotate, setIsRotate] = useState({ status: false, degree: 0 }); + const [isSubscribe, setIsSubscribe] = useState({ plan: "", isValid: true }); const divRef = useRef(null); const nodeRef = useRef(null); const [, drop] = useDrop({ accept: "BOX", drop: (item, monitor) => addPositionOfSignature(item, monitor), - collect: (monitor) => ({ - isOver: !!monitor.isOver() - }) + collect: (monitor) => ({ isOver: !!monitor.isOver() }) }); const pdfRef = useRef(); const [{ isDragSign }, dragSignature] = useDrag({ type: "BOX", - item: { - id: 1, - text: "signature" - }, - collect: (monitor) => ({ - isDragSign: !!monitor.isDragging() - }) + item: { id: 1, text: "signature" }, + collect: (monitor) => ({ isDragSign: !!monitor.isDragging() }) }); - const [{ isDragStamp }, dragStamp] = useDrag({ type: "BOX", - item: { - id: 2, - text: "stamp" - }, - - collect: (monitor) => ({ - isDragStamp: !!monitor.isDragging() - }) + item: { id: 2, text: "stamp" }, + collect: (monitor) => ({ isDragStamp: !!monitor.isDragging() }) }); const index = xyPostion?.findIndex((object) => { return object.pageNumber === pageNumber; }); - // rowlevel={JSON.parse(localStorage.getItem("rowlevel"))} const rowLevel = localStorage.getItem("rowlevel") && JSON.parse(localStorage.getItem("rowlevel")); - const signObjId = rowLevel && rowLevel?.id ? rowLevel.id : rowLevel?.objectId && rowLevel.objectId; - const documentId = docId ? docId : signObjId && signObjId; const senderUser = localStorage.getItem( @@ -217,6 +199,12 @@ function SignYourSelf() { //function for get document details for perticular signer with signer'object id const getDocumentDetails = async (showComplete) => { + try { + const subscribe = await checkIsSubscribed(); + setIsSubscribe(subscribe); + } catch (err) { + console.log("err in fetch sub", err); + } try { let isCompleted; //getting document details @@ -585,8 +573,7 @@ function SignYourSelf() { docCls.id = documentId; docCls.set("Placeholders", xyPostion); docCls.set("IsSignyourself", true); - const res = await docCls.save(); - console.log("Res", res); + await docCls.save(); } catch (e) { console.log("error", e); alert(t("something-went-wrong-mssg")); @@ -730,7 +717,7 @@ function SignYourSelf() { //function for get digital signature const signPdfFun = async (base64Url, documentId) => { let isCustomCompletionMail = false; - const getIsSubscribe = await checkIsSubscribed(); + const tenantDetails = await getTenantDetails(jsonSender.objectId); if (tenantDetails && tenantDetails === "user does not exist!") { alert(t("user-not-exist")); @@ -738,7 +725,7 @@ function SignYourSelf() { if ( tenantDetails?.CompletionBody && tenantDetails?.CompletionSubject && - getIsSubscribe.isValid + isSubscribe?.isValid ) { isCustomCompletionMail = true; } @@ -1255,14 +1242,29 @@ function SignYourSelf() { <div className="w-full md:w-[95%]"> <ModalUi isOpen={isAlert.isShow} - title={isAlert?.header || t("alert")} + title={ + isAlert.alertMessage === "quotareached" + ? false + : isAlert?.header || t("alert") + } handleClose={() => - setIsAlert({ isShow: false, alertMessage: "" }) + isAlert.alertMessage === "quotareached" + ? false + : setIsAlert({ isShow: false, alertMessage: "" }) } > - <div className="p-[20px] h-full"> - <p>{isAlert.alertMessage}</p> - </div> + {isAlert.alertMessage === "quotareached" ? ( + <QuotaCard + isSignyourself={true} + handlClose={() => + setIsAlert({ isShow: false, alertMessage: "" }) + } + /> + ) : ( + <div className="p-[20px] h-full"> + <p>{isAlert.alertMessage}</p> + </div> + )} </ModalUi> {/* this modal is used show this document is already sign */} @@ -1342,6 +1344,7 @@ function SignYourSelf() { setIsAlert={setIsAlert} extUserId={extUserId} activeMailAdapter={activeMailAdapter} + planCode={isSubscribe?.plan} /> {/* pdf header which contain funish back button */} <Header diff --git a/apps/OpenSign/src/pages/Webhook.js b/apps/OpenSign/src/pages/Webhook.js index b01f95a79..939d8ea5c 100644 --- a/apps/OpenSign/src/pages/Webhook.js +++ b/apps/OpenSign/src/pages/Webhook.js @@ -10,7 +10,6 @@ import Tooltip from "../primitives/Tooltip"; import Loader from "../primitives/Loader"; import SubscribeCard from "../primitives/SubscribeCard"; import Tour from "reactour"; -import { validplan } from "../json/plansArr"; import { useTranslation } from "react-i18next"; function Webhook() { @@ -90,7 +89,7 @@ function Webhook() { }; const handleModal = () => { - if (!validplan[isSubscribe.plan] && isEnableSubscription) { + if (!isSubscribe?.isValid && isEnableSubscription) { setIsTour(true); } else { setIsModal(!isModal); @@ -146,7 +145,7 @@ function Webhook() { </div> <ModalUi isOpen={isModal} - title={"Regenerate Token"} + title={t("Add-Webhook")} handleClose={handleModal} > {error && <Alert type="danger">{error}</Alert>} @@ -178,7 +177,7 @@ function Webhook() { </div> </ModalUi> </div> - {!validplan[isSubscribe.plan] && isEnableSubscription && ( + {!isSubscribe?.isValid && isEnableSubscription && ( <div data-tut="webhooksubscribe"> <SubscribeCard plan_code={isSubscribe.plan} /> </div> diff --git a/apps/OpenSign/src/primitives/ModalUi.js b/apps/OpenSign/src/primitives/ModalUi.js index c11094627..2f03c0d33 100644 --- a/apps/OpenSign/src/primitives/ModalUi.js +++ b/apps/OpenSign/src/primitives/ModalUi.js @@ -21,9 +21,11 @@ const ModalUi = ({ > {showHeader && ( <> - <h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]"> - {title} - </h3> + {title && ( + <h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]"> + {title} + </h3> + )} {showClose && ( <button className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2" diff --git a/apps/OpenSign/src/primitives/QuotaCard.js b/apps/OpenSign/src/primitives/QuotaCard.js new file mode 100644 index 000000000..1a29bbbd3 --- /dev/null +++ b/apps/OpenSign/src/primitives/QuotaCard.js @@ -0,0 +1,53 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { useNavigate } from "react-router-dom"; + +const QuotaCard = ({ isSignyourself, handlClose }) => { + const { t } = useTranslation(); + const navigate = useNavigate(); + return isSignyourself ? ( + <> + <div + className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-primary-content absolute right-2 top-2 z-40" + onClick={() => handlClose && handlClose()} + > + ✕ + </div> + <div className="op-card op-bg-primary text-primary-content w-full shadow-lg"> + <div className="op-card-body"> + <h2 className="op-card-title"> + {t("upgrade-to") + " Paid " + t("plan")} + </h2> + <p className="text-primary-content">{t("quotamailselfsign")}</p> + <div className="op-card-actions justify-end"> + <button + onClick={() => navigate("/subscription")} + className="op-btn op-btn-accent" + > + {t("upgrade-now")} + </button> + </div> + </div> + </div> + </> + ) : ( + <> + <div className="op-card op-bg-primary text-primary-content w-full shadow-lg"> + <div className="op-card-body"> + <p className="text-primary-content">{t("quotamail")}</p> + <p className="text-primary-content">{t("quotamailTip")}</p> + <div className="op-card-actions justify-end"> + <button + onClick={() => navigate("/subscription")} + className="op-btn op-btn-accent" + > + {t("upgrade-now")} + </button> + </div> + </div> + </div> + </> + ); +}; + +export default QuotaCard; diff --git a/apps/OpenSignServer/Utils.js b/apps/OpenSignServer/Utils.js index 3e2660a21..2ff086bdd 100644 --- a/apps/OpenSignServer/Utils.js +++ b/apps/OpenSignServer/Utils.js @@ -91,7 +91,7 @@ const saveDataFile = async (size, fileUrl, tenantPtr) => { } }; -export const updateMailCount = async extUserId => { +export const updateMailCount = async (extUserId, plan, monthchange) => { // Update count in contracts_Users class const query = new Parse.Query('contracts_Users'); query.equalTo('objectId', extUserId); @@ -100,13 +100,23 @@ export const updateMailCount = async extUserId => { const contractUser = await query.first({ useMasterKey: true }); if (contractUser) { contractUser.increment('EmailCount', 1); + if (plan === 'freeplan') { + if (monthchange) { + contractUser.set('LastEmailCountReset', new Date()); + contractUser.set('MontlyfreeEmails', 1); + } else { + if (contractUser?.get('MontlyfreeEmails')) { + contractUser.increment('MontlyfreeEmails', 1); + if (contractUser?.get('LastEmailCountReset')) { + contractUser.set('LastEmailCountReset', new Date()); + } + } else { + contractUser.set('MontlyfreeEmails', 1); + contractUser.set('LastEmailCountReset', new Date()); + } + } + } await contractUser.save(null, { useMasterKey: true }); - } else { - // Create new entry if not found - const ContractsUsers = Parse.Object.extend('contracts_Users'); - const newContractUser = new ContractsUsers(); - newContractUser.set('EmailCount', 1); - await newContractUser.save(null, { useMasterKey: true }); } } catch (error) { console.log('Error updating EmailCount in contracts_Users: ' + error.message); diff --git a/apps/OpenSignServer/cloud/parsefunction/sendMailGmailProvider.js b/apps/OpenSignServer/cloud/parsefunction/sendMailGmailProvider.js index 0a826f701..f614e5754 100644 --- a/apps/OpenSignServer/cloud/parsefunction/sendMailGmailProvider.js +++ b/apps/OpenSignServer/cloud/parsefunction/sendMailGmailProvider.js @@ -142,8 +142,7 @@ export default async function sendMailGmailProvider(_extRes, template) { raw: email, }, }); - // console.log('response ', response); - + console.log('gmail provider res: ', response?.status); return { code: 200, message: 'Email sent successfully' }; } catch (error) { console.error('Error sending email:', error); diff --git a/apps/OpenSignServer/cloud/parsefunction/sendMailv3.js b/apps/OpenSignServer/cloud/parsefunction/sendMailv3.js index eb23be4e4..4cef012d6 100644 --- a/apps/OpenSignServer/cloud/parsefunction/sendMailv3.js +++ b/apps/OpenSignServer/cloud/parsefunction/sendMailv3.js @@ -6,7 +6,7 @@ import Mailgun from 'mailgun.js'; import { smtpenable, smtpsecure, updateMailCount, useLocal } from '../../Utils.js'; import sendMailGmailProvider from './sendMailGmailProvider.js'; import { createTransport } from 'nodemailer'; -async function sendMailProvider(req) { +async function sendMailProvider(req, plan, monthchange) { const mailgunApiKey = process.env.MAILGUN_API_KEY; try { let transporterSMTP; @@ -69,18 +69,23 @@ async function sendMailProvider(req) { }; let attachment; - // `certificateBuffer` used to create buffer from pdf file - try { - const certificateBuffer = fs.readFileSync('./exports/certificate.pdf'); - const certificate = { - filename: 'certificate.pdf', - content: smtpenable ? certificateBuffer : undefined, //fs.readFileSync('./exports/exported_file_1223.pdf'), - data: smtpenable ? undefined : certificateBuffer, - }; - attachment = [file, certificate]; - } catch (err) { + const certificatePath = './exports/certificate.pdf'; + if (fs.existsSync(certificatePath)) { + try { + // `certificateBuffer` used to create buffer from pdf file + const certificateBuffer = fs.readFileSync(certificatePath); + const certificate = { + filename: 'certificate.pdf', + content: smtpenable ? certificateBuffer : undefined, //fs.readFileSync('./exports/exported_file_1223.pdf'), + data: smtpenable ? undefined : certificateBuffer, + }; + attachment = [file, certificate]; + } catch (err) { + attachment = [file]; + console.log('Err in read certificate sendmailv3', err); + } + } else { attachment = [file]; - console.log('Err in read certificate sendmailv3', err); } const from = req.params.from || ''; const mailsender = smtpenable ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER; @@ -96,38 +101,44 @@ async function sendMailProvider(req) { }; if (transporterSMTP) { const res = await transporterSMTP.sendMail(messageParams); - console.log('Res ', res); + console.log('smtp transporter res: ', res?.response); if (!res.err) { if (req.params?.extUserId) { - await updateMailCount(req.params.extUserId); + await updateMailCount(req.params.extUserId, plan, monthchange); } - try { - fs.unlinkSync('./exports/certificate.pdf'); - } catch (err) { - console.log('Err in unlink certificate sendmailv3'); + if (fs.existsSync(certificatePath)) { + try { + fs.unlinkSync(certificatePath); + } catch (err) { + console.log('Err in unlink certificate sendmailv3'); + } } return { status: 'success' }; } } else { if (mailgunApiKey) { const res = await mailgunClient.messages.create(mailgunDomain, messageParams); - console.log('Res ', res); + console.log('mailgun res: ', res?.status); if (res.status === 200) { if (req.params?.extUserId) { - await updateMailCount(req.params.extUserId); + await updateMailCount(req.params.extUserId, plan, monthchange); } - try { - fs.unlinkSync('./exports/certificate.pdf'); - } catch (err) { - console.log('Err in unlink certificate sendmailv3'); + if (fs.existsSync(certificatePath)) { + try { + fs.unlinkSync(certificatePath); + } catch (err) { + console.log('Err in unlink certificate sendmailv3'); + } } return { status: 'success' }; } } else { - try { - fs.unlinkSync('./exports/certificate.pdf'); - } catch (err) { - console.log('Err in unlink certificate sendmailv3'); + if (fs.existsSync(certificatePath)) { + try { + fs.unlinkSync(certificatePath); + } catch (err) { + console.log('Err in unlink certificate sendmailv3'); + } } return { status: 'error' }; } @@ -147,20 +158,20 @@ async function sendMailProvider(req) { if (transporterSMTP) { const res = await transporterSMTP.sendMail(messageParams); - console.log('Res ', res); + console.log('smtp transporter res: ', res?.response); if (!res.err) { if (req.params?.extUserId) { - await updateMailCount(req.params.extUserId); + await updateMailCount(req.params.extUserId, plan, monthchange); } return { status: 'success' }; } } else { if (mailgunApiKey) { const res = await mailgunClient.messages.create(mailgunDomain, messageParams); - console.log('Res ', res); + console.log('mailgun res: ', res?.status); if (res.status === 200) { if (req.params?.extUserId) { - await updateMailCount(req.params.extUserId); + await updateMailCount(req.params.extUserId, plan, monthchange); } return { status: 'success' }; } @@ -180,6 +191,7 @@ async function sendmailv3(req) { const mailProvider = req.params.mailProvider || 'default'; if (mailProvider) { try { + const Plan = req.params.plan; const extUserId = req.params.extUserId || ''; const pdfName = req.params.pdfName || ''; const template = { @@ -203,8 +215,31 @@ async function sendmailv3(req) { return { status: 'error' }; } } else { - const nonCustomMail = await sendMailProvider(req); - return nonCustomMail; + if (Plan && Plan === 'freeplan') { + let MontlyfreeEmails = _extRes?.MontlyfreeEmails || 0; + if (_extRes?.LastEmailCountReset?.iso) { + const lastDate = new Date(_extRes?.LastEmailCountReset?.iso); + const newDate = new Date(); + const isMonthChange = newDate.getMonth() > lastDate.getMonth(); + if (isMonthChange) { + const nonCustomMail = await sendMailProvider(req, Plan, true); + return nonCustomMail; + } else { + if (MontlyfreeEmails >= 20) { + return { status: 'quota-reached' }; + } else { + const nonCustomMail = await sendMailProvider(req, Plan); + return nonCustomMail; + } + } + } else { + const nonCustomMail = await sendMailProvider(req, Plan); + return nonCustomMail; + } + } else { + const nonCustomMail = await sendMailProvider(req, ''); + return nonCustomMail; + } } } } catch (err) { From a765668354c6f70341bd5d2bbdf0f7d8948de798 Mon Sep 17 00:00:00 2001 From: prafull-opensignlabs <prafull.navkar@nxglabs.com> Date: Mon, 2 Sep 2024 19:31:38 +0530 Subject: [PATCH 3/3] fix: failed to load pdf issue on self-host with docker --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index b7f6455f5..63d4e19d6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,7 +9,7 @@ services: env_file: .env.prod environment: - NODE_ENV=production - - SERVER_URL=${HOST_URL:-https://localhost:3001/app} + - SERVER_URL=${HOST_URL:-https://localhost:3001}/app networks: - app-network mongo: