mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-07 02:07:40 +02:00
Compare commits
44
Commits
v1.4.0-beta
...
v1.4.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97bd375de3 | ||
|
|
e2d450f9aa | ||
|
|
add01cb02a | ||
|
|
cea1653805 | ||
|
|
79e3762b36 | ||
|
|
aa04a957ed | ||
|
|
d31910aefa | ||
|
|
96a4a2e7fa | ||
|
|
e8aaab99f9 | ||
|
|
0ee85f53da | ||
|
|
748e2196da | ||
|
|
58199a934a | ||
|
|
7eec822a65 | ||
|
|
6c21028523 | ||
|
|
099a3cc46d | ||
|
|
5adaffc684 | ||
|
|
d588caf6d4 | ||
|
|
5930fd940d | ||
|
|
741f66b019 | ||
|
|
0bf07c2703 | ||
|
|
de26c2d719 | ||
|
|
881ac12b03 | ||
|
|
1932dda6d6 | ||
|
|
46159b7214 | ||
|
|
c57c15a4cb | ||
|
|
724fa7c27e | ||
|
|
2762c3e170 | ||
|
|
10a0c60056 | ||
|
|
036c9b8d4a | ||
|
|
1f50368259 | ||
|
|
6d5e07dac7 | ||
|
|
3656175f11 | ||
|
|
febb50c3cd | ||
|
|
f8ba0d357b | ||
|
|
74bfd39abc | ||
|
|
5a25b2d874 | ||
|
|
3115ff3e2a | ||
|
|
d1e7b9a2ab | ||
|
|
adbf1fe1e0 | ||
|
|
60140885e0 | ||
|
|
fe2f3c5f7c | ||
|
|
a06723ff3f | ||
|
|
8a01efee4c | ||
|
|
eafb26d462 |
@@ -42,24 +42,24 @@ Please star ⭐ the repo to support us! 😀
|
|||||||
|
|
||||||
### Introduction
|
### Introduction
|
||||||
|
|
||||||
Welcome to OpenSign, the premier open-source docusign alternative - document e-signing solution designed to provide a secure, reliable, and free alternative to commercial platforms like DocuSign, PandaDoc, SignNow, Adobe Sign, Smartwaiver, SignRequest, HelloSign & Zoho sign. Developed under the OpenSignLabs organization, our mission is to democratize the e-signing process, making it accessible and straightforward for everyone.
|
Welcome to OpenSign, the premier open source docusign alternative - document e-signing solution designed to provide a secure, reliable and free alternative to commercial esign platforms like DocuSign, PandaDoc, SignNow, Adobe Sign, Smartwaiver, SignRequest, HelloSign & Zoho sign. Our mission is to democratize the e-signing process, making it accessible and straightforward for everyone.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- **Secure PDF E-Signing:** With the help of Robust encryption algorithms, OpenSign™ ensures maximum security, privacy & compatibility.
|
- **Secure PDF E-Signing:** With the help of robust encryption algorithms, OpenSign™ ensures maximum security, privacy & compatibility.
|
||||||
- **Annotate Documents:** OpenSign™ allows you to annotate PDF documents with an advanced signing pad that comes with hand drawn signatures support as well as uploaded images & saved signatures for the simplest signing experience.
|
- **Annotate Documents:** OpenSign™ allows you to annotate PDF documents with an advanced signing pad that allows hand drawn signatures, uploaded images, typed signatures & saved signatures for the simplest signing experience ever.
|
||||||
- **User-Friendly Interface:** OpenSign™ was built while keeping Intuitive design in mind for ease of use. Features like "Sign yourself", "One click signatures" and "OpenSign Drive" makes it stand out of the crowd and even makes it better than a lot of so-called industry leaders.
|
- **User-Friendly Interface:** OpenSign™ was built while keeping Intuitive design in mind for ease of use. Features like "Sign yourself", "Templates", "One click signatures" and "OpenSign™ Drive" makes it stand out of the crowd and even makes it better than a lot of so-called industry leaders.
|
||||||
- **Multi-signer Support:** OpenSign's ability to invite multiple signers for signing along with the ability to invite witnesses & being able to enforce signing in a sequence makes it the only open source solution that is fully loaded and allows it to compete head-to-head with established players.
|
- **Multi-signer Support:** OpenSign's ability to invite multiple signers for signing along with the ability to invite witnesses & being able to enforce signing in a sequence makes it the only open source solution that is fully loaded and allows it to compete head-to-head with established players in e-signature space.
|
||||||
- **Email Unique Code(OTP) verification support for guest signers:** With OpenSign™, your documents are fully secure even when being signed by guest users. Guest signers can only sign the document after entering a unique code sent to their email address.
|
- **Email Unique Code(OTP) verification support for guest signers:** With OpenSign™, your documents are fully secure even when being signed by guest users. Guest signers can only sign the document after entering a unique code sent to their email address.
|
||||||
- **"Expiring Docs" & "Rejection":** You can set documents to expire after certain number of days after which nobody will be able to sign it. Not just this, OpenSign also allows signers to reject signing a document.
|
- **"Expiring Docs" & "Rejection":** You can set documents to expire after certain number of days after which nobody will be able to sign. Not just this, OpenSign™ also allows signers to reject signing a document.
|
||||||
- **Beautiful email templates:** All document signing invitations, completion notifications & reminders are formatted using great looking email templates.
|
- **Beautiful email templates:** All document signing invitations, completion notifications & reminders are formatted using great looking email templates.
|
||||||
- **PDF Template Creation(coming soon):** OpenSign™ allows you to create and store PDF document templates for repeated use thereby saving you a lot of time.
|
- **PDF Template Creation:** OpenSign™ allows you to create and store PDF document templates for repeated use thereby saving you a lot of time & collect e-signatures seamlessly.
|
||||||
- **OpenSign™ Drive:** It is a centralised secure vault for your signed documents that makes storing, signing, organizing, sharing & achieving your docs a breeze.
|
- **OpenSign™ Drive:** It is a centralised secure vault for your digital documents that makes storing, signing, organizing, sharing & achieving your docs a breeze.
|
||||||
- **Audit Trails & completion certificate:** Being a security focused solution, OpenSign™ makes it a top priority to save detailed logs for tracking document activities along with time-stamps, IP addresses, email IDs & phone numbers. A completion certificate is generated as soon as document is completed which contains all the document related logs for added safety.
|
- **Audit Trails & completion certificate:** Being a security focused solution, OpenSign™ makes it a top priority to save detailed logs for tracking document activities along with time-stamps, IP addresses, email IDs & phone numbers. A completion certificate is generated as soon as document is completed which contains all the document related logs for added safety.
|
||||||
- **API Support(coming soon):** OpenSign™ API allows seamless integration into existing systems and software. APIs will soon be available as a cloud hosted solution.
|
- **API Support:** OpenSign™ API allows seamless integration into existing systems and software. You can generate an API key from the app and refer the [docs](https://docs.opensignlabs.com) to start integrating it in your existing applications.
|
||||||
- **Integrations:** Seamless integrations with various Cloud storage systems, CRMs & enterprise platforms is coming soon.
|
- **Integrations:** Seamless integrations with various Cloud storage systems, CRMs & enterprise platforms is available. We also have a Zapier integration that allows you to integrate it with virtually any application.
|
||||||
|
|
||||||
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/b37ff443-7099-4273-9aeb-21c46d7154cf height='200'>
|
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/b37ff443-7099-4273-9aeb-21c46d7154cf height='200'>
|
||||||
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/86db91b7-6c2f-4885-a33c-58f4fd35ec89 height='200'>
|
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/86db91b7-6c2f-4885-a33c-58f4fd35ec89 height='200'>
|
||||||
@@ -76,7 +76,7 @@ Please refer to the [Installation Guide](INSTALLATION.md) for detailed instructi
|
|||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
For comprehensive guidelines on how to use OpenSign, please consult our [User Manual](USAGE.md).
|
For comprehensive guidelines on how to use OpenSign™, please consult our [User Manual](USAGE.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import DraftDocument from "./components/pdf/DraftDocument";
|
|||||||
import PlaceHolderSign from "./pages/PlaceHolderSign";
|
import PlaceHolderSign from "./pages/PlaceHolderSign";
|
||||||
import PdfRequestFiles from "./pages/PdfRequestFiles";
|
import PdfRequestFiles from "./pages/PdfRequestFiles";
|
||||||
import LazyPage from "./primitives/LazyPage";
|
import LazyPage from "./primitives/LazyPage";
|
||||||
|
import { isEnableSubscription } from "./constant/const";
|
||||||
const DebugPdf = lazy(() => import("./pages/DebugPdf"));
|
const DebugPdf = lazy(() => import("./pages/DebugPdf"));
|
||||||
const ForgetPassword = lazy(() => import("./pages/ForgetPassword"));
|
const ForgetPassword = lazy(() => import("./pages/ForgetPassword"));
|
||||||
const GuestLogin = lazy(() => import("./pages/GuestLogin"));
|
const GuestLogin = lazy(() => import("./pages/GuestLogin"));
|
||||||
@@ -113,7 +114,7 @@ function App() {
|
|||||||
path="/forgetpassword"
|
path="/forgetpassword"
|
||||||
element={<LazyPage Page={ForgetPassword} />}
|
element={<LazyPage Page={ForgetPassword} />}
|
||||||
/>
|
/>
|
||||||
{process.env.REACT_APP_ENABLE_SUBSCRIPTION && (
|
{isEnableSubscription && (
|
||||||
<>
|
<>
|
||||||
<Route
|
<Route
|
||||||
path="/pgsignup"
|
path="/pgsignup"
|
||||||
|
|||||||
@@ -56,11 +56,11 @@ const AddSigner = (props) => {
|
|||||||
contactQuery.set("Email", email);
|
contactQuery.set("Email", email);
|
||||||
contactQuery.set("UserRole", "contracts_Guest");
|
contactQuery.set("UserRole", "contracts_Guest");
|
||||||
|
|
||||||
if (localStorage.getItem("TenetId")) {
|
if (localStorage.getItem("TenantId")) {
|
||||||
contactQuery.set("TenantId", {
|
contactQuery.set("TenantId", {
|
||||||
__type: "Pointer",
|
__type: "Pointer",
|
||||||
className: "partners_Tenant",
|
className: "partners_Tenant",
|
||||||
objectId: localStorage.getItem("TenetId")
|
objectId: localStorage.getItem("TenantId")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,11 +48,11 @@ const AddUser = (props) => {
|
|||||||
contactQuery.set("Email", email);
|
contactQuery.set("Email", email);
|
||||||
contactQuery.set("UserRole", "contracts_User");
|
contactQuery.set("UserRole", "contracts_User");
|
||||||
|
|
||||||
if (localStorage.getItem("TenetId")) {
|
if (localStorage.getItem("TenantId")) {
|
||||||
contactQuery.set("TenantId", {
|
contactQuery.set("TenantId", {
|
||||||
__type: "Pointer",
|
__type: "Pointer",
|
||||||
className: "partners_Tenant",
|
className: "partners_Tenant",
|
||||||
objectId: localStorage.getItem("TenetId")
|
objectId: localStorage.getItem("TenantId")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,20 +4,32 @@ import FullScreenButton from "./FullScreenButton";
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import { useWindowSize } from "../hook/useWindowSize";
|
import { useWindowSize } from "../hook/useWindowSize";
|
||||||
import { openInNewTab } from "../constant/Utils";
|
import { checkIsSubscribed, openInNewTab } from "../constant/Utils";
|
||||||
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
|
||||||
const Header = ({ showSidebar }) => {
|
const Header = ({ showSidebar }) => {
|
||||||
const navigation = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
let applogo = localStorage.getItem("appLogo") || "";
|
let applogo = localStorage.getItem("appLogo") || "";
|
||||||
let username = localStorage.getItem("username");
|
let username = localStorage.getItem("username");
|
||||||
const image = localStorage.getItem("profileImg") || dp;
|
const image = localStorage.getItem("profileImg") || dp;
|
||||||
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [isSubscribe, setIsSubscribe] = useState(true);
|
||||||
|
|
||||||
const toggleDropdown = () => {
|
const toggleDropdown = () => {
|
||||||
setIsOpen(!isOpen);
|
setIsOpen(!isOpen);
|
||||||
};
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
checkSubscription();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
async function checkSubscription() {
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const getIsSubscribe = await checkIsSubscribed();
|
||||||
|
setIsSubscribe(getIsSubscribe);
|
||||||
|
}
|
||||||
|
}
|
||||||
const closeDropdown = () => {
|
const closeDropdown = () => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
Parse.User.logOut();
|
Parse.User.logOut();
|
||||||
@@ -43,7 +55,7 @@ const Header = ({ showSidebar }) => {
|
|||||||
localStorage.setItem("baseUrl", baseUrl);
|
localStorage.setItem("baseUrl", baseUrl);
|
||||||
localStorage.setItem("parseAppId", appid);
|
localStorage.setItem("parseAppId", appid);
|
||||||
|
|
||||||
navigation("/");
|
navigate("/");
|
||||||
};
|
};
|
||||||
|
|
||||||
//handle to close profile drop down menu onclick screen
|
//handle to close profile drop down menu onclick screen
|
||||||
@@ -83,6 +95,16 @@ const Header = ({ showSidebar }) => {
|
|||||||
id="profile-menu"
|
id="profile-menu"
|
||||||
className="flex justify-between items-center gap-x-3"
|
className="flex justify-between items-center gap-x-3"
|
||||||
>
|
>
|
||||||
|
{!isSubscribe && (
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
className="text-xs bg-[#002864] p-2 text-white rounded shadow"
|
||||||
|
onClick={() => navigate("/subscription")}
|
||||||
|
>
|
||||||
|
Upgrade Now
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div>
|
<div>
|
||||||
<FullScreenButton />
|
<FullScreenButton />
|
||||||
</div>
|
</div>
|
||||||
@@ -123,7 +145,7 @@ const Header = ({ showSidebar }) => {
|
|||||||
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
|
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
navigation("/profile");
|
navigate("/profile");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<i className="fa-regular fa-user"></i> Profile
|
<i className="fa-regular fa-user"></i> Profile
|
||||||
@@ -132,7 +154,7 @@ const Header = ({ showSidebar }) => {
|
|||||||
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
|
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
navigation("/changepassword");
|
navigate("/changepassword");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-lock"></i> Change Password
|
<i className="fa-solid fa-lock"></i> Change Password
|
||||||
|
|||||||
@@ -353,7 +353,7 @@ const DashboardCard = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs absolute top-1 right-1">
|
<div className="text-xs absolute top-2 right-1">
|
||||||
<Tooltip id={props.Label} iconColor={"white"} message={props?.Data?.tourMessage} />
|
<Tooltip id={props.Label} iconColor={"white"} message={props?.Data?.tourMessage} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const AddRoleModal = (props) => {
|
|||||||
margin: "10px 0 10px 5px"
|
margin: "10px 0 10px 5px"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
e.g: Hr, Director, Manager, New joinee, Accountant, etc...
|
e.g: Customer, Hr, Director, Manager, Student, etc...
|
||||||
</p>
|
</p>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { themeColor } from "../../constant/const";
|
import { isEnableSubscription, themeColor } from "../../constant/const";
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
import { radioButtonWidget } from "../../constant/Utils";
|
import { radioButtonWidget } from "../../constant/Utils";
|
||||||
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
||||||
|
import Upgrade from "../../primitives/Upgrade";
|
||||||
function DropdownWidgetOption(props) {
|
function DropdownWidgetOption(props) {
|
||||||
const [dropdownOptionList, setDropdownOptionList] = useState([
|
const [dropdownOptionList, setDropdownOptionList] = useState([
|
||||||
"option-1",
|
"option-1",
|
||||||
@@ -241,36 +242,59 @@ function DropdownWidgetOption(props) {
|
|||||||
}}
|
}}
|
||||||
className="fa-solid fa-square-plus"
|
className="fa-solid fa-square-plus"
|
||||||
></i>
|
></i>
|
||||||
{props.type === "checkbox" && !props.isSignYourself && (
|
<div>
|
||||||
<>
|
{props.type === "checkbox" && !props.isSignYourself && (
|
||||||
<label style={{ fontSize: "13px", fontWeight: "600" }}>
|
<>
|
||||||
Minimun check
|
<label
|
||||||
</label>
|
style={{
|
||||||
<input
|
fontSize: "13px",
|
||||||
required
|
fontWeight: "600",
|
||||||
defaultValue={0}
|
color: !props.isSubscribe && "gray"
|
||||||
value={minCount}
|
}}
|
||||||
onChange={(e) => {
|
>
|
||||||
const count = handleSetMinMax(e);
|
Minimun check
|
||||||
setMinCount(count);
|
</label>
|
||||||
}}
|
{!props.isSubscribe && isEnableSubscription && <Upgrade />}
|
||||||
className="drodown-input"
|
<input
|
||||||
/>
|
required
|
||||||
<label style={{ fontSize: "13px", fontWeight: "600" }}>
|
defaultValue={0}
|
||||||
Maximum check
|
value={minCount}
|
||||||
</label>
|
onChange={(e) => {
|
||||||
<input
|
const count = handleSetMinMax(e);
|
||||||
required
|
setMinCount(count);
|
||||||
defaultValue={0}
|
}}
|
||||||
value={maxCount}
|
className={
|
||||||
onChange={(e) => {
|
props.isSubscribe || !isEnableSubscription
|
||||||
const count = handleSetMinMax(e);
|
? "drodown-input"
|
||||||
setMaxCount(count);
|
: "disabled drodown-input"
|
||||||
}}
|
}
|
||||||
className="drodown-input"
|
/>
|
||||||
/>
|
<label
|
||||||
</>
|
style={{
|
||||||
)}
|
fontSize: "13px",
|
||||||
|
fontWeight: "600",
|
||||||
|
color: !props.isSubscribe && "gray"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Maximum check
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
required
|
||||||
|
defaultValue={0}
|
||||||
|
value={maxCount}
|
||||||
|
onChange={(e) => {
|
||||||
|
const count = handleSetMinMax(e);
|
||||||
|
setMaxCount(count);
|
||||||
|
}}
|
||||||
|
className={
|
||||||
|
props.isSubscribe || !isEnableSubscription
|
||||||
|
? "drodown-input"
|
||||||
|
: "disabled drodown-input"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{["dropdown", radioButtonWidget].includes(props.type) && (
|
{["dropdown", radioButtonWidget].includes(props.type) && (
|
||||||
<>
|
<>
|
||||||
@@ -378,13 +402,15 @@ function DropdownWidgetOption(props) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{props.type === "checkbox" && !props.isSignYourself && (
|
{props.type === "checkbox" &&
|
||||||
<PremiumAlertHeader
|
!props.isSignYourself &&
|
||||||
message={
|
!isEnableSubscription && (
|
||||||
"Field validations are free in beta, this feature will incur a fee later."
|
<PremiumAlertHeader
|
||||||
}
|
message={
|
||||||
/>
|
"Field validations are free in beta, this feature will incur a fee later."
|
||||||
)}
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
props.type === "checkbox" && !props.isSignYourself
|
props.type === "checkbox" && !props.isSignYourself
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ function EmailComponent({
|
|||||||
setSuccessEmail,
|
setSuccessEmail,
|
||||||
pdfName,
|
pdfName,
|
||||||
sender,
|
sender,
|
||||||
setIsAlert
|
setIsAlert,
|
||||||
|
extUserId
|
||||||
}) {
|
}) {
|
||||||
const [emailList, setEmailList] = useState([]);
|
const [emailList, setEmailList] = useState([]);
|
||||||
const [emailValue, setEmailValue] = useState();
|
const [emailValue, setEmailValue] = useState();
|
||||||
@@ -38,6 +39,7 @@ function EmailComponent({
|
|||||||
const openSignUrl = "https://www.opensignlabs.com/contact-us";
|
const openSignUrl = "https://www.opensignlabs.com/contact-us";
|
||||||
const themeBGcolor = themeColor;
|
const themeBGcolor = themeColor;
|
||||||
let params = {
|
let params = {
|
||||||
|
extUserId: extUserId,
|
||||||
pdfName: pdfName,
|
pdfName: pdfName,
|
||||||
url: pdfUrl,
|
url: pdfUrl,
|
||||||
recipient: emailList[i],
|
recipient: emailList[i],
|
||||||
|
|||||||
@@ -275,6 +275,7 @@ function Placeholder(props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleOnClickPlaceholder = () => {
|
const handleOnClickPlaceholder = () => {
|
||||||
|
props.setCurrWidgetsDetails && props.setCurrWidgetsDetails(props.pos);
|
||||||
if (!props.isNeedSign) {
|
if (!props.isNeedSign) {
|
||||||
props.setWidgetType(props.pos.type);
|
props.setWidgetType(props.pos.type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -307,6 +307,7 @@ function PlaceholderType(props) {
|
|||||||
return props.pos.SignUrl ? (
|
return props.pos.SignUrl ? (
|
||||||
<img
|
<img
|
||||||
alt="signimg"
|
alt="signimg"
|
||||||
|
draggable="false"
|
||||||
src={props.pos.SignUrl}
|
src={props.pos.SignUrl}
|
||||||
style={{
|
style={{
|
||||||
width: "99%",
|
width: "99%",
|
||||||
@@ -328,6 +329,7 @@ function PlaceholderType(props) {
|
|||||||
return props.pos.SignUrl ? (
|
return props.pos.SignUrl ? (
|
||||||
<img
|
<img
|
||||||
alt="signimg"
|
alt="signimg"
|
||||||
|
draggable="false"
|
||||||
src={props.pos.SignUrl}
|
src={props.pos.SignUrl}
|
||||||
style={{
|
style={{
|
||||||
width: "99%",
|
width: "99%",
|
||||||
@@ -483,6 +485,7 @@ function PlaceholderType(props) {
|
|||||||
return props.pos.SignUrl ? (
|
return props.pos.SignUrl ? (
|
||||||
<img
|
<img
|
||||||
alt="signimg"
|
alt="signimg"
|
||||||
|
draggable="false"
|
||||||
src={props.pos.SignUrl}
|
src={props.pos.SignUrl}
|
||||||
style={{
|
style={{
|
||||||
width: "99%",
|
width: "99%",
|
||||||
@@ -668,6 +671,7 @@ function PlaceholderType(props) {
|
|||||||
return props.pos.SignUrl ? (
|
return props.pos.SignUrl ? (
|
||||||
<img
|
<img
|
||||||
alt="signimg"
|
alt="signimg"
|
||||||
|
draggable="false"
|
||||||
src={props.pos.SignUrl}
|
src={props.pos.SignUrl}
|
||||||
style={{
|
style={{
|
||||||
width: "99%",
|
width: "99%",
|
||||||
@@ -787,6 +791,7 @@ function PlaceholderType(props) {
|
|||||||
<div style={{ pointerEvents: "none" }}>
|
<div style={{ pointerEvents: "none" }}>
|
||||||
<img
|
<img
|
||||||
alt="signimg"
|
alt="signimg"
|
||||||
|
draggable="false"
|
||||||
src={props.pos.SignUrl}
|
src={props.pos.SignUrl}
|
||||||
style={{
|
style={{
|
||||||
width: "99%",
|
width: "99%",
|
||||||
|
|||||||
@@ -116,7 +116,13 @@ const RecipientList = (props) => {
|
|||||||
data-tut="reactourFirst"
|
data-tut="reactourFirst"
|
||||||
onMouseEnter={() => setIsHover(ind)}
|
onMouseEnter={() => setIsHover(ind)}
|
||||||
onMouseLeave={() => setIsHover(null)}
|
onMouseLeave={() => setIsHover(null)}
|
||||||
className={props.sendInOrder && "dragCursor"}
|
className={
|
||||||
|
props.sendInOrder
|
||||||
|
? props.isMailSend
|
||||||
|
? "disabled"
|
||||||
|
: "dragCursor"
|
||||||
|
: props.isMailSend && "disabled"
|
||||||
|
}
|
||||||
style={
|
style={
|
||||||
(!isMobile && isHover === ind) || props.isSelectListId === ind
|
(!isMobile && isHover === ind) || props.isSelectListId === ind
|
||||||
? onHoverStyle(ind, obj?.blockColor)
|
? onHoverStyle(ind, obj?.blockColor)
|
||||||
|
|||||||
@@ -272,6 +272,7 @@ function RenderPdf({
|
|||||||
unSignedWidgetId={unSignedWidgetId}
|
unSignedWidgetId={unSignedWidgetId}
|
||||||
setSelectWidgetId={setSelectWidgetId}
|
setSelectWidgetId={setSelectWidgetId}
|
||||||
selectWidgetId={selectWidgetId}
|
selectWidgetId={selectWidgetId}
|
||||||
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ function SignPad({
|
|||||||
isInitial,
|
isInitial,
|
||||||
setIsInitial,
|
setIsInitial,
|
||||||
setIsStamp,
|
setIsStamp,
|
||||||
widgetType
|
widgetType,
|
||||||
|
currWidgetsDetails,
|
||||||
|
setCurrWidgetsDetails
|
||||||
}) {
|
}) {
|
||||||
const [penColor, setPenColor] = useState("blue");
|
const [penColor, setPenColor] = useState("blue");
|
||||||
const allColor = ["blue", "red", "black"];
|
const allColor = ["blue", "red", "black"];
|
||||||
@@ -31,6 +33,7 @@ function SignPad({
|
|||||||
const [signValue, setSignValue] = useState("");
|
const [signValue, setSignValue] = useState("");
|
||||||
const [textWidth, setTextWidth] = useState(null);
|
const [textWidth, setTextWidth] = useState(null);
|
||||||
const [textHeight, setTextHeight] = useState(null);
|
const [textHeight, setTextHeight] = useState(null);
|
||||||
|
const [signatureType, setSignatureType] = useState("draw");
|
||||||
const fontOptions = [
|
const fontOptions = [
|
||||||
{ value: "Fasthand" },
|
{ value: "Fasthand" },
|
||||||
{ value: "Dancing Script" },
|
{ value: "Dancing Script" },
|
||||||
@@ -48,19 +51,11 @@ function SignPad({
|
|||||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
);
|
);
|
||||||
const jsonSender = JSON.parse(senderUser);
|
const jsonSender = JSON.parse(senderUser);
|
||||||
|
|
||||||
const currentUserName = jsonSender && jsonSender.name;
|
const currentUserName = jsonSender && jsonSender.name;
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const trimmedName = currentUserName.trim();
|
|
||||||
const firstCharacter = trimmedName.charAt(0);
|
|
||||||
const userName = isInitial ? firstCharacter : currentUserName;
|
|
||||||
setSignValue(userName);
|
|
||||||
setFontSelect("Fasthand");
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
//function for clear signature image
|
//function for clear signature image
|
||||||
const handleClear = () => {
|
const handleClear = () => {
|
||||||
|
setCurrWidgetsDetails({});
|
||||||
if (isTab === "draw") {
|
if (isTab === "draw") {
|
||||||
if (canvasRef.current) {
|
if (canvasRef.current) {
|
||||||
canvasRef.current.clear();
|
canvasRef.current.clear();
|
||||||
@@ -72,7 +67,7 @@ function SignPad({
|
|||||||
} else if (isTab === "uploadImage") {
|
} else if (isTab === "uploadImage") {
|
||||||
setImage("");
|
setImage("");
|
||||||
}
|
}
|
||||||
setIsInitial(false);
|
// setIsInitial(false);
|
||||||
};
|
};
|
||||||
//function for set signature url
|
//function for set signature url
|
||||||
const handleSignatureChange = () => {
|
const handleSignatureChange = () => {
|
||||||
@@ -100,27 +95,28 @@ function SignPad({
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
setCurrWidgetsDetails({});
|
||||||
if (!image) {
|
if (!image) {
|
||||||
if (isTab === "mysignature") {
|
if (isTab === "mysignature") {
|
||||||
setIsSignImg("");
|
setIsSignImg("");
|
||||||
if (isInitial) {
|
if (isInitial) {
|
||||||
onSaveSign("initials");
|
onSaveSign(signatureType, "initials");
|
||||||
} else {
|
} else {
|
||||||
onSaveSign("default");
|
onSaveSign(null, "default");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isTab === "type") {
|
if (isTab === "type") {
|
||||||
setIsSignImg("");
|
setIsSignImg("");
|
||||||
onSaveSign(false, textWidth, textHeight);
|
onSaveSign(null, false, textWidth, textHeight);
|
||||||
} else {
|
} else {
|
||||||
onSaveSign();
|
onSaveSign(signatureType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setPenColor("blue");
|
setPenColor("blue");
|
||||||
} else {
|
} else {
|
||||||
setIsSignImg("");
|
setIsSignImg("");
|
||||||
onSaveImage();
|
onSaveImage(signatureType);
|
||||||
}
|
}
|
||||||
setIsSignPad(false);
|
setIsSignPad(false);
|
||||||
setIsInitial(false);
|
setIsInitial(false);
|
||||||
@@ -150,11 +146,27 @@ function SignPad({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
//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(() => {
|
useEffect(() => {
|
||||||
if (canvasRef.current && isSignImg) {
|
if (currWidgetsDetails && canvasRef.current) {
|
||||||
canvasRef.current.fromDataURL(isSignImg);
|
const isWidgetType = currWidgetsDetails?.type;
|
||||||
|
const signatureType = currWidgetsDetails?.signatureType;
|
||||||
|
const url = currWidgetsDetails?.SignUrl;
|
||||||
|
|
||||||
|
//checking widget type and draw type signature url
|
||||||
|
if (isInitial) {
|
||||||
|
if (isWidgetType === "initials" && signatureType === "draw" && url) {
|
||||||
|
canvasRef.current.fromDataURL(url);
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
isWidgetType === "signature" &&
|
||||||
|
signatureType === "draw" &&
|
||||||
|
url
|
||||||
|
) {
|
||||||
|
canvasRef.current.fromDataURL(url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const trimmedName = currentUserName.trim();
|
const trimmedName = currentUserName.trim();
|
||||||
const firstCharacter = trimmedName.charAt(0);
|
const firstCharacter = trimmedName.charAt(0);
|
||||||
const userName = isInitial ? firstCharacter : currentUserName;
|
const userName = isInitial ? firstCharacter : currentUserName;
|
||||||
@@ -349,6 +361,7 @@ function SignPad({
|
|||||||
setIsDefaultSign(false);
|
setIsDefaultSign(false);
|
||||||
setIsImageSelect(true);
|
setIsImageSelect(true);
|
||||||
setIsTab("uploadImage");
|
setIsTab("uploadImage");
|
||||||
|
setSignatureType("");
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
color:
|
color:
|
||||||
@@ -373,6 +386,7 @@ function SignPad({
|
|||||||
setIsDefaultSign(false);
|
setIsDefaultSign(false);
|
||||||
setIsImageSelect(false);
|
setIsImageSelect(false);
|
||||||
setIsTab("type");
|
setIsTab("type");
|
||||||
|
setSignatureType("");
|
||||||
setImage();
|
setImage();
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
@@ -400,6 +414,7 @@ function SignPad({
|
|||||||
setIsDefaultSign(true);
|
setIsDefaultSign(true);
|
||||||
setIsImageSelect(true);
|
setIsImageSelect(true);
|
||||||
setIsTab("mysignature");
|
setIsTab("mysignature");
|
||||||
|
setSignatureType("");
|
||||||
setImage();
|
setImage();
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
@@ -430,6 +445,7 @@ function SignPad({
|
|||||||
setIsDefaultSign(true);
|
setIsDefaultSign(true);
|
||||||
setIsImageSelect(true);
|
setIsImageSelect(true);
|
||||||
setIsTab("mysignature");
|
setIsTab("mysignature");
|
||||||
|
setSignatureType("");
|
||||||
setImage();
|
setImage();
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
@@ -469,6 +485,7 @@ function SignPad({
|
|||||||
setIsDefaultSign(false);
|
setIsDefaultSign(false);
|
||||||
setImage();
|
setImage();
|
||||||
setIsTab("draw");
|
setIsTab("draw");
|
||||||
|
setSignatureType("draw");
|
||||||
setSignValue("");
|
setSignValue("");
|
||||||
setIsStamp(false);
|
setIsStamp(false);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { themeColor } from "../../constant/const";
|
import { themeColor } from "../../constant/const";
|
||||||
import RecipientList from "./RecipientList";
|
import RecipientList from "./RecipientList";
|
||||||
|
import { Tooltip } from "react-tooltip";
|
||||||
|
|
||||||
function SignerListPlace(props) {
|
function SignerListPlace(props) {
|
||||||
return (
|
return (
|
||||||
@@ -13,6 +14,58 @@ function SignerListPlace(props) {
|
|||||||
>
|
>
|
||||||
<span className="signedStyle">
|
<span className="signedStyle">
|
||||||
{props.title ? props.title : "Recipients"}
|
{props.title ? props.title : "Recipients"}
|
||||||
|
<span className="absolute text-xs z-[30] mt-1 ml-0.5">
|
||||||
|
{props?.title === "Roles" && (
|
||||||
|
<>
|
||||||
|
<a data-tooltip-id="my-tooltip">
|
||||||
|
<sup>
|
||||||
|
<i
|
||||||
|
className="fa-solid fa-question rounded-full"
|
||||||
|
style={{
|
||||||
|
borderColor: "white",
|
||||||
|
color: "white",
|
||||||
|
fontSize: 11,
|
||||||
|
borderWidth: 1.5,
|
||||||
|
padding: "1px 3px"
|
||||||
|
}}
|
||||||
|
></i>
|
||||||
|
</sup>
|
||||||
|
</a>
|
||||||
|
<Tooltip id="my-tooltip">
|
||||||
|
<div className="max-w-[450px]">
|
||||||
|
<p className="font-bold">What are template roles?</p>
|
||||||
|
<p>
|
||||||
|
Begin by specifying each role needed for the completion of
|
||||||
|
the document. Think about the parties involved in the
|
||||||
|
signing process and what their responsibilities are.
|
||||||
|
Common roles include HR for internal documents, Customer
|
||||||
|
for agreements or Vendor for business agreements.{" "}
|
||||||
|
</p>
|
||||||
|
<p className="font-bold">
|
||||||
|
Why pre-attach users to some roles?
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
For roles that consistently involve the same individual
|
||||||
|
(e.g., the CEO's signature on employee offer
|
||||||
|
letters), you can pre-attach a user to a role within the
|
||||||
|
template. This step is optional but recommended for
|
||||||
|
efficiency and consistency across documents.
|
||||||
|
</p>
|
||||||
|
<p className="font-bold">
|
||||||
|
When do i specify the user attached to each role?
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
When you create a document from your template, you'll
|
||||||
|
be prompted to attach users to each defined role. If a
|
||||||
|
role already has a user attached, this will be pre-filled,
|
||||||
|
but you can modify it as needed before sending out the
|
||||||
|
document.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="signerList">
|
<div className="signerList">
|
||||||
@@ -23,6 +76,10 @@ function SignerListPlace(props) {
|
|||||||
data-tut="reactourAddbtn"
|
data-tut="reactourAddbtn"
|
||||||
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
|
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
|
||||||
onClick={() => props.handleAddSigner()}
|
onClick={() => props.handleAddSigner()}
|
||||||
|
style={{
|
||||||
|
opacity: props.isMailSend && "0.5",
|
||||||
|
pointerEvents: props.isMailSend && "none"
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-plus"></i>
|
<i className="fa-solid fa-plus"></i>
|
||||||
<span style={{ marginLeft: 2 }}>Add role</span>
|
<span style={{ marginLeft: 2 }}>Add role</span>
|
||||||
|
|||||||
@@ -364,7 +364,12 @@ function WidgetComponent({
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<div data-tut={dataTut} className="signerComponent">
|
<div
|
||||||
|
data-tut={dataTut}
|
||||||
|
className={
|
||||||
|
isMailSend ? "disabled signerComponent " : "signerComponent"
|
||||||
|
}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
background: themeColor,
|
background: themeColor,
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import "../../styles/AddUser.css";
|
|||||||
import RegexParser from "regex-parser";
|
import RegexParser from "regex-parser";
|
||||||
import { textInputWidget } from "../../constant/Utils";
|
import { textInputWidget } from "../../constant/Utils";
|
||||||
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
||||||
|
import Upgrade from "../../primitives/Upgrade";
|
||||||
|
import { isEnableSubscription } from "../../constant/const";
|
||||||
|
|
||||||
const WidgetNameModal = (props) => {
|
const WidgetNameModal = (props) => {
|
||||||
const [formdata, setFormdata] = useState({
|
const [formdata, setFormdata] = useState({
|
||||||
@@ -100,13 +102,14 @@ const WidgetNameModal = (props) => {
|
|||||||
title={"Widget info"}
|
title={"Widget info"}
|
||||||
>
|
>
|
||||||
{(props.defaultdata?.type === textInputWidget ||
|
{(props.defaultdata?.type === textInputWidget ||
|
||||||
props.widgetName === textInputWidget) && (
|
props.widgetName === textInputWidget) &&
|
||||||
<PremiumAlertHeader
|
!isEnableSubscription && (
|
||||||
message={
|
<PremiumAlertHeader
|
||||||
"Field validations are free in beta, this feature will incur a fee later."
|
message={
|
||||||
}
|
"Field validations are free in beta, this feature will incur a fee later."
|
||||||
/>
|
}
|
||||||
)}
|
/>
|
||||||
|
)}
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className={`${
|
className={`${
|
||||||
@@ -133,10 +136,20 @@ const WidgetNameModal = (props) => {
|
|||||||
props.widgetName === textInputWidget) && (
|
props.widgetName === textInputWidget) && (
|
||||||
<>
|
<>
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<label htmlFor="textvalidate" style={{ fontSize: 13 }}>
|
<label
|
||||||
|
htmlFor="textvalidate"
|
||||||
|
className={
|
||||||
|
!props.isSubscribe && isEnableSubscription && "disabled"
|
||||||
|
}
|
||||||
|
style={{ fontSize: 13 }}
|
||||||
|
>
|
||||||
Validation
|
Validation
|
||||||
</label>
|
</label>
|
||||||
|
{!props.isSubscribe && isEnableSubscription && <Upgrade />}
|
||||||
<div
|
<div
|
||||||
|
className={
|
||||||
|
!props.isSubscribe && isEnableSubscription && "disabled"
|
||||||
|
}
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
@@ -178,6 +191,7 @@ const WidgetNameModal = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
<label htmlFor="name" style={{ fontSize: 13 }}>
|
||||||
Default value
|
Default value
|
||||||
@@ -196,7 +210,10 @@ const WidgetNameModal = (props) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{isValid === false && (
|
{isValid === false && (
|
||||||
<div className="warning defaultvalueWarning" style={{ fontSize: 12 }}>
|
<div
|
||||||
|
className="warning defaultvalueWarning"
|
||||||
|
style={{ fontSize: 12 }}
|
||||||
|
>
|
||||||
<i
|
<i
|
||||||
className="fas fa-exclamation-circle"
|
className="fas fa-exclamation-circle"
|
||||||
style={{ color: "#fab005", fontSize: 15 }}
|
style={{ color: "#fab005", fontSize: 15 }}
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
|||||||
{selectFolder && selectFolder.Name ? `(${folderPath})` : ""}
|
{selectFolder && selectFolder.Name ? `(${folderPath})` : ""}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="absolute top-1 right-1 cursor-pointer">
|
<div className="absolute top-2 right-1 cursor-pointer">
|
||||||
<Tooltip
|
<Tooltip
|
||||||
message={
|
message={
|
||||||
"If you do not select a folder, your signed document will be saved in the Main OpenSign drive folder."
|
"If you do not select a folder, your signed document will be saved in the Main OpenSign drive folder."
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ const SignersInput = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="text-xs mt-2 ">
|
<div className="text-xs mt-2 ">
|
||||||
<label className="block">
|
<label className="block relative">
|
||||||
Signers
|
Signers
|
||||||
{props.required && <span className="text-red-500 text-[13px]">*</span>}
|
{props.required && <span className="text-red-500 text-[13px]">*</span>}
|
||||||
<span className="absolute ml-1 text-xs z-50">
|
<span className="absolute ml-1 text-xs z-50">
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import moment from "moment";
|
|||||||
import { themeColor } from "./const";
|
import { themeColor } from "./const";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { rgb } from "pdf-lib";
|
import { rgb } from "pdf-lib";
|
||||||
|
import Parse from "parse";
|
||||||
|
|
||||||
export const isMobile = window.innerWidth < 767;
|
export const isMobile = window.innerWidth < 767;
|
||||||
export const textInputWidget = "text input";
|
export const textInputWidget = "text input";
|
||||||
@@ -12,6 +13,29 @@ export const openInNewTab = (url) => {
|
|||||||
window.open(url, "_blank", "noopener,noreferrer");
|
window.open(url, "_blank", "noopener,noreferrer");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//function to get subcripition details from Extand user class
|
||||||
|
export async function checkIsSubscribed() {
|
||||||
|
const extClass = localStorage.getItem("Extand_Class");
|
||||||
|
const jsonSender = JSON.parse(extClass);
|
||||||
|
const user = await Parse.Cloud.run("getUserDetails", {
|
||||||
|
email: jsonSender[0].Email
|
||||||
|
});
|
||||||
|
const freeplan = user?.get("Plan") && user?.get("Plan")?.plan_code;
|
||||||
|
const billingDate =
|
||||||
|
user?.get("Next_billing_date") && user?.get("Next_billing_date");
|
||||||
|
if (freeplan === "freeplan") {
|
||||||
|
return false;
|
||||||
|
} else if (billingDate) {
|
||||||
|
if (billingDate > new Date()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const color = [
|
export const color = [
|
||||||
"#93a3db",
|
"#93a3db",
|
||||||
"#e6c3db",
|
"#e6c3db",
|
||||||
@@ -935,6 +959,7 @@ export const embedDocId = async (pdfDoc, documentId, allPages) => {
|
|||||||
|
|
||||||
//function for save button to save signature or image url
|
//function for save button to save signature or image url
|
||||||
export function onSaveSign(
|
export function onSaveSign(
|
||||||
|
type,
|
||||||
xyPostion,
|
xyPostion,
|
||||||
index,
|
index,
|
||||||
signKey,
|
signKey,
|
||||||
@@ -975,6 +1000,7 @@ export function onSaveSign(
|
|||||||
Width: posWidth,
|
Width: posWidth,
|
||||||
Height: posHeight,
|
Height: posHeight,
|
||||||
SignUrl: signatureImg,
|
SignUrl: signatureImg,
|
||||||
|
signatureType: type && type,
|
||||||
options: {
|
options: {
|
||||||
...position.options,
|
...position.options,
|
||||||
response: signatureImg
|
response: signatureImg
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ export const modalSubmitBtnColor = "#17a2b8";
|
|||||||
export const modalCancelBtnColor = "white";
|
export const modalCancelBtnColor = "white";
|
||||||
export const themeColor = "#47a3ad";
|
export const themeColor = "#47a3ad";
|
||||||
export const iconColor = "#686968";
|
export const iconColor = "#686968";
|
||||||
|
export const isEnableSubscription = process.env.REACT_APP_ENABLE_SUBSCRIPTION;
|
||||||
|
|||||||
@@ -2,26 +2,25 @@ import axios from "axios";
|
|||||||
const parseAppId = localStorage.getItem("parseAppId");
|
const parseAppId = localStorage.getItem("parseAppId");
|
||||||
const serverUrl = localStorage.getItem("baseUrl");
|
const serverUrl = localStorage.getItem("baseUrl");
|
||||||
|
|
||||||
export const SaveFileSize = async (size, imageUrl) => {
|
export const SaveFileSize = async (size, imageUrl, tenantId) => {
|
||||||
//checking server url and save file's size
|
//checking server url and save file's size
|
||||||
|
const tenantPtr = {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: "partners_Tenant",
|
||||||
|
objectId: tenantId
|
||||||
|
};
|
||||||
|
const _tenantPtr = JSON.stringify(tenantPtr);
|
||||||
try {
|
try {
|
||||||
const response = await axios
|
const res = await axios.get(
|
||||||
.get(`${serverUrl}classes/partners_TenantCredits`, {
|
`${serverUrl}classes/partners_TenantCredits?where={"PartnersTenant":${_tenantPtr}}`,
|
||||||
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": parseAppId
|
"X-Parse-Application-Id": parseAppId
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.then((result) => {
|
);
|
||||||
const res = result.data;
|
const response = res.data.results;
|
||||||
// console.log("res", res);
|
|
||||||
|
|
||||||
return res.results;
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log("axois err ", err);
|
|
||||||
});
|
|
||||||
let data;
|
let data;
|
||||||
// console.log("response", response);
|
// console.log("response", response);
|
||||||
if (response && response.length > 0) {
|
if (response && response.length > 0) {
|
||||||
@@ -30,69 +29,49 @@ export const SaveFileSize = async (size, imageUrl) => {
|
|||||||
? response[0].usedStorage + size
|
? response[0].usedStorage + size
|
||||||
: size
|
: size
|
||||||
};
|
};
|
||||||
await axios
|
await axios.put(
|
||||||
.put(
|
`${serverUrl}classes/partners_TenantCredits/${response[0].objectId}`,
|
||||||
`${serverUrl}classes/partners_TenantCredits/${response[0].objectId}`,
|
data,
|
||||||
data,
|
{
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
// const res = result.data;
|
|
||||||
// console.log("save res", res);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log("axois err ", err);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
data = {
|
|
||||||
usedStorage: size
|
|
||||||
};
|
|
||||||
await axios
|
|
||||||
.post(`${serverUrl}classes/partners_TenantCredits`, data, {
|
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": parseAppId
|
"X-Parse-Application-Id": parseAppId
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.then(() => {
|
);
|
||||||
// const res = result.data;
|
} else {
|
||||||
// console.log("res", res);
|
data = { usedStorage: size, PartnersTenant: tenantPtr };
|
||||||
})
|
await axios.post(`${serverUrl}classes/partners_TenantCredits`, data, {
|
||||||
.catch((err) => {
|
headers: {
|
||||||
console.log("axois err ", err);
|
"Content-Type": "application/json",
|
||||||
});
|
"X-Parse-Application-Id": parseAppId
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
console.log("org app error", e);
|
console.log("err in save usage", err);
|
||||||
}
|
}
|
||||||
saveDataFile(size, imageUrl);
|
saveDataFile(size, imageUrl, tenantPtr);
|
||||||
};
|
};
|
||||||
|
|
||||||
//function for save fileUrl and file size in particular client db class partners_DataFiles
|
//function for save fileUrl and file size in particular client db class partners_DataFiles
|
||||||
const saveDataFile = async (size, imageUrl) => {
|
const saveDataFile = async (size, imageUrl, tenantPtr) => {
|
||||||
const data = {
|
const data = {
|
||||||
FileUrl: imageUrl,
|
FileUrl: imageUrl,
|
||||||
FileSize: size
|
FileSize: size,
|
||||||
|
TenantPtr: tenantPtr
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log("data save",file, data)
|
// console.log("data save",file, data)
|
||||||
await axios
|
try {
|
||||||
.post(`${serverUrl}classes/partners_DataFiles`, data, {
|
await axios.post(`${serverUrl}classes/partners_DataFiles`, data, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": parseAppId
|
"X-Parse-Application-Id": parseAppId
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
// const res = result.data;
|
|
||||||
// console.log("res", res);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log("axois err ", err);
|
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in save usage ", err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ export default function reportJson(id) {
|
|||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
helpMsg: "This are documents you have started but have not finalized for sending."
|
helpMsg: "These are documents you have started but have not finalized for sending."
|
||||||
};
|
};
|
||||||
// Need your sign report
|
// Need your sign report
|
||||||
case "4Hhwbp482K":
|
case "4Hhwbp482K":
|
||||||
|
|||||||
@@ -1,65 +1,70 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"planName": "SELF HOSTED",
|
"planName": "OPENSIGN™ FREE",
|
||||||
"currency": "",
|
"currency": "",
|
||||||
"price": "Free",
|
"monthlyPrice": "Free",
|
||||||
"subtitle": "Free for life One click install.",
|
"yearlyPrice": "Free",
|
||||||
"btnText": "Visit github",
|
"subtitle": "Free Unlimited E-signatures, Forever.",
|
||||||
"url": "https://github.com/opensignlabs/opensign",
|
"btnText": "Subscribe",
|
||||||
"target": "_blank",
|
"url": "",
|
||||||
"benefits": [
|
"target": "_blank",
|
||||||
"Sign Unlimited Documents",
|
"benefits": [
|
||||||
"S3 Doc Storage",
|
"Unlimited envelopes",
|
||||||
"Unlimited Guest Signers",
|
"Sign documents yourself",
|
||||||
"Unlimited completion certificates",
|
"Request signatures from others",
|
||||||
"Unique Code(OTP) verification for guest signers",
|
"14 field types",
|
||||||
"Expiring docs & reject signature support",
|
"Automatic e-signatures",
|
||||||
"PDF Template Creation(coming soon)",
|
"Completion certificates",
|
||||||
"Audit Trails",
|
"Send in order",
|
||||||
"API support",
|
"Document templates",
|
||||||
"Add-ons support(coming soon)",
|
"Import from Dropbox",
|
||||||
"Self hosted cloud infrastructure",
|
"Contact book",
|
||||||
"Free for lifetime",
|
"Document expiry support",
|
||||||
"Community support"
|
"Decline document support",
|
||||||
]
|
"Email notifications",
|
||||||
},
|
"Recipient authentication using OTP",
|
||||||
{
|
"And much more"
|
||||||
"planName": "THANKS PLAN",
|
]
|
||||||
"currency": "$",
|
},
|
||||||
"price": "29.99",
|
{
|
||||||
"subtitle": "Use code <span style='background-color: yellow;'>'FREEBETA'</span> to get this for free(First 1000 users)",
|
"planName": "OPENSIGN™ PROFESSIONAL",
|
||||||
"btnText": "Subscribe",
|
"currency": "$",
|
||||||
"url": "https://subscriptions.zoho.in/subscribe/ef798486e6a0a11ea65f2bae8f2af901dbadf3175d495584fd25b9af5d2f2b9e/thanks",
|
"monthlyPrice": "29.99",
|
||||||
"target": "_self",
|
"yearlyPrice": "329.99",
|
||||||
"benefits": [
|
"subtitle": "Exclusive Access to advanced features.",
|
||||||
"Sign Unlimited Documents",
|
"btnText": "Subscribe",
|
||||||
"Unlimited Secure Doc Storage with OpenSign™ Drive",
|
"url": "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d1a09dfa8085585cdd4ec4d7f32137f3/professional-monthly",
|
||||||
"Unlimited Guest Signers",
|
"yearlyUrl": "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d8ad1135190dff951330360e47585a71/professional-yearly",
|
||||||
"Unlimited completion certificates",
|
"target": "_self",
|
||||||
"Unique Code(OTP) verification for guest signers",
|
"benefits": [
|
||||||
"Expiring docs & reject signature support",
|
"Everything in OpenSign™ professional",
|
||||||
"PDF Template Creation(coming soon)",
|
"Field validations",
|
||||||
"Audit Trails",
|
"Regular expression validations",
|
||||||
"API support",
|
"Organize docs in OpenSign™ Drive",
|
||||||
"Add-ons support(coming soon)",
|
"Webhooks",
|
||||||
"Self hosted cloud infrastructure"
|
"Zapier integration",
|
||||||
]
|
"API Access",
|
||||||
},
|
"100 API signatures included",
|
||||||
{
|
"DocumentId removal from signed docs",
|
||||||
"planName": "ENTERPRISE",
|
"Custom email templates(coming soon)"
|
||||||
"currency": "",
|
]
|
||||||
"price": "Request Price",
|
},
|
||||||
"subtitle": "Customization available Priority support.",
|
{
|
||||||
"btnText": "Contact us",
|
"planName": "OPENSIGN™ ENTERPRISE",
|
||||||
"url": "https://www.opensignlabs.com/contact-us",
|
"currency": "",
|
||||||
"target": "_blank",
|
"monthlyPrice": "Request Price",
|
||||||
"benefits": [
|
"yearlyPrice": "Request Price",
|
||||||
"All features",
|
"subtitle": "Scalable Features with priority support.",
|
||||||
"Custom domain",
|
"btnText": "Contact us",
|
||||||
"Whitelabeling",
|
"url": "https://www.opensignlabs.com/contact-us",
|
||||||
"Uptime SLA",
|
"target": "_blank",
|
||||||
"SSO support",
|
"benefits": [
|
||||||
"24/7 support"
|
"All features",
|
||||||
]
|
"Custom domain",
|
||||||
}
|
"Custom branding",
|
||||||
]
|
"Uptime SLA",
|
||||||
|
"SSO support",
|
||||||
|
"Priority support"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { useSelector } from "react-redux";
|
|||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import { useNavigate, useLocation, Outlet } from "react-router-dom";
|
import { useNavigate, useLocation, Outlet } from "react-router-dom";
|
||||||
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
|
||||||
const HomeLayout = () => {
|
const HomeLayout = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -18,6 +19,12 @@ const HomeLayout = () => {
|
|||||||
const arr = useSelector((state) => state.TourSteps);
|
const arr = useSelector((state) => state.TourSteps);
|
||||||
const [isUserValid, setIsUserValid] = useState(true);
|
const [isUserValid, setIsUserValid] = useState(true);
|
||||||
const [isLoader, setIsLoader] = useState(true);
|
const [isLoader, setIsLoader] = useState(true);
|
||||||
|
// reactour state
|
||||||
|
const [isCloseBtn, setIsCloseBtn] = useState(true);
|
||||||
|
const [isTour, setIsTour] = useState(false);
|
||||||
|
const [tourStatusArr, setTourStatusArr] = useState([]);
|
||||||
|
const [tourConfigs, setTourConfigs] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -27,8 +34,7 @@ const HomeLayout = () => {
|
|||||||
sessionToken: localStorage.getItem("accesstoken")
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
});
|
});
|
||||||
if (user) {
|
if (user) {
|
||||||
setIsUserValid(true);
|
checkIsSubscribed();
|
||||||
setIsLoader(false);
|
|
||||||
} else {
|
} else {
|
||||||
setIsUserValid(false);
|
setIsUserValid(false);
|
||||||
}
|
}
|
||||||
@@ -37,14 +43,36 @@ const HomeLayout = () => {
|
|||||||
setIsUserValid(false);
|
setIsUserValid(false);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// reactour state
|
async function checkIsSubscribed() {
|
||||||
const [isCloseBtn, setIsCloseBtn] = useState(true);
|
const currentUser = Parse.User.current();
|
||||||
const [isTour, setIsTour] = useState(false);
|
const user = await Parse.Cloud.run("getUserDetails", {
|
||||||
const [tourStatusArr, setTourStatusArr] = useState([]);
|
email: currentUser.get("email")
|
||||||
const [tourConfigs, setTourConfigs] = useState([]);
|
});
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const freeplan = user?.get("Plan") && user?.get("Plan").plan_code;
|
||||||
|
const billingDate =
|
||||||
|
user?.get("Next_billing_date") && user?.get("Next_billing_date");
|
||||||
|
if (freeplan === "freeplan") {
|
||||||
|
setIsUserValid(true);
|
||||||
|
setIsLoader(false);
|
||||||
|
} else if (billingDate) {
|
||||||
|
if (billingDate > new Date()) {
|
||||||
|
setIsUserValid(true);
|
||||||
|
setIsLoader(false);
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsUserValid(true);
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
const showSidebar = () => {
|
const showSidebar = () => {
|
||||||
setIsOpen((value) => !value);
|
setIsOpen((value) => !value);
|
||||||
};
|
};
|
||||||
@@ -198,7 +226,7 @@ const HomeLayout = () => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="sticky top-0 z-50">
|
<div className="sticky top-0 z-50">
|
||||||
<Header showSidebar={showSidebar} />
|
{!isLoader && <Header showSidebar={showSidebar} />}
|
||||||
</div>
|
</div>
|
||||||
{isUserValid ? (
|
{isUserValid ? (
|
||||||
<>
|
<>
|
||||||
@@ -223,7 +251,6 @@ const HomeLayout = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="flex md:flex-row flex-col z-50">
|
<div className="flex md:flex-row flex-col z-50">
|
||||||
<Sidebar isOpen={isOpen} closeSidebar={closeSidebar} />
|
<Sidebar isOpen={isOpen} closeSidebar={closeSidebar} />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id="renderList"
|
id="renderList"
|
||||||
className="relative h-screen flex flex-col justify-between w-full overflow-y-auto"
|
className="relative h-screen flex flex-col justify-between w-full overflow-y-auto"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import SelectFolder from "../components/shared/fields/SelectFolder";
|
|||||||
import SignersInput from "../components/shared/fields/SignersInput";
|
import SignersInput from "../components/shared/fields/SignersInput";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import PageNotFound from "./PageNotFound";
|
import PageNotFound from "./PageNotFound";
|
||||||
|
import { SaveFileSize } from "../constant/saveFileSize";
|
||||||
|
|
||||||
// `Form` render all type of Form on this basis of their provided in path
|
// `Form` render all type of Form on this basis of their provided in path
|
||||||
function Form() {
|
function Form() {
|
||||||
@@ -82,6 +83,7 @@ const Forms = (props) => {
|
|||||||
const handleFileUpload = async (file) => {
|
const handleFileUpload = async (file) => {
|
||||||
setfileload(true);
|
setfileload(true);
|
||||||
const fileName = file.name;
|
const fileName = file.name;
|
||||||
|
const size = file.size;
|
||||||
const name = sanitizeFileName(fileName);
|
const name = sanitizeFileName(fileName);
|
||||||
const pdfFile = file;
|
const pdfFile = file;
|
||||||
const parseFile = new Parse.File(name, pdfFile);
|
const parseFile = new Parse.File(name, pdfFile);
|
||||||
@@ -101,6 +103,8 @@ const Forms = (props) => {
|
|||||||
setFileUpload(response.url());
|
setFileUpload(response.url());
|
||||||
setfileload(false);
|
setfileload(false);
|
||||||
if (response.url()) {
|
if (response.url()) {
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
SaveFileSize(size, response.url(), tenantId);
|
||||||
return response.url();
|
return response.url();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -113,6 +117,7 @@ const Forms = (props) => {
|
|||||||
const dropboxSuccess = async (files) => {
|
const dropboxSuccess = async (files) => {
|
||||||
setfileload(true);
|
setfileload(true);
|
||||||
const file = files[0];
|
const file = files[0];
|
||||||
|
const size = file.bytes;
|
||||||
const url = file.link;
|
const url = file.link;
|
||||||
const mb = Math.round(file.bytes / Math.pow(1024, 2));
|
const mb = Math.round(file.bytes / Math.pow(1024, 2));
|
||||||
|
|
||||||
@@ -141,6 +146,8 @@ const Forms = (props) => {
|
|||||||
setfileload(false);
|
setfileload(false);
|
||||||
|
|
||||||
if (response.url()) {
|
if (response.url()) {
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
SaveFileSize(size, response.url(), tenantId);
|
||||||
return response.url();
|
return response.url();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import { rejectBtn, submitBtn } from "../constant/const";
|
import { isEnableSubscription, rejectBtn, submitBtn } from "../constant/const";
|
||||||
import { openInNewTab } from "../constant/Utils";
|
import { checkIsSubscribed, openInNewTab } from "../constant/Utils";
|
||||||
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||||
import Tooltip from "../primitives/Tooltip";
|
import Tooltip from "../primitives/Tooltip";
|
||||||
|
|
||||||
function GenerateToken() {
|
function GenerateToken() {
|
||||||
|
const navigation = useNavigate();
|
||||||
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
|
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
|
||||||
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
|
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
|
||||||
const [apiToken, SetApiToken] = useState("");
|
const [apiToken, SetApiToken] = useState("");
|
||||||
@@ -17,6 +19,7 @@ function GenerateToken() {
|
|||||||
const [isGenerate, setIsGenerate] = useState(false);
|
const [isGenerate, setIsGenerate] = useState(false);
|
||||||
const [isErr, setIsErr] = useState(false);
|
const [isErr, setIsErr] = useState(false);
|
||||||
const [isModal, setIsModal] = useState(false);
|
const [isModal, setIsModal] = useState(false);
|
||||||
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchToken();
|
fetchToken();
|
||||||
@@ -25,6 +28,11 @@ function GenerateToken() {
|
|||||||
|
|
||||||
const fetchToken = async () => {
|
const fetchToken = async () => {
|
||||||
try {
|
try {
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const getIsSubscribe = await checkIsSubscribed();
|
||||||
|
setIsSubscribe(getIsSubscribe);
|
||||||
|
}
|
||||||
|
|
||||||
const url = parseBaseUrl + "functions/getapitoken";
|
const url = parseBaseUrl + "functions/getapitoken";
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -35,6 +43,7 @@ function GenerateToken() {
|
|||||||
if (res) {
|
if (res) {
|
||||||
SetApiToken(res.data.result.result);
|
SetApiToken(res.data.result.result);
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
SetApiToken();
|
SetApiToken();
|
||||||
@@ -90,6 +99,7 @@ function GenerateToken() {
|
|||||||
}, 1500); // Reset copied state after 1.5 seconds
|
}, 1500); // Reset copied state after 1.5 seconds
|
||||||
};
|
};
|
||||||
const handleModal = () => setIsModal(!isModal);
|
const handleModal = () => setIsModal(!isModal);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Title title={"API Token"} />
|
<Title title={"API Token"} />
|
||||||
@@ -117,35 +127,47 @@ function GenerateToken() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="bg-white flex flex-col justify-center shadow rounded">
|
<div className="bg-white flex flex-col justify-center shadow rounded">
|
||||||
<PremiumAlertHeader />
|
{!isEnableSubscription && <PremiumAlertHeader />}
|
||||||
<h1 className="ml-4 mt-3 mb-2 font-semibold">
|
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||||
API Token{" "}
|
OpenSign™ API{" "}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
url={"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"}
|
url={
|
||||||
|
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
||||||
|
}
|
||||||
|
isSubscribe={true}
|
||||||
/>
|
/>
|
||||||
</h1>
|
</h1>
|
||||||
<ul className="w-full flex flex-col p-2 text-sm">
|
<ul
|
||||||
|
className={
|
||||||
|
isSubscribe || !isEnableSubscription
|
||||||
|
? "w-full flex flex-col p-2 text-sm "
|
||||||
|
: "w-full flex flex-col p-2 text-sm opacity-20 pointer-events-none select-none"
|
||||||
|
}
|
||||||
|
>
|
||||||
<li
|
<li
|
||||||
className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
|
className={`flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
|
||||||
>
|
>
|
||||||
<span className="w-[40%]">Api Token:</span>{" "}
|
<div className="w-[70%] flex-col md:flex-row flex items-center gap-5 ">
|
||||||
<span
|
<span className="">Api Token:</span>{" "}
|
||||||
id="token"
|
<span
|
||||||
className="w-[60%] md:text-end cursor-pointer"
|
id="token"
|
||||||
onClick={() => copytoclipboard(apiToken)}
|
className=" md:text-end cursor-pointer"
|
||||||
|
onClick={() => copytoclipboard(apiToken)}
|
||||||
|
>
|
||||||
|
{apiToken ? apiToken : "_____"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={apiToken ? handleModal : handleSubmit}
|
||||||
|
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base focus:outline-none"
|
||||||
>
|
>
|
||||||
{apiToken && apiToken}
|
{apiToken ? "Regenerate Token" : "Generate Token"}
|
||||||
</span>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div className="flex flex-col md:flex-row items-center justify-center gap-2 pb-4">
|
|
||||||
<button
|
<div className="flex items-center justify-center ">
|
||||||
type="button"
|
|
||||||
onClick={apiToken ? handleModal : handleSubmit}
|
|
||||||
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base focus:outline-none"
|
|
||||||
>
|
|
||||||
{apiToken ? "Regenerate Token" : "Generate Token"}
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -153,12 +175,41 @@ function GenerateToken() {
|
|||||||
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
|
className="rounded hover:bg-[#15b4e9] border-[1px] my-2 border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
|
||||||
>
|
>
|
||||||
View Docs
|
View Docs
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{!isSubscribe && isEnableSubscription && (
|
||||||
|
<>
|
||||||
|
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||||
|
Upgrade to PRO Plan
|
||||||
|
</h1>
|
||||||
|
<ul className={"w-full flex flex-col p-2 text-sm "}>
|
||||||
|
<li
|
||||||
|
className={`flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
|
||||||
|
>
|
||||||
|
<div className="w-[70%] flex-col md:flex-row flex items-center gap-3 ">
|
||||||
|
<span className="">$29.99/month:</span>{" "}
|
||||||
|
<span id="token" className=" md:text-end cursor-pointer">
|
||||||
|
Sign 100 docs using API. Only 0.15/docs after that.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{!isSubscribe && isEnableSubscription && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => navigation("/subscription")}
|
||||||
|
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
|
||||||
|
>
|
||||||
|
Upgrade Now
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen={isModal}
|
isOpen={isModal}
|
||||||
title={"Regenerate Token"}
|
title={"Regenerate Token"}
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ function GuestLogin() {
|
|||||||
"X-Parse-Application-Id": parseId
|
"X-Parse-Application-Id": parseId
|
||||||
};
|
};
|
||||||
let body = {
|
let body = {
|
||||||
email: email.toString()
|
email: email.toString(),
|
||||||
|
docId: id
|
||||||
};
|
};
|
||||||
let Otp = await axios.post(url, body, { headers: headers });
|
let Otp = await axios.post(url, body, { headers: headers });
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ import { NavLink, useNavigate, useLocation } from "react-router-dom";
|
|||||||
import login_img from "../assets/images/login_img.svg";
|
import login_img from "../assets/images/login_img.svg";
|
||||||
import { useWindowSize } from "../hook/useWindowSize";
|
import { useWindowSize } from "../hook/useWindowSize";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const";
|
import {
|
||||||
|
isEnableSubscription,
|
||||||
|
modalCancelBtnColor,
|
||||||
|
modalSubmitBtnColor
|
||||||
|
} from "../constant/const";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
import { appInfo } from "../constant/appinfo";
|
import { appInfo } from "../constant/appinfo";
|
||||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
@@ -209,7 +213,7 @@ function Login() {
|
|||||||
x.TenantId.TenantName || ""
|
x.TenantId.TenantName || ""
|
||||||
};
|
};
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenetId",
|
"TenantId",
|
||||||
x.TenantId.objectId
|
x.TenantId.objectId
|
||||||
);
|
);
|
||||||
tenentInfo.push(obj);
|
tenentInfo.push(obj);
|
||||||
@@ -239,10 +243,7 @@ function Login() {
|
|||||||
element.pageType
|
element.pageType
|
||||||
);
|
);
|
||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
if (
|
if (isEnableSubscription) {
|
||||||
process.env
|
|
||||||
.REACT_APP_ENABLE_SUBSCRIPTION
|
|
||||||
) {
|
|
||||||
const LocalUserDetails = {
|
const LocalUserDetails = {
|
||||||
name: results[0].get("Name"),
|
name: results[0].get("Name"),
|
||||||
email: results[0].get("Email"),
|
email: results[0].get("Email"),
|
||||||
@@ -253,10 +254,15 @@ function Login() {
|
|||||||
"userDetails",
|
"userDetails",
|
||||||
JSON.stringify(LocalUserDetails)
|
JSON.stringify(LocalUserDetails)
|
||||||
);
|
);
|
||||||
|
const freeplan =
|
||||||
|
results[0].get("Plan") &&
|
||||||
|
results[0].get("Plan").plan_code;
|
||||||
const billingDate =
|
const billingDate =
|
||||||
results[0].get("Next_billing_date") &&
|
results[0].get("Next_billing_date") &&
|
||||||
results[0].get("Next_billing_date");
|
results[0].get("Next_billing_date");
|
||||||
if (billingDate) {
|
if (freeplan === "freeplan") {
|
||||||
|
navigate(redirectUrl);
|
||||||
|
} else if (billingDate) {
|
||||||
if (billingDate > new Date()) {
|
if (billingDate > new Date()) {
|
||||||
localStorage.removeItem(
|
localStorage.removeItem(
|
||||||
"userDetails"
|
"userDetails"
|
||||||
@@ -292,9 +298,7 @@ function Login() {
|
|||||||
element.pageType
|
element.pageType
|
||||||
);
|
);
|
||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
if (
|
if (isEnableSubscription) {
|
||||||
process.env.REACT_APP_ENABLE_SUBSCRIPTION
|
|
||||||
) {
|
|
||||||
const LocalUserDetails = {
|
const LocalUserDetails = {
|
||||||
name: _user.name,
|
name: _user.name,
|
||||||
email: email,
|
email: email,
|
||||||
@@ -391,6 +395,18 @@ function Login() {
|
|||||||
const setThirdpartyLoader = (value) => {
|
const setThirdpartyLoader = (value) => {
|
||||||
setState({ ...state, thirdpartyLoader: value });
|
setState({ ...state, thirdpartyLoader: value });
|
||||||
};
|
};
|
||||||
|
const handleFreePlan = async (id) => {
|
||||||
|
try {
|
||||||
|
const params = { userId: id };
|
||||||
|
const res = await Parse.Cloud.run("freesubscription", params);
|
||||||
|
if (res.status === "error") {
|
||||||
|
alert(res.result);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in free subscribe", err.message);
|
||||||
|
alert("Somenthing went wrong, please try again later!");
|
||||||
|
}
|
||||||
|
};
|
||||||
const thirdpartyLoginfn = async (sessionToken, billingDate) => {
|
const thirdpartyLoginfn = async (sessionToken, billingDate) => {
|
||||||
const baseUrl = localStorage.getItem("baseUrl");
|
const baseUrl = localStorage.getItem("baseUrl");
|
||||||
const parseAppId = localStorage.getItem("parseAppId");
|
const parseAppId = localStorage.getItem("parseAppId");
|
||||||
@@ -400,6 +416,11 @@ function Login() {
|
|||||||
"X-Parse-Application-Id": parseAppId
|
"X-Parse-Application-Id": parseAppId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const param = new URLSearchParams(location.search);
|
||||||
|
const isFreeplan = param?.get("subscription") === "freeplan";
|
||||||
|
if (isFreeplan) {
|
||||||
|
await handleFreePlan(res.data.objectId);
|
||||||
|
}
|
||||||
await Parse.User.become(sessionToken).then(() => {
|
await Parse.User.become(sessionToken).then(() => {
|
||||||
window.localStorage.setItem("accesstoken", sessionToken);
|
window.localStorage.setItem("accesstoken", sessionToken);
|
||||||
});
|
});
|
||||||
@@ -542,7 +563,7 @@ function Login() {
|
|||||||
tenentName: x.TenantId.TenantName || ""
|
tenentName: x.TenantId.TenantName || ""
|
||||||
};
|
};
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenetId",
|
"TenantId",
|
||||||
x.TenantId.objectId
|
x.TenantId.objectId
|
||||||
);
|
);
|
||||||
tenentInfo.push(obj);
|
tenentInfo.push(obj);
|
||||||
@@ -571,18 +592,28 @@ function Login() {
|
|||||||
);
|
);
|
||||||
setThirdpartyLoader(false);
|
setThirdpartyLoader(false);
|
||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
if (process.env.REACT_APP_ENABLE_SUBSCRIPTION) {
|
if (isEnableSubscription) {
|
||||||
if (billingDate) {
|
if (billingDate) {
|
||||||
if (billingDate > new Date()) {
|
if (billingDate > new Date()) {
|
||||||
localStorage.removeItem("userDetails");
|
localStorage.removeItem("userDetails");
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
|
} else {
|
||||||
|
if (isFreeplan) {
|
||||||
|
navigate(redirectUrl);
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`, {
|
||||||
|
replace: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isFreeplan) {
|
||||||
|
navigate(redirectUrl);
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`, {
|
navigate(`/subscription`, {
|
||||||
replace: true
|
replace: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
navigate(`/subscription`, { replace: true });
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
@@ -597,17 +628,29 @@ function Login() {
|
|||||||
localStorage.setItem("pageType", element.pageType);
|
localStorage.setItem("pageType", element.pageType);
|
||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
setThirdpartyLoader(false);
|
setThirdpartyLoader(false);
|
||||||
if (process.env.REACT_APP_ENABLE_SUBSCRIPTION) {
|
if (isEnableSubscription) {
|
||||||
if (billingDate) {
|
if (billingDate) {
|
||||||
if (billingDate > new Date()) {
|
if (billingDate > new Date()) {
|
||||||
localStorage.removeItem("userDetails");
|
localStorage.removeItem("userDetails");
|
||||||
// Redirect to the appropriate URL after successful login
|
// Redirect to the appropriate URL after successful login
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`, { replace: true });
|
if (isFreeplan) {
|
||||||
|
navigate(redirectUrl);
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`, {
|
||||||
|
replace: true
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`, { replace: true });
|
if (isFreeplan) {
|
||||||
|
navigate(redirectUrl);
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`, {
|
||||||
|
replace: true
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
@@ -745,6 +788,13 @@ function Login() {
|
|||||||
// Get TenentID from Extendend Class
|
// Get TenentID from Extendend Class
|
||||||
localStorage.setItem("extended_class", item.extended_class);
|
localStorage.setItem("extended_class", item.extended_class);
|
||||||
const currentUser = Parse.User.current();
|
const currentUser = Parse.User.current();
|
||||||
|
const userSettings = appInfo.settings;
|
||||||
|
const setting = userSettings.find(
|
||||||
|
(x) => x.role === _currentRole
|
||||||
|
);
|
||||||
|
const redirectUrl =
|
||||||
|
location?.state?.from ||
|
||||||
|
`/${setting.pageType}/${setting.pageId}`;
|
||||||
await Parse.Cloud.run("getUserDetails", {
|
await Parse.Cloud.run("getUserDetails", {
|
||||||
email: currentUser.get("email")
|
email: currentUser.get("email")
|
||||||
}).then(
|
}).then(
|
||||||
@@ -777,22 +827,78 @@ function Login() {
|
|||||||
tenentName: x.TenantId.TenantName || ""
|
tenentName: x.TenantId.TenantName || ""
|
||||||
};
|
};
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenetId",
|
"TenantId",
|
||||||
x.TenantId.objectId
|
x.TenantId.objectId
|
||||||
);
|
);
|
||||||
tenentInfo.push(obj);
|
tenentInfo.push(obj);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
localStorage.setItem("PageLanding", item.pageId);
|
localStorage.setItem("PageLanding", setting.pageId);
|
||||||
localStorage.setItem("defaultmenuid", item.menuId);
|
localStorage.setItem(
|
||||||
localStorage.setItem("pageType", item.pageType);
|
"defaultmenuid",
|
||||||
navigate(`/${item.pageType}/${item.pageId}`);
|
setting.menuId
|
||||||
|
);
|
||||||
|
localStorage.setItem("pageType", setting.pageType);
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const LocalUserDetails = {
|
||||||
|
name: results[0].get("Name"),
|
||||||
|
email: results[0].get("Email"),
|
||||||
|
phone: results[0].get("Phone"),
|
||||||
|
company: results[0].get("Company")
|
||||||
|
};
|
||||||
|
localStorage.setItem(
|
||||||
|
"userDetails",
|
||||||
|
JSON.stringify(LocalUserDetails)
|
||||||
|
);
|
||||||
|
const billingDate =
|
||||||
|
results[0].get("Next_billing_date") &&
|
||||||
|
results[0].get("Next_billing_date");
|
||||||
|
const freeplan =
|
||||||
|
results[0]?.get("Plan") &&
|
||||||
|
results[0]?.get("Plan").plan_code;
|
||||||
|
|
||||||
|
if (freeplan === "freeplan") {
|
||||||
|
navigate(redirectUrl);
|
||||||
|
} else if (billingDate) {
|
||||||
|
if (billingDate > new Date()) {
|
||||||
|
localStorage.removeItem("userDetails");
|
||||||
|
// Redirect to the appropriate URL after successful login
|
||||||
|
navigate(redirectUrl);
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Redirect to the appropriate URL after successful login
|
||||||
|
navigate(redirectUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
localStorage.setItem("PageLanding", item.pageId);
|
localStorage.setItem("PageLanding", setting.pageId);
|
||||||
localStorage.setItem("defaultmenuid", item.menuId);
|
localStorage.setItem("defaultmenuid", setting.menuId);
|
||||||
localStorage.setItem("pageType", item.pageType);
|
localStorage.setItem("pageType", setting.pageType);
|
||||||
navigate(`/${item.pageType}/${item.pageId}`);
|
setState({ ...state, loading: false });
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const LocalUserDetails = {
|
||||||
|
name: results[0].get("Name"),
|
||||||
|
email: results[0].get("Email"),
|
||||||
|
phone: results[0].get("Phone")
|
||||||
|
// company: results.get("Company"),
|
||||||
|
};
|
||||||
|
localStorage.setItem(
|
||||||
|
"userDetails",
|
||||||
|
JSON.stringify(LocalUserDetails)
|
||||||
|
);
|
||||||
|
const billingDate = "";
|
||||||
|
if (billingDate) {
|
||||||
|
navigate(`/subscription`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Redirect to the appropriate URL after successful login
|
||||||
|
navigate(redirectUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
@@ -1045,7 +1151,11 @@ function Login() {
|
|||||||
</button>
|
</button>
|
||||||
<NavLink
|
<NavLink
|
||||||
className="rounded-sm cursor-pointer bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] w-full py-3 shadow uppercase"
|
className="rounded-sm cursor-pointer bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] w-full py-3 shadow uppercase"
|
||||||
to="/signup"
|
to={
|
||||||
|
location.search
|
||||||
|
? "/signup" + location.search
|
||||||
|
: "/signup"
|
||||||
|
}
|
||||||
style={width < 768 ? { textAlign: "center" } : {}}
|
style={width < 768 ? { textAlign: "center" } : {}}
|
||||||
>
|
>
|
||||||
Create Account
|
Create Account
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import "../styles/signature.css";
|
|||||||
import { toDataUrl } from "../constant/Utils";
|
import { toDataUrl } from "../constant/Utils";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import { appInfo } from "../constant/appinfo";
|
import { appInfo } from "../constant/appinfo";
|
||||||
|
import { SaveFileSize } from "../constant/saveFileSize";
|
||||||
const ManageSign = () => {
|
const ManageSign = () => {
|
||||||
const appName = appInfo.appname;
|
const appName = appInfo.appname;
|
||||||
const [penColor, setPenColor] = useState("blue");
|
const [penColor, setPenColor] = useState("blue");
|
||||||
@@ -158,7 +159,11 @@ const ManageSign = () => {
|
|||||||
try {
|
try {
|
||||||
const parseFile = new Parse.File(file.name, file);
|
const parseFile = new Parse.File(file.name, file);
|
||||||
const response = await parseFile.save();
|
const response = await parseFile.save();
|
||||||
return response?.url();
|
if (response?.url()) {
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
SaveFileSize(file.size, response.url(), tenantId);
|
||||||
|
return response?.url();
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("sign upload err", err);
|
console.log("sign upload err", err);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ function Opensigndrive() {
|
|||||||
const scrollRef = useRef(null);
|
const scrollRef = useRef(null);
|
||||||
const [isList, setIsList] = useState(false);
|
const [isList, setIsList] = useState(false);
|
||||||
const [selectedSort, setSelectedSort] = useState("Date");
|
const [selectedSort, setSelectedSort] = useState("Date");
|
||||||
const [sortingOrder, setSortingOrder] = useState("Decending");
|
const [sortingOrder, setSortingOrder] = useState("Descending");
|
||||||
const [pdfData, setPdfData] = useState([]);
|
const [pdfData, setPdfData] = useState([]);
|
||||||
const [isFolder, setIsFolder] = useState(false);
|
const [isFolder, setIsFolder] = useState(false);
|
||||||
const [newFolderName, setNewFolderName] = useState();
|
const [newFolderName, setNewFolderName] = useState();
|
||||||
@@ -54,6 +54,14 @@ function Opensigndrive() {
|
|||||||
const [skip, setSkip] = useState(0);
|
const [skip, setSkip] = useState(0);
|
||||||
const limit = 100;
|
const limit = 100;
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const sortOrder = ["Ascending", "Descending"];
|
||||||
|
const sortingValue = ["Name", "Date"];
|
||||||
|
const orderName = {
|
||||||
|
Ascending: "Ascending",
|
||||||
|
Descending: "Descending",
|
||||||
|
Name: "Name",
|
||||||
|
Date: "Date"
|
||||||
|
};
|
||||||
const currentUser =
|
const currentUser =
|
||||||
localStorage.getItem(
|
localStorage.getItem(
|
||||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
@@ -80,7 +88,7 @@ function Opensigndrive() {
|
|||||||
setHandleError("Error: Something went wrong!");
|
setHandleError("Error: Something went wrong!");
|
||||||
} else if (driveDetails && driveDetails.length > 0) {
|
} else if (driveDetails && driveDetails.length > 0) {
|
||||||
setSkip((prevSkip) => prevSkip + limit);
|
setSkip((prevSkip) => prevSkip + limit);
|
||||||
sortApps("Date", "Decending", driveDetails, true);
|
sortingData(null, null, driveDetails, true);
|
||||||
}
|
}
|
||||||
if (!docId) {
|
if (!docId) {
|
||||||
setFolderName([{ name: "OpenSign™ Drive", objectId: "" }]);
|
setFolderName([{ name: "OpenSign™ Drive", objectId: "" }]);
|
||||||
@@ -114,6 +122,7 @@ function Opensigndrive() {
|
|||||||
//disableLoading is used disable initial loader
|
//disableLoading is used disable initial loader
|
||||||
const disableLoading = true;
|
const disableLoading = true;
|
||||||
// If the fetched data length is less than the limit, it means there's no more data to fetch
|
// If the fetched data length is less than the limit, it means there's no more data to fetch
|
||||||
|
|
||||||
if (!loading && pdfData.length % 100 === 0) {
|
if (!loading && pdfData.length % 100 === 0) {
|
||||||
getPdfDocumentList(disableLoading);
|
getPdfDocumentList(disableLoading);
|
||||||
}
|
}
|
||||||
@@ -129,7 +138,7 @@ function Opensigndrive() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [loading]); // Add/remove scroll event listener when loading changes
|
}, [loading, sortingOrder, selectedSort]); // Add/remove scroll event listener when loading changes
|
||||||
|
|
||||||
//function for handle folder name path
|
//function for handle folder name path
|
||||||
const handleRoute = (index) => {
|
const handleRoute = (index) => {
|
||||||
@@ -210,35 +219,38 @@ function Opensigndrive() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortingApp = (appInfo, type, order) => {
|
//function to use sorting document list according to type and order
|
||||||
if (type === "Name") {
|
const sortedBy = (appInfo, type, order) => {
|
||||||
if (order === "Accending") {
|
if (type === orderName.Name) {
|
||||||
|
if (order === orderName.Ascending) {
|
||||||
return appInfo.sort((a, b) => (a.Name > b.Name ? 1 : -1));
|
return appInfo.sort((a, b) => (a.Name > b.Name ? 1 : -1));
|
||||||
} else if (order === "Decending") {
|
} else if (order === orderName.Descending) {
|
||||||
return appInfo.sort((a, b) => (a.Name > b.Name ? -1 : 1));
|
return appInfo.sort((a, b) => (a.Name > b.Name ? -1 : 1));
|
||||||
}
|
}
|
||||||
} else if (type === "Date") {
|
} else if (type === orderName.Date) {
|
||||||
if (order === "Accending") {
|
if (order === orderName.Ascending) {
|
||||||
return appInfo.sort((a, b) => (a.createdAt > b.createdAt ? 1 : -1));
|
return appInfo.sort((a, b) => (a.createdAt > b.createdAt ? 1 : -1));
|
||||||
} else if (order === "Decending") {
|
} else if (order === orderName.Descending) {
|
||||||
return appInfo.sort((a, b) => (a.createdAt > b.createdAt ? -1 : 1));
|
return appInfo.sort((a, b) => (a.createdAt > b.createdAt ? -1 : 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortApps = (type, order, driveDetails, isInitial) => {
|
//function to use get sorting type, order and document list to sort
|
||||||
const selectedSortType = type ? type : selectedSort ? selectedSort : "Date";
|
const sortingData = (type, order, driveDetails, isInitial) => {
|
||||||
const sortOrder = order ? order : sortingOrder ? sortingOrder : "Decending";
|
const selectedSortType = type ? type : selectedSort;
|
||||||
if (selectedSortType === "Name") {
|
const sortOrder = order ? order : sortingOrder;
|
||||||
sortingApp(driveDetails, "Name", sortOrder);
|
|
||||||
} else if (selectedSortType === "Date") {
|
//check isInitial true it means sort previous 20 and get on scrolling 20 = 40 document list
|
||||||
sortingApp(driveDetails, "Date", sortOrder);
|
const allPdfData = isInitial ? [...pdfData, ...driveDetails] : driveDetails;
|
||||||
}
|
//call sortedBy function according to selected Type and order
|
||||||
if (isInitial) {
|
if (selectedSortType === orderName.Name) {
|
||||||
setPdfData([...pdfData, ...driveDetails]);
|
sortedBy(allPdfData, orderName.Name, sortOrder);
|
||||||
} else {
|
} else if (selectedSortType === orderName.Date) {
|
||||||
setPdfData(driveDetails);
|
sortedBy(allPdfData, orderName.Date, sortOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPdfData(allPdfData);
|
||||||
};
|
};
|
||||||
|
|
||||||
//function for handle auto scroll on folder path
|
//function for handle auto scroll on folder path
|
||||||
@@ -611,95 +623,56 @@ function Opensigndrive() {
|
|||||||
aria-labelledby="dropdownMenuButton"
|
aria-labelledby="dropdownMenuButton"
|
||||||
aria-expanded={isShowSort ? "true" : "false"}
|
aria-expanded={isShowSort ? "true" : "false"}
|
||||||
>
|
>
|
||||||
<span
|
{sortingValue.map((value, ind) => {
|
||||||
onClick={() => {
|
return (
|
||||||
setSelectedSort("Name");
|
<span
|
||||||
sortApps("Name", null, pdfData);
|
key={ind}
|
||||||
}}
|
onClick={() => {
|
||||||
className="dropdown-item itemColor"
|
setSelectedSort(value);
|
||||||
>
|
sortingData(value, null, pdfData);
|
||||||
{selectedSort !== "Name" ? (
|
}}
|
||||||
<i
|
className="dropdown-item itemColor"
|
||||||
className="fa fa-arrow-up"
|
style={{
|
||||||
aria-hidden="true"
|
paddingLeft: selectedSort !== value && "33px"
|
||||||
style={{ marginRight: "5px" }}
|
}}
|
||||||
></i>
|
>
|
||||||
) : (
|
{selectedSort === value && (
|
||||||
<i
|
<i
|
||||||
className="fa fa-check"
|
className="fa fa-check"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
style={{ marginRight: "5px" }}
|
style={{ marginRight: "5px" }}
|
||||||
></i>
|
></i>
|
||||||
)}
|
)}
|
||||||
Name
|
{value}
|
||||||
</span>
|
</span>
|
||||||
<span
|
);
|
||||||
onClick={() => {
|
})}
|
||||||
setSelectedSort("Date");
|
|
||||||
sortApps("Date", null, pdfData);
|
|
||||||
}}
|
|
||||||
className="dropdown-item itemColor"
|
|
||||||
>
|
|
||||||
{selectedSort !== "Date" ? (
|
|
||||||
<i
|
|
||||||
className="fa fa-arrow-up"
|
|
||||||
aria-hidden="true"
|
|
||||||
style={{ marginRight: "5px" }}
|
|
||||||
></i>
|
|
||||||
) : (
|
|
||||||
<i
|
|
||||||
className="fa fa-check"
|
|
||||||
aria-hidden="true"
|
|
||||||
style={{ marginRight: "5px" }}
|
|
||||||
></i>
|
|
||||||
)}
|
|
||||||
Date
|
|
||||||
</span>
|
|
||||||
<hr className="hrStyle" />
|
<hr className="hrStyle" />
|
||||||
<span
|
{sortOrder.map((order, ind) => {
|
||||||
onClick={() => {
|
return (
|
||||||
setSortingOrder("Accending");
|
<span
|
||||||
sortApps(null, "Accending", pdfData);
|
key={ind}
|
||||||
}}
|
onClick={() => {
|
||||||
className="dropdown-item itemColor"
|
setSortingOrder(order);
|
||||||
>
|
sortingData(null, order, pdfData);
|
||||||
{sortingOrder !== "Accending" ? (
|
}}
|
||||||
<i
|
className="dropdown-item itemColor"
|
||||||
className="fa fa-arrow-up"
|
style={{
|
||||||
aria-hidden="true"
|
paddingLeft: sortingOrder !== order && "33px"
|
||||||
style={{ marginRight: "5px" }}
|
}}
|
||||||
></i>
|
>
|
||||||
) : (
|
{sortingOrder === order && (
|
||||||
<i
|
<i
|
||||||
className="fa fa-check"
|
className="fa fa-check"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
style={{ marginRight: "5px" }}
|
style={{ marginRight: "5px" }}
|
||||||
></i>
|
></i>
|
||||||
)}
|
)}
|
||||||
Accending
|
{order}
|
||||||
</span>
|
</span>
|
||||||
<span
|
);
|
||||||
onClick={() => {
|
})}
|
||||||
setSortingOrder("Decending");
|
|
||||||
sortApps(null, "Decending", pdfData);
|
|
||||||
}}
|
|
||||||
className="dropdown-item itemColor"
|
|
||||||
>
|
|
||||||
{sortingOrder !== "Decending" ? (
|
|
||||||
<i
|
|
||||||
className="fa fa-arrow-up"
|
|
||||||
aria-hidden="true"
|
|
||||||
style={{ marginRight: "5px" }}
|
|
||||||
></i>
|
|
||||||
) : (
|
|
||||||
<i
|
|
||||||
className="fa fa-check"
|
|
||||||
aria-hidden="true"
|
|
||||||
style={{ marginRight: "5px" }}
|
|
||||||
></i>
|
|
||||||
)}
|
|
||||||
Decending
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -353,7 +353,7 @@ const PgSignUp = () => {
|
|||||||
tenentName: x.TenantId.TenantName || ""
|
tenentName: x.TenantId.TenantName || ""
|
||||||
};
|
};
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenetId",
|
"TenantId",
|
||||||
x.TenantId.objectId
|
x.TenantId.objectId
|
||||||
);
|
);
|
||||||
tenentInfo.push(obj);
|
tenentInfo.push(obj);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import axios from "axios";
|
|||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import "../styles/signature.css";
|
import "../styles/signature.css";
|
||||||
import { PDFDocument } from "pdf-lib";
|
import { PDFDocument } from "pdf-lib";
|
||||||
import { themeColor } from "../constant/const";
|
import { isEnableSubscription, themeColor } from "../constant/const";
|
||||||
import { DndProvider } from "react-dnd";
|
import { DndProvider } from "react-dnd";
|
||||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||||
import { useDrag, useDrop } from "react-dnd";
|
import { useDrag, useDrop } from "react-dnd";
|
||||||
@@ -39,6 +39,7 @@ import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
|||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
||||||
import WidgetNameModal from "../components/pdf/WidgetNameModal";
|
import WidgetNameModal from "../components/pdf/WidgetNameModal";
|
||||||
|
import { SaveFileSize } from "../constant/saveFileSize";
|
||||||
|
|
||||||
function PlaceHolderSign() {
|
function PlaceHolderSign() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -97,18 +98,19 @@ function PlaceHolderSign() {
|
|||||||
const [widgetType, setWidgetType] = useState("");
|
const [widgetType, setWidgetType] = useState("");
|
||||||
const [isUiLoading, setIsUiLoading] = useState(false);
|
const [isUiLoading, setIsUiLoading] = useState(false);
|
||||||
const [isRadio, setIsRadio] = useState(false);
|
const [isRadio, setIsRadio] = useState(false);
|
||||||
const [currWidgetsDetails, setCurrWidgetsDetails] = useState([]);
|
const [currWidgetsDetails, setCurrWidgetsDetails] = useState({});
|
||||||
const [selectWidgetId, setSelectWidgetId] = useState("");
|
const [selectWidgetId, setSelectWidgetId] = useState("");
|
||||||
const [isCheckbox, setIsCheckbox] = useState(false);
|
const [isCheckbox, setIsCheckbox] = useState(false);
|
||||||
const [isNameModal, setIsNameModal] = useState(false);
|
const [isNameModal, setIsNameModal] = useState(false);
|
||||||
const [widgetName, setWidgetName] = useState(false);
|
const [widgetName, setWidgetName] = useState(false);
|
||||||
const [mailStatus, setMailStatus] = useState("");
|
const [mailStatus, setMailStatus] = useState("");
|
||||||
const [isCurrUser, setIsCurrUser] = useState(false);
|
const [isCurrUser, setIsCurrUser] = useState(false);
|
||||||
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||||
const [isAlreadyPlace, setIsAlreadyPlace] = useState({
|
const [isAlreadyPlace, setIsAlreadyPlace] = useState({
|
||||||
status: false,
|
status: false,
|
||||||
message: ""
|
message: ""
|
||||||
});
|
});
|
||||||
|
const [extUserId, setExtUserId] = useState("");
|
||||||
const isMobile = window.innerWidth < 767;
|
const isMobile = window.innerWidth < 767;
|
||||||
const [, drop] = useDrop({
|
const [, drop] = useDrop({
|
||||||
accept: "BOX",
|
accept: "BOX",
|
||||||
@@ -180,11 +182,35 @@ function PlaceHolderSign() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [divRef.current]);
|
}, [divRef.current]);
|
||||||
|
|
||||||
|
async function checkIsSubscribed(email) {
|
||||||
|
const user = await Parse.Cloud.run("getUserDetails", {
|
||||||
|
email: email
|
||||||
|
});
|
||||||
|
const freeplan = user?.get("Plan") && user?.get("Plan").plan_code;
|
||||||
|
const billingDate =
|
||||||
|
user?.get("Next_billing_date") && user?.get("Next_billing_date");
|
||||||
|
if (freeplan === "freeplan") {
|
||||||
|
return true;
|
||||||
|
} else if (billingDate) {
|
||||||
|
if (billingDate > new Date()) {
|
||||||
|
setIsSubscribe(true);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`);
|
||||||
|
}
|
||||||
|
}
|
||||||
//function for get document details
|
//function for get document details
|
||||||
const getDocumentDetails = async () => {
|
const getDocumentDetails = async () => {
|
||||||
//getting document details
|
//getting document details
|
||||||
const documentData = await contractDocument(documentId);
|
const documentData = await contractDocument(documentId);
|
||||||
if (documentData && documentData.length > 0) {
|
if (documentData && documentData.length > 0) {
|
||||||
|
setExtUserId(documentData[0]?.ExtUserPtr?.objectId);
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
checkIsSubscribed(documentData[0]?.ExtUserPtr?.Email);
|
||||||
|
}
|
||||||
const alreadyPlaceholder = documentData[0]?.SignedUrl;
|
const alreadyPlaceholder = documentData[0]?.SignedUrl;
|
||||||
// Check if document is sent for signing
|
// Check if document is sent for signing
|
||||||
if (alreadyPlaceholder) {
|
if (alreadyPlaceholder) {
|
||||||
@@ -736,6 +762,9 @@ function PlaceHolderSign() {
|
|||||||
// Save the Parse File if needed
|
// Save the Parse File if needed
|
||||||
const pdfData = await pdfFile.save();
|
const pdfData = await pdfFile.save();
|
||||||
const pdfUrl = pdfData.url();
|
const pdfUrl = pdfData.url();
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
const buffer = atob(pdfBytes);
|
||||||
|
SaveFileSize(buffer.length, pdfUrl, tenantId);
|
||||||
return pdfUrl;
|
return pdfUrl;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("error", e);
|
console.log("error", e);
|
||||||
@@ -829,6 +858,7 @@ function PlaceHolderSign() {
|
|||||||
: "";
|
: "";
|
||||||
const themeBGcolor = themeColor;
|
const themeBGcolor = themeColor;
|
||||||
let params = {
|
let params = {
|
||||||
|
extUserId: extUserId,
|
||||||
recipient: signerMail[i].Email,
|
recipient: signerMail[i].Email,
|
||||||
subject: `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign ${pdfDetails?.[0].Name}`,
|
subject: `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign ${pdfDetails?.[0].Name}`,
|
||||||
from: sender,
|
from: sender,
|
||||||
@@ -1450,7 +1480,7 @@ function PlaceHolderSign() {
|
|||||||
{isSendAlert.mssg === "sure" ? (
|
{isSendAlert.mssg === "sure" ? (
|
||||||
<p>Please add field for all recipients.</p>
|
<p>Please add field for all recipients.</p>
|
||||||
) : isSendAlert.mssg === textWidget ? (
|
) : isSendAlert.mssg === textWidget ? (
|
||||||
<p>Please confirm that you have filled label widget.</p>
|
<p>Please confirm that you have filled the text field.</p>
|
||||||
) : (
|
) : (
|
||||||
isSendAlert.mssg === "confirm" && (
|
isSendAlert.mssg === "confirm" && (
|
||||||
<p>
|
<p>
|
||||||
@@ -1596,6 +1626,7 @@ function PlaceHolderSign() {
|
|||||||
currWidgetsDetails={currWidgetsDetails}
|
currWidgetsDetails={currWidgetsDetails}
|
||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
handleClose={handleNameModal}
|
handleClose={handleNameModal}
|
||||||
|
isSubscribe={isSubscribe}
|
||||||
/>
|
/>
|
||||||
<DropdownWidgetOption
|
<DropdownWidgetOption
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -1606,6 +1637,7 @@ function PlaceHolderSign() {
|
|||||||
currWidgetsDetails={currWidgetsDetails}
|
currWidgetsDetails={currWidgetsDetails}
|
||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
handleClose={handleNameModal}
|
handleClose={handleNameModal}
|
||||||
|
isSubscribe={isSubscribe}
|
||||||
/>
|
/>
|
||||||
<DropdownWidgetOption
|
<DropdownWidgetOption
|
||||||
type="dropdown"
|
type="dropdown"
|
||||||
@@ -1616,6 +1648,7 @@ function PlaceHolderSign() {
|
|||||||
currWidgetsDetails={currWidgetsDetails}
|
currWidgetsDetails={currWidgetsDetails}
|
||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
handleClose={handleNameModal}
|
handleClose={handleNameModal}
|
||||||
|
isSubscribe={isSubscribe}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* pdf header which contain funish back button */}
|
{/* pdf header which contain funish back button */}
|
||||||
@@ -1716,9 +1749,11 @@ function PlaceHolderSign() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<div className="signerComponent">
|
<div className="signerComponent" aria-disabled>
|
||||||
<div
|
<div
|
||||||
style={{ maxHeight: window.innerHeight - 70 + "px" }}
|
style={{
|
||||||
|
maxHeight: window.innerHeight - 70 + "px"
|
||||||
|
}}
|
||||||
className="autoSignScroll"
|
className="autoSignScroll"
|
||||||
>
|
>
|
||||||
<SignerListPlace
|
<SignerListPlace
|
||||||
@@ -1734,11 +1769,12 @@ function PlaceHolderSign() {
|
|||||||
setSignersData={setSignersData}
|
setSignersData={setSignersData}
|
||||||
blockColor={blockColor}
|
blockColor={blockColor}
|
||||||
setBlockColor={setBlockColor}
|
setBlockColor={setBlockColor}
|
||||||
|
isMailSend={isMailSend}
|
||||||
// handleAddSigner={handleAddSigner}
|
// handleAddSigner={handleAddSigner}
|
||||||
/>
|
/>
|
||||||
<div data-tut="reactourSecond">
|
<div data-tut="reactourSecond">
|
||||||
<WidgetComponent
|
<WidgetComponent
|
||||||
pdfUrl={isMailSend}
|
isMailSend={isMailSend}
|
||||||
dragSignature={dragSignature}
|
dragSignature={dragSignature}
|
||||||
signRef={signRef}
|
signRef={signRef}
|
||||||
handleDivClick={handleDivClick}
|
handleDivClick={handleDivClick}
|
||||||
@@ -1828,6 +1864,7 @@ function PlaceHolderSign() {
|
|||||||
isOpen={isNameModal}
|
isOpen={isNameModal}
|
||||||
handleClose={handleNameModal}
|
handleClose={handleNameModal}
|
||||||
handleData={handleWidgetdefaultdata}
|
handleData={handleWidgetdefaultdata}
|
||||||
|
isSubscribe={isSubscribe}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useNavigate } from "react-router";
|
import { NavLink, useNavigate } from "react-router-dom";
|
||||||
import { NavLink } from "react-router-dom";
|
|
||||||
import checkmark from "../assets/images/checkmark.png";
|
import checkmark from "../assets/images/checkmark.png";
|
||||||
import plansArr from "../json/plansArr.json";
|
import plansArr from "../json/plansArr.json";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
|
import Parse from "parse";
|
||||||
const listItemStyle = {
|
const listItemStyle = {
|
||||||
paddingLeft: "20px", // Add padding to create space for the image
|
paddingLeft: "20px", // Add padding to create space for the image
|
||||||
backgroundImage: `url(${checkmark})`, // Set your image as the list style image
|
backgroundImage: `url(${checkmark})`, // Set your image as the list style image
|
||||||
@@ -35,15 +35,35 @@ const PlanSubscriptions = () => {
|
|||||||
company +
|
company +
|
||||||
phone;
|
phone;
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (localStorage.getItem("accesstoken")) {
|
// if (localStorage.getItem("accesstoken")) {
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
setYearlyVisible(false);
|
// } else {
|
||||||
} else {
|
// navigate("/", { replace: true });
|
||||||
navigate("/", { replace: true });
|
// }
|
||||||
}
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleFreePlan = async () => {
|
||||||
|
setIsLoader(true);
|
||||||
|
try {
|
||||||
|
const params = { userId: Parse.User.current().id };
|
||||||
|
const res = await Parse.Cloud.run("freesubscription", params);
|
||||||
|
if (res.status === "success" && res.result === "already subscribed!") {
|
||||||
|
setIsLoader(false);
|
||||||
|
alert("You have already subscribed to plan!");
|
||||||
|
} else if (res.status === "success") {
|
||||||
|
setIsLoader(false);
|
||||||
|
navigate("/");
|
||||||
|
} else if (res.status === "error") {
|
||||||
|
setIsLoader(false);
|
||||||
|
alert(res.result);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setIsLoader(false);
|
||||||
|
console.log("err in free subscribe", err.message);
|
||||||
|
alert("Somenthing went wrong, please try again later!");
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title title={"Subscriptions"} />
|
<Title title={"Subscriptions"} />
|
||||||
@@ -69,23 +89,40 @@ const PlanSubscriptions = () => {
|
|||||||
style={{
|
style={{
|
||||||
backgroundColor: "white",
|
backgroundColor: "white",
|
||||||
overflowY: "auto",
|
overflowY: "auto",
|
||||||
maxHeight: "100%",
|
maxHeight: "100%"
|
||||||
"--theme-color": "#7952b3",
|
|
||||||
"--plan-width": 30
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div id="monthlyPlans" className="block my-2">
|
||||||
id="monthlyPlans"
|
<div className="flex flex-col justify-center items-center w-full">
|
||||||
className={`${yearlyVisible ? "none" : "block my-2"}`}
|
<div className="mb-6 mt-2 flex flex-row border-[1px] p-2 border-gray-300 rounded text-sm">
|
||||||
>
|
<span
|
||||||
<div className="flex justify-center w-full my-2">
|
onClick={() => setYearlyVisible(false)}
|
||||||
<ul className=" flex flex-col md:flex-row h-full bg-white justify-center border-collapse border-[1px] border-gray-300">
|
className={`${
|
||||||
|
!yearlyVisible
|
||||||
|
? "bg-[#002862] text-white"
|
||||||
|
: "bg-white text-black"
|
||||||
|
} px-4 py-1 rounded cursor-pointer`}
|
||||||
|
>
|
||||||
|
Monthly
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
onClick={() => setYearlyVisible(true)}
|
||||||
|
className={`${
|
||||||
|
yearlyVisible
|
||||||
|
? "bg-[#002862] text-white"
|
||||||
|
: "bg-white text-black"
|
||||||
|
} px-4 py-1 rounded cursor-pointer`}
|
||||||
|
>
|
||||||
|
Yearly (10% off)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<ul className="flex flex-col md:flex-row h-full bg-white justify-center">
|
||||||
{plansArr.map((item) => (
|
{plansArr.map((item) => (
|
||||||
<li
|
<li
|
||||||
className="flex flex-col md:my-0 text-center border-[1px] border-gray-300 w-[260px]"
|
className="flex flex-col md:my-0 text-center border-collapse border-[1px] border-gray-300 w-[260px]"
|
||||||
key={item.planName}
|
key={item.planName}
|
||||||
>
|
>
|
||||||
<div className="p-2 flex flex-col justify-center items-center">
|
<div className="p-2 flex flex-col justify-center items-center min-h-[320px]">
|
||||||
<h3 className="text-[#002862] uppercase">
|
<h3 className="text-[#002862] uppercase">
|
||||||
{item.planName}
|
{item.planName}
|
||||||
</h3>
|
</h3>
|
||||||
@@ -99,17 +136,23 @@ const PlanSubscriptions = () => {
|
|||||||
<div className="">
|
<div className="">
|
||||||
<span className="text-3xl">
|
<span className="text-3xl">
|
||||||
{item.currency && <small>{item.currency}</small>}
|
{item.currency && <small>{item.currency}</small>}
|
||||||
{item.price}
|
{yearlyVisible
|
||||||
|
? item?.yearlyPrice
|
||||||
|
: item.monthlyPrice}
|
||||||
</span>
|
</span>
|
||||||
|
<p className="font-semibold pt-2 text-sm">
|
||||||
|
{yearlyVisible ? "Billed Yearly" : "Billed Monthly"}
|
||||||
|
</p>
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
item.subtitle.length <= 32
|
item.subtitle.length <= 32
|
||||||
? "w-[150px] text-center"
|
? "w-[150px] h-[40px] text-center"
|
||||||
: ""
|
: ""
|
||||||
} text-sm text-center my-2`}
|
} text-sm text-center my-2`}
|
||||||
>
|
>
|
||||||
<p
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
textAlign: "center",
|
||||||
backgroundColor: item.subtitlecolor
|
backgroundColor: item.subtitlecolor
|
||||||
? item.subtitlecolor
|
? item.subtitlecolor
|
||||||
: "white"
|
: "white"
|
||||||
@@ -124,23 +167,33 @@ const PlanSubscriptions = () => {
|
|||||||
) : (
|
) : (
|
||||||
<span>{item.subtitle}</span>
|
<span>{item.subtitle}</span>
|
||||||
)}
|
)}
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{item.url ? (
|
||||||
<NavLink
|
<NavLink
|
||||||
to={
|
to={
|
||||||
item.btnText === "Subscribe"
|
item.btnText === "Subscribe"
|
||||||
? item.url + details
|
? yearlyVisible
|
||||||
: item.url
|
? item.yearlyUrl + details
|
||||||
}
|
: item.url + details
|
||||||
className="bg-[#002862] w-full text-white py-2 rounded uppercase hover:no-underline hover:text-white"
|
: item.url
|
||||||
target={item.target}
|
}
|
||||||
>
|
className="bg-[#002862] w-full mt-1 text-white py-2 rounded uppercase hover:no-underline hover:text-white cursor-pointer"
|
||||||
{item.btnText}
|
target={item.target}
|
||||||
</NavLink>
|
>
|
||||||
|
{item.btnText}
|
||||||
|
</NavLink>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
className="bg-[#002862] w-full mt-1 text-white py-2 rounded uppercase hover:no-underline hover:text-white cursor-pointer"
|
||||||
|
onClick={() => handleFreePlan()}
|
||||||
|
>
|
||||||
|
{item.btnText}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<hr className="w-full bg-gray-300 p-[.5px]" />
|
<hr className="w-full bg-gray-300 h-[0.5px]" />
|
||||||
<ul className="mx-1 p-3 text-left break-words text-sm list-none">
|
<ul className="mx-1 p-3 text-left break-words text-sm list-none">
|
||||||
{item.benefits.map((subitem, index) => (
|
{item.benefits.map((subitem, index) => (
|
||||||
<li style={listItemStyle} key={index} className="m-1">
|
<li style={listItemStyle} key={index} className="m-1">
|
||||||
@@ -154,6 +207,38 @@ const PlanSubscriptions = () => {
|
|||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center"
|
||||||
|
}}
|
||||||
|
className="text-sm"
|
||||||
|
>
|
||||||
|
<hr
|
||||||
|
className={"border-[1px] border-gray-300 w-[20%]"}
|
||||||
|
style={{ color: "grey" }}
|
||||||
|
/>
|
||||||
|
<span style={{ color: "grey" }} className="px-2 ">
|
||||||
|
or
|
||||||
|
</span>
|
||||||
|
<hr
|
||||||
|
className={"border-[1px] border-gray-300 w-[20%]"}
|
||||||
|
style={{ color: "grey" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col justify-center w-full items-center">
|
||||||
|
<h3 className="text-[#002862] mt-1 mb-2">
|
||||||
|
Host it yourself for free
|
||||||
|
</h3>
|
||||||
|
<NavLink
|
||||||
|
to={"https://github.com/OpenSignLabs/OpenSign"}
|
||||||
|
className="bg-[#002862] w-[200px] text-center text-white py-2 rounded uppercase hover:no-underline hover:text-white cursor-pointer"
|
||||||
|
target={"_blank"}
|
||||||
|
>
|
||||||
|
Visit Github
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -2,17 +2,19 @@ import React, { useState, useEffect } from "react";
|
|||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import { useNavigate, NavLink } from "react-router-dom";
|
import { useNavigate, NavLink, useLocation } from "react-router-dom";
|
||||||
import login_img from "../assets/images/login_img.svg";
|
import login_img from "../assets/images/login_img.svg";
|
||||||
import { useWindowSize } from "../hook/useWindowSize";
|
import { useWindowSize } from "../hook/useWindowSize";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
import { appInfo } from "../constant/appinfo";
|
import { appInfo } from "../constant/appinfo";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
import { showTenant } from "../redux/reducers/ShowTenant";
|
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||||
|
import { isEnableSubscription } from "../constant/const";
|
||||||
const Signup = () => {
|
const Signup = () => {
|
||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [phone, setPhone] = useState("");
|
const [phone, setPhone] = useState("");
|
||||||
@@ -67,6 +69,19 @@ const Signup = () => {
|
|||||||
localStorage.setItem("baseUrl", baseUrl);
|
localStorage.setItem("baseUrl", baseUrl);
|
||||||
localStorage.setItem("parseAppId", appid);
|
localStorage.setItem("parseAppId", appid);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleFreePlan = async (id) => {
|
||||||
|
try {
|
||||||
|
const params = { userId: id };
|
||||||
|
const res = await Parse.Cloud.run("freesubscription", params);
|
||||||
|
if (res.status === "error") {
|
||||||
|
alert(res.result);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in free subscribe", err.message);
|
||||||
|
alert("Somenthing went wrong, please try again later!");
|
||||||
|
}
|
||||||
|
};
|
||||||
const handleSubmit = (event) => {
|
const handleSubmit = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (lengthValid && caseDigitValid && specialCharValid) {
|
if (lengthValid && caseDigitValid && specialCharValid) {
|
||||||
@@ -110,7 +125,13 @@ const Signup = () => {
|
|||||||
params
|
params
|
||||||
);
|
);
|
||||||
if (usersignup) {
|
if (usersignup) {
|
||||||
handleNavigation(r.getSessionToken());
|
const param = new URLSearchParams(location.search);
|
||||||
|
const isFreeplan =
|
||||||
|
param?.get("subscription") === "freeplan";
|
||||||
|
if (isFreeplan) {
|
||||||
|
await handleFreePlan(r.id);
|
||||||
|
}
|
||||||
|
handleNavigation(r.getSessionToken(), isFreeplan);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert(err.message);
|
alert(err.message);
|
||||||
@@ -155,7 +176,7 @@ const Signup = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleNavigation = async (sessionToken) => {
|
const handleNavigation = async (sessionToken, isFreeplan = false) => {
|
||||||
const baseUrl = localStorage.getItem("baseUrl");
|
const baseUrl = localStorage.getItem("baseUrl");
|
||||||
const parseAppId = localStorage.getItem("parseAppId");
|
const parseAppId = localStorage.getItem("parseAppId");
|
||||||
const res = await axios.get(baseUrl + "users/me", {
|
const res = await axios.get(baseUrl + "users/me", {
|
||||||
@@ -259,9 +280,7 @@ const Signup = () => {
|
|||||||
});
|
});
|
||||||
if (tenentInfo.length) {
|
if (tenentInfo.length) {
|
||||||
dispatch(
|
dispatch(
|
||||||
showTenant(
|
showTenant(tenentInfo[0].tenentName || "")
|
||||||
tenentInfo[0].tenentName || ""
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenantName",
|
"TenantName",
|
||||||
@@ -297,7 +316,7 @@ const Signup = () => {
|
|||||||
tenentName: x.TenantId.TenantName || ""
|
tenentName: x.TenantId.TenantName || ""
|
||||||
};
|
};
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenetId",
|
"TenantId",
|
||||||
x.TenantId.objectId
|
x.TenantId.objectId
|
||||||
);
|
);
|
||||||
tenentInfo.push(obj);
|
tenentInfo.push(obj);
|
||||||
@@ -325,8 +344,14 @@ const Signup = () => {
|
|||||||
element.pageType
|
element.pageType
|
||||||
);
|
);
|
||||||
setState({ loading: false });
|
setState({ loading: false });
|
||||||
if (process.env.REACT_APP_ENABLE_SUBSCRIPTION) {
|
if (isEnableSubscription) {
|
||||||
navigate(`/subscription`, { replace: true });
|
if (isFreeplan) {
|
||||||
|
navigate(
|
||||||
|
`/${element.pageType}/${element.pageId}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`, { replace: true });
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
alert("Registered user successfully");
|
alert("Registered user successfully");
|
||||||
navigate(
|
navigate(
|
||||||
@@ -343,8 +368,14 @@ const Signup = () => {
|
|||||||
);
|
);
|
||||||
localStorage.setItem("pageType", element.pageType);
|
localStorage.setItem("pageType", element.pageType);
|
||||||
setState({ loading: false });
|
setState({ loading: false });
|
||||||
if (process.env.REACT_APP_ENABLE_SUBSCRIPTION) {
|
if (isEnableSubscription) {
|
||||||
navigate(`/subscription`, { replace: true });
|
if (isFreeplan) {
|
||||||
|
navigate(
|
||||||
|
`/${element.pageType}/${element.pageId}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`, { replace: true });
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
navigate(
|
navigate(
|
||||||
`/${element.pageType}/${element.pageId}`
|
`/${element.pageType}/${element.pageId}`
|
||||||
@@ -626,7 +657,7 @@ const Signup = () => {
|
|||||||
</button>
|
</button>
|
||||||
<NavLink
|
<NavLink
|
||||||
className="rounded-sm cursor-pointer bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] w-full py-3 shadow uppercase"
|
className="rounded-sm cursor-pointer bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] w-full py-3 shadow uppercase"
|
||||||
to="/"
|
to={location.search ? "/" + location.search : "/"}
|
||||||
style={width < 768 ? { textAlign: "center" } : {}}
|
style={width < 768 ? { textAlign: "center" } : {}}
|
||||||
>
|
>
|
||||||
Login
|
Login
|
||||||
@@ -661,4 +692,4 @@ const Signup = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Signup
|
export default Signup;
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ function SignYourSelf() {
|
|||||||
const [showAlreadySignDoc, setShowAlreadySignDoc] = useState({
|
const [showAlreadySignDoc, setShowAlreadySignDoc] = useState({
|
||||||
status: false
|
status: false
|
||||||
});
|
});
|
||||||
const [currWidgetsDetails, setCurrWidgetsDetails] = useState([]);
|
const [currWidgetsDetails, setCurrWidgetsDetails] = useState({});
|
||||||
const [isCheckbox, setIsCheckbox] = useState(false);
|
const [isCheckbox, setIsCheckbox] = useState(false);
|
||||||
const [widgetType, setWidgetType] = useState("");
|
const [widgetType, setWidgetType] = useState("");
|
||||||
const [pdfLoadFail, setPdfLoadFail] = useState({
|
const [pdfLoadFail, setPdfLoadFail] = useState({
|
||||||
@@ -99,6 +99,7 @@ function SignYourSelf() {
|
|||||||
});
|
});
|
||||||
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
|
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
|
||||||
const [isDontShow, setIsDontShow] = useState(false);
|
const [isDontShow, setIsDontShow] = useState(false);
|
||||||
|
const [extUserId, setExtUserId] = useState("");
|
||||||
const divRef = useRef(null);
|
const divRef = useRef(null);
|
||||||
const nodeRef = useRef(null);
|
const nodeRef = useRef(null);
|
||||||
const [, drop] = useDrop({
|
const [, drop] = useDrop({
|
||||||
@@ -180,14 +181,14 @@ function SignYourSelf() {
|
|||||||
|
|
||||||
//function for get document details for perticular signer with signer'object id
|
//function for get document details for perticular signer with signer'object id
|
||||||
const getDocumentDetails = async (showComplete) => {
|
const getDocumentDetails = async (showComplete) => {
|
||||||
|
let isCompleted;
|
||||||
//getting document details
|
//getting document details
|
||||||
const documentData = await contractDocument(documentId);
|
const documentData = await contractDocument(documentId);
|
||||||
|
|
||||||
if (documentData && documentData.length > 0) {
|
if (documentData && documentData.length > 0) {
|
||||||
setPdfDetails(documentData);
|
setPdfDetails(documentData);
|
||||||
|
setExtUserId(documentData[0]?.ExtUserPtr?.objectId);
|
||||||
const isCompleted =
|
isCompleted = documentData[0].IsCompleted && documentData[0].IsCompleted;
|
||||||
documentData[0].IsCompleted && documentData[0].IsCompleted;
|
|
||||||
if (isCompleted) {
|
if (isCompleted) {
|
||||||
const docStatus = {
|
const docStatus = {
|
||||||
isCompleted: isCompleted
|
isCompleted: isCompleted
|
||||||
@@ -263,8 +264,7 @@ function SignYourSelf() {
|
|||||||
setSignerUserId(contractUsersRes[0].objectId);
|
setSignerUserId(contractUsersRes[0].objectId);
|
||||||
const tourstatuss =
|
const tourstatuss =
|
||||||
contractUsersRes[0].TourStatus && contractUsersRes[0].TourStatus;
|
contractUsersRes[0].TourStatus && contractUsersRes[0].TourStatus;
|
||||||
|
if (tourstatuss && tourstatuss.length > 0 && !isCompleted) {
|
||||||
if (tourstatuss && tourstatuss.length > 0) {
|
|
||||||
setTourStatus(tourstatuss);
|
setTourStatus(tourstatuss);
|
||||||
const checkTourRecipients = tourstatuss.filter(
|
const checkTourRecipients = tourstatuss.filter(
|
||||||
(data) => data.signyourself
|
(data) => data.signyourself
|
||||||
@@ -272,6 +272,8 @@ function SignYourSelf() {
|
|||||||
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
||||||
setCheckTourStatus(checkTourRecipients[0].signyourself);
|
setCheckTourStatus(checkTourRecipients[0].signyourself);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setCheckTourStatus(true);
|
||||||
}
|
}
|
||||||
const loadObj = {
|
const loadObj = {
|
||||||
isLoad: false
|
isLoad: false
|
||||||
@@ -291,7 +293,8 @@ function SignYourSelf() {
|
|||||||
const tourstatuss =
|
const tourstatuss =
|
||||||
contractContactBook[0].TourStatus &&
|
contractContactBook[0].TourStatus &&
|
||||||
contractContactBook[0].TourStatus;
|
contractContactBook[0].TourStatus;
|
||||||
if (tourstatuss && tourstatuss.length > 0) {
|
|
||||||
|
if (tourstatuss && tourstatuss.length > 0 && !isCompleted) {
|
||||||
setTourStatus(tourstatuss);
|
setTourStatus(tourstatuss);
|
||||||
const checkTourRecipients = tourstatuss.filter(
|
const checkTourRecipients = tourstatuss.filter(
|
||||||
(data) => data.signyourself
|
(data) => data.signyourself
|
||||||
@@ -299,6 +302,8 @@ function SignYourSelf() {
|
|||||||
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
||||||
setCheckTourStatus(checkTourRecipients[0].signyourself);
|
setCheckTourStatus(checkTourRecipients[0].signyourself);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setCheckTourStatus(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setHandleError("No Data Found!");
|
setHandleError("No Data Found!");
|
||||||
@@ -429,13 +434,13 @@ function SignYourSelf() {
|
|||||||
Width: widgetTypeExist
|
Width: widgetTypeExist
|
||||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
|
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
|
||||||
: dragTypeValue === "initials"
|
: dragTypeValue === "initials"
|
||||||
? defaultWidthHeight(dragTypeValue).width
|
? defaultWidthHeight(dragTypeValue).width
|
||||||
: "",
|
: "",
|
||||||
Height: widgetTypeExist
|
Height: widgetTypeExist
|
||||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getHeight
|
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getHeight
|
||||||
: dragTypeValue === "initials"
|
: dragTypeValue === "initials"
|
||||||
? defaultWidthHeight(dragTypeValue).height
|
? defaultWidthHeight(dragTypeValue).height
|
||||||
: "",
|
: "",
|
||||||
options: addWidgetOptions(dragTypeValue)
|
options: addWidgetOptions(dragTypeValue)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -704,7 +709,7 @@ function SignYourSelf() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//function for save button to save signature or image url
|
//function for save button to save signature or image url
|
||||||
const saveSign = (isDefaultSign, width, height) => {
|
const saveSign = (type, isDefaultSign, width, height) => {
|
||||||
const isTypeText = width && height ? true : false;
|
const isTypeText = width && height ? true : false;
|
||||||
const signatureImg = isDefaultSign
|
const signatureImg = isDefaultSign
|
||||||
? isDefaultSign === "initials"
|
? isDefaultSign === "initials"
|
||||||
@@ -727,6 +732,7 @@ function SignYourSelf() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const getUpdatePosition = onSaveSign(
|
const getUpdatePosition = onSaveSign(
|
||||||
|
type,
|
||||||
xyPostion,
|
xyPostion,
|
||||||
index,
|
index,
|
||||||
signKey,
|
signKey,
|
||||||
@@ -763,6 +769,7 @@ function SignYourSelf() {
|
|||||||
|
|
||||||
//function for delete signature block
|
//function for delete signature block
|
||||||
const handleDeleteSign = (key) => {
|
const handleDeleteSign = (key) => {
|
||||||
|
setCurrWidgetsDetails({});
|
||||||
const updateResizeData = [];
|
const updateResizeData = [];
|
||||||
|
|
||||||
let filterData = xyPostion[index].pos.filter((data) => data.key !== key);
|
let filterData = xyPostion[index].pos.filter((data) => data.key !== key);
|
||||||
@@ -1101,6 +1108,8 @@ function SignYourSelf() {
|
|||||||
setIsInitial={setIsInitial}
|
setIsInitial={setIsInitial}
|
||||||
setIsStamp={setIsStamp}
|
setIsStamp={setIsStamp}
|
||||||
widgetType={widgetType}
|
widgetType={widgetType}
|
||||||
|
currWidgetsDetails={currWidgetsDetails}
|
||||||
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
/>
|
/>
|
||||||
{/*render email component to send email after finish signature on document */}
|
{/*render email component to send email after finish signature on document */}
|
||||||
<EmailComponent
|
<EmailComponent
|
||||||
@@ -1112,6 +1121,7 @@ function SignYourSelf() {
|
|||||||
setSuccessEmail={setSuccessEmail}
|
setSuccessEmail={setSuccessEmail}
|
||||||
sender={jsonSender}
|
sender={jsonSender}
|
||||||
setIsAlert={setIsAlert}
|
setIsAlert={setIsAlert}
|
||||||
|
extUserId={extUserId}
|
||||||
/>
|
/>
|
||||||
{/* pdf header which contain funish back button */}
|
{/* pdf header which contain funish back button */}
|
||||||
<Header
|
<Header
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage";
|
|||||||
import { useParams, useNavigate } from "react-router-dom";
|
import { useParams, useNavigate } from "react-router-dom";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import "../styles/signature.css";
|
import "../styles/signature.css";
|
||||||
import { themeColor } from "../constant/const";
|
import { isEnableSubscription, themeColor } from "../constant/const";
|
||||||
import { DndProvider } from "react-dnd";
|
import { DndProvider } from "react-dnd";
|
||||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||||
import { useDrag, useDrop } from "react-dnd";
|
import { useDrag, useDrop } from "react-dnd";
|
||||||
@@ -35,6 +35,7 @@ import AddRoleModal from "../components/pdf/AddRoleModal";
|
|||||||
import PlaceholderCopy from "../components/pdf/PlaceholderCopy";
|
import PlaceholderCopy from "../components/pdf/PlaceholderCopy";
|
||||||
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
||||||
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
||||||
|
import Parse from "parse";
|
||||||
const TemplatePlaceholder = () => {
|
const TemplatePlaceholder = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { templateId } = useParams();
|
const { templateId } = useParams();
|
||||||
@@ -52,6 +53,7 @@ const TemplatePlaceholder = () => {
|
|||||||
const [isSelectListId, setIsSelectId] = useState();
|
const [isSelectListId, setIsSelectId] = useState();
|
||||||
const [isSendAlert, setIsSendAlert] = useState(false);
|
const [isSendAlert, setIsSendAlert] = useState(false);
|
||||||
const [isCreateDocModal, setIsCreateDocModal] = useState(false);
|
const [isCreateDocModal, setIsCreateDocModal] = useState(false);
|
||||||
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState({
|
const [isLoading, setIsLoading] = useState({
|
||||||
isLoad: true,
|
isLoad: true,
|
||||||
message: "This might take some time"
|
message: "This might take some time"
|
||||||
@@ -168,7 +170,26 @@ const TemplatePlaceholder = () => {
|
|||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [divRef.current]);
|
}, [divRef.current]);
|
||||||
|
async function checkIsSubscribed(email) {
|
||||||
|
const user = await Parse.Cloud.run("getUserDetails", {
|
||||||
|
email: email
|
||||||
|
});
|
||||||
|
const freeplan = user?.get("Plan") && user?.get("Plan").plan_code;
|
||||||
|
const billingDate =
|
||||||
|
user?.get("Next_billing_date") && user?.get("Next_billing_date");
|
||||||
|
if (freeplan === "freeplan") {
|
||||||
|
return true;
|
||||||
|
} else if (billingDate) {
|
||||||
|
if (billingDate > new Date()) {
|
||||||
|
setIsSubscribe(true);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`);
|
||||||
|
}
|
||||||
|
}
|
||||||
// `fetchTemplate` function in used to get Template from server and setPlaceholder ,setSigner if present
|
// `fetchTemplate` function in used to get Template from server and setPlaceholder ,setSigner if present
|
||||||
const fetchTemplate = async () => {
|
const fetchTemplate = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -190,6 +211,9 @@ const TemplatePlaceholder = () => {
|
|||||||
: [];
|
: [];
|
||||||
|
|
||||||
if (documentData && documentData.length > 0) {
|
if (documentData && documentData.length > 0) {
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
checkIsSubscribed(documentData[0]?.ExtUserPtr?.Email);
|
||||||
|
}
|
||||||
setPdfDetails(documentData);
|
setPdfDetails(documentData);
|
||||||
setIsSigners(true);
|
setIsSigners(true);
|
||||||
if (documentData[0].Signers && documentData[0].Signers.length > 0) {
|
if (documentData[0].Signers && documentData[0].Signers.length > 0) {
|
||||||
@@ -1323,6 +1347,7 @@ const TemplatePlaceholder = () => {
|
|||||||
currWidgetsDetails={currWidgetsDetails}
|
currWidgetsDetails={currWidgetsDetails}
|
||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
handleClose={handleNameModal}
|
handleClose={handleNameModal}
|
||||||
|
isSubscribe={isSubscribe}
|
||||||
/>
|
/>
|
||||||
<DropdownWidgetOption
|
<DropdownWidgetOption
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -1333,6 +1358,7 @@ const TemplatePlaceholder = () => {
|
|||||||
currWidgetsDetails={currWidgetsDetails}
|
currWidgetsDetails={currWidgetsDetails}
|
||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
handleClose={handleNameModal}
|
handleClose={handleNameModal}
|
||||||
|
isSubscribe={isSubscribe}
|
||||||
/>
|
/>
|
||||||
<DropdownWidgetOption
|
<DropdownWidgetOption
|
||||||
type="dropdown"
|
type="dropdown"
|
||||||
@@ -1343,6 +1369,7 @@ const TemplatePlaceholder = () => {
|
|||||||
currWidgetsDetails={currWidgetsDetails}
|
currWidgetsDetails={currWidgetsDetails}
|
||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
handleClose={handleNameModal}
|
handleClose={handleNameModal}
|
||||||
|
isSubscribe={isSubscribe}
|
||||||
/>
|
/>
|
||||||
<PlaceholderCopy
|
<PlaceholderCopy
|
||||||
isPageCopy={isPageCopy}
|
isPageCopy={isPageCopy}
|
||||||
@@ -1464,6 +1491,7 @@ const TemplatePlaceholder = () => {
|
|||||||
className="autoSignScroll"
|
className="autoSignScroll"
|
||||||
>
|
>
|
||||||
<SignerListPlace
|
<SignerListPlace
|
||||||
|
isMailSend={isMailSend}
|
||||||
signerPos={signerPos}
|
signerPos={signerPos}
|
||||||
signersdata={signersdata}
|
signersdata={signersdata}
|
||||||
isSelectListId={isSelectListId}
|
isSelectListId={isSelectListId}
|
||||||
@@ -1484,7 +1512,7 @@ const TemplatePlaceholder = () => {
|
|||||||
/>
|
/>
|
||||||
<div data-tut="reactourSecond">
|
<div data-tut="reactourSecond">
|
||||||
<WidgetComponent
|
<WidgetComponent
|
||||||
pdfUrl={isMailSend}
|
isMailSend={isMailSend}
|
||||||
dragSignature={dragSignature}
|
dragSignature={dragSignature}
|
||||||
signRef={signRef}
|
signRef={signRef}
|
||||||
handleDivClick={handleDivClick}
|
handleDivClick={handleDivClick}
|
||||||
@@ -1541,6 +1569,7 @@ const TemplatePlaceholder = () => {
|
|||||||
isOpen={isNameModal}
|
isOpen={isNameModal}
|
||||||
handleClose={handleNameModal}
|
handleClose={handleNameModal}
|
||||||
handleData={handleWidgetdefaultdata}
|
handleData={handleWidgetdefaultdata}
|
||||||
|
isSubscribe={isSubscribe}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ import sanitizeFileName from "../primitives/sanitizeFileName";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||||
import Tooltip from "../primitives/Tooltip";
|
import Tooltip from "../primitives/Tooltip";
|
||||||
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
import { checkIsSubscribed } from "../constant/Utils";
|
||||||
|
import Upgrade from "../primitives/Upgrade";
|
||||||
|
|
||||||
function UserProfile() {
|
function UserProfile() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -21,15 +24,24 @@ function UserProfile() {
|
|||||||
const [isLoader, setIsLoader] = useState(false);
|
const [isLoader, setIsLoader] = useState(false);
|
||||||
const [percentage, setpercentage] = useState(0);
|
const [percentage, setpercentage] = useState(0);
|
||||||
const [isDisableDocId, setIsDisableDocId] = useState(false);
|
const [isDisableDocId, setIsDisableDocId] = useState(false);
|
||||||
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
getUserDetail();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getUserDetail = async () => {
|
||||||
const extClass = localStorage.getItem("Extand_Class");
|
const extClass = localStorage.getItem("Extand_Class");
|
||||||
const jsonSender = JSON.parse(extClass);
|
const jsonSender = JSON.parse(extClass);
|
||||||
const HeaderDocId = jsonSender[0]?.HeaderDocId;
|
const HeaderDocId = jsonSender[0]?.HeaderDocId;
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const getIsSubscribe = await checkIsSubscribed();
|
||||||
|
setIsSubscribe(getIsSubscribe);
|
||||||
|
}
|
||||||
if (HeaderDocId) {
|
if (HeaderDocId) {
|
||||||
setIsDisableDocId(HeaderDocId);
|
setIsDisableDocId(HeaderDocId);
|
||||||
}
|
}
|
||||||
}, []);
|
};
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setIsLoader(true);
|
setIsLoader(true);
|
||||||
@@ -137,7 +149,8 @@ function UserProfile() {
|
|||||||
setImage(response.url());
|
setImage(response.url());
|
||||||
localStorage.setItem("profileImg", response.url());
|
localStorage.setItem("profileImg", response.url());
|
||||||
setpercentage(0);
|
setpercentage(0);
|
||||||
SaveFileSize(size, response.url());
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
SaveFileSize(size, response.url(), tenantId);
|
||||||
return response.url();
|
return response.url();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -155,7 +168,6 @@ function UserProfile() {
|
|||||||
const handleDisableDocId = () => {
|
const handleDisableDocId = () => {
|
||||||
setIsDisableDocId((prevChecked) => !prevChecked);
|
setIsDisableDocId((prevChecked) => !prevChecked);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Title title={"Profile"} />
|
<Title title={"Profile"} />
|
||||||
@@ -262,14 +274,30 @@ function UserProfile() {
|
|||||||
</li>
|
</li>
|
||||||
<li className="border-y-[1px] border-gray-300 break-all">
|
<li className="border-y-[1px] border-gray-300 break-all">
|
||||||
<div className="flex justify-between items-center py-2">
|
<div className="flex justify-between items-center py-2">
|
||||||
<span className="font-semibold">
|
<span
|
||||||
|
className={
|
||||||
|
isSubscribe || !isEnableSubscription
|
||||||
|
? "font-semibold"
|
||||||
|
: "font-semibold text-gray-300"
|
||||||
|
}
|
||||||
|
>
|
||||||
Disable DocumentId :{" "}
|
Disable DocumentId :{" "}
|
||||||
<Tooltip url={"https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid"} />{" "}
|
<Tooltip
|
||||||
|
url={
|
||||||
|
"https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid"
|
||||||
|
}
|
||||||
|
isSubscribe={isSubscribe}
|
||||||
|
/>{" "}
|
||||||
|
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||||
</span>{" "}
|
</span>{" "}
|
||||||
<label
|
<label
|
||||||
className={`${
|
className={
|
||||||
editmode ? "cursor-pointer" : ""
|
isSubscribe || !isEnableSubscription
|
||||||
} relative inline-flex items-center mb-0`}
|
? `${
|
||||||
|
editmode ? "cursor-pointer" : ""
|
||||||
|
} relative inline-flex items-center mb-0`
|
||||||
|
: "relative inline-flex items-center mb-0 pointer-events-none opacity-50"
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
disabled={editmode ? false : true}
|
disabled={editmode ? false : true}
|
||||||
@@ -282,11 +310,13 @@ function UserProfile() {
|
|||||||
<div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-1 peer-focus:ring-black rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-black peer-checked:bg-blue-600"></div>
|
<div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-1 peer-focus:ring-black rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-black peer-checked:bg-blue-600"></div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<PremiumAlertHeader
|
{!isEnableSubscription && (
|
||||||
message={
|
<PremiumAlertHeader
|
||||||
"Disable documentId is free in beta, this feature will incur a fee later."
|
message={
|
||||||
}
|
"Disable documentId is free in beta, this feature will incur a fee later."
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div className="flex justify-center pt-2 pb-3 md:pt-3 md:pb-4">
|
<div className="flex justify-center pt-2 pb-3 md:pt-3 md:pb-4">
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import { rejectBtn, submitBtn } from "../constant/const";
|
import { isEnableSubscription, rejectBtn, submitBtn } from "../constant/const";
|
||||||
import { openInNewTab } from "../constant/Utils";
|
import { checkIsSubscribed, openInNewTab } from "../constant/Utils";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||||
import Tooltip from "../primitives/Tooltip";
|
import Tooltip from "../primitives/Tooltip";
|
||||||
|
|
||||||
function Webhook() {
|
function Webhook() {
|
||||||
|
const navigation = useNavigate();
|
||||||
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
|
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
|
||||||
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
|
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
|
||||||
const [webhook, setWebhook] = useState();
|
const [webhook, setWebhook] = useState();
|
||||||
@@ -17,6 +19,8 @@ function Webhook() {
|
|||||||
const [isGenerate, setIsGenerate] = useState(false);
|
const [isGenerate, setIsGenerate] = useState(false);
|
||||||
const [isErr, setIsErr] = useState(false);
|
const [isErr, setIsErr] = useState(false);
|
||||||
const [isModal, setIsModal] = useState(false);
|
const [isModal, setIsModal] = useState(false);
|
||||||
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchWebhook();
|
fetchWebhook();
|
||||||
@@ -25,6 +29,10 @@ function Webhook() {
|
|||||||
|
|
||||||
const fetchWebhook = async () => {
|
const fetchWebhook = async () => {
|
||||||
const email = Parse.User.current().getEmail();
|
const email = Parse.User.current().getEmail();
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const getIsSubscribe = await checkIsSubscribed();
|
||||||
|
setIsSubscribe(getIsSubscribe);
|
||||||
|
}
|
||||||
const params = { email: email };
|
const params = { email: email };
|
||||||
try {
|
try {
|
||||||
const extRes = await Parse.Cloud.run("getUserDetails", params);
|
const extRes = await Parse.Cloud.run("getUserDetails", params);
|
||||||
@@ -40,41 +48,48 @@ function Webhook() {
|
|||||||
};
|
};
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setIsLoader(true);
|
if (webhook && webhook.startsWith("https://")) {
|
||||||
setIsModal(false);
|
setIsLoader(true);
|
||||||
try {
|
setIsModal(false);
|
||||||
const params = { url: webhook };
|
try {
|
||||||
const url = parseBaseUrl + "functions/savewebhook";
|
const params = { url: webhook };
|
||||||
const headers = {
|
const url = parseBaseUrl + "functions/savewebhook";
|
||||||
"Content-Type": "application/json",
|
const headers = {
|
||||||
"X-Parse-Application-Id": parseAppId,
|
"Content-Type": "application/json",
|
||||||
sessiontoken: localStorage.getItem("accesstoken")
|
"X-Parse-Application-Id": parseAppId,
|
||||||
};
|
sessiontoken: localStorage.getItem("accesstoken")
|
||||||
await axios.post(url, params, { headers: headers }).then((res) => {
|
};
|
||||||
if (res.data && res.data.result && res.data.result.Webhook) {
|
await axios.post(url, params, { headers: headers }).then((res) => {
|
||||||
setWebhook(res.data.result.Webhook);
|
if (res.data && res.data.result && res.data.result.Webhook) {
|
||||||
setIsGenerate(true);
|
setWebhook(res.data.result.Webhook);
|
||||||
setTimeout(() => {
|
setIsGenerate(true);
|
||||||
setIsGenerate(false);
|
setTimeout(() => {
|
||||||
}, 1500);
|
setIsGenerate(false);
|
||||||
setIsLoader(false);
|
}, 1500);
|
||||||
} else {
|
setIsLoader(false);
|
||||||
console.error("Error while generating webhook");
|
} else {
|
||||||
setIsLoader(false);
|
console.error("Error while generating webhook");
|
||||||
setIsErr(true);
|
setIsLoader(false);
|
||||||
setTimeout(() => {
|
setIsErr(true);
|
||||||
setIsErr(false);
|
setTimeout(() => {
|
||||||
}, 1500);
|
setIsErr(false);
|
||||||
}
|
}, 1500);
|
||||||
});
|
}
|
||||||
} catch (error) {
|
});
|
||||||
setIsLoader(false);
|
} catch (error) {
|
||||||
setIsErr(true);
|
setIsLoader(false);
|
||||||
setTimeout(() => {
|
setIsErr(true);
|
||||||
setIsErr(false);
|
setTimeout(() => {
|
||||||
}, 1500);
|
setIsErr(false);
|
||||||
|
}, 1500);
|
||||||
|
|
||||||
console.log("err", error);
|
console.log("err", error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setError("The webhook url should always start with https://");
|
||||||
|
setTimeout(() => {
|
||||||
|
setError("");
|
||||||
|
}, 1500);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -84,6 +99,7 @@ function Webhook() {
|
|||||||
<Title title={"Webhook"} />
|
<Title title={"Webhook"} />
|
||||||
{isGenerate && <Alert type="success">Webhook added successfully!</Alert>}
|
{isGenerate && <Alert type="success">Webhook added successfully!</Alert>}
|
||||||
{isErr && <Alert type="danger">Something went wrong!</Alert>}
|
{isErr && <Alert type="danger">Something went wrong!</Alert>}
|
||||||
|
|
||||||
{isLoader ? (
|
{isLoader ? (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -103,31 +119,41 @@ function Webhook() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="bg-white flex flex-col justify-center shadow rounded">
|
<div className="bg-white flex flex-col justify-center shadow rounded">
|
||||||
<PremiumAlertHeader />
|
{!isEnableSubscription && <PremiumAlertHeader />}
|
||||||
<h1 className="ml-4 mt-3 mb-2 font-semibold">
|
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||||
Webhook{" "}
|
OpenSign™ Webhook{" "}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
url={"https://docs.opensignlabs.com/docs/API-docs/get-webhook"}
|
url={"https://docs.opensignlabs.com/docs/API-docs/get-webhook"}
|
||||||
|
isSubscribe={true}
|
||||||
/>
|
/>
|
||||||
</h1>
|
</h1>
|
||||||
<ul className="w-full flex flex-col p-2 text-sm">
|
<ul
|
||||||
|
className={
|
||||||
|
isSubscribe || !isEnableSubscription
|
||||||
|
? "w-full flex flex-col p-2 text-sm "
|
||||||
|
: "w-full flex flex-col p-2 text-sm opacity-20 pointer-events-none select-none"
|
||||||
|
}
|
||||||
|
>
|
||||||
<li
|
<li
|
||||||
className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
|
className={`flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
|
||||||
>
|
>
|
||||||
<span className="w-[40%]">Webhook:</span>{" "}
|
<div className="w-[70%] flex-col md:flex-row flex items-center gap-5 ">
|
||||||
<span id="token" className="w-[60%] md:text-end cursor-pointer">
|
<span className="">Webhook:</span>{" "}
|
||||||
{webhook && webhook}
|
<span id="token" className=" md:text-end cursor-pointer">
|
||||||
</span>
|
{webhook ? webhook : "_____"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleModal}
|
||||||
|
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base focus:outline-none"
|
||||||
|
>
|
||||||
|
{webhook ? "Update Webhook" : "Add Webhook"}
|
||||||
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div className="flex flex-col md:flex-row items-center justify-center gap-2 pb-4">
|
|
||||||
<button
|
<div className="flex items-center justify-center ">
|
||||||
type="button"
|
|
||||||
onClick={handleModal}
|
|
||||||
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base focus:outline-none"
|
|
||||||
>
|
|
||||||
{webhook ? "Update Webhook" : "Add Webhook"}
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -135,17 +161,47 @@ function Webhook() {
|
|||||||
"https://docs.opensignlabs.com/docs/API-docs/save-update-webhook"
|
"https://docs.opensignlabs.com/docs/API-docs/save-update-webhook"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
|
className="rounded hover:bg-[#15b4e9] border-[1px] my-2 border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
|
||||||
>
|
>
|
||||||
View Docs
|
View Docs
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{!isSubscribe && isEnableSubscription && (
|
||||||
|
<>
|
||||||
|
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||||
|
Upgrade to PRO Plan
|
||||||
|
</h1>
|
||||||
|
<ul className={"w-full flex flex-col p-2 text-sm "}>
|
||||||
|
<li
|
||||||
|
className={`flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
|
||||||
|
>
|
||||||
|
<div className="w-[70%] flex-col md:flex-row flex items-center gap-3 ">
|
||||||
|
<span className="">$29.99/month:</span>{" "}
|
||||||
|
<span id="token" className=" md:text-end cursor-pointer">
|
||||||
|
First 100 documents included, then just $0.15 per
|
||||||
|
document.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{!isSubscribe && isEnableSubscription && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => navigation("/subscription")}
|
||||||
|
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
|
||||||
|
>
|
||||||
|
Upgrade Now
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen={isModal}
|
isOpen={isModal}
|
||||||
title={"Regenerate Token"}
|
title={"Regenerate Token"}
|
||||||
handleClose={handleModal}
|
handleClose={handleModal}
|
||||||
>
|
>
|
||||||
|
{error && <Alert type="danger">{error}</Alert>}
|
||||||
<div className="m-[20px]">
|
<div className="m-[20px]">
|
||||||
<div className="text-lg font-normal text-black">
|
<div className="text-lg font-normal text-black">
|
||||||
<label className="text-sm ml-2">Webhook</label>
|
<label className="text-sm ml-2">Webhook</label>
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ const AddUser = (props) => {
|
|||||||
contactQuery.set("Email", email);
|
contactQuery.set("Email", email);
|
||||||
contactQuery.set("UserRole", "contracts_Guest");
|
contactQuery.set("UserRole", "contracts_Guest");
|
||||||
|
|
||||||
if (localStorage.getItem("TenetId")) {
|
if (localStorage.getItem("TenantId")) {
|
||||||
contactQuery.set("TenantId", {
|
contactQuery.set("TenantId", {
|
||||||
__type: "Pointer",
|
__type: "Pointer",
|
||||||
className: "partners_Tenant",
|
className: "partners_Tenant",
|
||||||
objectId: localStorage.getItem("TenetId")
|
objectId: localStorage.getItem("TenantId")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,29 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Tooltip as ReactTooltip } from "react-tooltip";
|
import { Tooltip as ReactTooltip } from "react-tooltip";
|
||||||
import { openInNewTab } from "../constant/Utils";
|
import { openInNewTab } from "../constant/Utils";
|
||||||
const Tooltip = ({ children, id, message, url, iconColor }) =>
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
const Tooltip = ({ id, message, url, iconColor, isSubscribe }) =>
|
||||||
url ? (
|
url ? (
|
||||||
<button onClick={() => openInNewTab(url)} className="text-center">
|
<button
|
||||||
{children ? (
|
onClick={() => openInNewTab(url)}
|
||||||
children
|
className={
|
||||||
) : (
|
isSubscribe || !isEnableSubscription
|
||||||
<i className="fa-solid fa-question text-xs border-[1.5px] px-1 rounded-full border-[#33bbff] text-[#33bbff]"></i>
|
? "text-center"
|
||||||
)}
|
: "text-center opacity-20 pointer-events-none"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<sup>
|
||||||
|
<i
|
||||||
|
className="fa-solid fa-question rounded-full"
|
||||||
|
style={{
|
||||||
|
borderColor: iconColor ? iconColor : "#33bbff",
|
||||||
|
color: iconColor ? iconColor : "#33bbff",
|
||||||
|
fontSize: 13,
|
||||||
|
borderWidth: 1.5,
|
||||||
|
padding: "1.5px 4px"
|
||||||
|
}}
|
||||||
|
></i>
|
||||||
|
</sup>
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
@@ -17,17 +32,18 @@ const Tooltip = ({ children, id, message, url, iconColor }) =>
|
|||||||
data-tooltip-content={message}
|
data-tooltip-content={message}
|
||||||
className="z-50"
|
className="z-50"
|
||||||
>
|
>
|
||||||
{children ? (
|
<sup>
|
||||||
children
|
|
||||||
) : (
|
|
||||||
<i
|
<i
|
||||||
className="fa-solid fa-question text-xs border-[1.5px] px-1 rounded-full border-[#33bbff] text-[#33bbff]"
|
className="fa-solid fa-question rounded-full"
|
||||||
style={{
|
style={{
|
||||||
borderColor: iconColor ? iconColor : "#33bbff",
|
borderColor: iconColor ? iconColor : "#33bbff",
|
||||||
color: iconColor ? iconColor : "#33bbff"
|
color: iconColor ? iconColor : "#33bbff",
|
||||||
|
fontSize: 13,
|
||||||
|
borderWidth: 1.5,
|
||||||
|
padding: "1.5px 4px"
|
||||||
}}
|
}}
|
||||||
></i>
|
></i>
|
||||||
)}
|
</sup>
|
||||||
</a>
|
</a>
|
||||||
<ReactTooltip id={id ? id : "my-tooltip"} className="max-w-[200px]" />
|
<ReactTooltip id={id ? id : "my-tooltip"} className="max-w-[200px]" />
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
function Upgrade() {
|
||||||
|
const navigation = useNavigate();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<sup>
|
||||||
|
<span
|
||||||
|
onClick={() => navigation("/subscription")}
|
||||||
|
className="text-blue-800 text-sm cursor-pointer hover:underline"
|
||||||
|
>
|
||||||
|
Upgrade now
|
||||||
|
</span>
|
||||||
|
</sup>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Upgrade;
|
||||||
@@ -24,7 +24,9 @@ const Validate = () => {
|
|||||||
setIsUserValid(false);
|
setIsUserValid(false);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleLoginBtn = () => {
|
const handleLoginBtn = () => {
|
||||||
try {
|
try {
|
||||||
Parse.User.logOut();
|
Parse.User.logOut();
|
||||||
|
|||||||
@@ -496,7 +496,11 @@
|
|||||||
overflow: hidden !important;
|
overflow: hidden !important;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
.disabled {
|
||||||
|
opacity: 0.5; /* Example: reduce opacity to visually indicate disabled state */
|
||||||
|
pointer-events: none; /* Prevents mouse clicks and other events */
|
||||||
|
/* background-color: #888; */
|
||||||
|
}
|
||||||
.useEmail {
|
.useEmail {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
color: #424242;
|
color: #424242;
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const appId = process.env.APP_ID;
|
||||||
|
const serverUrl = process.env.SERVER_URL;
|
||||||
export function customAPIurl() {
|
export function customAPIurl() {
|
||||||
const url = new URL(process.env.SERVER_URL);
|
const url = new URL(process.env.SERVER_URL);
|
||||||
return url.pathname === '/api/app' ? url.origin + '/api' : url.origin;
|
return url.pathname === '/api/app' ? url.origin + '/api' : url.origin;
|
||||||
@@ -38,3 +42,111 @@ export function replaceMailVaribles(subject, body, variables) {
|
|||||||
};
|
};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const saveFileUsage = async (size, imageUrl, userId) => {
|
||||||
|
//checking server url and save file's size
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tenantQuery = new Parse.Query('partners_Tenant');
|
||||||
|
tenantQuery.equalTo('UserId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: '_User',
|
||||||
|
objectId: userId,
|
||||||
|
});
|
||||||
|
const tenant = await tenantQuery.first();
|
||||||
|
if (tenant) {
|
||||||
|
const tenantPtr = {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: tenant.id,
|
||||||
|
};
|
||||||
|
const _tenantPtr = JSON.stringify(tenantPtr);
|
||||||
|
try {
|
||||||
|
const res = await axios.get(
|
||||||
|
`${serverUrl}/classes/partners_TenantCredits?where={"PartnersTenant":${_tenantPtr}}`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Parse-Application-Id': appId,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const response = res.data.results;
|
||||||
|
|
||||||
|
let data;
|
||||||
|
// console.log("response", response);
|
||||||
|
if (response && response.length > 0) {
|
||||||
|
data = {
|
||||||
|
usedStorage: response[0].usedStorage ? response[0].usedStorage + size : size,
|
||||||
|
};
|
||||||
|
await axios.put(
|
||||||
|
`${serverUrl}/classes/partners_TenantCredits/${response[0].objectId}`,
|
||||||
|
data,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Parse-Application-Id': appId,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
data = { usedStorage: size, PartnersTenant: tenantPtr };
|
||||||
|
await axios.post(`${serverUrl}/classes/partners_TenantCredits`, data, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Parse-Application-Id': appId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err in save usage', err);
|
||||||
|
}
|
||||||
|
saveDataFile(size, imageUrl, tenantPtr);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err in fetch tenant Id', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//function for save fileUrl and file size in particular client db class partners_DataFiles
|
||||||
|
const saveDataFile = async (size, imageUrl, tenantPtr) => {
|
||||||
|
const data = {
|
||||||
|
FileUrl: imageUrl,
|
||||||
|
FileSize: size,
|
||||||
|
TenantPtr: tenantPtr,
|
||||||
|
};
|
||||||
|
|
||||||
|
// console.log("data save",file, data)
|
||||||
|
try {
|
||||||
|
await axios.post(`${serverUrl}/classes/partners_DataFiles`, data, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Parse-Application-Id': appId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log('error in save usage ', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateMailCount = async extUserId => {
|
||||||
|
// Update count in contracts_Users class
|
||||||
|
const query = new Parse.Query('contracts_Users');
|
||||||
|
query.equalTo('objectId', extUserId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const contractUser = await query.first({ useMasterKey: true });
|
||||||
|
if (contractUser) {
|
||||||
|
contractUser.increment('EmailCount', 1);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -284,6 +284,7 @@ export default async function createDocumentWithTemplate(request, response) {
|
|||||||
subject: subject,
|
subject: subject,
|
||||||
from: sender,
|
from: sender,
|
||||||
html: html,
|
html: html,
|
||||||
|
extUserId: template.ExtUserPtr.objectId,
|
||||||
};
|
};
|
||||||
sendMail = await axios.post(url, params, { headers: headers });
|
sendMail = await axios.post(url, params, { headers: headers });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { color, customAPIurl, replaceMailVaribles } from '../../../../Utils.js';
|
import { color, customAPIurl, replaceMailVaribles, saveFileUsage } from '../../../../Utils.js';
|
||||||
|
|
||||||
// `sendDoctoWebhook` is used to send res data of document on webhook
|
// `sendDoctoWebhook` is used to send res data of document on webhook
|
||||||
async function sendDoctoWebhook(doc, WebhookUrl, userId) {
|
async function sendDoctoWebhook(doc, WebhookUrl, userId) {
|
||||||
@@ -8,6 +8,7 @@ async function sendDoctoWebhook(doc, WebhookUrl, userId) {
|
|||||||
event: 'created',
|
event: 'created',
|
||||||
...doc,
|
...doc,
|
||||||
};
|
};
|
||||||
|
|
||||||
await axios
|
await axios
|
||||||
.post(WebhookUrl, params, {
|
.post(WebhookUrl, params, {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
@@ -65,6 +66,7 @@ export default async function createDocumentwithCoordinate(request, response) {
|
|||||||
if (!reqToken) {
|
if (!reqToken) {
|
||||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const tokenQuery = new Parse.Query('appToken');
|
const tokenQuery = new Parse.Query('appToken');
|
||||||
tokenQuery.equalTo('token', reqToken);
|
tokenQuery.equalTo('token', reqToken);
|
||||||
@@ -81,17 +83,22 @@ export default async function createDocumentwithCoordinate(request, response) {
|
|||||||
if (signers && signers.length > 0) {
|
if (signers && signers.length > 0) {
|
||||||
let fileUrl;
|
let fileUrl;
|
||||||
if (request.files?.[0]) {
|
if (request.files?.[0]) {
|
||||||
|
const base64 = fileData?.toString('base64');
|
||||||
const file = new Parse.File(request.files?.[0]?.originalname, {
|
const file = new Parse.File(request.files?.[0]?.originalname, {
|
||||||
base64: fileData?.toString('base64'),
|
base64: base64,
|
||||||
});
|
});
|
||||||
await file.save({ useMasterKey: true });
|
await file.save({ useMasterKey: true });
|
||||||
fileUrl = file.url();
|
fileUrl = file.url();
|
||||||
|
const buffer = Buffer.from(base64, 'base64');
|
||||||
|
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||||
} else {
|
} else {
|
||||||
const file = new Parse.File(`${name}.pdf`, {
|
const file = new Parse.File(`${name}.pdf`, {
|
||||||
base64: base64File,
|
base64: base64File,
|
||||||
});
|
});
|
||||||
await file.save({ useMasterKey: true });
|
await file.save({ useMasterKey: true });
|
||||||
fileUrl = file.url();
|
fileUrl = file.url();
|
||||||
|
const buffer = Buffer.from(base64File, 'base64');
|
||||||
|
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||||
}
|
}
|
||||||
const contractsUser = new Parse.Query('contracts_Users');
|
const contractsUser = new Parse.Query('contracts_Users');
|
||||||
contractsUser.equalTo('UserId', userPtr);
|
contractsUser.equalTo('UserId', userPtr);
|
||||||
@@ -242,7 +249,6 @@ export default async function createDocumentwithCoordinate(request, response) {
|
|||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
});
|
});
|
||||||
let sender = parseExtUser.Email;
|
let sender = parseExtUser.Email;
|
||||||
let sendMail;
|
|
||||||
const serverUrl = process.env.SERVER_URL;
|
const serverUrl = process.env.SERVER_URL;
|
||||||
const newServer = serverUrl.replaceAll('/', '%2F');
|
const newServer = serverUrl.replaceAll('/', '%2F');
|
||||||
const serverParams = `${newServer}%2F&${process.env.APP_ID}&contracts`;
|
const serverParams = `${newServer}%2F&${process.env.APP_ID}&contracts`;
|
||||||
@@ -330,9 +336,10 @@ export default async function createDocumentwithCoordinate(request, response) {
|
|||||||
subject: subject,
|
subject: subject,
|
||||||
from: sender,
|
from: sender,
|
||||||
html: html,
|
html: html,
|
||||||
|
extUserId: extUser.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
sendMail = await axios.post(url, params, { headers: headers });
|
await axios.post(url, params, { headers: headers });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('error', error);
|
console.log('error', error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { customAPIurl } from '../../../../Utils.js';
|
import { saveFileUsage } from '../../../../Utils.js';
|
||||||
|
|
||||||
const randomId = () => Math.floor(1000 + Math.random() * 9000);
|
|
||||||
export default async function createTemplate(request, response) {
|
export default async function createTemplate(request, response) {
|
||||||
const name = request.body?.title;
|
const name = request.body?.title;
|
||||||
const note = request.body?.note;
|
const note = request.body?.note;
|
||||||
@@ -36,12 +34,17 @@ export default async function createTemplate(request, response) {
|
|||||||
});
|
});
|
||||||
await file.save({ useMasterKey: true });
|
await file.save({ useMasterKey: true });
|
||||||
fileUrl = file.url();
|
fileUrl = file.url();
|
||||||
|
const buffer = Buffer.from(base64File, 'base64');
|
||||||
|
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||||
} else {
|
} else {
|
||||||
|
const base64 = fileData?.toString('base64');
|
||||||
const file = new Parse.File(request.files?.[0]?.originalname, {
|
const file = new Parse.File(request.files?.[0]?.originalname, {
|
||||||
base64: fileData?.toString('base64'),
|
base64: base64,
|
||||||
});
|
});
|
||||||
await file.save({ useMasterKey: true });
|
await file.save({ useMasterKey: true });
|
||||||
fileUrl = file.url();
|
fileUrl = file.url();
|
||||||
|
const buffer = Buffer.from(base64, 'base64');
|
||||||
|
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const contractsUser = new Parse.Query('contracts_Users');
|
const contractsUser = new Parse.Query('contracts_Users');
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { color, customAPIurl } from '../../../../Utils.js';
|
import { color, customAPIurl, saveFileUsage } from '../../../../Utils.js';
|
||||||
|
|
||||||
const randomId = () => Math.floor(1000 + Math.random() * 9000);
|
const randomId = () => Math.floor(1000 + Math.random() * 9000);
|
||||||
export default async function createTemplatewithCoordinate(request, response) {
|
export default async function createTemplatewithCoordinate(request, response) {
|
||||||
@@ -34,17 +34,22 @@ export default async function createTemplatewithCoordinate(request, response) {
|
|||||||
if (signers && signers.length > 0) {
|
if (signers && signers.length > 0) {
|
||||||
let fileUrl;
|
let fileUrl;
|
||||||
if (request.files?.[0]) {
|
if (request.files?.[0]) {
|
||||||
|
const base64 = fileData?.toString('base64');
|
||||||
const file = new Parse.File(request.files?.[0]?.originalname, {
|
const file = new Parse.File(request.files?.[0]?.originalname, {
|
||||||
base64: fileData?.toString('base64'),
|
base64: base64,
|
||||||
});
|
});
|
||||||
await file.save({ useMasterKey: true });
|
await file.save({ useMasterKey: true });
|
||||||
fileUrl = file.url();
|
fileUrl = file.url();
|
||||||
|
const buffer = Buffer.from(base64, 'base64');
|
||||||
|
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||||
} else {
|
} else {
|
||||||
const file = new Parse.File(`${name}.pdf`, {
|
const file = new Parse.File(`${name}.pdf`, {
|
||||||
base64: base64File,
|
base64: base64File,
|
||||||
});
|
});
|
||||||
await file.save({ useMasterKey: true });
|
await file.save({ useMasterKey: true });
|
||||||
fileUrl = file.url();
|
fileUrl = file.url();
|
||||||
|
const buffer = Buffer.from(base64File, 'base64');
|
||||||
|
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||||
}
|
}
|
||||||
const contractsUser = new Parse.Query('contracts_Users');
|
const contractsUser = new Parse.Query('contracts_Users');
|
||||||
contractsUser.equalTo('UserId', userPtr);
|
contractsUser.equalTo('UserId', userPtr);
|
||||||
|
|||||||
@@ -36,17 +36,22 @@ export default async function draftDocument(request, response) {
|
|||||||
if (signers && signers.length > 0) {
|
if (signers && signers.length > 0) {
|
||||||
let fileUrl;
|
let fileUrl;
|
||||||
if (request.files?.[0]) {
|
if (request.files?.[0]) {
|
||||||
|
const base64 = fileData?.toString('base64');
|
||||||
const file = new Parse.File(request.files?.[0]?.originalname, {
|
const file = new Parse.File(request.files?.[0]?.originalname, {
|
||||||
base64: fileData?.toString('base64'),
|
base64: base64,
|
||||||
});
|
});
|
||||||
await file.save({ useMasterKey: true });
|
await file.save({ useMasterKey: true });
|
||||||
fileUrl = file.url();
|
fileUrl = file.url();
|
||||||
|
const buffer = Buffer.from(base64, 'base64');
|
||||||
|
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||||
} else {
|
} else {
|
||||||
const file = new Parse.File(`${name}.pdf`, {
|
const file = new Parse.File(`${name}.pdf`, {
|
||||||
base64: base64File,
|
base64: base64File,
|
||||||
});
|
});
|
||||||
await file.save({ useMasterKey: true });
|
await file.save({ useMasterKey: true });
|
||||||
fileUrl = file.url();
|
fileUrl = file.url();
|
||||||
|
const buffer = Buffer.from(base64File, 'base64');
|
||||||
|
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||||
}
|
}
|
||||||
const contractsUser = new Parse.Query('contracts_Users');
|
const contractsUser = new Parse.Query('contracts_Users');
|
||||||
contractsUser.equalTo('UserId', userPtr);
|
contractsUser.equalTo('UserId', userPtr);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import PDF from './parsefunction/pdf/PDF.min.js';
|
import PDF from './parsefunction/pdf/PDF.min.js';
|
||||||
import sendmail from './parsefunction/sendMail.js';
|
import sendmailv3 from './parsefunction/sendMailv3.js';
|
||||||
import GoogleSign from './parsefunction/GoogleSign.js';
|
import GoogleSign from './parsefunction/GoogleSign.js';
|
||||||
import ZohoDetails from './parsefunction/ZohoDetails.js';
|
import ZohoDetails from './parsefunction/ZohoDetails.js';
|
||||||
import usersignup from './parsefunction/usersignup.js';
|
import usersignup from './parsefunction/usersignup.js';
|
||||||
@@ -10,7 +10,6 @@ import DocumentAftersave from './parsefunction/DocumentAftersave.js';
|
|||||||
import ContactbookAftersave from './parsefunction/ContactBookAftersave.js';
|
import ContactbookAftersave from './parsefunction/ContactBookAftersave.js';
|
||||||
import ContractUsersAftersave from './parsefunction/ContractUsersAftersave.js';
|
import ContractUsersAftersave from './parsefunction/ContractUsersAftersave.js';
|
||||||
import sendMailOTPv1 from './parsefunction/SendMailOTPv1.js';
|
import sendMailOTPv1 from './parsefunction/SendMailOTPv1.js';
|
||||||
import SendMailv1 from './parsefunction/SendMailv1.js';
|
|
||||||
import AuthLoginAsMail from './parsefunction/AuthLoginAsMail.js';
|
import AuthLoginAsMail from './parsefunction/AuthLoginAsMail.js';
|
||||||
import getUserId from './parsefunction/getUserId.js';
|
import getUserId from './parsefunction/getUserId.js';
|
||||||
import getUserDetails from './parsefunction/getUserDetails.js';
|
import getUserDetails from './parsefunction/getUserDetails.js';
|
||||||
@@ -23,17 +22,19 @@ import TemplateAfterSave from './parsefunction/TemplateAfterSave.js';
|
|||||||
import GetTemplate from './parsefunction/GetTemplate.js';
|
import GetTemplate from './parsefunction/GetTemplate.js';
|
||||||
import savewebhook from './parsefunction/saveWebhook.js';
|
import savewebhook from './parsefunction/saveWebhook.js';
|
||||||
import callWebhook from './parsefunction/callWebhook.js';
|
import callWebhook from './parsefunction/callWebhook.js';
|
||||||
|
import SubscribeFree from './parsefunction/SubscribeFree.js';
|
||||||
|
import DocumentBeforesave from './parsefunction/DocumentBeforesave.js';
|
||||||
|
import TemplateBeforeSave from './parsefunction/TemplateBeforesave.js';
|
||||||
|
|
||||||
Parse.Cloud.define('AddUserToRole', addUserToGroups);
|
Parse.Cloud.define('AddUserToRole', addUserToGroups);
|
||||||
Parse.Cloud.define('UserGroups', getUserGroups);
|
Parse.Cloud.define('UserGroups', getUserGroups);
|
||||||
Parse.Cloud.define('signPdf', PDF);
|
Parse.Cloud.define('signPdf', PDF);
|
||||||
Parse.Cloud.define('sendmailv3', sendmail);
|
Parse.Cloud.define('sendmailv3', sendmailv3);
|
||||||
Parse.Cloud.define('googlesign', GoogleSign);
|
Parse.Cloud.define('googlesign', GoogleSign);
|
||||||
Parse.Cloud.define('zohodetails', ZohoDetails);
|
Parse.Cloud.define('zohodetails', ZohoDetails);
|
||||||
Parse.Cloud.define('usersignup', usersignup);
|
Parse.Cloud.define('usersignup', usersignup);
|
||||||
Parse.Cloud.define('facebooksign', FacebookSign);
|
Parse.Cloud.define('facebooksign', FacebookSign);
|
||||||
Parse.Cloud.define('SendOTPMailV1', sendMailOTPv1);
|
Parse.Cloud.define('SendOTPMailV1', sendMailOTPv1);
|
||||||
Parse.Cloud.define('sendmail', SendMailv1);
|
|
||||||
Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail);
|
Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail);
|
||||||
Parse.Cloud.define('getUserId', getUserId);
|
Parse.Cloud.define('getUserId', getUserId);
|
||||||
Parse.Cloud.define('getUserDetails', getUserDetails);
|
Parse.Cloud.define('getUserDetails', getUserDetails);
|
||||||
@@ -45,7 +46,10 @@ Parse.Cloud.define('getapitoken', getapitoken);
|
|||||||
Parse.Cloud.define('getTemplate', GetTemplate);
|
Parse.Cloud.define('getTemplate', GetTemplate);
|
||||||
Parse.Cloud.define('savewebhook', savewebhook);
|
Parse.Cloud.define('savewebhook', savewebhook);
|
||||||
Parse.Cloud.define('callwebhook', callWebhook);
|
Parse.Cloud.define('callwebhook', callWebhook);
|
||||||
|
Parse.Cloud.define('freesubscription', SubscribeFree);
|
||||||
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
|
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
|
||||||
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
|
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
|
||||||
Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
|
Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
|
||||||
Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave);
|
Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave);
|
||||||
|
Parse.Cloud.beforeSave('contracts_Document', DocumentBeforesave);
|
||||||
|
Parse.Cloud.beforeSave('contracts_Template', TemplateBeforeSave);
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
async function DocumentBeforesave(request) {
|
||||||
|
try {
|
||||||
|
// below code is used to update document when user sent document or self signed
|
||||||
|
const document = request.object;
|
||||||
|
const oldDocument = request.original;
|
||||||
|
|
||||||
|
// Check if SignedUrl field has been added (transition from undefined to defined)
|
||||||
|
if (!oldDocument.get('SignedUrl') && document.get('SignedUrl')) {
|
||||||
|
const SignedUrl = document.get('SignedUrl');
|
||||||
|
|
||||||
|
// Update count in contracts_Users class
|
||||||
|
const query = new Parse.Query('contracts_Users');
|
||||||
|
query.equalTo('objectId', oldDocument.get('ExtUserPtr').id);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const contractUser = await query.first({ useMasterKey: true });
|
||||||
|
if (contractUser) {
|
||||||
|
contractUser.increment('DocumentCount', 1);
|
||||||
|
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('DocumentCount', 1);
|
||||||
|
await newContractUser.save(null, { useMasterKey: true });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Error updating document count in contracts_users: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err in document beforesave', err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default DocumentBeforesave;
|
||||||
@@ -1,47 +1,65 @@
|
|||||||
import axios from 'axios'
|
import { updateMailCount } from '../../Utils.js';
|
||||||
|
async function getDocument(docId) {
|
||||||
|
try {
|
||||||
|
const query = new Parse.Query('contracts_Document');
|
||||||
|
query.equalTo('objectId', docId);
|
||||||
|
query.include('ExtUserPtr');
|
||||||
|
query.include('CreatedBy');
|
||||||
|
query.include('Signers');
|
||||||
|
query.include('AuditTrail.UserPtr');
|
||||||
|
query.include('Placeholders');
|
||||||
|
query.notEqualTo('IsArchive', true);
|
||||||
|
const res = await query.first({ useMasterKey: true });
|
||||||
|
const _res = res.toJSON();
|
||||||
|
return _res?.ExtUserPtr?.objectId;
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err ', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
async function sendMailOTPv1(request) {
|
async function sendMailOTPv1(request) {
|
||||||
try {
|
try {
|
||||||
//--for elearning app side
|
//--for elearning app side
|
||||||
let code = Math.floor(1000 + Math.random() * 9000);
|
let code = Math.floor(1000 + Math.random() * 9000);
|
||||||
let email = request.params.email;
|
let email = request.params.email;
|
||||||
var TenantId = request.params.TenantId ? request.params.TenantId : undefined;
|
var TenantId = request.params.TenantId ? request.params.TenantId : undefined;
|
||||||
// console.log("In tempSendOTPv2");
|
|
||||||
|
|
||||||
// console.log(JSON.stringify(request));
|
|
||||||
|
|
||||||
if (email) {
|
if (email) {
|
||||||
axios({
|
const recipient = request.params.email;
|
||||||
method: 'POST',
|
const mailsender = process.env.SMTP_ENABLE
|
||||||
url: process.env.SERVER_URL + '/functions/sendmail',
|
? process.env.SMTP_USER_EMAIL
|
||||||
headers: {
|
: process.env.MAILGUN_SENDER;
|
||||||
'Content-Type': 'application/json',
|
try {
|
||||||
'X-Parse-Application-Id': process.env.APP_ID,
|
await Parse.Cloud.sendEmail({
|
||||||
},
|
from: 'Opensign™' + ' <' + mailsender + '>',
|
||||||
params: {
|
recipient: recipient,
|
||||||
otp: code,
|
subject: 'Your OpenSign™ OTP',
|
||||||
email: email,
|
text: 'This email is a test.',
|
||||||
TenantId: TenantId,
|
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 style='background-color:red;padding:2px;font-family:system-ui; background-color:#47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',>OTP Verification</p></div><div style='padding:20px'><p style='font-family:system-ui;font-size:14px'>Your OTP for OpenSign™ verification is:</p><p style=' text-decoration: none; font-weight: bolder; color:blue;font-size:45px;margin:20px'>" +
|
||||||
}).then(
|
code +
|
||||||
function (httpResponse) {},
|
'</p></div> </div> </div></body></html>',
|
||||||
function (httpResponse) {
|
});
|
||||||
console.error('sms Request failed with response code ' + httpResponse.status);
|
console.log('OTP sent');
|
||||||
return Promise.reject('sms Request failed with response code ' + httpResponse.status);
|
if (request.params?.docId) {
|
||||||
|
const extUserId = await getDocument(request.params?.docId);
|
||||||
|
if (extUserId) {
|
||||||
|
updateMailCount(extUserId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
} catch (err) {
|
||||||
|
console.log('error in send OTP mail', err);
|
||||||
|
}
|
||||||
const tempOtp = new Parse.Query('defaultdata_Otp');
|
const tempOtp = new Parse.Query('defaultdata_Otp');
|
||||||
tempOtp.equalTo('Email', email);
|
tempOtp.equalTo('Email', email);
|
||||||
const resultOTP = await tempOtp.first({ useMasterKey: true });
|
const resultOTP = await tempOtp.first({ useMasterKey: true });
|
||||||
console.log('resultOTP', resultOTP);
|
// console.log('resultOTP', resultOTP);
|
||||||
if (resultOTP !== undefined) {
|
if (resultOTP !== undefined) {
|
||||||
const updateOtpQuery = new Parse.Query('defaultdata_Otp');
|
const updateOtpQuery = new Parse.Query('defaultdata_Otp');
|
||||||
const updateOtp = await updateOtpQuery.get(resultOTP.id, {
|
const updateOtp = await updateOtpQuery.get(resultOTP.id, {
|
||||||
useMasterKey: true,
|
useMasterKey: true,
|
||||||
});
|
});
|
||||||
updateOtp.set('OTP', code);
|
updateOtp.set('OTP', code);
|
||||||
const updateRes = updateOtp.save(null, { useMasterKey: true });
|
updateOtp.save(null, { useMasterKey: true });
|
||||||
// console.log("update otp Res in tempSendOtp ", updateRes);
|
// console.log("update otp Res in tempSendOtp ", updateRes);
|
||||||
} else {
|
} else {
|
||||||
const otpClass = Parse.Object.extend('defaultdata_Otp');
|
const otpClass = Parse.Object.extend('defaultdata_Otp');
|
||||||
@@ -49,17 +67,17 @@ async function sendMailOTPv1(request) {
|
|||||||
newOtpQuery.set('OTP', code);
|
newOtpQuery.set('OTP', code);
|
||||||
newOtpQuery.set('Email', email);
|
newOtpQuery.set('Email', email);
|
||||||
newOtpQuery.set('TenantId', TenantId);
|
newOtpQuery.set('TenantId', TenantId);
|
||||||
const newRes = await newOtpQuery.save(null, { useMasterKey: true });
|
await newOtpQuery.save(null, { useMasterKey: true });
|
||||||
// console.log("new otp Res in tempSendOtp ", newRes);
|
// console.log("new otp Res in tempSendOtp ", newRes);
|
||||||
}
|
}
|
||||||
return 'Otp send';
|
return 'Otp send';
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject('Please Enter valid email');
|
return 'Please Enter valid email';
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err in sendMailOTPv1');
|
console.log('err in sendMailOTPv1');
|
||||||
console.log(err);
|
console.log(err);
|
||||||
return Promise.reject(err);
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default sendMailOTPv1;
|
export default sendMailOTPv1;
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
async function SendMailv1(request) {
|
|
||||||
console.log('in SendMailv1');
|
|
||||||
|
|
||||||
try {
|
|
||||||
const recipient = request.params.email;
|
|
||||||
const otp = request.params.otp;
|
|
||||||
const res = await Parse.Cloud.sendEmail({
|
|
||||||
from: 'Test user' + ' <' + process.env.SMTP_ENABLE ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER + '>',
|
|
||||||
recipient: recipient,
|
|
||||||
subject: 'Your OpenSign™ OTP',
|
|
||||||
text: 'This email is a test.',
|
|
||||||
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 style='background-color:red;padding:2px;font-family:system-ui; background-color:#47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',>OTP Verification</p></div><div style='padding:20px'><p style='font-family:system-ui;font-size:14px'>Your OTP for OpenSign™ verification is:</p><p style=' text-decoration: none; font-weight: bolder; color:blue;font-size:45px;margin:20px'>" +
|
|
||||||
otp +
|
|
||||||
'</p></div> </div> </div></body></html>',
|
|
||||||
// "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body style='text-align: center;'><div style='display:flex;flex-direction:column;justify-content:center;align-item:center;margin:40px'> <p style='font-weight: bolder; font-size: large;'>Hello,</p> <span>Your OTP for LegaDaft verification . </span> <p style=' text-decoration: none; font-weight: bolder; color:blue;font-size:45px'>76984</p><span>Thank You!</span> </div> </body></html>"
|
|
||||||
});
|
|
||||||
console.log('Res');
|
|
||||||
console.log(res);
|
|
||||||
return otp;
|
|
||||||
} catch (err) {
|
|
||||||
console.log('err in SendMailv1');
|
|
||||||
console.log(err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default SendMailv1;
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
export default async function SubscribeFree(request) {
|
||||||
|
const userId = request.params.userId;
|
||||||
|
const userPtr = { __type: 'Pointer', className: '_User', objectId: userId };
|
||||||
|
try {
|
||||||
|
const extQuery = new Parse.Query('contracts_Users');
|
||||||
|
extQuery.equalTo('UserId', userPtr);
|
||||||
|
const extUser = await extQuery.first({ useMasterKey: true });
|
||||||
|
if (extUser) {
|
||||||
|
if (extUser?.get('Plan')?.plan_code === 'freeplan') {
|
||||||
|
return { status: 'success', result: 'already subscribed!' };
|
||||||
|
} else if (extUser?.get('Next_billing_date') < new Date()) {
|
||||||
|
try {
|
||||||
|
const extUpdate = new Parse.Object('contracts_Users');
|
||||||
|
extUpdate.id = extUser.id;
|
||||||
|
extUpdate.set('Plan', { plan_code: 'freeplan' });
|
||||||
|
await extUpdate.save(null, { useMasterKey: true });
|
||||||
|
return { status: 'success', result: 'subscribed!' };
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err ', err);
|
||||||
|
return { status: 'error', result: err.message };
|
||||||
|
}
|
||||||
|
} else if (extUser?.get('Next_billing_date') > new Date()) {
|
||||||
|
return { status: 'success', result: 'already subscribed!' };
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const extUpdate = new Parse.Object('contracts_Users');
|
||||||
|
extUpdate.id = extUser.id;
|
||||||
|
extUpdate.set('Plan', { plan_code: 'freeplan' });
|
||||||
|
await extUpdate.save(null, { useMasterKey: true });
|
||||||
|
return { status: 'success', result: 'subscribed!' };
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err ', err);
|
||||||
|
return { status: 'error', result: err.message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { status: 'error', result: 'User not found!' };
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err ', err);
|
||||||
|
return { status: 'error', result: err.message };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
async function TemplateBeforeSave(request) {
|
||||||
|
try {
|
||||||
|
if (!request.original) {
|
||||||
|
// below code is used to update template when user sent template or self signed
|
||||||
|
const template = request.object;
|
||||||
|
|
||||||
|
// Update count in contracts_Users class
|
||||||
|
const query = new Parse.Query('contracts_Users');
|
||||||
|
query.equalTo('objectId', template.get('ExtUserPtr').id);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const contractUser = await query.first({ useMasterKey: true });
|
||||||
|
if (contractUser) {
|
||||||
|
contractUser.increment('TemplateCount', 1);
|
||||||
|
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('TemplateCount', 1);
|
||||||
|
await newContractUser.save(null, { useMasterKey: true });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Error updating template count in contracts_users: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err in template beforesave', err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default TemplateBeforeSave;
|
||||||
+95
-122
@@ -3,6 +3,7 @@ import fs from 'node:fs';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { pdflibAddPlaceholder } from './customSignPdf/pdflibplaceholder.min.js';
|
import { pdflibAddPlaceholder } from './customSignPdf/pdflibplaceholder.min.js';
|
||||||
import { PDFDocument } from 'pdf-lib';
|
import { PDFDocument } from 'pdf-lib';
|
||||||
|
import { saveFileUsage } from '../../../Utils.js';
|
||||||
const serverUrl = process.env.SERVER_URL,
|
const serverUrl = process.env.SERVER_URL,
|
||||||
APPID = process.env.APP_ID,
|
APPID = process.env.APP_ID,
|
||||||
masterKEY = process.env.MASTER_KEY;
|
masterKEY = process.env.MASTER_KEY;
|
||||||
@@ -16,20 +17,20 @@ async function uploadFile(e, a) {
|
|||||||
console.log('Err ', e), fs.unlinkSync(a);
|
console.log('Err ', e), fs.unlinkSync(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function updateDoc(t, s, r, i, o, n) {
|
async function updateDoc(t, s, r, o, i, n) {
|
||||||
try {
|
try {
|
||||||
var d = {
|
var d = {
|
||||||
UserPtr: { __type: 'Pointer', className: n, objectId: r },
|
UserPtr: { __type: 'Pointer', className: n, objectId: r },
|
||||||
SignedUrl: s,
|
SignedUrl: s,
|
||||||
Activity: 'Signed',
|
Activity: 'Signed',
|
||||||
ipAddress: i,
|
ipAddress: o,
|
||||||
};
|
};
|
||||||
let e;
|
let e;
|
||||||
var l = (e = o.AuditTrail && 0 < o.AuditTrail.length ? [...o.AuditTrail, d] : [d]).filter(
|
var l = (e = i.AuditTrail && 0 < i.AuditTrail.length ? [...i.AuditTrail, d] : [d]).filter(
|
||||||
e => 'Signed' === e.Activity
|
e => 'Signed' === e.Activity
|
||||||
);
|
);
|
||||||
let a = !1;
|
let a = !1;
|
||||||
!((o.Signers && 0 < o.Signers.length && l.length !== o.Signers.length) || !(a = !0));
|
!((i.Signers && 0 < i.Signers.length && l.length !== i.Signers.length) || !(a = !0));
|
||||||
var c = { SignedUrl: s, AuditTrail: e, IsCompleted: a };
|
var c = { SignedUrl: s, AuditTrail: e, IsCompleted: a };
|
||||||
await axios.put(serverUrl + '/classes/contracts_Document/' + t, c, {
|
await axios.put(serverUrl + '/classes/contracts_Document/' + t, c, {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -43,39 +44,16 @@ async function updateDoc(t, s, r, i, o, n) {
|
|||||||
return console.log('update doc err ', e), 'err';
|
return console.log('update doc err ', e), 'err';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function sendMail(e) {
|
|
||||||
var a = e.url,
|
|
||||||
t = e.sender,
|
|
||||||
s = e.pdfName,
|
|
||||||
a = {
|
|
||||||
url: a,
|
|
||||||
from: 'OpenSign™',
|
|
||||||
recipient: e.receiver,
|
|
||||||
subject: 'You have signed the doc - ' + s,
|
|
||||||
pdfName: s,
|
|
||||||
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=https://qikinnovation.ams3.digitaloceanspaces.com/logo.png height='50' style='padding:20px'/> </div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document Copy</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document " +
|
|
||||||
s +
|
|
||||||
' Standard is attached to this email. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender ' +
|
|
||||||
t.Mail +
|
|
||||||
' directly. If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>',
|
|
||||||
};
|
|
||||||
await axios.post(serverUrl + '/functions/sendmailv3', a, {
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-Parse-Application-Id': APPID,
|
|
||||||
'X-Parse-Master-Key': masterKEY,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
async function sendCompletedMail(e) {
|
async function sendCompletedMail(e) {
|
||||||
var a = e.url,
|
var a = e.url,
|
||||||
t = e.sender,
|
t = e.sender,
|
||||||
s = e.pdfName,
|
s = e.pdfName,
|
||||||
a = {
|
r = e.receiver,
|
||||||
|
e = {
|
||||||
|
extUserId: e.extUserId,
|
||||||
url: a,
|
url: a,
|
||||||
from: 'OpenSign™',
|
from: 'OpenSign™',
|
||||||
recipient: e.receiver,
|
recipient: r,
|
||||||
subject: `Document ${s} has been signed by all parties`,
|
subject: `Document ${s} has been signed by all parties`,
|
||||||
pdfName: s,
|
pdfName: s,
|
||||||
html:
|
html:
|
||||||
@@ -85,7 +63,7 @@ async function sendCompletedMail(e) {
|
|||||||
t.Mail +
|
t.Mail +
|
||||||
' directly. If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>',
|
' directly. If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>',
|
||||||
};
|
};
|
||||||
await axios.post(serverUrl + '/functions/sendmailv3', a, {
|
await axios.post(serverUrl + '/functions/sendmailv3', e, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'X-Parse-Application-Id': APPID,
|
'X-Parse-Application-Id': APPID,
|
||||||
@@ -155,7 +133,7 @@ async function PDF(i) {
|
|||||||
try {
|
try {
|
||||||
var e = i.params.docId,
|
var e = i.params.docId,
|
||||||
a = i.params.userId,
|
a = i.params.userId,
|
||||||
o = await axios.get(
|
n = await axios.get(
|
||||||
serverUrl + '/classes/contracts_Document/' + e + '?include=ExtUserPtr,Signers',
|
serverUrl + '/classes/contracts_Document/' + e + '?include=ExtUserPtr,Signers',
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -165,142 +143,137 @@ async function PDF(i) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
t = await axios.get(serverUrl + '/users/me', {
|
d = await axios.get(serverUrl + '/users/me', {
|
||||||
headers: {
|
headers: {
|
||||||
'X-Parse-Application-Id': APPID,
|
'X-Parse-Application-Id': APPID,
|
||||||
'X-Parse-Session-Token': i.headers.sessiontoken,
|
'X-Parse-Session-Token': i.headers.sessiontoken,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!t.data || !t.data.objectId) return { status: 'error', message: 'this user not allowed!' };
|
if (!d.data || !d.data.objectId) return { status: 'error', message: 'This user not allowed!' };
|
||||||
{
|
{
|
||||||
var n,
|
var t,
|
||||||
d,
|
s,
|
||||||
l,
|
l,
|
||||||
c = JSON.stringify({ objectId: a });
|
c = JSON.stringify({ objectId: a });
|
||||||
let s, r;
|
let r, o;
|
||||||
r = a
|
o = a
|
||||||
? (n = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + c, {
|
? (t = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + c, {
|
||||||
headers: {
|
headers: {
|
||||||
'X-Parse-Application-Id': APPID,
|
'X-Parse-Application-Id': APPID,
|
||||||
'X-Parse-Session-Token': i.headers.sessiontoken,
|
'X-Parse-Session-Token': i.headers.sessiontoken,
|
||||||
},
|
},
|
||||||
})).data && 0 < n.data.results.length
|
})).data && 0 < t.data.results.length
|
||||||
? ((s = n), 'contracts_Contactbook')
|
? ((r = t), 'contracts_Contactbook')
|
||||||
: ((s = await axios.get(serverUrl + '/classes/contracts_Users?where=' + c, {
|
: ((r = await axios.get(serverUrl + '/classes/contracts_Users?where=' + c, {
|
||||||
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
|
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
|
||||||
})),
|
})),
|
||||||
'contracts_Users')
|
'contracts_Users')
|
||||||
: ((d = JSON.stringify({
|
: ((s = JSON.stringify({
|
||||||
UserId: { __type: 'Pointer', className: '_User', objectId: t.data.objectId },
|
UserId: { __type: 'Pointer', className: '_User', objectId: d.data.objectId },
|
||||||
})),
|
})),
|
||||||
(l = await axios.get(serverUrl + '/classes/contracts_Users?where=' + d, {
|
(l = await axios.get(serverUrl + '/classes/contracts_Users?where=' + s, {
|
||||||
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
|
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
|
||||||
})).data && 0 < l.data.results.length
|
})).data && 0 < l.data.results.length
|
||||||
? ((s = l), 'contracts_Users')
|
? ((r = l), 'contracts_Users')
|
||||||
: ((s = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + d, {
|
: ((r = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + s, {
|
||||||
headers: {
|
headers: {
|
||||||
'X-Parse-Application-Id': APPID,
|
'X-Parse-Application-Id': APPID,
|
||||||
'X-Parse-Session-Token': i.headers.sessiontoken,
|
'X-Parse-Session-Token': i.headers.sessiontoken,
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
'contracts_Contactbook'));
|
'contracts_Contactbook'));
|
||||||
var p = s.data.results[0].Name,
|
var p = r.data.results[0].Name,
|
||||||
m = s.data.results[0].Email;
|
m = r.data.results[0].Email;
|
||||||
if (!i.params.pdfFile) return { status: 'error', message: 'pdf file not present!' };
|
if (!i.params.pdfFile) return { status: 'error', message: 'pdf file not present!' };
|
||||||
{
|
{
|
||||||
let e = Buffer.from(i.params.pdfFile, 'base64');
|
let e = Buffer.from(i.params.pdfFile, 'base64');
|
||||||
var g = process.env.PFX_BASE64,
|
var g = process.env.PFX_BASE64,
|
||||||
h = Buffer.from(g, 'base64'),
|
u = Buffer.from(g, 'base64'),
|
||||||
u = {
|
h = {
|
||||||
UserPtr: { __type: 'Pointer', className: r, objectId: s.data.results[0].objectId },
|
UserPtr: { __type: 'Pointer', className: o, objectId: r.data.results[0].objectId },
|
||||||
SignedUrl: '',
|
SignedUrl: '',
|
||||||
Activity: 'Signed',
|
Activity: 'Signed',
|
||||||
ipAddress: i.headers['x-real-ip'],
|
ipAddress: i.headers['x-real-ip'],
|
||||||
};
|
};
|
||||||
let a;
|
let a;
|
||||||
var f = (a =
|
var f = (a =
|
||||||
o.data.AuditTrail && 0 < o.data.AuditTrail.length
|
n.data.AuditTrail && 0 < n.data.AuditTrail.length
|
||||||
? [...o.data.AuditTrail, u]
|
? [...n.data.AuditTrail, h]
|
||||||
: [u]).filter(e => 'Signed' === e.Activity);
|
: [h]).filter(e => 'Signed' === e.Activity);
|
||||||
let t = !1;
|
let t = !1;
|
||||||
!(
|
!(
|
||||||
(o.data.Signers && 0 < o.data.Signers.length && f.length !== o.data.Signers.length) ||
|
(n.data.Signers && 0 < n.data.Signers.length && f.length !== n.data.Signers.length) ||
|
||||||
!(t = !0)
|
!(t = !0)
|
||||||
);
|
);
|
||||||
var y,
|
var P,
|
||||||
P,
|
y,
|
||||||
v,
|
v,
|
||||||
b,
|
|
||||||
x,
|
|
||||||
w,
|
|
||||||
U,
|
U,
|
||||||
|
b,
|
||||||
I,
|
I,
|
||||||
S,
|
S = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`,
|
||||||
A = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`,
|
x = './exports/' + S;
|
||||||
D = './exports/' + A,
|
let s = e.length;
|
||||||
E =
|
s = (
|
||||||
(t
|
t
|
||||||
? ((y = o.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')),
|
? ((P = n.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')),
|
||||||
(e =
|
(e =
|
||||||
y && 0 < y.length
|
P && 0 < P.length
|
||||||
? ((P = await PDFDocument.load(e)),
|
? ((y = await PDFDocument.load(e)),
|
||||||
pdflibAddPlaceholder({
|
pdflibAddPlaceholder({
|
||||||
pdfDoc: P,
|
pdfDoc: y,
|
||||||
reason: 'Digitally signed by OpenSign for ' + y?.join(', '),
|
reason: 'Digitally signed by OpenSign for ' + P?.join(', '),
|
||||||
location: 'location',
|
location: 'location',
|
||||||
signatureLength: 15e3,
|
signatureLength: 15e3,
|
||||||
}),
|
}),
|
||||||
(v = await P.save()),
|
(v = await y.save()),
|
||||||
Buffer.from(v))
|
Buffer.from(v))
|
||||||
: ((b = await PDFDocument.load(e)),
|
: ((U = await PDFDocument.load(e)),
|
||||||
pdflibAddPlaceholder({
|
pdflibAddPlaceholder({
|
||||||
pdfDoc: b,
|
pdfDoc: U,
|
||||||
reason: 'Digitally signed by OpenSign for ' + p + ' <' + m + '>',
|
reason: 'Digitally signed by OpenSign for ' + p + ' <' + m + '>',
|
||||||
location: 'location',
|
location: 'location',
|
||||||
signatureLength: 15e3,
|
signatureLength: 15e3,
|
||||||
}),
|
}),
|
||||||
(x = await b.save()),
|
(b = await U.save()),
|
||||||
Buffer.from(x))),
|
Buffer.from(b))),
|
||||||
(w = await new SignPDF(e, h).signPDF()),
|
(I = await new SignPDF(e, u).signPDF()),
|
||||||
fs.writeFileSync(D, w))
|
fs.writeFileSync(x, I),
|
||||||
: fs.writeFileSync(D, e),
|
I)
|
||||||
await uploadFile(A, D));
|
: (fs.writeFileSync(x, e), e)
|
||||||
if (E && E.imageUrl)
|
).length;
|
||||||
|
var A,
|
||||||
|
w,
|
||||||
|
D = await uploadFile(S, x);
|
||||||
|
if (D && D.imageUrl)
|
||||||
return (
|
return (
|
||||||
(U = await updateDoc(
|
(A = await updateDoc(
|
||||||
i.params.docId,
|
i.params.docId,
|
||||||
E.imageUrl,
|
D.imageUrl,
|
||||||
s.data.results[0].objectId,
|
r.data.results[0].objectId,
|
||||||
i.headers['x-real-ip'],
|
i.headers['x-real-ip'],
|
||||||
o.data,
|
n.data,
|
||||||
r
|
o
|
||||||
)),
|
)),
|
||||||
(I = {
|
sendDoctoWebhook(n, D.imageUrl, 'signed', r?.data.results?.[0]),
|
||||||
url: E.imageUrl,
|
saveFileUsage(s, D.imageUrl, d.data.objectId),
|
||||||
sender: { Mail: o.data.ExtUserPtr.Email, Name: o.data.ExtUserPtr.Name },
|
A &&
|
||||||
pdfName: o.data.Name,
|
A.isCompleted &&
|
||||||
receiver: m,
|
((w = {
|
||||||
}),
|
url: D.imageUrl,
|
||||||
o.data.IsSendMail && !1 === o.data.IsSendMail
|
sender: { Mail: n.data.ExtUserPtr.Email, Name: 'OpenSign™' },
|
||||||
? console.log("don't send mail")
|
pdfName: n.data.Name,
|
||||||
: sendMail(I),
|
receiver: n.data.ExtUserPtr.Email,
|
||||||
sendDoctoWebhook(o, E.imageUrl, 'signed', s?.data.results?.[0]),
|
extUserId: n.data.ExtUserPtr.objectId,
|
||||||
U &&
|
|
||||||
U.isCompleted &&
|
|
||||||
((S = {
|
|
||||||
url: E.imageUrl,
|
|
||||||
sender: { Mail: o.data.ExtUserPtr.Email, Name: 'OpenSign™' },
|
|
||||||
pdfName: o.data.Name,
|
|
||||||
receiver: o.data.ExtUserPtr.Email,
|
|
||||||
}),
|
}),
|
||||||
o.data.IsSendMail && !1 === o.data.IsSendMail
|
n.data.IsSendMail && !1 === n.data.IsSendMail
|
||||||
? console.log("don't send mail")
|
? console.log("don't send mail")
|
||||||
: sendCompletedMail(S),
|
: sendCompletedMail(w),
|
||||||
sendDoctoWebhook(o, E.imageUrl, 'completed')),
|
sendDoctoWebhook(n, D.imageUrl, 'completed')),
|
||||||
fs.unlinkSync(D),
|
fs.unlinkSync(x),
|
||||||
console.log('New Signed PDF created called: ' + D),
|
console.log('New Signed PDF created called: ' + x),
|
||||||
'success' === U.message
|
'success' === A.message
|
||||||
? { status: 'success', data: E.imageUrl }
|
? { status: 'success', data: D.imageUrl }
|
||||||
: { status: 'error', message: 'please provide required parameters!' }
|
: { status: 'error', message: 'please provide required parameters!' }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-3
@@ -3,8 +3,9 @@ import https from 'https';
|
|||||||
import formData from 'form-data';
|
import formData from 'form-data';
|
||||||
import Mailgun from 'mailgun.js';
|
import Mailgun from 'mailgun.js';
|
||||||
import { createTransport } from 'nodemailer';
|
import { createTransport } from 'nodemailer';
|
||||||
|
import { updateMailCount } from '../../Utils.js';
|
||||||
|
|
||||||
async function sendmail(req) {
|
async function sendmailv3(req) {
|
||||||
try {
|
try {
|
||||||
let transporterSMTP;
|
let transporterSMTP;
|
||||||
let mailgunClient;
|
let mailgunClient;
|
||||||
@@ -77,6 +78,9 @@ async function sendmail(req) {
|
|||||||
const res = await transporterSMTP.sendMail(messageParams);
|
const res = await transporterSMTP.sendMail(messageParams);
|
||||||
console.log('Res ', res);
|
console.log('Res ', res);
|
||||||
if (!res.err) {
|
if (!res.err) {
|
||||||
|
if (req.params?.extUserId) {
|
||||||
|
await updateMailCount(req.params.extUserId);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
status: 'success',
|
status: 'success',
|
||||||
};
|
};
|
||||||
@@ -85,6 +89,9 @@ async function sendmail(req) {
|
|||||||
const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
|
const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
|
||||||
console.log('Res ', res);
|
console.log('Res ', res);
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
|
if (req.params?.extUserId) {
|
||||||
|
await updateMailCount(req.params.extUserId);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
status: 'success',
|
status: 'success',
|
||||||
};
|
};
|
||||||
@@ -109,6 +116,9 @@ async function sendmail(req) {
|
|||||||
const res = await transporterSMTP.sendMail(messageParams);
|
const res = await transporterSMTP.sendMail(messageParams);
|
||||||
console.log('Res ', res);
|
console.log('Res ', res);
|
||||||
if (!res.err) {
|
if (!res.err) {
|
||||||
|
if (req.params?.extUserId) {
|
||||||
|
await updateMailCount(req.params.extUserId);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
status: 'success',
|
status: 'success',
|
||||||
};
|
};
|
||||||
@@ -117,6 +127,9 @@ async function sendmail(req) {
|
|||||||
const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
|
const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
|
||||||
console.log('Res ', res);
|
console.log('Res ', res);
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
|
if (req.params?.extUserId) {
|
||||||
|
await updateMailCount(req.params.extUserId);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
status: 'success',
|
status: 'success',
|
||||||
};
|
};
|
||||||
@@ -124,11 +137,11 @@ async function sendmail(req) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err ', err);
|
console.log('err in sendmailv3', err);
|
||||||
if (err) {
|
if (err) {
|
||||||
return { status: 'error' };
|
return { status: 'error' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default sendmail;
|
export default sendmailv3;
|
||||||
@@ -86,7 +86,9 @@ if (process.env.SMTP_ENABLE) {
|
|||||||
console.log('Please provide valid Mailgun credentials');
|
console.log('Please provide valid Mailgun credentials');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const mailsender = process.env.SMTP_ENABLE
|
||||||
|
? process.env.SMTP_USER_EMAIL
|
||||||
|
: process.env.MAILGUN_SENDER;
|
||||||
export const config = {
|
export const config = {
|
||||||
databaseURI:
|
databaseURI:
|
||||||
process.env.DATABASE_URI || process.env.MONGODB_URI || 'mongodb://localhost:27017/dev',
|
process.env.DATABASE_URI || process.env.MONGODB_URI || 'mongodb://localhost:27017/dev',
|
||||||
@@ -102,7 +104,7 @@ export const config = {
|
|||||||
verifyUserEmails: isMailAdapter === true ? true : false,
|
verifyUserEmails: isMailAdapter === true ? true : false,
|
||||||
publicServerURL: process.env.SERVER_URL || 'http://localhost:8080/app',
|
publicServerURL: process.env.SERVER_URL || 'http://localhost:8080/app',
|
||||||
// Your apps name. This will appear in the subject and body of the emails that are sent.
|
// Your apps name. This will appear in the subject and body of the emails that are sent.
|
||||||
appName: 'Open Sign',
|
appName: 'Opensign',
|
||||||
allowClientClassCreation: false,
|
allowClientClassCreation: false,
|
||||||
allowExpiredAuthDataToken: false,
|
allowExpiredAuthDataToken: false,
|
||||||
encodeParseObjectInCloudFunction: true,
|
encodeParseObjectInCloudFunction: true,
|
||||||
@@ -112,9 +114,7 @@ export const config = {
|
|||||||
module: 'parse-server-api-mail-adapter',
|
module: 'parse-server-api-mail-adapter',
|
||||||
options: {
|
options: {
|
||||||
// The email address from which emails are sent.
|
// The email address from which emails are sent.
|
||||||
sender: process.env.SMTP_ENABLE
|
sender: 'Opensign™' + ' <' + mailsender + '>',
|
||||||
? process.env.SMTP_USER_EMAIL
|
|
||||||
: process.env.MAILGUN_SENDER,
|
|
||||||
// The email templates.
|
// The email templates.
|
||||||
templates: {
|
templates: {
|
||||||
// The template used by Parse Server to send an email for password
|
// The template used by Parse Server to send an email for password
|
||||||
@@ -147,6 +147,14 @@ export const config = {
|
|||||||
google: {
|
google: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
|
ldap: {
|
||||||
|
enabled: true,
|
||||||
|
url: 'ldap://ldap.forumsys.com:389',
|
||||||
|
suffix: 'dc=example,dc=com',
|
||||||
|
// dn: 'ou=mathematicians, dc=example, dc=com',
|
||||||
|
groupCn: 'mathematicians',
|
||||||
|
groupFilter: '(&(uniqueMember=uid=,dc=example,dc=com)(objectClass=groupOfUniqueNames))',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
|
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
|
||||||
|
|||||||
Reference in New Issue
Block a user