mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-04 16:58:05 +02:00
Compare commits
101
Commits
1.3.2-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 | ||
|
|
12a6a84450 | ||
|
|
1f350fc459 | ||
|
|
d9fd2a5531 | ||
|
|
cd4fd6e3de | ||
|
|
49cd30de96 | ||
|
|
a24ebe25a8 | ||
|
|
3e664bf677 | ||
|
|
6161e975fb | ||
|
|
c2a45c230b | ||
|
|
a629aa0bff | ||
|
|
899678d98a | ||
|
|
076a0f54c5 | ||
|
|
a94e67cd7c | ||
|
|
e78a3991f0 | ||
|
|
593a8499f4 | ||
|
|
70d643a5e2 | ||
|
|
f2b1a54695 | ||
|
|
4353a4f732 | ||
|
|
34c99edf1a | ||
|
|
91f3bdb299 | ||
|
|
276fc974fa | ||
|
|
081e11f9af | ||
|
|
4f056cc9d3 | ||
|
|
d9da25e908 | ||
|
|
99b3436c8c | ||
|
|
452d4d7a1d | ||
|
|
ed613c3424 | ||
|
|
bf70fa0b11 | ||
|
|
8684197d49 | ||
|
|
648d1224b3 | ||
|
|
126b6ad355 | ||
|
|
0512f27e2e | ||
|
|
2c61630017 | ||
|
|
72c2b2dde6 | ||
|
|
29eb78c960 | ||
|
|
aa9ba05dde | ||
|
|
365b074f62 | ||
|
|
af6cb4c17d | ||
|
|
6bcad91b0f | ||
|
|
1aa2b003b2 | ||
|
|
1a27e9addf | ||
|
|
c2891a0858 | ||
|
|
c1b226db96 | ||
|
|
8a01efee4c | ||
|
|
eafb26d462 | ||
|
|
62e1a1bd9b | ||
|
|
58eb71c52d | ||
|
|
c1e6f2b5ab | ||
|
|
ba0c18b591 | ||
|
|
c3a902dcc7 | ||
|
|
5ece3c0694 | ||
|
|
1053540410 | ||
|
|
24773759c2 | ||
|
|
7a6de70169 | ||
|
|
04b2c7c4da | ||
|
|
d11171e91c | ||
|
|
a4a78cb96c | ||
|
|
dfdcde8fcc | ||
|
|
5e1b84d2e6 |
+1
-1
@@ -20,7 +20,7 @@ appName=open_sign_server
|
|||||||
# A 12 character long random secret key that allows access to all the data. It is used in Parse dashboard config to view all the data in the database.
|
# A 12 character long random secret key that allows access to all the data. It is used in Parse dashboard config to view all the data in the database.
|
||||||
MASTER_KEY=XnAadwKxxByMr
|
MASTER_KEY=XnAadwKxxByMr
|
||||||
# Mongodb URI to connect to
|
# Mongodb URI to connect to
|
||||||
MONGODB_URI=mongodb://localhost:27017/OpenSignDB
|
MONGODB_URI=mongodb://mongo:27017/OpenSignDB
|
||||||
# Path on which APIs should be mounted. Do not change this. This variable shall be removed & value hardcoded in the source code in coming versions.
|
# Path on which APIs should be mounted. Do not change this. This variable shall be removed & value hardcoded in the source code in coming versions.
|
||||||
PARSE_MOUNT=/app
|
PARSE_MOUNT=/app
|
||||||
# Set it to the URL from where APIs will be accessible to the NodeJS functions, for local development it should be localhost:3000/api/app (use your local port number instead)
|
# Set it to the URL from where APIs will be accessible to the NodeJS functions, for local development it should be localhost:3000/api/app (use your local port number instead)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
build:
|
build:
|
||||||
cp .env.local_dev .env
|
cp .env.local_dev .env
|
||||||
cd apps/OpenSign && npm install && npm run build
|
cd apps/OpenSign && cp ../../.env.local_dev .env && npm install && npm run build
|
||||||
docker compose up --build --force-recreate
|
docker compose up --build --force-recreate
|
||||||
|
|
||||||
run:
|
run:
|
||||||
|
|||||||
@@ -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).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -21,5 +21,5 @@ EXPOSE 3000
|
|||||||
# ENV NODE_ENV production
|
# ENV NODE_ENV production
|
||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
ENTRYPOINT npm run start-dev
|
ENTRYPOINT npm run start
|
||||||
|
|
||||||
|
|||||||
Generated
+632
-710
File diff suppressed because it is too large
Load Diff
+16
-19
@@ -3,35 +3,32 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@formkit/auto-animate": "^0.8.1",
|
||||||
"@radix-ui/themes": "^2.0.3",
|
"@radix-ui/themes": "^2.0.3",
|
||||||
"@react-pdf/renderer": "^3.3.8",
|
"@react-pdf/renderer": "^3.4.0",
|
||||||
"@reduxjs/toolkit": "^2.2.1",
|
"@reduxjs/toolkit": "^2.2.1",
|
||||||
"axios": "^1.6.0",
|
"axios": "^1.6.8",
|
||||||
"daisyui": "^3.9.2",
|
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"html-react-parser": "^4.2.2",
|
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.30.1",
|
||||||
"parse": "^4.3.1",
|
"parse": "^4.3.1",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
"radix-ui": "^1.0.1",
|
"radix-ui": "^1.0.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-bootstrap": "^2.10.1",
|
"react-bootstrap": "^2.10.2",
|
||||||
"react-datepicker": "^6.2.0",
|
"react-datepicker": "^6.4.0",
|
||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
"react-dnd-html5-backend": "^16.0.1",
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
"react-dnd-multi-backend": "^8.0.3",
|
"react-dnd-multi-backend": "^8.0.3",
|
||||||
"react-dnd-touch-backend": "^16.0.1",
|
"react-dnd-touch-backend": "^16.0.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-drag-listview": "^2.0.0",
|
|
||||||
"react-draggable": "^4.4.6",
|
|
||||||
"react-gtm-module": "^2.0.11",
|
"react-gtm-module": "^2.0.11",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
"react-konva": "^18.2.10",
|
"react-konva": "^18.2.10",
|
||||||
"react-modal": "^3.16.1",
|
"react-modal": "^3.16.1",
|
||||||
"react-pdf": "^7.7.1",
|
"react-pdf": "^7.7.1",
|
||||||
"react-redux": "^8.1.3",
|
"react-redux": "^9.1.0",
|
||||||
"react-rnd": "^10.4.1",
|
"react-rnd": "^10.4.1",
|
||||||
"react-router-dom": "^6.22.3",
|
"react-router-dom": "^6.22.3",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
@@ -40,8 +37,8 @@
|
|||||||
"react-signature-canvas": "^1.0.6",
|
"react-signature-canvas": "^1.0.6",
|
||||||
"react-tooltip": "^5.26.3",
|
"react-tooltip": "^5.26.3",
|
||||||
"reactour": "^1.19.2",
|
"reactour": "^1.19.2",
|
||||||
"redux": "^4.2.1",
|
"redux": "^5.0.1",
|
||||||
"redux-thunk": "^2.4.2",
|
"redux-thunk": "^3.1.0",
|
||||||
"regex-parser": "^2.3.0",
|
"regex-parser": "^2.3.0",
|
||||||
"serve": "^14.2.1",
|
"serve": "^14.2.1",
|
||||||
"styled-components": "^4.4.1",
|
"styled-components": "^4.4.1",
|
||||||
@@ -83,16 +80,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/runtime-corejs2": "^7.23.9",
|
"@babel/runtime-corejs2": "^7.24.1",
|
||||||
"autoprefixer": "^10.4.18",
|
"autoprefixer": "^10.4.18",
|
||||||
"commitizen": "^4.3.0",
|
"commitizen": "^4.3.0",
|
||||||
"eslint": "^8.51.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"eslint-plugin-react": "^7.34.1",
|
||||||
"lint-staged": "^15.2.2",
|
"lint-staged": "^15.2.2",
|
||||||
"postcss": "^8.4.35",
|
"postcss": "^8.4.37",
|
||||||
"prettier": "^2.8.0",
|
"prettier": "^2.8.8",
|
||||||
"pretty-quick": "^3.1.3",
|
"pretty-quick": "^3.3.1",
|
||||||
"tailwindcss": "^3.3.3"
|
"tailwindcss": "^3.4.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+96
-72
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, Suspense, lazy } from "react";
|
import React, { useState, useEffect, lazy } from "react";
|
||||||
import { Routes, Route, BrowserRouter } from "react-router-dom";
|
import { Routes, Route, BrowserRouter } from "react-router-dom";
|
||||||
import { pdfjs } from "react-pdf";
|
import { pdfjs } from "react-pdf";
|
||||||
import Login from "./pages/Login";
|
import Login from "./pages/Login";
|
||||||
@@ -9,12 +9,13 @@ import HomeLayout from "./layout/HomeLayout";
|
|||||||
import PageNotFound from "./pages/PageNotFound";
|
import PageNotFound from "./pages/PageNotFound";
|
||||||
import ValidateRoute from "./primitives/ValidateRoute";
|
import ValidateRoute from "./primitives/ValidateRoute";
|
||||||
import Validate from "./primitives/Validate";
|
import Validate from "./primitives/Validate";
|
||||||
import ManageSign from "./pages/Managesign";
|
|
||||||
import TemplatePlaceholder from "./pages/TemplatePlaceholder";
|
import TemplatePlaceholder from "./pages/TemplatePlaceholder";
|
||||||
import SignYourSelf from "./pages/SignyourselfPdf";
|
import SignYourSelf from "./pages/SignyourselfPdf";
|
||||||
import DraftDocument from "./components/pdf/DraftDocument";
|
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 { 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"));
|
||||||
@@ -23,9 +24,10 @@ const Subscriptions = lazy(() => import("./pages/PlanSubscriptions"));
|
|||||||
const ChangePassword = lazy(() => import("./pages/ChangePassword"));
|
const ChangePassword = lazy(() => import("./pages/ChangePassword"));
|
||||||
const UserProfile = lazy(() => import("./pages/UserProfile"));
|
const UserProfile = lazy(() => import("./pages/UserProfile"));
|
||||||
const Signup = lazy(() => import("./pages/Signup"));
|
const Signup = lazy(() => import("./pages/Signup"));
|
||||||
|
const Opensigndrive = lazy(() => import("./pages/Opensigndrive"));
|
||||||
|
const ManageSign = lazy(() => import("./pages/Managesign"));
|
||||||
const GenerateToken = lazy(() => import("./pages/GenerateToken"));
|
const GenerateToken = lazy(() => import("./pages/GenerateToken"));
|
||||||
const Webhook = lazy(() => import("./pages/Webhook"));
|
const Webhook = lazy(() => import("./pages/Webhook"));
|
||||||
const Opensigndrive = lazy(() => import("./pages/Opensigndrive"));
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
|
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
|
||||||
|
|
||||||
const Loader = () => {
|
const Loader = () => {
|
||||||
@@ -78,83 +80,105 @@ function App() {
|
|||||||
<Loader />
|
<Loader />
|
||||||
) : (
|
) : (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Suspense fallback={<Loader />}>
|
<Routes>
|
||||||
<Routes>
|
<Route element={<ValidateRoute />}>
|
||||||
<Route element={<ValidateRoute />}>
|
<Route exact path="/" element={<Login />} />
|
||||||
<Route exact path="/" element={<Login />} />
|
<Route path="/signup" element={<LazyPage Page={Signup} />} />
|
||||||
<Route exact path="/signup" element={<Signup />} />
|
</Route>
|
||||||
</Route>
|
<Route element={<Validate />}>
|
||||||
<Route element={<Validate />}>
|
|
||||||
<Route
|
|
||||||
path="/load/template/:templateId"
|
|
||||||
element={<TemplatePlaceholder />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
exact
|
|
||||||
path="/load/placeholdersign/:docId"
|
|
||||||
element={<PlaceHolderSign />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
exact
|
|
||||||
path="/load/recipientSignPdf/:docId/:contactBookId"
|
|
||||||
element={<PdfRequestFiles />}
|
|
||||||
/>
|
|
||||||
</Route>
|
|
||||||
<Route
|
<Route
|
||||||
path="/loadmf/signmicroapp/login/:id/:userMail/:contactBookId/:serverUrl"
|
path="/load/template/:templateId"
|
||||||
element={<GuestLogin />}
|
element={<TemplatePlaceholder />}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="/login/:id/:userMail/:contactBookId/:serverUrl"
|
exact
|
||||||
element={<GuestLogin />}
|
path="/load/placeholdersign/:docId"
|
||||||
|
element={<PlaceHolderSign />}
|
||||||
/>
|
/>
|
||||||
<Route path="/debugpdf" element={<DebugPdf />} />
|
<Route
|
||||||
<Route path="/forgetpassword" element={<ForgetPassword />} />
|
exact
|
||||||
{process.env.REACT_APP_ENABLE_SUBSCRIPTION && (
|
path="/load/recipientSignPdf/:docId/:contactBookId"
|
||||||
<>
|
element={<PdfRequestFiles />}
|
||||||
<Route exact path="/pgsignup" element={<Pgsignup />} />
|
/>
|
||||||
<Route path="/subscription" element={<Subscriptions />} />
|
</Route>
|
||||||
</>
|
<Route
|
||||||
)}
|
path="/loadmf/signmicroapp/login/:id/:userMail/:contactBookId/:serverUrl"
|
||||||
<Route element={<HomeLayout />}>
|
element={<LazyPage Page={GuestLogin} />}
|
||||||
<Route path="/changepassword" element={<ChangePassword />} />
|
/>
|
||||||
<Route path="/form/:id" element={<Form />} />
|
<Route
|
||||||
<Route path="/report/:id" element={<Report />} />
|
path="/login/:id/:userMail/:contactBookId/:serverUrl"
|
||||||
<Route path="/dashboard/:id" element={<Dashboard />} />
|
element={<LazyPage Page={GuestLogin} />}
|
||||||
<Route path="/profile" element={<UserProfile />} />
|
/>
|
||||||
<Route path="/generatetoken" element={<GenerateToken />} />
|
<Route path="/debugpdf" element={<LazyPage Page={DebugPdf} />} />
|
||||||
<Route path="/webhook" element={<Webhook />} />
|
<Route
|
||||||
<Route path="/managesign" element={<ManageSign />} />
|
path="/forgetpassword"
|
||||||
<Route path="/opensigndrive" element={<Opensigndrive />} />
|
element={<LazyPage Page={ForgetPassword} />}
|
||||||
|
/>
|
||||||
|
{isEnableSubscription && (
|
||||||
|
<>
|
||||||
<Route
|
<Route
|
||||||
path="/template/:templateId"
|
path="/pgsignup"
|
||||||
element={<TemplatePlaceholder />}
|
element={<LazyPage Page={Pgsignup} />}
|
||||||
/>
|
/>
|
||||||
{/* signyouself route with no rowlevel data using docId from url */}
|
|
||||||
<Route path="/signaturePdf/:docId" element={<SignYourSelf />} />
|
|
||||||
{/* draft document route to handle and navigate route page accordiing to document status */}
|
|
||||||
<Route path="/draftDocument" element={<DraftDocument />} />
|
|
||||||
{/* recipient placeholder set route with no rowlevel data using docId from url*/}
|
|
||||||
<Route
|
<Route
|
||||||
path="/placeHolderSign/:docId"
|
path="/subscription"
|
||||||
element={<PlaceHolderSign />}
|
element={<LazyPage Page={Subscriptions} />}
|
||||||
/>
|
/>
|
||||||
{/* for user signature (need your sign route) with row level data */}
|
</>
|
||||||
<Route path="/pdfRequestFiles" element={<PdfRequestFiles />} />
|
)}
|
||||||
{/* for user signature (need your sign route) with no row level data */}
|
<Route element={<HomeLayout />}>
|
||||||
<Route
|
<Route
|
||||||
path="/pdfRequestFiles/:docId"
|
path="/changepassword"
|
||||||
element={<PdfRequestFiles />}
|
element={<LazyPage Page={ChangePassword} />}
|
||||||
/>
|
/>
|
||||||
{/* recipient signature route with no rowlevel data using docId from url */}
|
<Route path="/form/:id" element={<Form />} />
|
||||||
<Route
|
<Route path="/report/:id" element={<Report />} />
|
||||||
path="/recipientSignPdf/:docId/:contactBookId"
|
<Route path="/dashboard/:id" element={<Dashboard />} />
|
||||||
element={<PdfRequestFiles />}
|
<Route
|
||||||
/>
|
path="/profile"
|
||||||
</Route>
|
element={<LazyPage Page={UserProfile} />}
|
||||||
<Route path="*" element={<PageNotFound />} />
|
/>
|
||||||
</Routes>
|
<Route
|
||||||
</Suspense>
|
path="/opensigndrive"
|
||||||
|
element={<LazyPage Page={Opensigndrive} />}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="/managesign"
|
||||||
|
element={<LazyPage Page={ManageSign} />}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="/generatetoken"
|
||||||
|
element={<LazyPage Page={GenerateToken} />}
|
||||||
|
/>
|
||||||
|
<Route path="/webhook" element={<LazyPage Page={Webhook} />} />
|
||||||
|
<Route
|
||||||
|
path="/template/:templateId"
|
||||||
|
element={<TemplatePlaceholder />}
|
||||||
|
/>
|
||||||
|
{/* signyouself route with no rowlevel data using docId from url */}
|
||||||
|
<Route path="/signaturePdf/:docId" element={<SignYourSelf />} />
|
||||||
|
{/* draft document route to handle and navigate route page accordiing to document status */}
|
||||||
|
<Route path="/draftDocument" element={<DraftDocument />} />
|
||||||
|
{/* recipient placeholder set route with no rowlevel data using docId from url*/}
|
||||||
|
<Route
|
||||||
|
path="/placeHolderSign/:docId"
|
||||||
|
element={<PlaceHolderSign />}
|
||||||
|
/>
|
||||||
|
{/* for user signature (need your sign route) with row level data */}
|
||||||
|
<Route path="/pdfRequestFiles" element={<PdfRequestFiles />} />
|
||||||
|
{/* for user signature (need your sign route) with no row level data */}
|
||||||
|
<Route
|
||||||
|
path="/pdfRequestFiles/:docId"
|
||||||
|
element={<PdfRequestFiles />}
|
||||||
|
/>
|
||||||
|
{/* recipient signature route with no rowlevel data using docId from url */}
|
||||||
|
<Route
|
||||||
|
path="/recipientSignPdf/:docId/:contactBookId"
|
||||||
|
element={<PdfRequestFiles />}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
<Route path="*" element={<PageNotFound />} />
|
||||||
|
</Routes>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import Parse from "parse";
|
|||||||
import getReplacedHashQuery from "../../constant/getReplacedHashQuery";
|
import getReplacedHashQuery from "../../constant/getReplacedHashQuery";
|
||||||
import "../../styles/loader.css";
|
import "../../styles/loader.css";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import Tooltip from "../../primitives/Tooltip";
|
||||||
|
|
||||||
const DashboardCard = (props) => {
|
const DashboardCard = (props) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -335,7 +336,7 @@ const DashboardCard = (props) => {
|
|||||||
props.Data && props.Data.Redirect_type
|
props.Data && props.Data.Redirect_type
|
||||||
? "cursor-pointer"
|
? "cursor-pointer"
|
||||||
: "cursor-default"
|
: "cursor-default"
|
||||||
} w-full h-[140px] px-3 pt-4 pb-10 text-white rounded-md shadow overflow-hidden`}
|
} w-full h-[140px] px-3 pt-4 pb-10 text-white rounded-md shadow overflow-hidden relative`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-start gap-5">
|
<div className="flex items-center justify-start gap-5">
|
||||||
<span className="rounded-full bg-black bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
|
<span className="rounded-full bg-black bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
|
||||||
@@ -352,6 +353,9 @@ const DashboardCard = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="text-xs absolute top-2 right-1">
|
||||||
|
<Tooltip id={props.Label} iconColor={"white"} message={props?.Data?.tourMessage} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,16 +6,18 @@ const buttonList = [
|
|||||||
{
|
{
|
||||||
label: "Sign yourself",
|
label: "Sign yourself",
|
||||||
redirectId: "sHAnZphf69",
|
redirectId: "sHAnZphf69",
|
||||||
redirectType: "Form"
|
redirectType: "Form",
|
||||||
|
icon: "fas fa-pen-nib"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Request signature",
|
label: "Request signature",
|
||||||
redirectId: "8mZzFxbG1z",
|
redirectId: "8mZzFxbG1z",
|
||||||
redirectType: "Form"
|
redirectType: "Form",
|
||||||
|
icon: "fa-solid fa-paper-plane"
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
const GetDashboard = (props) => {
|
const GetDashboard = (props) => {
|
||||||
const Button = ({ label, redirectId, redirectType }) => (
|
const Button = ({ label, redirectId, redirectType, icon }) => (
|
||||||
<div className={"bg-white rounded-md shadow w-full"}>
|
<div className={"bg-white rounded-md shadow w-full"}>
|
||||||
<Suspense
|
<Suspense
|
||||||
fallback={
|
fallback={
|
||||||
@@ -33,7 +35,7 @@ const GetDashboard = (props) => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<DashboardButton
|
<DashboardButton
|
||||||
Icon={"fa-solid fa-plus"}
|
Icon={icon}
|
||||||
Label={label}
|
Label={label}
|
||||||
Data={{ Redirect_type: redirectType, Redirect_id: redirectId }}
|
Data={{ Redirect_type: redirectType, Redirect_id: redirectId }}
|
||||||
/>
|
/>
|
||||||
@@ -136,6 +138,7 @@ const GetDashboard = (props) => {
|
|||||||
label={btn.label}
|
label={btn.label}
|
||||||
redirectType={btn.redirectType}
|
redirectType={btn.redirectType}
|
||||||
redirectId={btn.redirectId}
|
redirectId={btn.redirectId}
|
||||||
|
icon={btn.icon}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,19 +8,11 @@ import { saveAs } from "file-saver";
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import Table from "react-bootstrap/Table";
|
import Table from "react-bootstrap/Table";
|
||||||
import * as HoverCard from "@radix-ui/react-hover-card";
|
import * as HoverCard from "@radix-ui/react-hover-card";
|
||||||
import SelectFolder from "../shared/fields/SelectFolder"; //check this one
|
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
import { themeColor } from "../../constant/const";
|
import { themeColor } from "../../constant/const";
|
||||||
|
import FolderModal from "../shared/fields/FolderModal";
|
||||||
|
|
||||||
function DriveBody({
|
function DriveBody(props) {
|
||||||
pdfData,
|
|
||||||
setFolderName,
|
|
||||||
setDocId,
|
|
||||||
setIsLoading,
|
|
||||||
setPdfData,
|
|
||||||
isList,
|
|
||||||
setIsAlert
|
|
||||||
}) {
|
|
||||||
const [rename, setRename] = useState("");
|
const [rename, setRename] = useState("");
|
||||||
const [renameValue, setRenameValue] = useState("");
|
const [renameValue, setRenameValue] = useState("");
|
||||||
const inputRef = useRef(null);
|
const inputRef = useRef(null);
|
||||||
@@ -50,28 +42,25 @@ function DriveBody({
|
|||||||
name: data.Name,
|
name: data.Name,
|
||||||
objectId: data.objectId
|
objectId: data.objectId
|
||||||
};
|
};
|
||||||
setFolderName((prev) => [...prev, folderData]);
|
props.setFolderName((prev) => [...prev, folderData]);
|
||||||
const loadObj = {
|
props.setIsLoading({
|
||||||
isLoad: true,
|
isLoad: true,
|
||||||
message: "This might take some time"
|
message: "This might take some time"
|
||||||
};
|
});
|
||||||
|
props.setDocId(data.objectId);
|
||||||
setIsLoading(loadObj);
|
props.setPdfData([]);
|
||||||
setDocId(data.objectId);
|
props.setSkip(0);
|
||||||
};
|
};
|
||||||
//function for change doc name and update doc name in _document class
|
//function for change doc name and update doc name in _document class
|
||||||
const handledRenameDoc = async (data) => {
|
const handledRenameDoc = async (data) => {
|
||||||
setRename("");
|
setRename("");
|
||||||
const trimmedValue = renameValue.trim();
|
const trimmedValue = renameValue.trim();
|
||||||
|
|
||||||
if (trimmedValue.length > 0) {
|
if (trimmedValue.length > 0) {
|
||||||
const updateName = {
|
const updateName = {
|
||||||
Name: renameValue
|
Name: renameValue
|
||||||
};
|
};
|
||||||
const docId = data.objectId;
|
const docId = data.objectId;
|
||||||
|
const docData = props.pdfData;
|
||||||
const docData = pdfData;
|
|
||||||
|
|
||||||
const updatedData = docData.map((item) => {
|
const updatedData = docData.map((item) => {
|
||||||
if (item.objectId === docId) {
|
if (item.objectId === docId) {
|
||||||
// If the item's ID matches the target ID, update the name
|
// If the item's ID matches the target ID, update the name
|
||||||
@@ -80,8 +69,7 @@ function DriveBody({
|
|||||||
// If the item's ID doesn't match, keep it unchanged
|
// If the item's ID doesn't match, keep it unchanged
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
|
props.setPdfData(updatedData);
|
||||||
setPdfData(updatedData);
|
|
||||||
await axios
|
await axios
|
||||||
.put(
|
.put(
|
||||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||||
@@ -102,7 +90,7 @@ function DriveBody({
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log("Err ", err);
|
console.log("Err ", err);
|
||||||
setIsAlert({
|
props.setIsAlert({
|
||||||
isShow: true,
|
isShow: true,
|
||||||
alertMessage: "something went wrong"
|
alertMessage: "something went wrong"
|
||||||
});
|
});
|
||||||
@@ -199,13 +187,13 @@ function DriveBody({
|
|||||||
.then((result) => {
|
.then((result) => {
|
||||||
const res = result.data;
|
const res = result.data;
|
||||||
if (res) {
|
if (res) {
|
||||||
const updatedData = pdfData.filter((x) => x.objectId !== docId);
|
const updatedData = props.pdfData.filter((x) => x.objectId !== docId);
|
||||||
setPdfData(updatedData);
|
props.setPdfData(updatedData);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log("Err ", err);
|
console.log("Err ", err);
|
||||||
setIsAlert({
|
props.setIsAlert({
|
||||||
isShow: true,
|
isShow: true,
|
||||||
alertMessage: "something went wrong"
|
alertMessage: "something went wrong"
|
||||||
});
|
});
|
||||||
@@ -226,8 +214,8 @@ function DriveBody({
|
|||||||
? true
|
? true
|
||||||
: false
|
: false
|
||||||
: selecFolderId
|
: selecFolderId
|
||||||
? false
|
? false
|
||||||
: true;
|
: true;
|
||||||
if (!checkExist) {
|
if (!checkExist) {
|
||||||
if (moveFolderId) {
|
if (moveFolderId) {
|
||||||
updateData = {
|
updateData = {
|
||||||
@@ -262,10 +250,10 @@ function DriveBody({
|
|||||||
// console.log("Listdata ", Listdata);
|
// console.log("Listdata ", Listdata);
|
||||||
const res = Listdata.data;
|
const res = Listdata.data;
|
||||||
if (res) {
|
if (res) {
|
||||||
const updatedData = pdfData.filter(
|
const updatedData = props.pdfData.filter(
|
||||||
(x) => x.objectId !== updateDocId
|
(x) => x.objectId !== updateDocId
|
||||||
);
|
);
|
||||||
setPdfData(updatedData);
|
props.setPdfData(updatedData);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@@ -292,14 +280,13 @@ function DriveBody({
|
|||||||
|
|
||||||
//component to handle type of document and render according to type
|
//component to handle type of document and render according to type
|
||||||
const handleFolderData = (data, ind, listType) => {
|
const handleFolderData = (data, ind, listType) => {
|
||||||
let createddate, status, isDecline, signerExist, isComplete, isPlaceholder;
|
let createddate, status, isDecline, signerExist, isComplete;
|
||||||
if (data.Type !== "Folder") {
|
if (data.Type !== "Folder") {
|
||||||
const expireDate = data.ExpiryDate && data.ExpiryDate.iso;
|
const expireDate = data.ExpiryDate && data.ExpiryDate.iso;
|
||||||
const createdDate = data.createdAt && data.createdAt;
|
const createdDate = data.createdAt && data.createdAt;
|
||||||
createddate = new Date(createdDate).toLocaleDateString();
|
createddate = new Date(createdDate).toLocaleDateString();
|
||||||
isComplete = data.IsCompleted && data.IsCompleted ? true : false;
|
isComplete = data.IsCompleted && data.IsCompleted ? true : false;
|
||||||
isDecline = data.IsDeclined && data.IsDeclined;
|
isDecline = data.IsDeclined && data.IsDeclined;
|
||||||
isPlaceholder = data.Placeholders && data.Placeholders;
|
|
||||||
signerExist = data.Signers && data.Signers;
|
signerExist = data.Signers && data.Signers;
|
||||||
const signedUrl = data.SignedUrl;
|
const signedUrl = data.SignedUrl;
|
||||||
|
|
||||||
@@ -314,18 +301,7 @@ function DriveBody({
|
|||||||
status = "Completed";
|
status = "Completed";
|
||||||
} else if (isDecline) {
|
} else if (isDecline) {
|
||||||
status = "Declined";
|
status = "Declined";
|
||||||
} else if (!signerExist || signerExist?.length === 0) {
|
} else if (!signedUrl) {
|
||||||
status = "Draft";
|
|
||||||
} else if (
|
|
||||||
signerExist?.length > 0 &&
|
|
||||||
(!isPlaceholder || isPlaceholder?.length === 0)
|
|
||||||
) {
|
|
||||||
status = "Draft";
|
|
||||||
} else if (
|
|
||||||
signerExist?.length > 0 &&
|
|
||||||
isPlaceholder?.length > 0 &&
|
|
||||||
!signedUrl
|
|
||||||
) {
|
|
||||||
status = "Draft";
|
status = "Draft";
|
||||||
} else if (isExpire) {
|
} else if (isExpire) {
|
||||||
status = "Expired";
|
status = "Expired";
|
||||||
@@ -584,7 +560,7 @@ function DriveBody({
|
|||||||
//component to handle type of document and render according to type
|
//component to handle type of document and render according to type
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isList ? (
|
{props.isList ? (
|
||||||
<div className="container" style={{ overflowX: "auto" }}>
|
<div className="container" style={{ overflowX: "auto" }}>
|
||||||
<Table striped bordered hover>
|
<Table striped bordered hover>
|
||||||
<thead>
|
<thead>
|
||||||
@@ -597,7 +573,7 @@ function DriveBody({
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{pdfData.map((data, ind) => {
|
{props.pdfData.map((data, ind) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={ind}>
|
<React.Fragment key={ind}>
|
||||||
{handleFolderData(data, ind, "table")}
|
{handleFolderData(data, ind, "table")}
|
||||||
@@ -609,7 +585,7 @@ function DriveBody({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="pdfContainer">
|
<div className="pdfContainer">
|
||||||
{pdfData.map((data, ind) => {
|
{props.pdfData.map((data, ind) => {
|
||||||
return (
|
return (
|
||||||
<div className="box" key={ind}>
|
<div className="box" key={ind}>
|
||||||
{handleFolderData(data, ind, "list")}
|
{handleFolderData(data, ind, "list")}
|
||||||
@@ -618,13 +594,14 @@ function DriveBody({
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isOpenMoveModal && (
|
{isOpenMoveModal && (
|
||||||
<SelectFolder
|
<FolderModal
|
||||||
onSuccess={handleMoveFolder}
|
onSuccess={handleMoveFolder}
|
||||||
isOpenModal={isOpenMoveModal}
|
isOpenModal={isOpenMoveModal}
|
||||||
folderCls={"contracts_Document"}
|
folderCls={"contracts_Document"}
|
||||||
setIsOpenMoveModal={setIsOpenMoveModal}
|
setIsOpenMoveModal={setIsOpenMoveModal}
|
||||||
setPdfData={setPdfData}
|
setPdfData={props.setPdfData}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ModalUi
|
<ModalUi
|
||||||
|
|||||||
@@ -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,7 +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 Upgrade from "../../primitives/Upgrade";
|
||||||
function DropdownWidgetOption(props) {
|
function DropdownWidgetOption(props) {
|
||||||
const [dropdownOptionList, setDropdownOptionList] = useState([
|
const [dropdownOptionList, setDropdownOptionList] = useState([
|
||||||
"option-1",
|
"option-1",
|
||||||
@@ -144,21 +146,15 @@ function DropdownWidgetOption(props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
//props.showDropdown
|
<ModalUi isOpen={props.showDropdown} title={props.title} showClose={false}>
|
||||||
<ModalUi
|
<div className="h-full p-[15px]">
|
||||||
// styleClass={"dropdownModal"}
|
|
||||||
isOpen={props.showDropdown}
|
|
||||||
title={props.title}
|
|
||||||
showClose={false}
|
|
||||||
>
|
|
||||||
<div style={{ height: "100%", padding: 20 }}>
|
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
onSubmit={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handleSaveOption();
|
handleSaveOption();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="dropdownContainer">
|
<div>
|
||||||
<label style={{ fontSize: "13px", fontWeight: "600" }}>
|
<label style={{ fontSize: "13px", fontWeight: "600" }}>
|
||||||
Name<span style={{ color: "red", fontSize: 13 }}> *</span>
|
Name<span style={{ color: "red", fontSize: 13 }}> *</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -246,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) && (
|
||||||
<>
|
<>
|
||||||
@@ -383,17 +402,24 @@ function DropdownWidgetOption(props) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{props.type === "checkbox" &&
|
||||||
|
!props.isSignYourself &&
|
||||||
|
!isEnableSubscription && (
|
||||||
|
<PremiumAlertHeader
|
||||||
|
message={
|
||||||
|
"Field validations are free in beta, this feature will incur a fee later."
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
style={{
|
className={`${
|
||||||
height: "1px",
|
props.type === "checkbox" && !props.isSignYourself
|
||||||
backgroundColor: "#9f9f9f",
|
? "mb-[15px]"
|
||||||
width: "100%",
|
: "my-[15px]"
|
||||||
marginTop: "15px",
|
} w-full h-[1px] bg-[#9f9f9f]`}
|
||||||
marginBottom: "15px"
|
|
||||||
}}
|
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
// onClick={() => handleSaveOption()}
|
|
||||||
disabled={dropdownOptionList.length === 0 && true}
|
disabled={dropdownOptionList.length === 0 && true}
|
||||||
style={{
|
style={{
|
||||||
background: themeColor,
|
background: themeColor,
|
||||||
|
|||||||
@@ -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],
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import PlaceholderBorder from "./PlaceholderBorder";
|
|||||||
import { Rnd } from "react-rnd";
|
import { Rnd } from "react-rnd";
|
||||||
import {
|
import {
|
||||||
defaultWidthHeight,
|
defaultWidthHeight,
|
||||||
|
handleCopyNextToWidget,
|
||||||
isMobile,
|
isMobile,
|
||||||
onChangeInput,
|
onChangeInput,
|
||||||
radioButtonWidget,
|
radioButtonWidget,
|
||||||
@@ -274,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);
|
||||||
}
|
}
|
||||||
@@ -302,8 +304,14 @@ function Placeholder(props) {
|
|||||||
props.setWidgetType(props.pos.type);
|
props.setWidgetType(props.pos.type);
|
||||||
props.setCurrWidgetsDetails(props.pos);
|
props.setCurrWidgetsDetails(props.pos);
|
||||||
};
|
};
|
||||||
//function ro set state value of onclick on widget's copy icon
|
//function to set required state value onclick on widget's copy icon
|
||||||
const handleCopyPlaceholder = (e) => {
|
const handleCopyPlaceholder = (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
//condition to handle text widget signer obj id and unique id
|
||||||
|
//when user click on copy icon of text widget in that condition text widget does not have any signerObjId
|
||||||
|
//in that case i have to save in tempSignerId as a unique id of previous select signer's unique id
|
||||||
|
//and on save or cancel button of copy all page popup i have set this temp signer Id in unique id
|
||||||
|
|
||||||
if (props.data && props?.pos?.type !== textWidget) {
|
if (props.data && props?.pos?.type !== textWidget) {
|
||||||
props.setSignerObjId(props?.data?.signerObjId);
|
props.setSignerObjId(props?.data?.signerObjId);
|
||||||
props.setUniqueId(props?.data?.Id);
|
props.setUniqueId(props?.data?.Id);
|
||||||
@@ -312,9 +320,24 @@ function Placeholder(props) {
|
|||||||
props.setSignerObjId(props?.data?.signerObjId);
|
props.setSignerObjId(props?.data?.signerObjId);
|
||||||
props.setUniqueId(props?.data?.Id);
|
props.setUniqueId(props?.data?.Id);
|
||||||
}
|
}
|
||||||
e.stopPropagation();
|
|
||||||
props.setIsPageCopy(true);
|
//checking widget's type and open widget copy modal for required widgets
|
||||||
props.setSignKey(props.pos.key);
|
if (
|
||||||
|
["signature", textWidget, "stamp", "initial"].includes(props.pos.type)
|
||||||
|
) {
|
||||||
|
props.setIsPageCopy(true);
|
||||||
|
props.setSignKey(props.pos.key);
|
||||||
|
} else {
|
||||||
|
//function to create new widget next to just widget
|
||||||
|
handleCopyNextToWidget(
|
||||||
|
props.pos,
|
||||||
|
props.pos.type,
|
||||||
|
props.xyPostion,
|
||||||
|
props.index,
|
||||||
|
props.setXyPostion,
|
||||||
|
props.data && props.data?.Id
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//function to save date and format on local array onchange date and onclick format
|
//function to save date and format on local array onchange date and onclick format
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
getMonth,
|
getMonth,
|
||||||
getYear,
|
getYear,
|
||||||
isMobile,
|
isMobile,
|
||||||
|
onChangeHeightOfTextArea,
|
||||||
onChangeInput,
|
onChangeInput,
|
||||||
radioButtonWidget,
|
radioButtonWidget,
|
||||||
range,
|
range,
|
||||||
@@ -285,11 +286,28 @@ function PlaceholderType(props) {
|
|||||||
};
|
};
|
||||||
props.handleSaveDate(dateObj, isDateChange);
|
props.handleSaveDate(dateObj, isDateChange);
|
||||||
};
|
};
|
||||||
|
//handle height on enter press in text area
|
||||||
|
const handleEnterPress = (e) => {
|
||||||
|
const height = 15;
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
//function to save height of text area
|
||||||
|
onChangeHeightOfTextArea(
|
||||||
|
height,
|
||||||
|
props.pos.type,
|
||||||
|
props.pos.key,
|
||||||
|
props.xyPostion,
|
||||||
|
props.index,
|
||||||
|
props.setXyPostion,
|
||||||
|
props.data && props.data?.Id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "signature":
|
case "signature":
|
||||||
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%",
|
||||||
@@ -311,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%",
|
||||||
@@ -336,7 +355,7 @@ function PlaceholderType(props) {
|
|||||||
<div key={ind} className="flex items-center text-center gap-0.5">
|
<div key={ind} className="flex items-center text-center gap-0.5">
|
||||||
<input
|
<input
|
||||||
style={{
|
style={{
|
||||||
width: props.pos.Width,
|
// width: props.pos.Width,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
marginTop: ind === 0 ? 0 : "5px"
|
marginTop: ind === 0 ? 0 : "5px"
|
||||||
@@ -443,7 +462,7 @@ function PlaceholderType(props) {
|
|||||||
>
|
>
|
||||||
{/* Default/Title option */}
|
{/* Default/Title option */}
|
||||||
<option value="" disabled hidden>
|
<option value="" disabled hidden>
|
||||||
{props.pos.options.name}
|
{props?.pos?.options?.name}
|
||||||
</option>
|
</option>
|
||||||
|
|
||||||
{props.pos?.options?.values.map((data, ind) => {
|
{props.pos?.options?.values.map((data, ind) => {
|
||||||
@@ -466,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%",
|
||||||
@@ -651,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%",
|
||||||
@@ -741,6 +762,7 @@ function PlaceholderType(props) {
|
|||||||
<textarea
|
<textarea
|
||||||
placeholder="Enter label"
|
placeholder="Enter label"
|
||||||
rows={1}
|
rows={1}
|
||||||
|
onKeyDown={handleEnterPress}
|
||||||
value={textValue}
|
value={textValue}
|
||||||
onBlur={handleInputBlur}
|
onBlur={handleInputBlur}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
@@ -769,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%",
|
||||||
|
|||||||
@@ -1,36 +1,15 @@
|
|||||||
import React, { useRef, useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import { darkenColor, getFirstLetter } from "../../constant/Utils";
|
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||||
|
import {
|
||||||
|
color,
|
||||||
|
darkenColor,
|
||||||
|
getFirstLetter,
|
||||||
|
isMobile,
|
||||||
|
nameColor
|
||||||
|
} from "../../constant/Utils";
|
||||||
|
|
||||||
const RecipientList = (props) => {
|
const RecipientList = (props) => {
|
||||||
const color = [
|
const [animationParent] = useAutoAnimate();
|
||||||
"#93a3db",
|
|
||||||
"#e6c3db",
|
|
||||||
"#c0e3bc",
|
|
||||||
"#bce3db",
|
|
||||||
"#b8ccdb",
|
|
||||||
"#ceb8db",
|
|
||||||
"#ffccff",
|
|
||||||
"#99ffcc",
|
|
||||||
"#cc99ff",
|
|
||||||
"#ffcc99",
|
|
||||||
"#66ccff",
|
|
||||||
"#ffffcc"
|
|
||||||
];
|
|
||||||
|
|
||||||
const nameColor = [
|
|
||||||
"#304fbf",
|
|
||||||
"#7d5270",
|
|
||||||
"#5f825b",
|
|
||||||
"#578077",
|
|
||||||
"#576e80",
|
|
||||||
"#6d527d",
|
|
||||||
"#cc00cc",
|
|
||||||
"#006666",
|
|
||||||
"#cc00ff",
|
|
||||||
"#ff9900",
|
|
||||||
"#336699",
|
|
||||||
"#cc9900"
|
|
||||||
];
|
|
||||||
const [isHover, setIsHover] = useState();
|
const [isHover, setIsHover] = useState();
|
||||||
const [isEdit, setIsEdit] = useState(false);
|
const [isEdit, setIsEdit] = useState(false);
|
||||||
//function for onhover signer name change background color
|
//function for onhover signer name change background color
|
||||||
@@ -63,27 +42,100 @@ const RecipientList = (props) => {
|
|||||||
return props.signerPos.some((x) => x.Id === Id);
|
return props.signerPos.some((x) => x.Id === Id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//handle drag start
|
||||||
|
const handleDragStart = (e, id) => {
|
||||||
|
// `e.dataTransfer.setData('text/plain')`is used to set the data to be transferred during a drag operation.
|
||||||
|
// The first argument specifies the type of data being set, and the second argument is the actual data you want to transfer.
|
||||||
|
e.dataTransfer.setData("text/plain", id);
|
||||||
|
};
|
||||||
|
|
||||||
|
//handleDragOver prevents the default behavior of the dragover event, which is necessary for the drop event to be triggered.
|
||||||
|
const handleDragOver = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
//handle draggable element drop and also used in mobile view on up and down key to chnage sequence of recipient's list
|
||||||
|
const handleChangeSequence = (e, ind, isUp, isDown) => {
|
||||||
|
e.preventDefault();
|
||||||
|
let draggedItemId;
|
||||||
|
let index = ind;
|
||||||
|
|
||||||
|
//if isUp true then set item's id and index in mobile view
|
||||||
|
if (isUp) {
|
||||||
|
draggedItemId = index;
|
||||||
|
index = index - 1;
|
||||||
|
}
|
||||||
|
//if isDown true then set item's id and index in mobile view
|
||||||
|
else if (isDown) {
|
||||||
|
draggedItemId = index;
|
||||||
|
index = index + 1;
|
||||||
|
} //else set id on drag element in desktop viiew
|
||||||
|
else {
|
||||||
|
//`e.dataTransfer.getData('text/plain')` is used to get data that you have saved.
|
||||||
|
draggedItemId = e.dataTransfer.getData("text/plain");
|
||||||
|
}
|
||||||
|
|
||||||
|
//convert string to number
|
||||||
|
const intDragId = parseInt(draggedItemId);
|
||||||
|
//get that item to change position
|
||||||
|
const draggedItem = props.signersdata.filter((_, ind) => ind === intDragId);
|
||||||
|
const remainingItems = props.signersdata.filter(
|
||||||
|
(_, ind) => ind !== intDragId
|
||||||
|
);
|
||||||
|
//splice method is used to replace or add new value in array at specific index
|
||||||
|
remainingItems.splice(index, 0, ...draggedItem);
|
||||||
|
|
||||||
|
//set current draggable recipient details,objectId,index,contract_className ... after replace recipient list
|
||||||
|
props.setSignersData(remainingItems);
|
||||||
|
props.setSignerObjId(remainingItems[index]?.objectId || "");
|
||||||
|
props.setIsSelectId(index);
|
||||||
|
props.setContractName(remainingItems[index]?.className || "");
|
||||||
|
props.setUniqueId(remainingItems[index]?.Id);
|
||||||
|
props.setRoleName(remainingItems[index]?.Role);
|
||||||
|
props.setBlockColor(remainingItems[index]?.blockColor);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{props.signersdata.length > 0 &&
|
{props.signersdata.length > 0 &&
|
||||||
props.signersdata.map((obj, ind) => {
|
props.signersdata.map((obj, ind) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
ref={animationParent}
|
||||||
|
key={ind}
|
||||||
|
draggable={props.sendInOrder && !isMobile ? true : false}
|
||||||
|
onDragStart={(e) =>
|
||||||
|
props.sendInOrder && !isMobile && handleDragStart(e, ind)
|
||||||
|
}
|
||||||
|
onDragOver={(e) =>
|
||||||
|
props.sendInOrder && !isMobile && handleDragOver(e)
|
||||||
|
}
|
||||||
|
onDrop={(e) =>
|
||||||
|
props.sendInOrder && !isMobile && handleChangeSequence(e, ind)
|
||||||
|
}
|
||||||
data-tut="reactourFirst"
|
data-tut="reactourFirst"
|
||||||
onMouseEnter={() => setIsHover(ind)}
|
onMouseEnter={() => setIsHover(ind)}
|
||||||
onMouseLeave={() => setIsHover(null)}
|
onMouseLeave={() => setIsHover(null)}
|
||||||
key={ind}
|
className={
|
||||||
|
props.sendInOrder
|
||||||
|
? props.isMailSend
|
||||||
|
? "disabled"
|
||||||
|
: "dragCursor"
|
||||||
|
: props.isMailSend && "disabled"
|
||||||
|
}
|
||||||
style={
|
style={
|
||||||
isHover === ind || props.isSelectListId === ind
|
(!isMobile && isHover === ind) || props.isSelectListId === ind
|
||||||
? onHoverStyle(ind, obj.blockColor)
|
? onHoverStyle(ind, obj?.blockColor)
|
||||||
: nonHoverStyle(ind)
|
: nonHoverStyle(ind)
|
||||||
}
|
}
|
||||||
onClick={() => {
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
props.setSignerObjId(obj?.objectId || "");
|
props.setSignerObjId(obj?.objectId || "");
|
||||||
props.setIsSelectId(ind);
|
props.setIsSelectId(ind);
|
||||||
props.setContractName(obj?.className || "");
|
props.setContractName(obj?.className || "");
|
||||||
props.setUniqueId(obj.Id);
|
props.setUniqueId(obj.Id);
|
||||||
props.setRoleName(obj.Role);
|
props.setRoleName(obj.Role);
|
||||||
|
props.setBlockColor(obj?.blockColor);
|
||||||
if (props.handleModal) {
|
if (props.handleModal) {
|
||||||
props.handleModal();
|
props.handleModal();
|
||||||
}
|
}
|
||||||
@@ -98,10 +150,9 @@ const RecipientList = (props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="signerStyle"
|
|
||||||
style={{
|
style={{
|
||||||
background: obj.blockColor
|
background: obj?.blockColor
|
||||||
? darkenColor(obj.blockColor, 0.4)
|
? darkenColor(obj?.blockColor, 0.4)
|
||||||
: nameColor[ind % nameColor.length],
|
: nameColor[ind % nameColor.length],
|
||||||
width: 30,
|
width: 30,
|
||||||
height: 30,
|
height: 30,
|
||||||
@@ -113,6 +164,7 @@ const RecipientList = (props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
className={props.sendInOrder && "dragCursor"}
|
||||||
style={{
|
style={{
|
||||||
fontSize: "12px",
|
fontSize: "12px",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
@@ -140,13 +192,12 @@ const RecipientList = (props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{obj.Name ? (
|
{obj.Name ? (
|
||||||
<span className="userName" style={{ cursor: "default" }}>
|
<span className={"userName"}>{obj.Name}</span>
|
||||||
{obj.Name}
|
|
||||||
</span>
|
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<span
|
<span
|
||||||
className="userName"
|
className="userName"
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsEdit({ [obj.Id]: true });
|
setIsEdit({ [obj.Id]: true });
|
||||||
props.setRoleName(obj.Role);
|
props.setRoleName(obj.Role);
|
||||||
@@ -157,7 +208,8 @@ const RecipientList = (props) => {
|
|||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "transparent",
|
backgroundColor: "transparent",
|
||||||
width: "inherit"
|
width: "inherit",
|
||||||
|
padding: "3px"
|
||||||
}}
|
}}
|
||||||
value={obj.Role}
|
value={obj.Role}
|
||||||
onChange={(e) => props.handleRoleChange(e, obj.Id)}
|
onChange={(e) => props.handleRoleChange(e, obj.Id)}
|
||||||
@@ -173,25 +225,57 @@ const RecipientList = (props) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
obj.Role
|
<span style={{ padding: "3px" }}>{obj.Role}</span>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{obj.Name && (
|
{obj.Name && <span className={"useEmail"}>{obj.Role}</span>}
|
||||||
<span className="useEmail" style={{ cursor: "default" }}>
|
|
||||||
{obj.Role}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{isMobile && props.sendInOrder && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 5
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
onClick={(e) => {
|
||||||
|
if (ind !== 0) {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleChangeSequence(e, ind, "up");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{ color: ind === 0 ? "gray" : "black" }}
|
||||||
|
>
|
||||||
|
▲
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
onClick={(e) => {
|
||||||
|
if (ind !== props.signersdata.length - 1) {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleChangeSequence(e, ind, null, "down");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
color:
|
||||||
|
ind === props.signersdata.length - 1 ? "gray" : "black"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
▼
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{props.handleDeleteUser && (
|
{props.handleDeleteUser && (
|
||||||
<div
|
<div
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
props.handleDeleteUser(obj.Id);
|
props.handleDeleteUser(obj.Id);
|
||||||
}}
|
}}
|
||||||
style={{ cursor: "pointer" }}
|
style={{ cursor: "pointer", marginLeft: "5px" }}
|
||||||
>
|
>
|
||||||
<i className="fa-regular fa-trash-can"></i>
|
<i className="fa-regular fa-trash-can"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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,11 +67,10 @@ 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 = () => {
|
||||||
// canvasRef.current.backgroundColor = 'rgb(165, 26, 26)'
|
|
||||||
setSignature(canvasRef.current.toDataURL());
|
setSignature(canvasRef.current.toDataURL());
|
||||||
setIsSignImg(canvasRef.current.toDataURL());
|
setIsSignImg(canvasRef.current.toDataURL());
|
||||||
};
|
};
|
||||||
@@ -101,28 +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 {
|
||||||
setIsSignImg("");
|
onSaveSign(signatureType);
|
||||||
onSaveSign();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setPenColor("blue");
|
setPenColor("blue");
|
||||||
} else {
|
} else {
|
||||||
setIsSignImg("");
|
setIsSignImg("");
|
||||||
onSaveImage();
|
onSaveImage(signatureType);
|
||||||
}
|
}
|
||||||
setIsSignPad(false);
|
setIsSignPad(false);
|
||||||
setIsInitial(false);
|
setIsInitial(false);
|
||||||
@@ -152,7 +146,35 @@ 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(() => {
|
||||||
|
if (currWidgetsDetails && canvasRef.current) {
|
||||||
|
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 firstCharacter = trimmedName.charAt(0);
|
||||||
|
const userName = isInitial ? firstCharacter : currentUserName;
|
||||||
|
setSignValue(userName);
|
||||||
|
setFontSelect("Fasthand");
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [isSignPad]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadFont = async () => {
|
const loadFont = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -186,7 +208,7 @@ function SignPad({
|
|||||||
}, [isTab]);
|
}, [isTab]);
|
||||||
|
|
||||||
//function for convert input text value in image
|
//function for convert input text value in image
|
||||||
const convertToImg = async (fontStyle, text) => {
|
const convertToImg = async (fontStyle, text, color) => {
|
||||||
//get text content to convert in image
|
//get text content to convert in image
|
||||||
const textContent = text;
|
const textContent = text;
|
||||||
const fontfamily = fontStyle
|
const fontfamily = fontStyle
|
||||||
@@ -199,6 +221,7 @@ function SignPad({
|
|||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.textContent = textContent;
|
span.textContent = textContent;
|
||||||
span.style.font = `20px ${fontfamily}`; // here put your text size and font family
|
span.style.font = `20px ${fontfamily}`; // here put your text size and font family
|
||||||
|
span.style.color = color ? color : penColor;
|
||||||
span.style.display = "hidden";
|
span.style.display = "hidden";
|
||||||
document.body.appendChild(span); // Replace 'container' with the ID of the container element
|
document.body.appendChild(span); // Replace 'container' with the ID of the container element
|
||||||
|
|
||||||
@@ -216,13 +239,9 @@ function SignPad({
|
|||||||
canvasElement.width = width * pixelRatio;
|
canvasElement.width = width * pixelRatio;
|
||||||
canvasElement.height = height * pixelRatio;
|
canvasElement.height = height * pixelRatio;
|
||||||
|
|
||||||
// Render the content of the span onto the canvas
|
|
||||||
// ctx.fillStyle = "white"; // Set the background color of the canvas
|
|
||||||
// ctx.fillRect(0, 0, width*pixelRatio, height*pixelRatio);
|
|
||||||
|
|
||||||
// You can customize text styles if needed
|
// You can customize text styles if needed
|
||||||
ctx.font = font;
|
ctx.font = font;
|
||||||
ctx.fillStyle = "black"; // Set the text color
|
ctx.fillStyle = color ? color : penColor; // Set the text color
|
||||||
ctx.textAlign = "center";
|
ctx.textAlign = "center";
|
||||||
ctx.textBaseline = "middle";
|
ctx.textBaseline = "middle";
|
||||||
ctx.scale(pixelRatio, pixelRatio);
|
ctx.scale(pixelRatio, pixelRatio);
|
||||||
@@ -235,6 +254,45 @@ function SignPad({
|
|||||||
setSignature(dataUrl);
|
setSignature(dataUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PenColorComponent = (props) => {
|
||||||
|
return (
|
||||||
|
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||||
|
{allColor.map((data, key) => {
|
||||||
|
return (
|
||||||
|
<i
|
||||||
|
style={{
|
||||||
|
margin: "5px",
|
||||||
|
color: data,
|
||||||
|
borderBottom:
|
||||||
|
key === 0 && penColor === "blue"
|
||||||
|
? "2px solid blue"
|
||||||
|
: key === 1 && penColor === "red"
|
||||||
|
? "2px solid red"
|
||||||
|
: key === 2 && penColor === "black"
|
||||||
|
? "2px solid black"
|
||||||
|
: "2px solid white"
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
props?.convertToImg &&
|
||||||
|
props?.convertToImg(fontSelect, signValue, data);
|
||||||
|
if (key === 0) {
|
||||||
|
setPenColor("blue");
|
||||||
|
} else if (key === 1) {
|
||||||
|
setPenColor("red");
|
||||||
|
} else if (key === 2) {
|
||||||
|
setPenColor("black");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
key={key}
|
||||||
|
className="fa solid fa-pen-nib"
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
></i>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{isSignPad && (
|
{isSignPad && (
|
||||||
@@ -303,6 +361,7 @@ function SignPad({
|
|||||||
setIsDefaultSign(false);
|
setIsDefaultSign(false);
|
||||||
setIsImageSelect(true);
|
setIsImageSelect(true);
|
||||||
setIsTab("uploadImage");
|
setIsTab("uploadImage");
|
||||||
|
setSignatureType("");
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
color:
|
color:
|
||||||
@@ -327,6 +386,7 @@ function SignPad({
|
|||||||
setIsDefaultSign(false);
|
setIsDefaultSign(false);
|
||||||
setIsImageSelect(false);
|
setIsImageSelect(false);
|
||||||
setIsTab("type");
|
setIsTab("type");
|
||||||
|
setSignatureType("");
|
||||||
setImage();
|
setImage();
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
@@ -354,6 +414,7 @@ function SignPad({
|
|||||||
setIsDefaultSign(true);
|
setIsDefaultSign(true);
|
||||||
setIsImageSelect(true);
|
setIsImageSelect(true);
|
||||||
setIsTab("mysignature");
|
setIsTab("mysignature");
|
||||||
|
setSignatureType("");
|
||||||
setImage();
|
setImage();
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
@@ -384,6 +445,7 @@ function SignPad({
|
|||||||
setIsDefaultSign(true);
|
setIsDefaultSign(true);
|
||||||
setIsImageSelect(true);
|
setIsImageSelect(true);
|
||||||
setIsTab("mysignature");
|
setIsTab("mysignature");
|
||||||
|
setSignatureType("");
|
||||||
setImage();
|
setImage();
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
@@ -423,6 +485,7 @@ function SignPad({
|
|||||||
setIsDefaultSign(false);
|
setIsDefaultSign(false);
|
||||||
setImage();
|
setImage();
|
||||||
setIsTab("draw");
|
setIsTab("draw");
|
||||||
|
setSignatureType("draw");
|
||||||
setSignValue("");
|
setSignValue("");
|
||||||
setIsStamp(false);
|
setIsStamp(false);
|
||||||
}}
|
}}
|
||||||
@@ -457,6 +520,7 @@ function SignPad({
|
|||||||
background: "rgb(255, 255, 255)",
|
background: "rgb(255, 255, 255)",
|
||||||
objectFit: "contain"
|
objectFit: "contain"
|
||||||
}}
|
}}
|
||||||
|
draggable="false"
|
||||||
src={isInitial ? myInitial : defaultSign}
|
src={isInitial ? myInitial : defaultSign}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -517,6 +581,7 @@ function SignPad({
|
|||||||
alt="print img"
|
alt="print img"
|
||||||
ref={imageRef}
|
ref={imageRef}
|
||||||
src={image.src}
|
src={image.src}
|
||||||
|
draggable="false"
|
||||||
style={{
|
style={{
|
||||||
objectFit: "contain",
|
objectFit: "contain",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
@@ -547,7 +612,7 @@ function SignPad({
|
|||||||
|
|
||||||
<input
|
<input
|
||||||
maxLength={isInitial ? 3 : 30}
|
maxLength={isInitial ? 3 : 30}
|
||||||
style={{ fontFamily: fontSelect }}
|
style={{ fontFamily: fontSelect, color: penColor }}
|
||||||
type="text"
|
type="text"
|
||||||
className="signatureInput"
|
className="signatureInput"
|
||||||
placeholder="Your signature"
|
placeholder="Your signature"
|
||||||
@@ -578,7 +643,8 @@ function SignPad({
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
padding: "5px 10px 5px 10px",
|
padding: "5px 10px 5px 10px",
|
||||||
fontSize: "20px"
|
fontSize: "20px",
|
||||||
|
color: penColor
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{signValue ? signValue : "Your signature"}
|
{signValue ? signValue : "Your signature"}
|
||||||
@@ -588,7 +654,15 @@ function SignPad({
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: "flex", justifyContent: "flex-end" }}>
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
marginTop: "10px"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PenColorComponent convertToImg={convertToImg} />
|
||||||
<SaveBtn />
|
<SaveBtn />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -622,39 +696,7 @@ function SignPad({
|
|||||||
marginTop: "10px"
|
marginTop: "10px"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
<PenColorComponent />
|
||||||
{allColor.map((data, key) => {
|
|
||||||
return (
|
|
||||||
<i
|
|
||||||
style={{
|
|
||||||
margin: "5px",
|
|
||||||
color: data,
|
|
||||||
borderBottom:
|
|
||||||
key === 0 && penColor === "blue"
|
|
||||||
? "2px solid blue"
|
|
||||||
: key === 1 && penColor === "red"
|
|
||||||
? "2px solid red"
|
|
||||||
: key === 2 && penColor === "black"
|
|
||||||
? "2px solid black"
|
|
||||||
: "2px solid white"
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
if (key === 0) {
|
|
||||||
setPenColor("blue");
|
|
||||||
} else if (key === 1) {
|
|
||||||
setPenColor("red");
|
|
||||||
} else if (key === 2) {
|
|
||||||
setPenColor("black");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
key={key}
|
|
||||||
className="fa solid fa-pen-nib"
|
|
||||||
width={20}
|
|
||||||
height={20}
|
|
||||||
></i>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
<SaveBtn />
|
<SaveBtn />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -34,8 +34,11 @@ function WidgetComponent({
|
|||||||
handleRoleChange,
|
handleRoleChange,
|
||||||
handleOnBlur,
|
handleOnBlur,
|
||||||
title,
|
title,
|
||||||
|
setSignersData,
|
||||||
isTemplateFlow
|
sendInOrder,
|
||||||
|
isTemplateFlow,
|
||||||
|
setBlockColor,
|
||||||
|
blockColor
|
||||||
}) {
|
}) {
|
||||||
const [isSignersModal, setIsSignersModal] = useState(false);
|
const [isSignersModal, setIsSignersModal] = useState(false);
|
||||||
|
|
||||||
@@ -233,14 +236,14 @@ function WidgetComponent({
|
|||||||
(data) =>
|
(data) =>
|
||||||
data.type !== "dropdown" &&
|
data.type !== "dropdown" &&
|
||||||
data.type !== radioButtonWidget &&
|
data.type !== radioButtonWidget &&
|
||||||
data.type !== textWidget
|
data.type !== textInputWidget
|
||||||
);
|
);
|
||||||
const textWidgetData = widget.filter((data) => data.type !== textWidget);
|
const textWidgetData = widget.filter((data) => data.type !== textWidget);
|
||||||
const updateWidgets = isSignYourself
|
const updateWidgets = isSignYourself
|
||||||
? filterWidgets
|
? filterWidgets
|
||||||
: isTemplateFlow
|
: isTemplateFlow
|
||||||
? textWidgetData
|
? textWidgetData
|
||||||
: widget;
|
: widget;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -256,9 +259,11 @@ function WidgetComponent({
|
|||||||
<div
|
<div
|
||||||
data-tut={dataTut}
|
data-tut={dataTut}
|
||||||
style={{
|
style={{
|
||||||
background: isSelectListId
|
background: blockColor
|
||||||
? color[isSelectListId % color.length]
|
? blockColor
|
||||||
: color[0],
|
: isSelectListId
|
||||||
|
? color[isSelectListId % color.length]
|
||||||
|
: color[0],
|
||||||
padding: "10px 20px",
|
padding: "10px 20px",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
@@ -359,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,
|
||||||
@@ -386,20 +396,25 @@ function WidgetComponent({
|
|||||||
handleClose={handleModal}
|
handleClose={handleModal}
|
||||||
>
|
>
|
||||||
{signersdata.length > 0 ? (
|
{signersdata.length > 0 ? (
|
||||||
<RecipientList
|
<div style={{ maxHeight: "600px", overflow: "auto" }}>
|
||||||
signerPos={signerPos}
|
<RecipientList
|
||||||
signersdata={signersdata}
|
signerPos={signerPos}
|
||||||
isSelectListId={isSelectListId}
|
signersdata={signersdata}
|
||||||
setSignerObjId={setSignerObjId}
|
isSelectListId={isSelectListId}
|
||||||
setIsSelectId={setIsSelectId}
|
setSignerObjId={setSignerObjId}
|
||||||
setContractName={setContractName}
|
setIsSelectId={setIsSelectId}
|
||||||
setUniqueId={setUniqueId}
|
setContractName={setContractName}
|
||||||
setRoleName={setRoleName}
|
setUniqueId={setUniqueId}
|
||||||
handleDeleteUser={handleDeleteUser}
|
setRoleName={setRoleName}
|
||||||
handleRoleChange={handleRoleChange}
|
handleDeleteUser={handleDeleteUser}
|
||||||
handleOnBlur={handleOnBlur}
|
handleRoleChange={handleRoleChange}
|
||||||
handleModal={handleModal}
|
handleOnBlur={handleOnBlur}
|
||||||
/>
|
handleModal={handleModal}
|
||||||
|
sendInOrder={sendInOrder}
|
||||||
|
setSignersData={setSignersData}
|
||||||
|
setBlockColor={setBlockColor}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ import ModalUi from "../../primitives/ModalUi";
|
|||||||
import "../../styles/AddUser.css";
|
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 Upgrade from "../../primitives/Upgrade";
|
||||||
|
import { isEnableSubscription } from "../../constant/const";
|
||||||
|
|
||||||
const WidgetNameModal = (props) => {
|
const WidgetNameModal = (props) => {
|
||||||
const [formdata, setFormdata] = useState({
|
const [formdata, setFormdata] = useState({
|
||||||
@@ -14,7 +17,7 @@ const WidgetNameModal = (props) => {
|
|||||||
});
|
});
|
||||||
const [isValid, setIsValid] = useState(true);
|
const [isValid, setIsValid] = useState(true);
|
||||||
const statusArr = ["Required", "Optional"];
|
const statusArr = ["Required", "Optional"];
|
||||||
const inputOpt = ["email", "number"];
|
const inputOpt = ["text", "email", "number"];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.defaultdata) {
|
if (props.defaultdata) {
|
||||||
@@ -70,7 +73,7 @@ const WidgetNameModal = (props) => {
|
|||||||
return "/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/";
|
return "/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/";
|
||||||
case "number":
|
case "number":
|
||||||
return "/^\\d+$/";
|
return "/^\\d+$/";
|
||||||
case textInputWidget:
|
case "text":
|
||||||
return "/^[a-zA-Zs]+$/";
|
return "/^[a-zA-Zs]+$/";
|
||||||
default:
|
default:
|
||||||
return type;
|
return type;
|
||||||
@@ -98,7 +101,24 @@ const WidgetNameModal = (props) => {
|
|||||||
handleClose={props.handleClose && props.handleClose}
|
handleClose={props.handleClose && props.handleClose}
|
||||||
title={"Widget info"}
|
title={"Widget info"}
|
||||||
>
|
>
|
||||||
<form onSubmit={handleSubmit} style={{ padding: 20 }}>
|
{(props.defaultdata?.type === textInputWidget ||
|
||||||
|
props.widgetName === textInputWidget) &&
|
||||||
|
!isEnableSubscription && (
|
||||||
|
<PremiumAlertHeader
|
||||||
|
message={
|
||||||
|
"Field validations are free in beta, this feature will incur a fee later."
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<form
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
className={`${
|
||||||
|
props.defaultdata?.type === textInputWidget ||
|
||||||
|
props.widgetName === textInputWidget
|
||||||
|
? "pt-0"
|
||||||
|
: ""
|
||||||
|
} p-[20px]`}
|
||||||
|
>
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
<label htmlFor="name" style={{ fontSize: 13 }}>
|
||||||
Name
|
Name
|
||||||
@@ -116,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",
|
||||||
@@ -161,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
|
||||||
@@ -170,25 +201,25 @@ const WidgetNameModal = (props) => {
|
|||||||
name="defaultValue"
|
name="defaultValue"
|
||||||
value={formdata.defaultValue}
|
value={formdata.defaultValue}
|
||||||
onChange={(e) => handledefaultChange(e)}
|
onChange={(e) => handledefaultChange(e)}
|
||||||
onBlur={() =>
|
autoComplete="off"
|
||||||
isValid === false &&
|
onBlur={() => {
|
||||||
setFormdata({ ...formdata, defaultValue: "" })
|
if (isValid === false) {
|
||||||
}
|
setFormdata({ ...formdata, defaultValue: "" });
|
||||||
|
setIsValid(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
{isValid === false ? (
|
{isValid === false && (
|
||||||
<p style={{ color: "Red", fontSize: 8 }}>
|
<div
|
||||||
invalid default value
|
className="warning defaultvalueWarning"
|
||||||
</p>
|
style={{ fontSize: 12 }}
|
||||||
) : (
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
color: "transparent",
|
|
||||||
fontSize: 10,
|
|
||||||
margin: "3px 8px"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
.
|
<i
|
||||||
</p>
|
className="fas fa-exclamation-circle"
|
||||||
|
style={{ color: "#fab005", fontSize: 15 }}
|
||||||
|
></i>{" "}
|
||||||
|
invalid default value
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -0,0 +1,234 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import Parse from "parse";
|
||||||
|
import CreateFolder from "./CreateFolder";
|
||||||
|
import ModalUi from "../../../primitives/ModalUi";
|
||||||
|
|
||||||
|
const FolderModal = (props) => {
|
||||||
|
const [clickFolder, setClickFolder] = useState("");
|
||||||
|
const [folderList, setFolderList] = useState([]);
|
||||||
|
const [tabList, setTabList] = useState([]);
|
||||||
|
const [isLoader, setIsLoader] = useState(false);
|
||||||
|
const [isAdd, setIsAdd] = useState(false);
|
||||||
|
// below useEffect is called when user open popup
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.isOpenModal) {
|
||||||
|
fetchFolder();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line
|
||||||
|
}, [props.isOpenModal]);
|
||||||
|
|
||||||
|
// `fetchFolder` is used to fetch of folder list created by user on basis of folderPtr or without folderPtr
|
||||||
|
const fetchFolder = async (folderPtr) => {
|
||||||
|
setIsLoader(true);
|
||||||
|
try {
|
||||||
|
const FolderQuery = new Parse.Query(props.folderCls);
|
||||||
|
if (folderPtr) {
|
||||||
|
FolderQuery.equalTo("Folder", folderPtr);
|
||||||
|
FolderQuery.equalTo("Type", "Folder");
|
||||||
|
} else {
|
||||||
|
FolderQuery.doesNotExist("Folder");
|
||||||
|
FolderQuery.equalTo("Type", "Folder");
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await FolderQuery.find();
|
||||||
|
if (res) {
|
||||||
|
const result = JSON.parse(JSON.stringify(res));
|
||||||
|
if (result) {
|
||||||
|
setFolderList(result);
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// `handleSelect` is used to save pointer of folder selected by user and it's path in state
|
||||||
|
const handleSelect = (item) => {
|
||||||
|
setFolderList([]);
|
||||||
|
setClickFolder({ ObjectId: item.objectId, Name: item.Name });
|
||||||
|
if (tabList.length > 0) {
|
||||||
|
const tab = tabList.some((x) => x.objectId === item.objectId);
|
||||||
|
if (!tab) {
|
||||||
|
setTabList((tabs) => [...tabs, item]);
|
||||||
|
const folderPtr = {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: props.folderCls,
|
||||||
|
objectId: item.objectId
|
||||||
|
};
|
||||||
|
fetchFolder(folderPtr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setTabList((tabs) => [...tabs, item]);
|
||||||
|
const folderPtr = {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: props.folderCls,
|
||||||
|
objectId: item.objectId
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchFolder(folderPtr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// `handleSubmit` is used to pass folderPtr to parent component
|
||||||
|
const handleSubmit = () => {
|
||||||
|
let url = "OpenSign™ Drive";
|
||||||
|
tabList.forEach((t) => {
|
||||||
|
url = url + " / " + t.Name;
|
||||||
|
});
|
||||||
|
if (props.onSuccess) {
|
||||||
|
props.onSuccess(clickFolder);
|
||||||
|
}
|
||||||
|
// SetIsOpen(false);
|
||||||
|
props.setIsOpenMoveModal(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// `handleCancel` is used to clear list of folder, close popup and folderUrl
|
||||||
|
const handleCancel = () => {
|
||||||
|
// SetIsOpen(false);
|
||||||
|
props.setIsOpenMoveModal(false);
|
||||||
|
setClickFolder({});
|
||||||
|
setFolderList([]);
|
||||||
|
setTabList([]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// `handleCancel` is call when user click on folder name from path/tab in popup
|
||||||
|
const removeTabListItem = async (e, i) => {
|
||||||
|
e.preventDefault();
|
||||||
|
// setEditable(false);
|
||||||
|
if (!isAdd) {
|
||||||
|
setIsLoader(true);
|
||||||
|
let folderPtr;
|
||||||
|
if (i) {
|
||||||
|
setFolderList([]);
|
||||||
|
let list = tabList.filter((itm, j) => {
|
||||||
|
if (j <= i) {
|
||||||
|
return itm;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _len = list.length - 1;
|
||||||
|
folderPtr = {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: props.folderCls,
|
||||||
|
objectId: list[_len].objectId
|
||||||
|
};
|
||||||
|
setTabList(list);
|
||||||
|
} else {
|
||||||
|
setClickFolder({});
|
||||||
|
setFolderList([]);
|
||||||
|
setTabList([]);
|
||||||
|
}
|
||||||
|
fetchFolder(folderPtr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// `handleCreate` is used to open folder creation form in popup
|
||||||
|
const handleCreate = () => {
|
||||||
|
setIsAdd(!isAdd);
|
||||||
|
};
|
||||||
|
// `handleAddFolder` is call when user folder created successfully and it fetch folder list on the basis of folderPtr or without folderPtr
|
||||||
|
const handleAddFolder = (newFolder) => {
|
||||||
|
props.setPdfData((prev) => [...prev, newFolder?.toJSON()]);
|
||||||
|
if (clickFolder && clickFolder.ObjectId) {
|
||||||
|
fetchFolder({
|
||||||
|
__type: "Pointer",
|
||||||
|
className: props.folderCls,
|
||||||
|
objectId: clickFolder.ObjectId
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
fetchFolder();
|
||||||
|
}
|
||||||
|
handleCreate();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="text-xs mt-2 ">
|
||||||
|
<ModalUi
|
||||||
|
title={"Select Folder"}
|
||||||
|
isOpen={props.isOpenModal}
|
||||||
|
handleClose={handleCancel}
|
||||||
|
>
|
||||||
|
<div className="w-full min-w-[300px] md:min-w-[500px] max-w-[500px] px-3">
|
||||||
|
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
|
||||||
|
<span
|
||||||
|
className="cursor-pointer"
|
||||||
|
title="OpenSign™ Drive"
|
||||||
|
onClick={(e) => removeTabListItem(e)}
|
||||||
|
>
|
||||||
|
OpenSign™ Drive /{" "}
|
||||||
|
</span>
|
||||||
|
{tabList &&
|
||||||
|
tabList.map((tab, i) => (
|
||||||
|
<React.Fragment key={`${tab.objectId}-${i}`}>
|
||||||
|
<span
|
||||||
|
className="cursor-pointer"
|
||||||
|
title={tab.Name}
|
||||||
|
onClick={(e) => removeTabListItem(e, i)}
|
||||||
|
>
|
||||||
|
{tab.Name}
|
||||||
|
</span>
|
||||||
|
{" / "}
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
<div className="mt-2 mb-3">
|
||||||
|
<div className="max-h-[210px] overflow-auto">
|
||||||
|
{!isAdd &&
|
||||||
|
folderList.length > 0 &&
|
||||||
|
folderList.map((folder) => (
|
||||||
|
<div
|
||||||
|
key={folder.Name}
|
||||||
|
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer "
|
||||||
|
onClick={() => handleSelect(folder)}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<i
|
||||||
|
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
<span className="font-semibold">{folder.Name}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{isAdd && (
|
||||||
|
<CreateFolder
|
||||||
|
parentFolderId={clickFolder && clickFolder.ObjectId}
|
||||||
|
folderCls={props.folderCls}
|
||||||
|
onSuccess={handleAddFolder}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{isLoader && (
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
|
||||||
|
<div
|
||||||
|
className="text-[30px] cursor-pointer text-[#32a3ac]"
|
||||||
|
title="Save Here"
|
||||||
|
onClick={handleCreate}
|
||||||
|
>
|
||||||
|
{isAdd ? (
|
||||||
|
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
|
||||||
|
) : (
|
||||||
|
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="text-[30px] cursor-pointer"
|
||||||
|
title="Save Here"
|
||||||
|
onClick={handleSubmit}
|
||||||
|
>
|
||||||
|
<i className="fas fa-save" aria-hidden="true"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FolderModal;
|
||||||
@@ -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."
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Select from "react-select";
|
|||||||
import AddSigner from "../../AddSigner";
|
import AddSigner from "../../AddSigner";
|
||||||
import Modal from "react-modal";
|
import Modal from "react-modal";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
|
import Tooltip from "../../../primitives/Tooltip";
|
||||||
function arrayMove(array, from, to) {
|
function arrayMove(array, from, to) {
|
||||||
array = array.slice();
|
array = array.slice();
|
||||||
array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]);
|
array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]);
|
||||||
@@ -104,9 +105,15 @@ 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">
|
||||||
|
<Tooltip
|
||||||
|
id={"signer-tooltip"}
|
||||||
|
message={"Begin typing a contact's name to see suggested signers from your saved contacts or add new ones. Arrange the signing order by adding signers in the desired sequence. Use the '+' button to include signers and the 'x' to remove them. Each signer will receive an email prompt to sign the document in the order listed."}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<div style={{ display: "flex", gap: 5 }}>
|
<div style={{ display: "flex", gap: 5 }}>
|
||||||
<div style={{ flexWrap: "wrap", width: "100%" }}>
|
<div style={{ flexWrap: "wrap", width: "100%" }}>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const Menu = ({ item, isOpen, closeSidebar }) => {
|
|||||||
? `/${item.pageType}/${item.objectId}`
|
? `/${item.pageType}/${item.objectId}`
|
||||||
: `/${item.objectId}`
|
: `/${item.objectId}`
|
||||||
}
|
}
|
||||||
className="mx-auto flex items-center hover:bg-[#eef1f5] p-3 lg:p-4 cursor-pointer"
|
className="mx-auto flex items-center hover:bg-[#eef1f5] p-3 lg:p-4 cursor-pointer focus:text-[#0056b3] focus:bg-[#eef1f5]"
|
||||||
onClick={closeSidebar}
|
onClick={closeSidebar}
|
||||||
tabIndex={isOpen ? 0 : -1}
|
tabIndex={isOpen ? 0 : -1}
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const Submenu = ({ item, closeSidebar }) => {
|
|||||||
<li role="none">
|
<li role="none">
|
||||||
<button
|
<button
|
||||||
onClick={toggleSubmenu}
|
onClick={toggleSubmenu}
|
||||||
className="w-full flex items-center text-left text-[#444] p-3 lg:p-4 hover:bg-[#eef1f5] focus:ring-2 focus:ring-blue-600"
|
className="w-full flex items-center text-left text-[#444] p-3 lg:p-4 hover:bg-[#eef1f5] focus:outline-none focus:text-[#0056b3] focus:bg-[#eef1f5]"
|
||||||
aria-expanded={submenuOpen}
|
aria-expanded={submenuOpen}
|
||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
aria-controls={`submenu-${title}`}
|
aria-controls={`submenu-${title}`}
|
||||||
@@ -39,7 +39,7 @@ const Submenu = ({ item, closeSidebar }) => {
|
|||||||
? `/${childItem.pageType}/${childItem.objectId}`
|
? `/${childItem.pageType}/${childItem.objectId}`
|
||||||
: `/${childItem.objectId}`
|
: `/${childItem.objectId}`
|
||||||
}
|
}
|
||||||
className="block pl-6 md:pl-8 py-2 text-sm text-gray-700 hover:bg-blue-500 hover:text-white cursor-pointer"
|
className="block pl-6 md:pl-8 py-2 text-sm text-gray-700 hover:bg-blue-500 hover:text-white focus:text-[#0056b3] focus:bg-[#eef1f5] cursor-pointer"
|
||||||
onClick={closeSidebar}
|
onClick={closeSidebar}
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
tabIndex={submenuOpen ? 0 : -1}
|
tabIndex={submenuOpen ? 0 : -1}
|
||||||
|
|||||||
@@ -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,58 @@ 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 = [
|
||||||
|
"#93a3db",
|
||||||
|
"#e6c3db",
|
||||||
|
"#c0e3bc",
|
||||||
|
"#bce3db",
|
||||||
|
"#b8ccdb",
|
||||||
|
"#ceb8db",
|
||||||
|
"#ffccff",
|
||||||
|
"#99ffcc",
|
||||||
|
"#cc99ff",
|
||||||
|
"#ffcc99",
|
||||||
|
"#66ccff",
|
||||||
|
"#ffffcc"
|
||||||
|
];
|
||||||
|
|
||||||
|
export const nameColor = [
|
||||||
|
"#304fbf",
|
||||||
|
"#7d5270",
|
||||||
|
"#5f825b",
|
||||||
|
"#578077",
|
||||||
|
"#576e80",
|
||||||
|
"#6d527d",
|
||||||
|
"#cc00cc",
|
||||||
|
"#006666",
|
||||||
|
"#cc00ff",
|
||||||
|
"#ff9900",
|
||||||
|
"#336699",
|
||||||
|
"#cc9900"
|
||||||
|
];
|
||||||
export const toDataUrl = (file) => {
|
export const toDataUrl = (file) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
@@ -22,10 +75,12 @@ export const toDataUrl = (file) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//function for getting document details for getDrive
|
//function for getting document details for getDrive cloud function
|
||||||
export const getDrive = async (documentId) => {
|
export const getDrive = async (documentId, skip = 0, limit = 100) => {
|
||||||
const data = {
|
const data = {
|
||||||
docId: documentId && documentId
|
docId: documentId && documentId,
|
||||||
|
limit: limit,
|
||||||
|
skip: skip
|
||||||
};
|
};
|
||||||
const driveDeatils = await axios
|
const driveDeatils = await axios
|
||||||
.post(`${localStorage.getItem("baseUrl")}functions/getDrive`, data, {
|
.post(`${localStorage.getItem("baseUrl")}functions/getDrive`, data, {
|
||||||
@@ -729,6 +784,82 @@ export const onChangeInput = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//function to increase height of text area on press enter
|
||||||
|
export const onChangeHeightOfTextArea = (
|
||||||
|
height,
|
||||||
|
widgetType,
|
||||||
|
signKey,
|
||||||
|
xyPostion,
|
||||||
|
index,
|
||||||
|
setXyPostion,
|
||||||
|
userId
|
||||||
|
) => {
|
||||||
|
const isSigners = xyPostion.some((data) => data.signerPtr);
|
||||||
|
let filterSignerPos;
|
||||||
|
if (isSigners) {
|
||||||
|
if (userId) {
|
||||||
|
filterSignerPos = xyPostion.filter((data) => data.Id === userId);
|
||||||
|
}
|
||||||
|
const getPlaceHolder = filterSignerPos[0]?.placeHolder;
|
||||||
|
|
||||||
|
const getPageNumer = getPlaceHolder.filter(
|
||||||
|
(data) => data.pageNumber === index
|
||||||
|
);
|
||||||
|
if (getPageNumer.length > 0) {
|
||||||
|
const getXYdata = getPageNumer[0].pos;
|
||||||
|
const getPosData = getXYdata;
|
||||||
|
const addSignPos = getPosData.map((position) => {
|
||||||
|
if (position.key === signKey) {
|
||||||
|
return {
|
||||||
|
...position,
|
||||||
|
Height: position.Height
|
||||||
|
? position.Height + height
|
||||||
|
: defaultWidthHeight(widgetType).height + height
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return position;
|
||||||
|
});
|
||||||
|
const newUpdateSignPos = getPlaceHolder.map((obj) => {
|
||||||
|
if (obj.pageNumber === index) {
|
||||||
|
return { ...obj, pos: addSignPos };
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
|
||||||
|
const newUpdateSigner = xyPostion.map((obj) => {
|
||||||
|
if (obj.Id === userId) {
|
||||||
|
return { ...obj, placeHolder: newUpdateSignPos };
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
|
||||||
|
setXyPostion(newUpdateSigner);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let getXYdata = xyPostion[index].pos;
|
||||||
|
|
||||||
|
const updatePosition = getXYdata.map((position) => {
|
||||||
|
if (position.key === signKey) {
|
||||||
|
return {
|
||||||
|
...position,
|
||||||
|
Height: position.Height
|
||||||
|
? position.Height + height
|
||||||
|
: defaultWidthHeight(widgetType).height + height
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return position;
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatePlaceholder = xyPostion.map((obj, ind) => {
|
||||||
|
if (ind === index) {
|
||||||
|
return { ...obj, pos: updatePosition };
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
setXyPostion(updatePlaceholder);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const addInitialData = (signerPos, setXyPostion, value, userId) => {
|
export const addInitialData = (signerPos, setXyPostion, value, userId) => {
|
||||||
function widgetDataValue(type) {
|
function widgetDataValue(type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -828,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,
|
||||||
@@ -868,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
|
||||||
@@ -1078,8 +1211,8 @@ export const multiSignEmbed = async (
|
|||||||
position.type === radioButtonWidget
|
position.type === radioButtonWidget
|
||||||
? 10
|
? 10
|
||||||
: position.type === "checkbox"
|
: position.type === "checkbox"
|
||||||
? 10
|
? 10
|
||||||
: newUpdateHeight;
|
: newUpdateHeight;
|
||||||
const newHeight = ind ? (ind > 0 ? widgetHeight : 0) : widgetHeight;
|
const newHeight = ind ? (ind > 0 ? widgetHeight : 0) : widgetHeight;
|
||||||
|
|
||||||
if (signyourself) {
|
if (signyourself) {
|
||||||
@@ -1148,13 +1281,14 @@ export const multiSignEmbed = async (
|
|||||||
"email"
|
"email"
|
||||||
].includes(position.type);
|
].includes(position.type);
|
||||||
if (position.type === "checkbox") {
|
if (position.type === "checkbox") {
|
||||||
let addYPosition, isCheck;
|
let addYPosition = 0,
|
||||||
|
isCheck;
|
||||||
|
|
||||||
if (position?.options?.values.length > 0) {
|
if (position?.options?.values.length > 0) {
|
||||||
position?.options?.values.forEach((item, ind) => {
|
position?.options?.values.forEach((item, ind) => {
|
||||||
const checkboxRandomId = "checkbox" + randomId();
|
const checkboxRandomId = "checkbox" + randomId();
|
||||||
let yPosition;
|
let yPosition;
|
||||||
const height = 10;
|
const height = 13;
|
||||||
if (
|
if (
|
||||||
position?.options?.response &&
|
position?.options?.response &&
|
||||||
position?.options?.response?.length > 0
|
position?.options?.response?.length > 0
|
||||||
@@ -1175,14 +1309,14 @@ export const multiSignEmbed = async (
|
|||||||
if (!position?.options?.isHideLabel) {
|
if (!position?.options?.isHideLabel) {
|
||||||
// below line of code is used to embed label with radio button in pdf
|
// below line of code is used to embed label with radio button in pdf
|
||||||
page.drawText(item, {
|
page.drawText(item, {
|
||||||
x: xPos(position) + 15,
|
x: xPos(position) + 17,
|
||||||
y: yPosition + 2,
|
y: yPosition + 2,
|
||||||
size: height
|
size: height
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
checkbox.addToPage(page, {
|
checkbox.addToPage(page, {
|
||||||
x: xPos(position),
|
x: xPos(position),
|
||||||
y: yPosition,
|
y: yPosition - 3,
|
||||||
width: height,
|
width: height,
|
||||||
height: height
|
height: height
|
||||||
});
|
});
|
||||||
@@ -1203,19 +1337,21 @@ export const multiSignEmbed = async (
|
|||||||
} else if (position?.options?.defaultValue) {
|
} else if (position?.options?.defaultValue) {
|
||||||
textContent = position?.options?.defaultValue;
|
textContent = position?.options?.defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fixedWidth = scaleWidth; // Set your fixed width
|
const fixedWidth = scaleWidth; // Set your fixed width
|
||||||
|
const isNewOnEnterLineExist = textContent.includes("\n");
|
||||||
|
|
||||||
// Function to break text into lines based on the fixed width
|
// Function to break text into lines based on the fixed width
|
||||||
const breakTextIntoLines = (textContent, width) => {
|
const NewbreakTextIntoLines = (textContent, width) => {
|
||||||
const lines = [];
|
const lines = [];
|
||||||
let currentLine = "";
|
let currentLine = "";
|
||||||
|
|
||||||
for (const word of textContent.split(" ")) {
|
for (const word of textContent.split(" ")) {
|
||||||
|
//get text line width
|
||||||
const lineWidth = font.widthOfTextAtSize(
|
const lineWidth = font.widthOfTextAtSize(
|
||||||
`${currentLine} ${word}`,
|
`${currentLine} ${word}`,
|
||||||
fontSize
|
fontSize
|
||||||
);
|
);
|
||||||
|
//check text content line width is less or equal to container width
|
||||||
if (lineWidth <= width) {
|
if (lineWidth <= width) {
|
||||||
currentLine += ` ${word}`;
|
currentLine += ` ${word}`;
|
||||||
} else {
|
} else {
|
||||||
@@ -1226,7 +1362,33 @@ export const multiSignEmbed = async (
|
|||||||
lines.push(currentLine.trim());
|
lines.push(currentLine.trim());
|
||||||
return lines;
|
return lines;
|
||||||
};
|
};
|
||||||
const lines = breakTextIntoLines(textContent, fixedWidth);
|
|
||||||
|
// Function to break text into lines based on when user go next line on press enter button
|
||||||
|
const breakTextIntoLines = (textContent, width) => {
|
||||||
|
const lines = [];
|
||||||
|
|
||||||
|
for (const word of textContent.split("\n")) {
|
||||||
|
const lineWidth = font.widthOfTextAtSize(`${word}`, fontSize);
|
||||||
|
//checking string length to container width
|
||||||
|
//if string length is less then container width it means user press enter button
|
||||||
|
if (lineWidth <= width) {
|
||||||
|
lines.push(word);
|
||||||
|
}
|
||||||
|
//else adjust text content according to width and send it in new line
|
||||||
|
else {
|
||||||
|
const newLine = NewbreakTextIntoLines(word, width);
|
||||||
|
lines.push(...newLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
};
|
||||||
|
|
||||||
|
//check if text content have `\n` string it means user press enter to go next line and handle condition
|
||||||
|
//else auto adjust text content according to container width
|
||||||
|
const lines = isNewOnEnterLineExist
|
||||||
|
? breakTextIntoLines(textContent, fixedWidth)
|
||||||
|
: NewbreakTextIntoLines(textContent, fixedWidth);
|
||||||
// Set initial y-coordinate for the first line
|
// Set initial y-coordinate for the first line
|
||||||
const labelDefaultHeight = defaultWidthHeight(position.type).height;
|
const labelDefaultHeight = defaultWidthHeight(position.type).height;
|
||||||
|
|
||||||
@@ -1327,9 +1489,7 @@ export const multiSignEmbed = async (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const pdfBytes = await pdfDoc.saveAsBase64({ useObjectStreams: false });
|
const pdfBytes = await pdfDoc.saveAsBase64({ useObjectStreams: false });
|
||||||
|
|
||||||
return pdfBytes;
|
return pdfBytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1569,3 +1729,66 @@ export const getYear = (date) => {
|
|||||||
const newYear = new Date(date).getFullYear();
|
const newYear = new Date(date).getFullYear();
|
||||||
return newYear;
|
return newYear;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//function to create/copy widget next to already dropped widget
|
||||||
|
export const handleCopyNextToWidget = (
|
||||||
|
position,
|
||||||
|
widgetType,
|
||||||
|
xyPostion,
|
||||||
|
index,
|
||||||
|
setXyPostion,
|
||||||
|
userId
|
||||||
|
) => {
|
||||||
|
const isSigners = xyPostion.some((data) => data.signerPtr);
|
||||||
|
let filterSignerPos;
|
||||||
|
//get position of previous widget and create new widget next to that widget on same data except
|
||||||
|
// xPosition and key
|
||||||
|
let newpos = position;
|
||||||
|
const calculateXPosition =
|
||||||
|
parseInt(position.xPosition) +
|
||||||
|
defaultWidthHeight(widgetType).width +
|
||||||
|
resizeBorderExtraWidth();
|
||||||
|
const newId = randomId();
|
||||||
|
newpos = { ...newpos, xPosition: calculateXPosition, key: newId };
|
||||||
|
//if condition to create widget in request-sign flow
|
||||||
|
if (isSigners) {
|
||||||
|
if (userId) {
|
||||||
|
filterSignerPos = xyPostion.filter((data) => data.Id === userId);
|
||||||
|
}
|
||||||
|
const getPlaceHolder = filterSignerPos[0]?.placeHolder;
|
||||||
|
const getPageNumer = getPlaceHolder.filter(
|
||||||
|
(data) => data.pageNumber === index
|
||||||
|
);
|
||||||
|
const getXYdata = getPageNumer[0].pos;
|
||||||
|
getXYdata.push(newpos);
|
||||||
|
if (getPageNumer.length > 0) {
|
||||||
|
const newUpdateSignPos = getPlaceHolder.map((obj) => {
|
||||||
|
if (obj.pageNumber === index) {
|
||||||
|
return { ...obj, pos: getXYdata };
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
|
||||||
|
const newUpdateSigner = xyPostion.map((obj) => {
|
||||||
|
if (obj.Id === userId) {
|
||||||
|
return { ...obj, placeHolder: newUpdateSignPos };
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
|
||||||
|
setXyPostion(newUpdateSigner);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// else condition to create widget in sign-yourself flow
|
||||||
|
let getXYdata = xyPostion[index].pos;
|
||||||
|
getXYdata.push(newpos);
|
||||||
|
const updatePlaceholder = xyPostion.map((obj, ind) => {
|
||||||
|
if (ind === index) {
|
||||||
|
return { ...obj, pos: getXYdata };
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
|
||||||
|
setXyPostion(updatePlaceholder);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -18,7 +18,8 @@ export default function reportJson(id) {
|
|||||||
btnIcon: "fa fa-plus",
|
btnIcon: "fa fa-plus",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
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":
|
||||||
@@ -33,7 +34,9 @@ export default function reportJson(id) {
|
|||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa fa-eye",
|
||||||
redirectUrl: "pdfRequestFiles"
|
redirectUrl: "pdfRequestFiles"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
helpMsg:
|
||||||
|
"This is a list of documents that are waiting for your signature"
|
||||||
};
|
};
|
||||||
// In progess report
|
// In progess report
|
||||||
case "1MwEuxLEkF":
|
case "1MwEuxLEkF":
|
||||||
@@ -48,7 +51,9 @@ export default function reportJson(id) {
|
|||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa fa-eye",
|
||||||
redirectUrl: "pdfRequestFiles"
|
redirectUrl: "pdfRequestFiles"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
helpMsg:
|
||||||
|
"This is a list of documents you've sent to other parties for signature."
|
||||||
};
|
};
|
||||||
// completed documents report
|
// completed documents report
|
||||||
case "kQUoW4hUXz":
|
case "kQUoW4hUXz":
|
||||||
@@ -63,7 +68,8 @@ export default function reportJson(id) {
|
|||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa fa-eye",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
helpMsg: "This is a list of documents that have been signed by all parties."
|
||||||
};
|
};
|
||||||
// declined documents report
|
// declined documents report
|
||||||
case "UPr2Fm5WY3":
|
case "UPr2Fm5WY3":
|
||||||
@@ -78,7 +84,8 @@ export default function reportJson(id) {
|
|||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa fa-eye",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
helpMsg: "This is a list of documents that have been declined by one of the signers."
|
||||||
};
|
};
|
||||||
// Expired Documents report
|
// Expired Documents report
|
||||||
case "zNqBHXHsYH":
|
case "zNqBHXHsYH":
|
||||||
@@ -93,7 +100,8 @@ export default function reportJson(id) {
|
|||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa fa-eye",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
helpMsg: "This is a list of documents that have reached their expiration date."
|
||||||
};
|
};
|
||||||
// Recently sent for signatures report show on dashboard
|
// Recently sent for signatures report show on dashboard
|
||||||
case "d9k3UfYHBc":
|
case "d9k3UfYHBc":
|
||||||
@@ -153,7 +161,8 @@ export default function reportJson(id) {
|
|||||||
btnIcon: "fa-solid fa-trash"
|
btnIcon: "fa-solid fa-trash"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
form: "ContactBook"
|
form: "ContactBook",
|
||||||
|
helpMsg: "This is a list of contacts/signers added by you. These will appear as suggestions when you try to add signers to a new document."
|
||||||
};
|
};
|
||||||
// template report
|
// template report
|
||||||
case "6TeaPr321t":
|
case "6TeaPr321t":
|
||||||
@@ -175,7 +184,9 @@ export default function reportJson(id) {
|
|||||||
btnIcon: "fa fa-plus",
|
btnIcon: "fa fa-plus",
|
||||||
redirectUrl: "template"
|
redirectUrl: "template"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
helpMsg:
|
||||||
|
"This is a list of templates that are available to you for creating documents. You can click the 'use' button to create a new document using a template, modify the document & add signers in the next step."
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -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,8 +251,10 @@ 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 className="relative h-screen flex flex-col justify-between w-full overflow-y-auto">
|
id="renderList"
|
||||||
|
className="relative h-screen flex flex-col justify-between w-full overflow-y-auto"
|
||||||
|
>
|
||||||
<div className="bg-[#eef1f5] p-3">{<Outlet />}</div>
|
<div className="bg-[#eef1f5] p-3">{<Outlet />}</div>
|
||||||
<div className="z-30">
|
<div className="z-30">
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import "../styles/loader.css";
|
|||||||
import GetDashboard from "../components/dashboard/GetDashboard";
|
import GetDashboard from "../components/dashboard/GetDashboard";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import { save_tourSteps } from "../redux/actions";
|
import { useDispatch } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
import { saveTourSteps } from "../redux/reducers/TourStepsReducer";
|
||||||
const Dashboard = (props) => {
|
const Dashboard = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const dispatch = useDispatch();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const [dashboard, setdashboard] = useState([]);
|
const [dashboard, setdashboard] = useState([]);
|
||||||
const [classnameArray, setclassnameArray] = useState([]);
|
const [classnameArray, setclassnameArray] = useState([]);
|
||||||
@@ -88,7 +89,7 @@ const Dashboard = (props) => {
|
|||||||
// style: { backgroundColor: "#abd4d2" },
|
// style: { backgroundColor: "#abd4d2" },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
props.save_tourSteps(arr);
|
dispatch(saveTourSteps(arr));
|
||||||
// console.log("arr ", arr);
|
// console.log("arr ", arr);
|
||||||
setclassnameArray(classArray);
|
setclassnameArray(classArray);
|
||||||
if (localStorage.getItem("DashboardDefaultFilter")) {
|
if (localStorage.getItem("DashboardDefaultFilter")) {
|
||||||
@@ -133,6 +134,4 @@ const Dashboard = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(null, {
|
export default Dashboard;
|
||||||
save_tourSteps
|
|
||||||
})(Dashboard);
|
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { fetchAppInfo, forgetPassword } from "../redux/actions";
|
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import { NavLink } from "react-router-dom";
|
import { NavLink } from "react-router-dom";
|
||||||
import login_img from "../assets/images/login_img.svg";
|
import login_img from "../assets/images/login_img.svg";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
function ForgotPassword(props) {
|
import { appInfo } from "../constant/appinfo";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
|
|
||||||
|
function ForgotPassword() {
|
||||||
|
const dispatch = useDispatch();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
email: "",
|
email: "",
|
||||||
password: "",
|
password: "",
|
||||||
@@ -27,14 +30,11 @@ function ForgotPassword(props) {
|
|||||||
|
|
||||||
const handleSubmit = async (event) => {
|
const handleSubmit = async (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
localStorage.setItem("appLogo", props.appInfo.applogo);
|
localStorage.setItem("appLogo", appInfo.applogo);
|
||||||
localStorage.setItem("appName", props.appInfo.appname);
|
localStorage.setItem("appName", appInfo.appname);
|
||||||
localStorage.setItem("defaultmenuid", props.appInfo.defaultmenuid);
|
// localStorage.setItem("defaultmenuid", props.appInfo.defaultmenuid);
|
||||||
localStorage.setItem("PageLanding", props.appInfo.LandingPageId);
|
// localStorage.setItem("PageLanding", props.appInfo.LandingPageId);
|
||||||
localStorage.setItem(
|
localStorage.setItem("userSettings", JSON.stringify(appInfo.settings));
|
||||||
"userSettings",
|
|
||||||
JSON.stringify(props.appInfo.settings)
|
|
||||||
);
|
|
||||||
if (state.email) {
|
if (state.email) {
|
||||||
const username = state.email;
|
const username = state.email;
|
||||||
try {
|
try {
|
||||||
@@ -50,14 +50,14 @@ function ForgotPassword(props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
props.fetchAppInfo();
|
dispatch(fetchAppInfo());
|
||||||
resize();
|
resize();
|
||||||
window.addEventListener("resize", resize);
|
window.addEventListener("resize", resize);
|
||||||
return () => window.removeEventListener("resize", resize);
|
return () => window.removeEventListener("resize", resize);
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
let image = props.appInfo.applogo;
|
let image = appInfo.applogo;
|
||||||
return (
|
return (
|
||||||
<div className="bg-white">
|
<div className="bg-white">
|
||||||
<Title title="Forgot password page" />
|
<Title title="Forgot password page" />
|
||||||
@@ -129,10 +129,4 @@ function ForgotPassword(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
export default ForgotPassword;
|
||||||
return { appInfo: state.appInfo, forgotPassword: state.forgotPassword };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, { fetchAppInfo, forgetPassword })(
|
|
||||||
ForgotPassword
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -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() {
|
||||||
@@ -35,7 +36,7 @@ const Forms = (props) => {
|
|||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
Name: "",
|
Name: "",
|
||||||
Description: "",
|
Description: "",
|
||||||
Note: "Please review and sign this document",
|
Note: "",
|
||||||
TimeToCompleteDays: 15,
|
TimeToCompleteDays: 15,
|
||||||
SendinOrder: "false"
|
SendinOrder: "false"
|
||||||
});
|
});
|
||||||
@@ -51,6 +52,7 @@ const Forms = (props) => {
|
|||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleReset();
|
handleReset();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [props.title]);
|
}, [props.title]);
|
||||||
const handleFileInput = (e) => {
|
const handleFileInput = (e) => {
|
||||||
setpercentage(0);
|
setpercentage(0);
|
||||||
@@ -81,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);
|
||||||
@@ -100,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) {
|
||||||
@@ -112,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));
|
||||||
|
|
||||||
@@ -140,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) {
|
||||||
@@ -165,7 +173,9 @@ const Forms = (props) => {
|
|||||||
"TimeToCompleteDays",
|
"TimeToCompleteDays",
|
||||||
parseInt(formData?.TimeToCompleteDays)
|
parseInt(formData?.TimeToCompleteDays)
|
||||||
);
|
);
|
||||||
const isChecked = formData.SendinOrder === "true" ? true : false;
|
}
|
||||||
|
if (props.title !== "Sign Yourself") {
|
||||||
|
const isChecked = formData.SendinOrder === "false" ? false : true;
|
||||||
object.set("SendinOrder", isChecked);
|
object.set("SendinOrder", isChecked);
|
||||||
}
|
}
|
||||||
object.set("URL", fileupload);
|
object.set("URL", fileupload);
|
||||||
@@ -233,9 +243,12 @@ const Forms = (props) => {
|
|||||||
setFormData({
|
setFormData({
|
||||||
Name: "",
|
Name: "",
|
||||||
Description: "",
|
Description: "",
|
||||||
Note: "Please review and sign this document",
|
Note:
|
||||||
|
props.title === "Sign Yourself"
|
||||||
|
? "Note to myself"
|
||||||
|
: "Please review and sign this document",
|
||||||
TimeToCompleteDays: 15,
|
TimeToCompleteDays: 15,
|
||||||
SendinOrder: "false"
|
SendinOrder: "true"
|
||||||
});
|
});
|
||||||
setFileUpload([]);
|
setFileUpload([]);
|
||||||
setpercentage(0);
|
setpercentage(0);
|
||||||
@@ -324,7 +337,10 @@ const Forms = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="text-xs mt-2">
|
<div className="text-xs mt-2">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
Title<span className="text-red-500 text-[13px]">*</span>
|
{props.title === "New Template"
|
||||||
|
? "Template Title"
|
||||||
|
: "Document Title"}
|
||||||
|
<span className="text-red-500 text-[13px]">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
name="Name"
|
name="Name"
|
||||||
|
|||||||
@@ -1,12 +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 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("");
|
||||||
@@ -15,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();
|
||||||
@@ -23,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",
|
||||||
@@ -33,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();
|
||||||
@@ -88,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"} />
|
||||||
@@ -115,29 +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">
|
||||||
<h1 className="ml-4 mt-3 mb-2 font-semibold">API Token</h1>
|
{!isEnableSubscription && <PremiumAlertHeader />}
|
||||||
<ul className="w-full flex flex-col p-2 text-sm">
|
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||||
|
OpenSign™ API{" "}
|
||||||
|
<Tooltip
|
||||||
|
url={
|
||||||
|
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
||||||
|
}
|
||||||
|
isSubscribe={true}
|
||||||
|
/>
|
||||||
|
</h1>
|
||||||
|
<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={() =>
|
||||||
@@ -145,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 });
|
||||||
|
|
||||||
|
|||||||
+235
-136
@@ -1,8 +1,7 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import "../styles/loader.css";
|
import "../styles/loader.css";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { fetchAppInfo, showTenantName } from "../redux/actions";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import GoogleSignInBtn from "../components/LoginGoogle";
|
import GoogleSignInBtn from "../components/LoginGoogle";
|
||||||
@@ -11,12 +10,19 @@ 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";
|
||||||
function Login(props) {
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
|
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||||
|
function Login() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
email: "",
|
email: "",
|
||||||
@@ -37,14 +43,14 @@ function Login(props) {
|
|||||||
Destination: ""
|
Destination: ""
|
||||||
});
|
});
|
||||||
const [isModal, setIsModal] = useState(false);
|
const [isModal, setIsModal] = useState(false);
|
||||||
const image = props?.appInfo?.applogo || undefined;
|
const image = appInfo?.applogo || undefined;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (localStorage.getItem("accesstoken")) {
|
if (localStorage.getItem("accesstoken")) {
|
||||||
setState({ ...state, loading: true });
|
setState({ ...state, loading: true });
|
||||||
GetLoginData();
|
GetLoginData();
|
||||||
}
|
}
|
||||||
props.fetchAppInfo();
|
dispatch(fetchAppInfo());
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
const handleChange = (event) => {
|
const handleChange = (event) => {
|
||||||
@@ -61,8 +67,8 @@ function Login(props) {
|
|||||||
setState({ ...state, loading: true });
|
setState({ ...state, loading: true });
|
||||||
let baseUrl = localStorage.getItem("baseUrl");
|
let baseUrl = localStorage.getItem("baseUrl");
|
||||||
let parseAppId = localStorage.getItem("parseAppId");
|
let parseAppId = localStorage.getItem("parseAppId");
|
||||||
localStorage.setItem("appLogo", props.appInfo.applogo);
|
localStorage.setItem("appLogo", appInfo.applogo);
|
||||||
localStorage.setItem("appName", props.appInfo.appname);
|
localStorage.setItem("appName", appInfo.appname);
|
||||||
// Pass the username and password to logIn function
|
// Pass the username and password to logIn function
|
||||||
await Parse.User.logIn(email, password)
|
await Parse.User.logIn(email, password)
|
||||||
.then(async (user) => {
|
.then(async (user) => {
|
||||||
@@ -81,8 +87,8 @@ function Login(props) {
|
|||||||
// Check extended class user role and tenentId
|
// Check extended class user role and tenentId
|
||||||
try {
|
try {
|
||||||
let userRoles = [];
|
let userRoles = [];
|
||||||
if (props.appInfo.settings) {
|
if (appInfo.settings) {
|
||||||
let userSettings = props.appInfo.settings;
|
let userSettings = appInfo.settings;
|
||||||
|
|
||||||
//Get Current user roles
|
//Get Current user roles
|
||||||
let url = `${baseUrl}functions/UserGroups`;
|
let url = `${baseUrl}functions/UserGroups`;
|
||||||
@@ -172,8 +178,10 @@ function Login(props) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (tenentInfo.length) {
|
if (tenentInfo.length) {
|
||||||
props.showTenantName(
|
dispatch(
|
||||||
tenentInfo[0].tenentName || ""
|
showTenant(
|
||||||
|
tenentInfo[0].tenentName || ""
|
||||||
|
)
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenantName",
|
"TenantName",
|
||||||
@@ -205,15 +213,17 @@ function Login(props) {
|
|||||||
x.TenantId.TenantName || ""
|
x.TenantId.TenantName || ""
|
||||||
};
|
};
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenetId",
|
"TenantId",
|
||||||
x.TenantId.objectId
|
x.TenantId.objectId
|
||||||
);
|
);
|
||||||
tenentInfo.push(obj);
|
tenentInfo.push(obj);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (tenentInfo.length) {
|
if (tenentInfo.length) {
|
||||||
props.showTenantName(
|
dispatch(
|
||||||
tenentInfo[0].tenentName || ""
|
showTenant(
|
||||||
|
tenentInfo[0].tenentName || ""
|
||||||
|
)
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenantName",
|
"TenantName",
|
||||||
@@ -233,10 +243,7 @@ function Login(props) {
|
|||||||
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"),
|
||||||
@@ -247,10 +254,15 @@ function Login(props) {
|
|||||||
"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"
|
||||||
@@ -286,9 +298,7 @@ function Login(props) {
|
|||||||
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,
|
||||||
@@ -385,6 +395,18 @@ function Login(props) {
|
|||||||
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");
|
||||||
@@ -394,6 +416,11 @@ function Login(props) {
|
|||||||
"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);
|
||||||
});
|
});
|
||||||
@@ -412,8 +439,8 @@ function Login(props) {
|
|||||||
// Check extended class user role and tenentId
|
// Check extended class user role and tenentId
|
||||||
try {
|
try {
|
||||||
let userRoles = [];
|
let userRoles = [];
|
||||||
if (props.appInfo.settings) {
|
if (appInfo.settings) {
|
||||||
let userSettings = props.appInfo.settings;
|
let userSettings = appInfo.settings;
|
||||||
|
|
||||||
//Get Current user roles
|
//Get Current user roles
|
||||||
let url = `${baseUrl}functions/UserGroups`;
|
let url = `${baseUrl}functions/UserGroups`;
|
||||||
@@ -503,8 +530,8 @@ function Login(props) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (tenentInfo.length) {
|
if (tenentInfo.length) {
|
||||||
props.showTenantName(
|
dispatch(
|
||||||
tenentInfo[0].tenentName || ""
|
showTenant(tenentInfo[0].tenentName || "")
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenantName",
|
"TenantName",
|
||||||
@@ -536,15 +563,15 @@ function Login(props) {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (tenentInfo.length) {
|
if (tenentInfo.length) {
|
||||||
props.showTenantName(
|
dispatch(
|
||||||
tenentInfo[0].tenentName || ""
|
showTenant(tenentInfo[0].tenentName || "")
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenantName",
|
"TenantName",
|
||||||
@@ -565,18 +592,28 @@ function Login(props) {
|
|||||||
);
|
);
|
||||||
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);
|
||||||
@@ -591,17 +628,29 @@ function Login(props) {
|
|||||||
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);
|
||||||
@@ -730,94 +779,153 @@ function Login(props) {
|
|||||||
} else {
|
} else {
|
||||||
_currentRole = userRoles[0];
|
_currentRole = userRoles[0];
|
||||||
}
|
}
|
||||||
let SettingsUser = JSON.parse(userSettings);
|
if (_currentRole && _currentRole !== "contracts_Guest") {
|
||||||
SettingsUser.forEach(async (element) => {
|
let SettingsUser = JSON.parse(userSettings);
|
||||||
if (element.role === _currentRole) {
|
SettingsUser.forEach(async (item) => {
|
||||||
let _role = _currentRole.replace(
|
if (item.role === _currentRole) {
|
||||||
`${localStorage.getItem("_appName")}_`,
|
let _role = _currentRole.replace(`${appInfo.appname}_`, "");
|
||||||
""
|
localStorage.setItem("_user_role", _role);
|
||||||
);
|
// Get TenentID from Extendend Class
|
||||||
localStorage.setItem("_user_role", _role);
|
localStorage.setItem("extended_class", item.extended_class);
|
||||||
|
const currentUser = Parse.User.current();
|
||||||
// Get TenentID from Extendend Class
|
const userSettings = appInfo.settings;
|
||||||
localStorage.setItem(
|
const setting = userSettings.find(
|
||||||
"extended_class",
|
(x) => x.role === _currentRole
|
||||||
element.extended_class
|
);
|
||||||
);
|
const redirectUrl =
|
||||||
|
location?.state?.from ||
|
||||||
const currentUser = Parse.User.current();
|
`/${setting.pageType}/${setting.pageId}`;
|
||||||
await Parse.Cloud.run("getUserDetails", {
|
await Parse.Cloud.run("getUserDetails", {
|
||||||
email: currentUser.get("email")
|
email: currentUser.get("email")
|
||||||
}).then(
|
}).then(
|
||||||
(result) => {
|
(result) => {
|
||||||
let tenentInfo = [];
|
let tenentInfo = [];
|
||||||
const results = [result];
|
const results = [result];
|
||||||
if (results) {
|
if (results) {
|
||||||
let extendedInfo_stringify = JSON.stringify(results);
|
let extendedInfo_stringify = JSON.stringify(results);
|
||||||
let extendedInfo = JSON.parse(extendedInfo_stringify);
|
let extendedInfo = JSON.parse(extendedInfo_stringify);
|
||||||
if (extendedInfo.length > 1) {
|
if (extendedInfo.length > 1) {
|
||||||
extendedInfo.forEach((x) => {
|
extendedInfo.forEach((x) => {
|
||||||
if (x.TenantId) {
|
if (x.TenantId) {
|
||||||
let obj = {
|
let obj = {
|
||||||
tenentId: x.TenantId.objectId,
|
tenentId: x.TenantId.objectId,
|
||||||
tenentName: x.TenantId.TenantName || ""
|
tenentName: x.TenantId.TenantName || ""
|
||||||
};
|
};
|
||||||
tenentInfo.push(obj);
|
tenentInfo.push(obj);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
localStorage.setItem("showpopup", true);
|
||||||
localStorage.setItem("showpopup", true);
|
localStorage.setItem("PageLanding", item.pageId);
|
||||||
localStorage.setItem("PageLanding", element.pageId);
|
localStorage.setItem("defaultmenuid", item.menuId);
|
||||||
localStorage.setItem("defaultmenuid", element.menuId);
|
localStorage.setItem("pageType", item.pageType);
|
||||||
localStorage.setItem("pageType", element.pageType);
|
navigate("/");
|
||||||
navigate("/");
|
} else {
|
||||||
} else {
|
extendedInfo.forEach((x) => {
|
||||||
extendedInfo.forEach((x) => {
|
if (x.TenantId) {
|
||||||
if (x.TenantId) {
|
let obj = {
|
||||||
let obj = {
|
tenentId: x.TenantId.objectId,
|
||||||
tenentId: x.TenantId.objectId,
|
tenentName: x.TenantId.TenantName || ""
|
||||||
tenentName: x.TenantId.TenantName || ""
|
};
|
||||||
|
localStorage.setItem(
|
||||||
|
"TenantId",
|
||||||
|
x.TenantId.objectId
|
||||||
|
);
|
||||||
|
tenentInfo.push(obj);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
localStorage.setItem("PageLanding", setting.pageId);
|
||||||
|
localStorage.setItem(
|
||||||
|
"defaultmenuid",
|
||||||
|
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(
|
localStorage.setItem(
|
||||||
"TenetId",
|
"userDetails",
|
||||||
x.TenantId.objectId
|
JSON.stringify(LocalUserDetails)
|
||||||
);
|
);
|
||||||
tenentInfo.push(obj);
|
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);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
localStorage.setItem("PageLanding", element.pageId);
|
} else {
|
||||||
localStorage.setItem("defaultmenuid", element.menuId);
|
localStorage.setItem("PageLanding", setting.pageId);
|
||||||
localStorage.setItem("pageType", element.pageType);
|
localStorage.setItem("defaultmenuid", setting.menuId);
|
||||||
navigate(`/${element.pageType}/${element.pageId}`);
|
localStorage.setItem("pageType", setting.pageType);
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
},
|
||||||
localStorage.setItem("PageLanding", element.pageId);
|
(error) => {
|
||||||
localStorage.setItem("defaultmenuid", element.menuId);
|
|
||||||
localStorage.setItem("pageType", element.pageType);
|
|
||||||
navigate(`/${element.pageType}/${element.pageId}`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
setState({
|
|
||||||
...state,
|
|
||||||
loading: false,
|
|
||||||
alertType: "danger",
|
|
||||||
alertMsg: "You don`t have access to this application!"
|
|
||||||
});
|
|
||||||
setTimeout(function () {
|
|
||||||
setState({
|
setState({
|
||||||
...state,
|
...state,
|
||||||
loading: false,
|
loading: false,
|
||||||
alertType: "danger",
|
alertType: "danger",
|
||||||
alertMsg: ""
|
alertMsg: "You don`t have access to this application!"
|
||||||
});
|
});
|
||||||
}, 2000);
|
setTimeout(function () {
|
||||||
localStorage.setItem("accesstoken", null);
|
setState({
|
||||||
console.error("Error while fetching Follow", error);
|
...state,
|
||||||
}
|
loading: false,
|
||||||
);
|
alertType: "danger",
|
||||||
}
|
alertMsg: ""
|
||||||
});
|
});
|
||||||
|
}, 2000);
|
||||||
|
localStorage.setItem("accesstoken", null);
|
||||||
|
console.error("Error while fetching Follow", error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState({ ...state, loading: false });
|
||||||
|
handleCloseModal();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log("User Role Not Found.");
|
console.log("User Role Not Found.");
|
||||||
}
|
}
|
||||||
@@ -943,7 +1051,7 @@ function Login(props) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{props.isloginVisible && props.isloginVisible ? (
|
{appInfo && appInfo.appId ? (
|
||||||
<>
|
<>
|
||||||
<div aria-labelledby="loginHeading" role="region">
|
<div aria-labelledby="loginHeading" role="region">
|
||||||
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-4 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-4 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
||||||
@@ -1043,7 +1151,11 @@ function Login(props) {
|
|||||||
</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
|
||||||
@@ -1051,7 +1163,7 @@ function Login(props) {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<br />
|
<br />
|
||||||
{(props.appInfo.fbAppId || props.appInfo.googleClietId) && (
|
{(appInfo.fbAppId || appInfo.googleClietId) && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@@ -1082,9 +1194,9 @@ function Login(props) {
|
|||||||
justifyContent: "center"
|
justifyContent: "center"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* {props.appInfo.fbAppId && props.appInfo.fbAppId !== "" ? (
|
{/* {appInfo.fbAppId && appInfo.fbAppId !== "" ? (
|
||||||
<LoginFacebook
|
<LoginFacebook
|
||||||
FBCred={props.appInfo.fbAppId}
|
FBCred={appInfo.fbAppId}
|
||||||
thirdpartyLoginfn={thirdpartyLoginfn}
|
thirdpartyLoginfn={thirdpartyLoginfn}
|
||||||
thirdpartyLoader={state.thirdpartyLoader}
|
thirdpartyLoader={state.thirdpartyLoader}
|
||||||
setThirdpartyLoader={setThirdpartyLoader}
|
setThirdpartyLoader={setThirdpartyLoader}
|
||||||
@@ -1100,10 +1212,9 @@ function Login(props) {
|
|||||||
justifyContent: "center"
|
justifyContent: "center"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.appInfo.googleClietId &&
|
{appInfo.googleClietId && appInfo.googleClietId !== "" ? (
|
||||||
props.appInfo.googleClietId !== "" ? (
|
|
||||||
<GoogleSignInBtn
|
<GoogleSignInBtn
|
||||||
GoogleCred={props.appInfo.googleClietId}
|
GoogleCred={appInfo.googleClietId}
|
||||||
thirdpartyLoginfn={thirdpartyLoginfn}
|
thirdpartyLoginfn={thirdpartyLoginfn}
|
||||||
thirdpartyLoader={state.thirdpartyLoader}
|
thirdpartyLoader={state.thirdpartyLoader}
|
||||||
setThirdpartyLoader={setThirdpartyLoader}
|
setThirdpartyLoader={setThirdpartyLoader}
|
||||||
@@ -1213,16 +1324,4 @@ function Login(props) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
export default Login;
|
||||||
const mapStateToProps = (state) => {
|
|
||||||
if (Object.keys(state.appInfo).length !== 0) {
|
|
||||||
return { appInfo: state.appInfo, isloginVisible: true };
|
|
||||||
} else {
|
|
||||||
return { appInfo: state.appInfo, isloginVisible: false };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, {
|
|
||||||
fetchAppInfo,
|
|
||||||
showTenantName
|
|
||||||
})(Login);
|
|
||||||
|
|||||||
@@ -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");
|
||||||
@@ -13,7 +14,6 @@ const ManageSign = () => {
|
|||||||
const [signName, setSignName] = useState("");
|
const [signName, setSignName] = useState("");
|
||||||
const [signature, setSignature] = useState("");
|
const [signature, setSignature] = useState("");
|
||||||
const [warning, setWarning] = useState(false);
|
const [warning, setWarning] = useState(false);
|
||||||
const [nameWarning, setNameWarning] = useState(false);
|
|
||||||
const [isvalue, setIsValue] = useState(false);
|
const [isvalue, setIsValue] = useState(false);
|
||||||
const allColor = ["blue", "red", "black"];
|
const allColor = ["blue", "red", "black"];
|
||||||
const [isLoader, setIsLoader] = useState(true);
|
const [isLoader, setIsLoader] = useState(true);
|
||||||
@@ -105,9 +105,7 @@ const ManageSign = () => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const isUrl = image.includes("https");
|
const isUrl = image.includes("https");
|
||||||
|
|
||||||
if (!signName) {
|
if (!isvalue) {
|
||||||
setNameWarning(true);
|
|
||||||
} else if (!isvalue) {
|
|
||||||
setWarning(true);
|
setWarning(true);
|
||||||
setTimeout(() => setWarning(false), 1000);
|
setTimeout(() => setWarning(false), 1000);
|
||||||
} else {
|
} else {
|
||||||
@@ -161,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);
|
||||||
@@ -222,26 +224,13 @@ const ManageSign = () => {
|
|||||||
setIsValue(true);
|
setIsValue(true);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="relative h-full bg-white flex shadow rounded overflow-auto">
|
||||||
style={{
|
|
||||||
backgroundColor: "white",
|
|
||||||
maxHeight: "500px",
|
|
||||||
overflow: "auto"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isLoader && (
|
{isLoader && (
|
||||||
<div className="absolute bg-black bg-opacity-75 inset-0 z-50 flex justify-center items-center">
|
<div className="absolute bg-black bg-opacity-75 z-50 w-full h-full flex justify-center items-center">
|
||||||
<div style={{ height: "300px" }}>
|
<div
|
||||||
<div
|
style={{ color: "#3dd3e0" }}
|
||||||
style={{
|
className="loader-37 text-[45px]"
|
||||||
marginLeft: "45%",
|
></div>
|
||||||
marginTop: "150px",
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isSuccess && (
|
{isSuccess && (
|
||||||
@@ -269,61 +258,9 @@ const ManageSign = () => {
|
|||||||
paddingBottom: 8
|
paddingBottom: 8
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Manage Signature
|
My Signature
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
<div className="signBlock mt-4">
|
||||||
<label
|
|
||||||
htmlFor="signName"
|
|
||||||
style={{
|
|
||||||
fontSize: 12,
|
|
||||||
position: "relative",
|
|
||||||
paddingBottom: 5
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Signer's Name
|
|
||||||
{nameWarning && (
|
|
||||||
<div
|
|
||||||
className="warning nameWarning"
|
|
||||||
style={{ fontSize: 12 }}
|
|
||||||
onAnimationEnd={() => setNameWarning(false)}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fas fa-exclamation-circle"
|
|
||||||
style={{ color: "#fab005", fontSize: 15 }}
|
|
||||||
></i>{" "}
|
|
||||||
Please fill input field
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="signName"
|
|
||||||
className="signInputManage"
|
|
||||||
value={signName}
|
|
||||||
style={{
|
|
||||||
border: "1px solid #ccc",
|
|
||||||
borderRadius: 4,
|
|
||||||
|
|
||||||
height: 35,
|
|
||||||
padding: "6px 12px",
|
|
||||||
marginBottom: 10,
|
|
||||||
fontSize: 12
|
|
||||||
}}
|
|
||||||
required
|
|
||||||
onFocus={() => setNameWarning(false)}
|
|
||||||
onChange={(e) => setSignName(e.target.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<label
|
|
||||||
htmlFor="imgoverview"
|
|
||||||
style={{
|
|
||||||
fontSize: 12,
|
|
||||||
paddingBottom: 5
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Signature/Image
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className="signBlock">
|
|
||||||
<div>
|
<div>
|
||||||
<div style={{ position: "relative" }}>
|
<div style={{ position: "relative" }}>
|
||||||
<div
|
<div
|
||||||
@@ -429,10 +366,10 @@ const ManageSign = () => {
|
|||||||
key === 0 && penColor === "blue"
|
key === 0 && penColor === "blue"
|
||||||
? "2px solid blue"
|
? "2px solid blue"
|
||||||
: key === 1 && penColor === "red"
|
: key === 1 && penColor === "red"
|
||||||
? "2px solid red"
|
? "2px solid red"
|
||||||
: key === 2 && penColor === "black"
|
: key === 2 && penColor === "black"
|
||||||
? "2px solid black"
|
? "2px solid black"
|
||||||
: "2px solid white"
|
: "2px solid white"
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (key === 0) {
|
if (key === 0) {
|
||||||
@@ -537,10 +474,10 @@ const ManageSign = () => {
|
|||||||
key === 0 && initialPen === "blue"
|
key === 0 && initialPen === "blue"
|
||||||
? "2px solid blue"
|
? "2px solid blue"
|
||||||
: key === 1 && initialPen === "red"
|
: key === 1 && initialPen === "red"
|
||||||
? "2px solid red"
|
? "2px solid red"
|
||||||
: key === 2 && initialPen === "black"
|
: key === 2 && initialPen === "black"
|
||||||
? "2px solid black"
|
? "2px solid black"
|
||||||
: "2px solid white"
|
: "2px solid white"
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (key === 0) {
|
if (key === 0) {
|
||||||
|
|||||||
@@ -1,20 +1,41 @@
|
|||||||
import React, { useEffect, useState, useRef } from "react";
|
import React, { useEffect, useState, useRef } from "react";
|
||||||
import "../styles/opensigndrive.css";
|
import "../styles/opensigndrive.css";
|
||||||
import loader from "../assets/images/loader2.gif";
|
import loader from "../assets/images/loader2.gif";
|
||||||
import DriveBody from "../components/opensigndrive/DriveBody";
|
|
||||||
import { themeColor, iconColor } from "../constant/const";
|
import { themeColor, iconColor } from "../constant/const";
|
||||||
import { getDrive } from "../constant/Utils";
|
import { getDrive } from "../constant/Utils";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
|
const DriveBody = React.lazy(
|
||||||
|
() => import("../components/opensigndrive/DriveBody")
|
||||||
|
);
|
||||||
|
const Loader = () => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: "100vh",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: "45px",
|
||||||
|
color: "#3dd3e0"
|
||||||
|
}}
|
||||||
|
className="loader-37"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
function Opensigndrive() {
|
function Opensigndrive() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
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();
|
||||||
@@ -30,6 +51,17 @@ function Opensigndrive() {
|
|||||||
const [folderName, setFolderName] = useState([]);
|
const [folderName, setFolderName] = useState([]);
|
||||||
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
|
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
|
||||||
const [isNewFol, setIsNewFol] = useState(false);
|
const [isNewFol, setIsNewFol] = useState(false);
|
||||||
|
const [skip, setSkip] = useState(0);
|
||||||
|
const limit = 100;
|
||||||
|
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`
|
||||||
@@ -40,103 +72,83 @@ function Opensigndrive() {
|
|||||||
const jsonCurrentUser = JSON.parse(currentUser);
|
const jsonCurrentUser = JSON.parse(currentUser);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (docId) {
|
getPdfDocumentList();
|
||||||
getPdfFolderDocumentList();
|
|
||||||
} else {
|
|
||||||
getPdfDocumentList();
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [docId]);
|
}, [docId]);
|
||||||
|
|
||||||
//function for get all pdf document list
|
//function for get all pdf document list
|
||||||
const getPdfDocumentList = async () => {
|
const getPdfDocumentList = async (disbaleLoading) => {
|
||||||
const load = {
|
setLoading(true);
|
||||||
isLoad: true,
|
if (!disbaleLoading) {
|
||||||
message: "This might take some time"
|
setIsLoading({ isLoad: true, message: "This might take some time" });
|
||||||
};
|
}
|
||||||
let driveDetails;
|
|
||||||
setIsLoading(load);
|
|
||||||
try {
|
try {
|
||||||
driveDetails = await getDrive();
|
const driveDetails = await getDrive(docId, skip, limit);
|
||||||
if (driveDetails) {
|
if (driveDetails && driveDetails === "Error: Something went wrong!") {
|
||||||
if (driveDetails.length > 0) {
|
|
||||||
setPdfData(driveDetails);
|
|
||||||
sortApps(null, null, driveDetails);
|
|
||||||
}
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
name: "OpenSign™ Drive",
|
|
||||||
objectId: ""
|
|
||||||
}
|
|
||||||
];
|
|
||||||
setFolderName(data);
|
|
||||||
const loadObj = {
|
|
||||||
isLoad: false
|
|
||||||
};
|
|
||||||
setIsLoading(loadObj);
|
|
||||||
} else if (driveDetails === "Error: Something went wrong!") {
|
|
||||||
const loadObj = {
|
|
||||||
isLoad: false
|
|
||||||
};
|
|
||||||
setHandleError("Error: Something went wrong!");
|
setHandleError("Error: Something went wrong!");
|
||||||
setIsLoading(loadObj);
|
} else if (driveDetails && driveDetails.length > 0) {
|
||||||
|
setSkip((prevSkip) => prevSkip + limit);
|
||||||
|
sortingData(null, null, driveDetails, true);
|
||||||
|
}
|
||||||
|
if (!docId) {
|
||||||
|
setFolderName([{ name: "OpenSign™ Drive", objectId: "" }]);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setIsAlert({
|
setIsAlert({
|
||||||
isShow: true,
|
isShow: true,
|
||||||
alertMessage: "something went wrong"
|
alertMessage: "something went wrong"
|
||||||
});
|
});
|
||||||
}
|
} finally {
|
||||||
};
|
setLoading(false);
|
||||||
//function for get parent folder document list
|
setIsLoading({
|
||||||
const getPdfFolderDocumentList = async () => {
|
isLoad: false
|
||||||
const load = {
|
|
||||||
isLoad: true,
|
|
||||||
message: "This might take some time"
|
|
||||||
};
|
|
||||||
setIsLoading(load);
|
|
||||||
let driveDetails;
|
|
||||||
try {
|
|
||||||
driveDetails = await getDrive(docId);
|
|
||||||
|
|
||||||
if (driveDetails) {
|
|
||||||
if (driveDetails.length > 0) {
|
|
||||||
setPdfData(driveDetails);
|
|
||||||
sortApps(null, null, driveDetails);
|
|
||||||
} else {
|
|
||||||
setPdfData([]);
|
|
||||||
}
|
|
||||||
const loadObj = {
|
|
||||||
isLoad: false
|
|
||||||
};
|
|
||||||
setIsLoading(loadObj);
|
|
||||||
} else if (driveDetails === "Error: Something went wrong!") {
|
|
||||||
const loadObj = {
|
|
||||||
isLoad: false
|
|
||||||
};
|
|
||||||
setHandleError("Error: Something went wrong!");
|
|
||||||
setIsLoading(loadObj);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
setIsAlert({
|
|
||||||
isShow: true,
|
|
||||||
alertMessage: "something went wrong!"
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//function for get all pdf document list
|
//function to fetch drive details list on scroll bottom
|
||||||
const getParentFolder = async () => {
|
const handleScroll = () => {
|
||||||
setIsFolder(true);
|
//get document of render openSign-drive component using id
|
||||||
|
const documentList = document.getElementById("renderList");
|
||||||
|
//documentList.clientHeight property returns the height of an element's content area, including padding but not including borders, margins, or scrollbars.
|
||||||
|
//documentList.scrollHeight property returns the entire height of an element,including the parts that are not visible due to overflow..
|
||||||
|
// documentList.scrollTop property show height of element, how much the content has been scrolled from the top.
|
||||||
|
// When the sum of scrollTop and clientHeight is equal to scrollHeight, it means that the user has scrolled to the bottom of the div.
|
||||||
|
if (
|
||||||
|
documentList &&
|
||||||
|
documentList.scrollTop + documentList.clientHeight >=
|
||||||
|
documentList.scrollHeight
|
||||||
|
) {
|
||||||
|
//disableLoading is used disable initial loader
|
||||||
|
const disableLoading = true;
|
||||||
|
// 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) {
|
||||||
|
getPdfDocumentList(disableLoading);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
//useEffect is used to call handleScroll function on scrolling event
|
||||||
|
useEffect(() => {
|
||||||
|
const documentList = document.getElementById("renderList");
|
||||||
|
if (documentList) {
|
||||||
|
documentList.addEventListener("scroll", handleScroll);
|
||||||
|
return () => {
|
||||||
|
documentList.removeEventListener("scroll", handleScroll);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line
|
||||||
|
}, [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) => {
|
||||||
|
setPdfData([]);
|
||||||
|
setSkip(0);
|
||||||
const updateFolderName = folderName.filter((x, i) => {
|
const updateFolderName = folderName.filter((x, i) => {
|
||||||
if (i <= index) {
|
if (i <= index) {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setFolderName(updateFolderName);
|
setFolderName(updateFolderName);
|
||||||
const getLastId = updateFolderName[updateFolderName.length - 1];
|
const getLastId = updateFolderName[updateFolderName.length - 1];
|
||||||
setDocId(getLastId.objectId);
|
setDocId(getLastId.objectId);
|
||||||
@@ -207,34 +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) => {
|
//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;
|
||||||
|
const sortOrder = order ? order : sortingOrder;
|
||||||
|
|
||||||
let sortingData = driveDetails;
|
//check isInitial true it means sort previous 20 and get on scrolling 20 = 40 document list
|
||||||
if (selectedSortType === "Name") {
|
const allPdfData = isInitial ? [...pdfData, ...driveDetails] : driveDetails;
|
||||||
sortingApp(sortingData, "Name", sortOrder);
|
//call sortedBy function according to selected Type and order
|
||||||
} else if (selectedSortType === "Date") {
|
if (selectedSortType === orderName.Name) {
|
||||||
sortingApp(sortingData, "Date", sortOrder);
|
sortedBy(allPdfData, orderName.Name, sortOrder);
|
||||||
|
} else if (selectedSortType === orderName.Date) {
|
||||||
|
sortedBy(allPdfData, orderName.Date, sortOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
setPdfData(sortingData);
|
setPdfData(allPdfData);
|
||||||
};
|
};
|
||||||
|
|
||||||
//function for handle auto scroll on folder path
|
//function for handle auto scroll on folder path
|
||||||
@@ -301,6 +317,7 @@ function Opensigndrive() {
|
|||||||
// Cleanup the event listener when the component unmounts
|
// Cleanup the event listener when the component unmounts
|
||||||
document.removeEventListener("click", closeMenuOnOutsideClick);
|
document.removeEventListener("click", closeMenuOnOutsideClick);
|
||||||
};
|
};
|
||||||
|
// eslint-disable-next-line
|
||||||
}, [isShowSort, isNewFol]);
|
}, [isShowSort, isNewFol]);
|
||||||
|
|
||||||
const handleFolderTab = (folderData) => {
|
const handleFolderTab = (folderData) => {
|
||||||
@@ -542,7 +559,7 @@ function Opensigndrive() {
|
|||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="dropdown-item itemColor"
|
className="dropdown-item itemColor"
|
||||||
onClick={() => getParentFolder()}
|
onClick={() => setIsFolder(true)}
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
style={{ marginRight: "5px" }}
|
style={{ marginRight: "5px" }}
|
||||||
@@ -606,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>
|
||||||
|
|
||||||
@@ -734,18 +712,23 @@ function Opensigndrive() {
|
|||||||
<span style={{ fontWeight: "bold" }}>No Data Found!</span>
|
<span style={{ fontWeight: "bold" }}>No Data Found!</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<DriveBody
|
<React.Suspense fallback={<Loader />}>
|
||||||
pdfData={pdfData}
|
<DriveBody
|
||||||
setFolderName={setFolderName}
|
pdfData={pdfData}
|
||||||
setIsLoading={setIsLoading}
|
setFolderName={setFolderName}
|
||||||
setDocId={setDocId}
|
setIsLoading={setIsLoading}
|
||||||
getPdfFolderDocumentList={getPdfFolderDocumentList}
|
setDocId={setDocId}
|
||||||
getPdfDocumentList={getPdfDocumentList}
|
getPdfDocumentList={getPdfDocumentList}
|
||||||
isDocId={docId}
|
isDocId={docId}
|
||||||
setPdfData={setPdfData}
|
setPdfData={setPdfData}
|
||||||
isList={isList}
|
isList={isList}
|
||||||
setIsAlert={setIsAlert}
|
setIsAlert={setIsAlert}
|
||||||
/>
|
setSkip={setSkip}
|
||||||
|
/>
|
||||||
|
{loading && (
|
||||||
|
<div style={{ textAlign: "center" }}>Loading...</div>
|
||||||
|
)}
|
||||||
|
</React.Suspense>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,14 +2,17 @@ import React, { useState, useEffect } from "react";
|
|||||||
import "../styles/pgsignup.css";
|
import "../styles/pgsignup.css";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { fetchAppInfo, showTenantName } from "../redux/actions/index";
|
import { useDispatch } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import { useNavigate, useLocation } from "react-router-dom";
|
import { useNavigate, useLocation } from "react-router-dom";
|
||||||
|
import { appInfo } from "../constant/appinfo";
|
||||||
|
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||||
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
|
|
||||||
const PgSignUp = (props) => {
|
const PgSignUp = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
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 [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
@@ -24,8 +27,7 @@ const PgSignUp = (props) => {
|
|||||||
|
|
||||||
// below useEffect is used to fetch App data and save to redux state
|
// below useEffect is used to fetch App data and save to redux state
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Parse.User.logOut()
|
dispatch(fetchAppInfo());
|
||||||
props.fetchAppInfo();
|
|
||||||
handleSignedUpUser();
|
handleSignedUpUser();
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
@@ -243,8 +245,8 @@ const PgSignUp = (props) => {
|
|||||||
// Check extended class user role and tenentId
|
// Check extended class user role and tenentId
|
||||||
try {
|
try {
|
||||||
let userRoles = [];
|
let userRoles = [];
|
||||||
if (props.appInfo.settings) {
|
if (appInfo.settings) {
|
||||||
let userSettings = props.appInfo.settings;
|
let userSettings = appInfo.settings;
|
||||||
|
|
||||||
//Get Current user roles
|
//Get Current user roles
|
||||||
let url = `${baseUrl}functions/UserGroups`;
|
let url = `${baseUrl}functions/UserGroups`;
|
||||||
@@ -319,8 +321,8 @@ const PgSignUp = (props) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (tenentInfo.length) {
|
if (tenentInfo.length) {
|
||||||
props.showTenantName(
|
dispatch(
|
||||||
tenentInfo[0].tenentName || ""
|
showTenant(tenentInfo[0].tenentName || "")
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenantName",
|
"TenantName",
|
||||||
@@ -351,15 +353,15 @@ const PgSignUp = (props) => {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (tenentInfo.length) {
|
if (tenentInfo.length) {
|
||||||
props.showTenantName(
|
dispatch(
|
||||||
tenentInfo[0].tenentName || ""
|
showTenant(tenentInfo[0].tenentName || "")
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenantName",
|
"TenantName",
|
||||||
@@ -537,15 +539,4 @@ const PgSignUp = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
export default PgSignUp;
|
||||||
if (Object.keys(state.appInfo).length !== 0) {
|
|
||||||
return { appInfo: state.appInfo, isloginVisible: true };
|
|
||||||
} else {
|
|
||||||
return { appInfo: state.appInfo, isloginVisible: false };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, {
|
|
||||||
fetchAppInfo,
|
|
||||||
showTenantName
|
|
||||||
})(PgSignUp);
|
|
||||||
|
|||||||
@@ -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";
|
||||||
@@ -27,7 +27,8 @@ import {
|
|||||||
addWidgetOptions,
|
addWidgetOptions,
|
||||||
textInputWidget,
|
textInputWidget,
|
||||||
textWidget,
|
textWidget,
|
||||||
radioButtonWidget
|
radioButtonWidget,
|
||||||
|
color
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import RenderPdf from "../components/pdf/RenderPdf";
|
import RenderPdf from "../components/pdf/RenderPdf";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
@@ -38,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();
|
||||||
@@ -80,6 +82,7 @@ function PlaceHolderSign() {
|
|||||||
const [zIndex, setZIndex] = useState(1);
|
const [zIndex, setZIndex] = useState(1);
|
||||||
const [signKey, setSignKey] = useState();
|
const [signKey, setSignKey] = useState();
|
||||||
const [tempSignerId, setTempSignerId] = useState("");
|
const [tempSignerId, setTempSignerId] = useState("");
|
||||||
|
const [blockColor, setBlockColor] = useState("");
|
||||||
const [pdfLoadFail, setPdfLoadFail] = useState({
|
const [pdfLoadFail, setPdfLoadFail] = useState({
|
||||||
status: false,
|
status: false,
|
||||||
type: "load"
|
type: "load"
|
||||||
@@ -95,32 +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 color = [
|
const [extUserId, setExtUserId] = useState("");
|
||||||
"#93a3db",
|
|
||||||
"#e6c3db",
|
|
||||||
"#c0e3bc",
|
|
||||||
"#bce3db",
|
|
||||||
"#b8ccdb",
|
|
||||||
"#ceb8db",
|
|
||||||
"#ffccff",
|
|
||||||
"#99ffcc",
|
|
||||||
"#cc99ff",
|
|
||||||
"#ffcc99",
|
|
||||||
"#66ccff",
|
|
||||||
"#ffffcc"
|
|
||||||
];
|
|
||||||
|
|
||||||
const isMobile = window.innerWidth < 767;
|
const isMobile = window.innerWidth < 767;
|
||||||
const [, drop] = useDrop({
|
const [, drop] = useDrop({
|
||||||
accept: "BOX",
|
accept: "BOX",
|
||||||
@@ -192,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) {
|
||||||
@@ -276,14 +290,17 @@ function PlaceHolderSign() {
|
|||||||
});
|
});
|
||||||
setSignersData(updatedSigners);
|
setSignersData(updatedSigners);
|
||||||
setUniqueId(updatedSigners[0].Id);
|
setUniqueId(updatedSigners[0].Id);
|
||||||
|
setBlockColor(updatedSigners[0].blockColor);
|
||||||
} else {
|
} else {
|
||||||
const updatedSigners = documentData[0].Signers.map((x, index) => ({
|
const updatedSigners = documentData[0].Signers.map((x, index) => ({
|
||||||
...x,
|
...x,
|
||||||
Id: randomId(),
|
Id: randomId(),
|
||||||
Role: "User " + (index + 1)
|
Role: "User " + (index + 1),
|
||||||
|
blockColor: color[index % color.length]
|
||||||
}));
|
}));
|
||||||
setSignersData(updatedSigners);
|
setSignersData(updatedSigners);
|
||||||
setUniqueId(updatedSigners[0].Id);
|
setUniqueId(updatedSigners[0].Id);
|
||||||
|
setBlockColor(updatedSigners[0].blockColor);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setRoleName("User 1");
|
setRoleName("User 1");
|
||||||
@@ -303,6 +320,7 @@ function PlaceHolderSign() {
|
|||||||
setSignersData(updatedSigners);
|
setSignersData(updatedSigners);
|
||||||
setIsSelectId(0);
|
setIsSelectId(0);
|
||||||
setUniqueId(updatedSigners[0].Id);
|
setUniqueId(updatedSigners[0].Id);
|
||||||
|
setBlockColor(updatedSigners[0].blockColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
@@ -744,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);
|
||||||
@@ -837,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,
|
||||||
@@ -1034,7 +1056,7 @@ function PlaceHolderSign() {
|
|||||||
selector: '[data-tut="reactourSecond"]',
|
selector: '[data-tut="reactourSecond"]',
|
||||||
content: () => (
|
content: () => (
|
||||||
<TourContentWithBtn
|
<TourContentWithBtn
|
||||||
message={`Drag the signature or stamp placeholder onto the PDF to choose your desired signing location.`}
|
message={`Drag or click on a field to add it to the document.`}
|
||||||
isChecked={handleDontShow}
|
isChecked={handleDontShow}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
@@ -1372,7 +1394,6 @@ function PlaceHolderSign() {
|
|||||||
const closePopup = () => {
|
const closePopup = () => {
|
||||||
setIsAddUser({});
|
setIsAddUser({});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title title={state?.title ? state.title : "New Document"} />
|
<Title title={state?.title ? state.title : "New Document"} />
|
||||||
@@ -1459,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>
|
||||||
@@ -1605,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"
|
||||||
@@ -1615,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"
|
||||||
@@ -1625,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 */}
|
||||||
@@ -1717,13 +1741,19 @@ function PlaceHolderSign() {
|
|||||||
setUniqueId={setUniqueId}
|
setUniqueId={setUniqueId}
|
||||||
setRoleName={setRoleName}
|
setRoleName={setRoleName}
|
||||||
initial={true}
|
initial={true}
|
||||||
|
sendInOrder={pdfDetails[0].SendinOrder}
|
||||||
|
setSignersData={setSignersData}
|
||||||
|
blockColor={blockColor}
|
||||||
|
setBlockColor={setBlockColor}
|
||||||
/>
|
/>
|
||||||
</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
|
||||||
@@ -1735,11 +1765,16 @@ function PlaceHolderSign() {
|
|||||||
setContractName={setContractName}
|
setContractName={setContractName}
|
||||||
setUniqueId={setUniqueId}
|
setUniqueId={setUniqueId}
|
||||||
setRoleName={setRoleName}
|
setRoleName={setRoleName}
|
||||||
|
sendInOrder={pdfDetails[0].SendinOrder}
|
||||||
|
setSignersData={setSignersData}
|
||||||
|
blockColor={blockColor}
|
||||||
|
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}
|
||||||
@@ -1829,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>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const Report = () => {
|
|||||||
const [List, setList] = useState([]);
|
const [List, setList] = useState([]);
|
||||||
const [isLoader, setIsLoader] = useState(true);
|
const [isLoader, setIsLoader] = useState(true);
|
||||||
const [reportName, setReportName] = useState("");
|
const [reportName, setReportName] = useState("");
|
||||||
|
const [reporthelp, setReportHelp] = useState("");
|
||||||
const [actions, setActions] = useState([]);
|
const [actions, setActions] = useState([]);
|
||||||
const [heading, setHeading] = useState([]);
|
const [heading, setHeading] = useState([]);
|
||||||
const [isNextRecord, setIsNextRecord] = useState(false);
|
const [isNextRecord, setIsNextRecord] = useState(false);
|
||||||
@@ -53,6 +54,7 @@ const Report = () => {
|
|||||||
setHeading(json.heading);
|
setHeading(json.heading);
|
||||||
setReportName(json.reportName);
|
setReportName(json.reportName);
|
||||||
setForm(json.form);
|
setForm(json.form);
|
||||||
|
setReportHelp(json?.helpMsg)
|
||||||
const currentUser = Parse.User.current().id;
|
const currentUser = Parse.User.current().id;
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
@@ -156,6 +158,7 @@ const Report = () => {
|
|||||||
isMoreDocs={isMoreDocs}
|
isMoreDocs={isMoreDocs}
|
||||||
docPerPage={docPerPage}
|
docPerPage={docPerPage}
|
||||||
form={form}
|
form={form}
|
||||||
|
report_help={reporthelp}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<PageNotFound prefix={"Report"} />
|
<PageNotFound prefix={"Report"} />
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { connect } from "react-redux";
|
|
||||||
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 { fetchAppInfo, showTenantName } from "../redux/actions";
|
import { useNavigate, NavLink, useLocation } from "react-router-dom";
|
||||||
import { useNavigate, NavLink } 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";
|
||||||
const Signup = (props) => {
|
import { useDispatch } from "react-redux";
|
||||||
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
|
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||||
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
const Signup = () => {
|
||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [phone, setPhone] = useState("");
|
const [phone, setPhone] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
@@ -29,7 +33,7 @@ const Signup = (props) => {
|
|||||||
const [specialCharValid, setSpecialCharValid] = useState(false);
|
const [specialCharValid, setSpecialCharValid] = useState(false);
|
||||||
|
|
||||||
const togglePasswordVisibility = () => setShowPassword(!showPassword);
|
const togglePasswordVisibility = () => setShowPassword(!showPassword);
|
||||||
const image = props.appInfo.applogo;
|
const image = appInfo.applogo;
|
||||||
|
|
||||||
const clearStorage = async () => {
|
const clearStorage = async () => {
|
||||||
if (Parse.User.current()) {
|
if (Parse.User.current()) {
|
||||||
@@ -65,6 +69,19 @@ const Signup = (props) => {
|
|||||||
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) {
|
||||||
@@ -90,7 +107,7 @@ const Signup = (props) => {
|
|||||||
res
|
res
|
||||||
.then(async (r) => {
|
.then(async (r) => {
|
||||||
if (r) {
|
if (r) {
|
||||||
let roleData = props.appInfo.settings;
|
let roleData = appInfo.settings;
|
||||||
if (roleData && roleData.length > 0) {
|
if (roleData && roleData.length > 0) {
|
||||||
const params = {
|
const params = {
|
||||||
userDetails: {
|
userDetails: {
|
||||||
@@ -99,7 +116,7 @@ const Signup = (props) => {
|
|||||||
name: name,
|
name: name,
|
||||||
email: email,
|
email: email,
|
||||||
phone: phone,
|
phone: phone,
|
||||||
role: props.appInfo.defaultRole
|
role: appInfo.defaultRole
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
@@ -108,7 +125,13 @@ const Signup = (props) => {
|
|||||||
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);
|
||||||
@@ -153,7 +176,7 @@ const Signup = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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", {
|
||||||
@@ -181,8 +204,8 @@ const Signup = (props) => {
|
|||||||
// Check extended class user role and tenentId
|
// Check extended class user role and tenentId
|
||||||
try {
|
try {
|
||||||
let userRoles = [];
|
let userRoles = [];
|
||||||
if (props.appInfo.settings) {
|
if (appInfo.settings) {
|
||||||
let userSettings = props.appInfo.settings;
|
let userSettings = appInfo.settings;
|
||||||
|
|
||||||
//Get Current user roles
|
//Get Current user roles
|
||||||
let url = `${baseUrl}functions/UserGroups`;
|
let url = `${baseUrl}functions/UserGroups`;
|
||||||
@@ -256,8 +279,8 @@ const Signup = (props) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (tenentInfo.length) {
|
if (tenentInfo.length) {
|
||||||
props.showTenantName(
|
dispatch(
|
||||||
tenentInfo[0].tenentName || ""
|
showTenant(tenentInfo[0].tenentName || "")
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenantName",
|
"TenantName",
|
||||||
@@ -293,15 +316,15 @@ const Signup = (props) => {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (tenentInfo.length) {
|
if (tenentInfo.length) {
|
||||||
props.showTenantName(
|
dispatch(
|
||||||
tenentInfo[0].tenentName || ""
|
showTenant(tenentInfo[0].tenentName || "")
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenantName",
|
"TenantName",
|
||||||
@@ -321,8 +344,14 @@ const Signup = (props) => {
|
|||||||
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(
|
||||||
@@ -339,8 +368,14 @@ const Signup = (props) => {
|
|||||||
);
|
);
|
||||||
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}`
|
||||||
@@ -433,7 +468,7 @@ const Signup = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
props.fetchAppInfo();
|
dispatch(fetchAppInfo());
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -479,7 +514,7 @@ const Signup = (props) => {
|
|||||||
|
|
||||||
<Title title={"Signup page"} />
|
<Title title={"Signup page"} />
|
||||||
|
|
||||||
{props.isloginVisible && props.isloginVisible ? (
|
{appInfo && appInfo.applogo ? (
|
||||||
<div>
|
<div>
|
||||||
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
||||||
<div className="w-[250px] h-[66px] inline-block">
|
<div className="w-[250px] h-[66px] inline-block">
|
||||||
@@ -622,7 +657,7 @@ const Signup = (props) => {
|
|||||||
</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
|
||||||
@@ -657,15 +692,4 @@ const Signup = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
export default Signup;
|
||||||
if (Object.keys(state.appInfo).length !== 0) {
|
|
||||||
return { appInfo: state.appInfo, isloginVisible: true };
|
|
||||||
} else {
|
|
||||||
return { appInfo: state.appInfo, isloginVisible: false };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, {
|
|
||||||
fetchAppInfo,
|
|
||||||
showTenantName
|
|
||||||
})(Signup);
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
contactBook,
|
contactBook,
|
||||||
randomId,
|
randomId,
|
||||||
getDate,
|
getDate,
|
||||||
textInputWidget
|
textWidget
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import Tour from "reactour";
|
import Tour from "reactour";
|
||||||
@@ -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!");
|
||||||
@@ -342,8 +347,7 @@ function SignYourSelf() {
|
|||||||
return {
|
return {
|
||||||
name: "checkbox"
|
name: "checkbox"
|
||||||
};
|
};
|
||||||
|
case textWidget:
|
||||||
case textInputWidget:
|
|
||||||
return {
|
return {
|
||||||
name: "text"
|
name: "text"
|
||||||
};
|
};
|
||||||
@@ -430,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)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -528,7 +532,6 @@ function SignYourSelf() {
|
|||||||
checkSigned = requiredWidgets[i]?.options?.response;
|
checkSigned = requiredWidgets[i]?.options?.response;
|
||||||
if (!checkSigned) {
|
if (!checkSigned) {
|
||||||
const checkSignUrl = requiredWidgets[i]?.pos?.SignUrl;
|
const checkSignUrl = requiredWidgets[i]?.pos?.SignUrl;
|
||||||
|
|
||||||
let checkDefaultSigned = requiredWidgets[i]?.options?.defaultValue;
|
let checkDefaultSigned = requiredWidgets[i]?.options?.defaultValue;
|
||||||
if (!checkSignUrl) {
|
if (!checkSignUrl) {
|
||||||
if (!checkDefaultSigned) {
|
if (!checkDefaultSigned) {
|
||||||
@@ -587,11 +590,12 @@ function SignYourSelf() {
|
|||||||
flag,
|
flag,
|
||||||
containerWH
|
containerWH
|
||||||
);
|
);
|
||||||
// console.log('pdf',pdfBytes)
|
// console.log("pdf", pdfBytes);
|
||||||
//function for call to embed signature in pdf and get digital signature pdf
|
//function for call to embed signature in pdf and get digital signature pdf
|
||||||
await signPdfFun(pdfBytes, documentId);
|
await signPdfFun(pdfBytes, documentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// console.log("signyourself", xyPostion);
|
||||||
//function for get digital signature
|
//function for get digital signature
|
||||||
const signPdfFun = async (base64Url, documentId) => {
|
const signPdfFun = async (base64Url, documentId) => {
|
||||||
let singleSign = {
|
let singleSign = {
|
||||||
@@ -705,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"
|
||||||
@@ -728,6 +732,7 @@ function SignYourSelf() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const getUpdatePosition = onSaveSign(
|
const getUpdatePosition = onSaveSign(
|
||||||
|
type,
|
||||||
xyPostion,
|
xyPostion,
|
||||||
index,
|
index,
|
||||||
signKey,
|
signKey,
|
||||||
@@ -764,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);
|
||||||
@@ -1102,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
|
||||||
@@ -1113,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"
|
||||||
@@ -77,6 +79,7 @@ const TemplatePlaceholder = () => {
|
|||||||
const [showDropdown, setShowDropdown] = useState(false);
|
const [showDropdown, setShowDropdown] = useState(false);
|
||||||
const [widgetType, setWidgetType] = useState("");
|
const [widgetType, setWidgetType] = useState("");
|
||||||
const [isRadio, setIsRadio] = useState(false);
|
const [isRadio, setIsRadio] = useState(false);
|
||||||
|
const [blockColor, setBlockColor] = useState("");
|
||||||
const [selectWidgetId, setSelectWidgetId] = useState("");
|
const [selectWidgetId, setSelectWidgetId] = useState("");
|
||||||
const [isNameModal, setIsNameModal] = useState(false);
|
const [isNameModal, setIsNameModal] = useState(false);
|
||||||
const [pdfLoadFail, setPdfLoadFail] = useState({
|
const [pdfLoadFail, setPdfLoadFail] = useState({
|
||||||
@@ -167,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 {
|
||||||
@@ -189,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) {
|
||||||
@@ -223,6 +248,7 @@ const TemplatePlaceholder = () => {
|
|||||||
});
|
});
|
||||||
setSignersData(updatedSigners);
|
setSignersData(updatedSigners);
|
||||||
setUniqueId(updatedSigners[0].Id);
|
setUniqueId(updatedSigners[0].Id);
|
||||||
|
setBlockColor(updatedSigners[0].blockColor);
|
||||||
} else {
|
} else {
|
||||||
const updatedSigners = documentData[0].Signers.map((x, index) => ({
|
const updatedSigners = documentData[0].Signers.map((x, index) => ({
|
||||||
...x,
|
...x,
|
||||||
@@ -231,6 +257,7 @@ const TemplatePlaceholder = () => {
|
|||||||
}));
|
}));
|
||||||
setSignersData(updatedSigners);
|
setSignersData(updatedSigners);
|
||||||
setUniqueId(updatedSigners[0].Id);
|
setUniqueId(updatedSigners[0].Id);
|
||||||
|
setBlockColor(updatedSigners[0].blockColor);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setRoleName("User 1");
|
setRoleName("User 1");
|
||||||
@@ -249,6 +276,7 @@ const TemplatePlaceholder = () => {
|
|||||||
setUniqueId(updatedSigners[0].Id);
|
setUniqueId(updatedSigners[0].Id);
|
||||||
setSignersData(updatedSigners);
|
setSignersData(updatedSigners);
|
||||||
setIsSelectId(0);
|
setIsSelectId(0);
|
||||||
|
setBlockColor(updatedSigners[0].blockColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
@@ -446,7 +474,7 @@ const TemplatePlaceholder = () => {
|
|||||||
setIsCheckbox(true);
|
setIsCheckbox(true);
|
||||||
} else if (dragTypeValue === radioButtonWidget) {
|
} else if (dragTypeValue === radioButtonWidget) {
|
||||||
setIsRadio(true);
|
setIsRadio(true);
|
||||||
}
|
}
|
||||||
setCurrWidgetsDetails({});
|
setCurrWidgetsDetails({});
|
||||||
setWidgetType(dragTypeValue);
|
setWidgetType(dragTypeValue);
|
||||||
setSignKey(key);
|
setSignKey(key);
|
||||||
@@ -854,6 +882,7 @@ const TemplatePlaceholder = () => {
|
|||||||
setIsModalRole(false);
|
setIsModalRole(false);
|
||||||
setRoleName("");
|
setRoleName("");
|
||||||
setUniqueId(Id);
|
setUniqueId(Id);
|
||||||
|
setBlockColor(color[index]);
|
||||||
setIsSelectId(index);
|
setIsSelectId(index);
|
||||||
setIsMailSend(false);
|
setIsMailSend(false);
|
||||||
};
|
};
|
||||||
@@ -870,9 +899,11 @@ const TemplatePlaceholder = () => {
|
|||||||
if (index === signersdata.length - 1) {
|
if (index === signersdata.length - 1) {
|
||||||
setUniqueId(updateSigner[updateSigner.length - 1]?.Id || "");
|
setUniqueId(updateSigner[updateSigner.length - 1]?.Id || "");
|
||||||
setIsSelectId(index - 1 || 0);
|
setIsSelectId(index - 1 || 0);
|
||||||
|
setBlockColor(color[index - 1 || 0]);
|
||||||
} else {
|
} else {
|
||||||
setUniqueId(updateSigner[index]?.Id || "");
|
setUniqueId(updateSigner[index]?.Id || "");
|
||||||
setIsSelectId(index);
|
setIsSelectId(index);
|
||||||
|
setBlockColor(color[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSignerPos(updatePlaceholderUser);
|
setSignerPos(updatePlaceholderUser);
|
||||||
@@ -1316,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"
|
||||||
@@ -1326,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"
|
||||||
@@ -1336,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}
|
||||||
@@ -1443,6 +1477,10 @@ const TemplatePlaceholder = () => {
|
|||||||
title={"Roles"}
|
title={"Roles"}
|
||||||
initial={true}
|
initial={true}
|
||||||
isTemplateFlow={true}
|
isTemplateFlow={true}
|
||||||
|
sendInOrder={pdfDetails[0].SendinOrder}
|
||||||
|
setSignersData={setSignersData}
|
||||||
|
blockColor={blockColor}
|
||||||
|
setBlockColor={setBlockColor}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -1453,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}
|
||||||
@@ -1466,10 +1505,14 @@ const TemplatePlaceholder = () => {
|
|||||||
handleRoleChange={handleRoleChange}
|
handleRoleChange={handleRoleChange}
|
||||||
handleOnBlur={handleOnBlur}
|
handleOnBlur={handleOnBlur}
|
||||||
title={"Roles"}
|
title={"Roles"}
|
||||||
|
sendInOrder={pdfDetails[0]?.SendinOrder}
|
||||||
|
setSignersData={setSignersData}
|
||||||
|
blockColor={blockColor}
|
||||||
|
setBlockColor={setBlockColor}
|
||||||
/>
|
/>
|
||||||
<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}
|
||||||
@@ -1526,6 +1569,7 @@ const TemplatePlaceholder = () => {
|
|||||||
isOpen={isNameModal}
|
isOpen={isNameModal}
|
||||||
handleClose={handleNameModal}
|
handleClose={handleNameModal}
|
||||||
handleData={handleWidgetdefaultdata}
|
handleData={handleWidgetdefaultdata}
|
||||||
|
isSubscribe={isSubscribe}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ import dp from "../assets/images/dp.png";
|
|||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import sanitizeFileName from "../primitives/sanitizeFileName";
|
import sanitizeFileName from "../primitives/sanitizeFileName";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||||
|
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();
|
||||||
@@ -19,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);
|
||||||
@@ -135,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) {
|
||||||
@@ -153,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"} />
|
||||||
@@ -250,7 +264,7 @@ function UserProfile() {
|
|||||||
<span className="font-semibold">Email:</span>{" "}
|
<span className="font-semibold">Email:</span>{" "}
|
||||||
<span>{UserProfile && UserProfile.email}</span>
|
<span>{UserProfile && UserProfile.email}</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex justify-between items-center border-y-[1px] border-gray-300 py-2 break-all">
|
<li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all">
|
||||||
<span className="font-semibold">Is Email verified:</span>{" "}
|
<span className="font-semibold">Is Email verified:</span>{" "}
|
||||||
<span>
|
<span>
|
||||||
{UserProfile && UserProfile.emailVerified
|
{UserProfile && UserProfile.emailVerified
|
||||||
@@ -258,10 +272,33 @@ function UserProfile() {
|
|||||||
: "Not verified"}
|
: "Not verified"}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex justify-between items-center border-y-[1px] border-gray-300 py-2 break-all">
|
<li className="border-y-[1px] border-gray-300 break-all">
|
||||||
<span className="font-semibold">Disable DocumentId :</span>{" "}
|
<div className="flex justify-between items-center py-2">
|
||||||
<span>
|
<span
|
||||||
<label className="relative inline-flex items-center cursor-pointer mb-0">
|
className={
|
||||||
|
isSubscribe || !isEnableSubscription
|
||||||
|
? "font-semibold"
|
||||||
|
: "font-semibold text-gray-300"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Disable DocumentId :{" "}
|
||||||
|
<Tooltip
|
||||||
|
url={
|
||||||
|
"https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid"
|
||||||
|
}
|
||||||
|
isSubscribe={isSubscribe}
|
||||||
|
/>{" "}
|
||||||
|
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||||
|
</span>{" "}
|
||||||
|
<label
|
||||||
|
className={
|
||||||
|
isSubscribe || !isEnableSubscription
|
||||||
|
? `${
|
||||||
|
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}
|
||||||
checked={isDisableDocId}
|
checked={isDisableDocId}
|
||||||
@@ -270,9 +307,16 @@ function UserProfile() {
|
|||||||
value=""
|
value=""
|
||||||
className="sr-only peer"
|
className="sr-only peer"
|
||||||
/>
|
/>
|
||||||
<div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 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-gray-600 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>
|
||||||
</span>
|
</div>
|
||||||
|
{!isEnableSubscription && (
|
||||||
|
<PremiumAlertHeader
|
||||||
|
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,13 +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 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();
|
||||||
@@ -15,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();
|
||||||
@@ -23,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);
|
||||||
@@ -38,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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,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={{
|
||||||
@@ -101,25 +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">
|
||||||
<h1 className="ml-4 mt-3 mb-2 font-semibold">Webhook</h1>
|
{!isEnableSubscription && <PremiumAlertHeader />}
|
||||||
<ul className="w-full flex flex-col p-2 text-sm">
|
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||||
|
OpenSign™ Webhook{" "}
|
||||||
|
<Tooltip
|
||||||
|
url={"https://docs.opensignlabs.com/docs/API-docs/get-webhook"}
|
||||||
|
isSubscribe={true}
|
||||||
|
/>
|
||||||
|
</h1>
|
||||||
|
<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={() =>
|
||||||
@@ -127,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")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import ModalUi from "./ModalUi";
|
|||||||
import AddSigner from "../components/AddSigner";
|
import AddSigner from "../components/AddSigner";
|
||||||
import { modalSubmitBtnColor, modalCancelBtnColor } from "../constant/const";
|
import { modalSubmitBtnColor, modalCancelBtnColor } from "../constant/const";
|
||||||
import Alert from "./Alert";
|
import Alert from "./Alert";
|
||||||
|
import Tooltip from "./Tooltip";
|
||||||
const ReportTable = ({
|
const ReportTable = ({
|
||||||
ReportName,
|
ReportName,
|
||||||
List,
|
List,
|
||||||
@@ -15,7 +16,8 @@ const ReportTable = ({
|
|||||||
setIsNextRecord,
|
setIsNextRecord,
|
||||||
isMoreDocs,
|
isMoreDocs,
|
||||||
docPerPage,
|
docPerPage,
|
||||||
form
|
form,
|
||||||
|
report_help
|
||||||
}) => {
|
}) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
@@ -255,7 +257,14 @@ const ReportTable = ({
|
|||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
||||||
<div className="font-light">{ReportName}</div>
|
<div className="font-light">
|
||||||
|
{ReportName}{" "}
|
||||||
|
{report_help && (
|
||||||
|
<span className="text-xs md:text-[13px] font-normal">
|
||||||
|
<Tooltip message={report_help} />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
{ReportName === "Templates" && (
|
{ReportName === "Templates" && (
|
||||||
<i
|
<i
|
||||||
onClick={() => navigate("/form/template")}
|
onClick={() => navigate("/form/template")}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import React, { Suspense } from "react";
|
||||||
|
|
||||||
|
const LazyPage = ({ Page }) => {
|
||||||
|
return (
|
||||||
|
<Suspense
|
||||||
|
fallback={
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: "100vh",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: "45px",
|
||||||
|
color: "#3dd3e0"
|
||||||
|
}}
|
||||||
|
className="loader-37"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Page />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LazyPage;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const PremiumAlertHeader = ({ message }) => (
|
||||||
|
<marquee className="bg-yellow-300 text-black px-2">
|
||||||
|
{message
|
||||||
|
? message
|
||||||
|
: "Currently free in Beta, this feature will incur a fee later."}
|
||||||
|
</marquee>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default PremiumAlertHeader;
|
||||||
@@ -1,18 +1,52 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
// import * as HoverCard from "@radix-ui/react-hover-card";
|
|
||||||
// import "../styles/opensigndrive.css";
|
|
||||||
import { Tooltip as ReactTooltip } from "react-tooltip";
|
import { Tooltip as ReactTooltip } from "react-tooltip";
|
||||||
const Tooltip = ({ children, message }) => (
|
import { openInNewTab } from "../constant/Utils";
|
||||||
<>
|
import { isEnableSubscription } from "../constant/const";
|
||||||
<a data-tooltip-id="my-tooltip" data-tooltip-content={message}>
|
const Tooltip = ({ id, message, url, iconColor, isSubscribe }) =>
|
||||||
{children ? (
|
url ? (
|
||||||
children
|
<button
|
||||||
) : (
|
onClick={() => openInNewTab(url)}
|
||||||
<i className="fa-solid fa-question border-[1.5px] px-1.5 py-0.5 rounded-full border-[#33bbff] text-xs text-[#33bbff]"></i>
|
className={
|
||||||
)}
|
isSubscribe || !isEnableSubscription
|
||||||
</a>
|
? "text-center"
|
||||||
<ReactTooltip id="my-tooltip" className="max-w-[200px]" />
|
: "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>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<a
|
||||||
|
data-tooltip-id={id ? id : "my-tooltip"}
|
||||||
|
data-tooltip-content={message}
|
||||||
|
className="z-50"
|
||||||
|
>
|
||||||
|
<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>
|
||||||
|
</a>
|
||||||
|
<ReactTooltip id={id ? id : "my-tooltip"} className="max-w-[200px]" />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
export default Tooltip;
|
export default Tooltip;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -1,200 +0,0 @@
|
|||||||
import Parse from "parse";
|
|
||||||
import axios from "axios";
|
|
||||||
import { appInfo } from "../../constant/appinfo";
|
|
||||||
|
|
||||||
//For fetching application Information
|
|
||||||
export const fetchAppInfo = () => async (dispatch) => {
|
|
||||||
localStorage.setItem("_appName", appInfo.appname);
|
|
||||||
localStorage.setItem("_app_objectId", appInfo.objectId);
|
|
||||||
localStorage.setItem("baseUrl", `${appInfo.baseUrl}/`);
|
|
||||||
localStorage.setItem("parseAppId", appInfo.appId);
|
|
||||||
localStorage.setItem("appLogo", appInfo.applogo);
|
|
||||||
localStorage.setItem("appVersion", appInfo.version);
|
|
||||||
localStorage.removeItem("userSettings");
|
|
||||||
localStorage.setItem("userSettings", JSON.stringify(appInfo.settings));
|
|
||||||
localStorage.setItem("appTitle", appInfo.appTitle);
|
|
||||||
localStorage.setItem("fev_Icon", appInfo.fev_Icon);
|
|
||||||
// console.log("response ", response);
|
|
||||||
dispatch({ type: "FATCH_APPINFO", payload: appInfo });
|
|
||||||
};
|
|
||||||
|
|
||||||
//for simple login
|
|
||||||
export const login = (username, password) => async (dispatch) => {
|
|
||||||
let res = {};
|
|
||||||
let baseUrl = localStorage.getItem("baseUrl");
|
|
||||||
let parseAppId = localStorage.getItem("parseAppId");
|
|
||||||
try {
|
|
||||||
await Parse.User.logIn(username, password).then(
|
|
||||||
async function (res1) {
|
|
||||||
var resultjson = res1.toJSON();
|
|
||||||
res = res1.toJSON();
|
|
||||||
localStorage.setItem("userEmail", username);
|
|
||||||
localStorage.setItem("username", resultjson.name);
|
|
||||||
localStorage.setItem("accesstoken", resultjson.sessionToken);
|
|
||||||
localStorage.setItem("scriptId", true);
|
|
||||||
if (resultjson.ProfilePic) {
|
|
||||||
localStorage.setItem("profileImg", resultjson.ProfilePic);
|
|
||||||
} else {
|
|
||||||
localStorage.setItem("profileImg", "");
|
|
||||||
}
|
|
||||||
let url = `${baseUrl}functions/UserGroups`;
|
|
||||||
const headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId,
|
|
||||||
sessionToken: resultjson.sessionToken
|
|
||||||
};
|
|
||||||
|
|
||||||
let body = {
|
|
||||||
appname: localStorage.getItem("domain")
|
|
||||||
};
|
|
||||||
let userGroup = "",
|
|
||||||
userGroup1 = "";
|
|
||||||
await axios
|
|
||||||
.post(url, JSON.stringify(body), { headers: headers })
|
|
||||||
.then(async (response) => {
|
|
||||||
userGroup = response.data.result[0];
|
|
||||||
userGroup1 = response.data.result[1];
|
|
||||||
localStorage.setItem("_userGroup", userGroup);
|
|
||||||
});
|
|
||||||
|
|
||||||
let appSetings = JSON.parse(localStorage.getItem("userSettings"));
|
|
||||||
let defaultmenuid = "",
|
|
||||||
PageLanding = "",
|
|
||||||
pageType = "";
|
|
||||||
|
|
||||||
appSetings.forEach(async (element) => {
|
|
||||||
if (`${localStorage.getItem("_appName")}_appeditor` === userGroup) {
|
|
||||||
if (element.role === userGroup1) {
|
|
||||||
defaultmenuid = element.menuId;
|
|
||||||
PageLanding = element.pageId;
|
|
||||||
pageType = element.pageType;
|
|
||||||
localStorage.setItem("PageLanding", PageLanding);
|
|
||||||
localStorage.setItem("defaultmenuid", defaultmenuid);
|
|
||||||
localStorage.setItem("pageType", pageType);
|
|
||||||
let _role = userGroup1.replace(
|
|
||||||
`${localStorage.getItem("_appName")}_`,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
if (userGroup1) {
|
|
||||||
localStorage.setItem("_user_role", _role);
|
|
||||||
} else {
|
|
||||||
localStorage.setItem("_user_role", _role);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (element.role === userGroup) {
|
|
||||||
defaultmenuid = element.menuId;
|
|
||||||
PageLanding = element.pageId;
|
|
||||||
pageType = element.pageType;
|
|
||||||
localStorage.setItem("PageLanding", PageLanding);
|
|
||||||
localStorage.setItem("defaultmenuid", defaultmenuid);
|
|
||||||
localStorage.setItem("pageType", pageType);
|
|
||||||
localStorage.setItem("extended_class", element.extended_class);
|
|
||||||
let _role = userGroup.replace(
|
|
||||||
`${localStorage.getItem("domain")}_`,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
if (userGroup) {
|
|
||||||
localStorage.setItem("_user_role", _role);
|
|
||||||
} else {
|
|
||||||
localStorage.setItem("_user_role", _role);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const currentUser = Parse.User.current();
|
|
||||||
await Parse.Cloud.run("getUserDetails", {
|
|
||||||
email: currentUser.get("email")
|
|
||||||
}).then(
|
|
||||||
(results) => {
|
|
||||||
let userinfo = results.toJSON();
|
|
||||||
if (userinfo.TenantId) {
|
|
||||||
localStorage.setItem("TenetId", userinfo.TenantId.objectId);
|
|
||||||
}
|
|
||||||
// console.log("tour found", results);
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
console.error("Error while fetching tour", error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("err ", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch({ type: "APP_LOGIN", payload: res });
|
|
||||||
|
|
||||||
if (pageType !== "") {
|
|
||||||
window.location = `/${pageType}/${PageLanding}`;
|
|
||||||
} else {
|
|
||||||
alert("You dont have access to this application.");
|
|
||||||
localStorage.setItem("accesstoken", null);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function () {
|
|
||||||
alert("Invalid Login");
|
|
||||||
localStorage.setItem("accesstoken", null);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
alert("You dont have access to this application.");
|
|
||||||
localStorage.setItem("accesstoken", null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//for reset password
|
|
||||||
export const forgetPassword = (username) => async () => {
|
|
||||||
try {
|
|
||||||
await Parse.User.requestPasswordReset(username).then(
|
|
||||||
async function (res1) {
|
|
||||||
// var resultjson = res1;
|
|
||||||
// console.log("post data", resultjson.length);
|
|
||||||
if (res1.data === undefined) {
|
|
||||||
alert("Reset password link has been sent to your email id ");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function () {
|
|
||||||
// alert("Password Reset Done")
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Role field wizard
|
|
||||||
export const fetchRoleEnum = (name) => async (dispatch) => {
|
|
||||||
let response = [];
|
|
||||||
let baseUrl = localStorage.getItem("baseUrl");
|
|
||||||
let parseAppId = localStorage.getItem("parseAppId");
|
|
||||||
try {
|
|
||||||
let url = `${baseUrl}roles?where={"name":{"$regex":"${name}","$ne":"${localStorage.getItem(
|
|
||||||
"domain"
|
|
||||||
)}_appeditor"}}`;
|
|
||||||
const headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId
|
|
||||||
};
|
|
||||||
await axios.get(url, { headers: headers }).then((res) => {
|
|
||||||
let temp = [];
|
|
||||||
res.data.results.forEach((x) => {
|
|
||||||
temp.push(x["name"]);
|
|
||||||
});
|
|
||||||
response = temp;
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Problem", e);
|
|
||||||
}
|
|
||||||
dispatch({ type: "FETCH_ROLE", payload: response });
|
|
||||||
};
|
|
||||||
|
|
||||||
export const showTenantName = (name) => async (dispatch) => {
|
|
||||||
dispatch({ type: "SHOW_TENANT", payload: name || null });
|
|
||||||
};
|
|
||||||
|
|
||||||
export const save_tourSteps = (steps) => async (dispatch) => {
|
|
||||||
dispatch({ type: "SAVE_TOURSTEPS", payload: steps });
|
|
||||||
};
|
|
||||||
|
|
||||||
export const remove_tourSteps = () => async (dispatch) => {
|
|
||||||
dispatch({ type: "REMOVE_TOURSTEPS", payload: [] });
|
|
||||||
};
|
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
const ShowTenant = (state = "", action) => {
|
import { createSlice } from "@reduxjs/toolkit";
|
||||||
switch (action.type) {
|
|
||||||
case "SHOW_TENANT":
|
const showTenantSlice = createSlice({
|
||||||
|
name: "showTenant",
|
||||||
|
initialState: "",
|
||||||
|
reducers: {
|
||||||
|
showTenant: (state, action) => {
|
||||||
return action.payload;
|
return action.payload;
|
||||||
default:
|
},
|
||||||
return state;
|
},
|
||||||
}
|
});
|
||||||
};
|
|
||||||
export default ShowTenant;
|
export const { showTenant } = showTenantSlice.actions;
|
||||||
|
export default showTenantSlice.reducer;
|
||||||
@@ -1,11 +1,17 @@
|
|||||||
const tourStepReducer = (state = "", action) => {
|
import { createSlice } from "@reduxjs/toolkit";
|
||||||
switch (action.type) {
|
|
||||||
case "SAVE_TOURSTEPS":
|
const tourStepSlice = createSlice({
|
||||||
|
name: "tourStep",
|
||||||
|
initialState: [],
|
||||||
|
reducers: {
|
||||||
|
saveTourSteps: (state, action) => {
|
||||||
return action.payload;
|
return action.payload;
|
||||||
case "REMOVE_TOURSTEPS":
|
},
|
||||||
|
removeTourSteps: () => {
|
||||||
return [];
|
return [];
|
||||||
default:
|
}
|
||||||
return state;
|
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
export default tourStepReducer;
|
|
||||||
|
export const { saveTourSteps, removeTourSteps } = tourStepSlice.actions;
|
||||||
|
export default tourStepSlice.reducer;
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import { combineReducers } from "redux";
|
import { combineReducers } from "redux";
|
||||||
import infoReducer from "./infoReducer";
|
import infoReducer from "./infoReducer";
|
||||||
import loginReducer from "./loginReducer";
|
|
||||||
import ShowTenant from "./ShowTenant";
|
import ShowTenant from "./ShowTenant";
|
||||||
import TourStepsReducer from "./TourStepsReducer";
|
import TourStepsReducer from "./TourStepsReducer";
|
||||||
|
|
||||||
export default combineReducers({
|
export default combineReducers({
|
||||||
appInfo: infoReducer,
|
appInfo: infoReducer,
|
||||||
login: loginReducer,
|
TourSteps: TourStepsReducer,
|
||||||
ShowTenant,
|
ShowTenant
|
||||||
TourSteps: TourStepsReducer
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,24 @@
|
|||||||
const infoReducer = (state = {}, action) => {
|
import { createSlice } from "@reduxjs/toolkit";
|
||||||
switch (action.type) {
|
import { appInfo } from "../../constant/appinfo";
|
||||||
case "FATCH_APPINFO":
|
|
||||||
return action.payload;
|
const infoSlice = createSlice({
|
||||||
default:
|
name: "info",
|
||||||
return state;
|
initialState: {},
|
||||||
|
reducers: {
|
||||||
|
fetchAppInfo: () => {
|
||||||
|
localStorage.setItem("_appName", appInfo.appname);
|
||||||
|
localStorage.setItem("_app_objectId", appInfo.objectId);
|
||||||
|
localStorage.setItem("baseUrl", `${appInfo.baseUrl}/`);
|
||||||
|
localStorage.setItem("parseAppId", appInfo.appId);
|
||||||
|
localStorage.setItem("appLogo", appInfo.applogo);
|
||||||
|
localStorage.setItem("appVersion", appInfo.version);
|
||||||
|
localStorage.removeItem("userSettings");
|
||||||
|
localStorage.setItem("userSettings", JSON.stringify(appInfo.settings));
|
||||||
|
localStorage.setItem("appTitle", appInfo.appTitle);
|
||||||
|
localStorage.setItem("fev_Icon", appInfo.fev_Icon);
|
||||||
|
return appInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
export default infoReducer;
|
export const { fetchAppInfo } = infoSlice.actions;
|
||||||
|
export default infoSlice.reducer;
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
const loginReducer = (state = {}, action) => {
|
|
||||||
switch (action.type) {
|
|
||||||
case "APP_LOGIN":
|
|
||||||
return action.payload;
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
export default loginReducer;
|
|
||||||
@@ -1,5 +1,16 @@
|
|||||||
import { createStore, applyMiddleware } from "redux";
|
// import { createStore, applyMiddleware } from "redux";
|
||||||
import thunk from "redux-thunk";
|
// import thunk from "redux-thunk";
|
||||||
import reducers from "./reducers";
|
// import reducers from "./reducers";
|
||||||
|
|
||||||
export const store = createStore(reducers, applyMiddleware(thunk));
|
// export const store = createStore(reducers, applyMiddleware(thunk));
|
||||||
|
import { configureStore } from "@reduxjs/toolkit";
|
||||||
|
import infoReducer from "./reducers/infoReducer";
|
||||||
|
import ShowTenant from "./reducers/ShowTenant";
|
||||||
|
import TourStepsReducer from "./reducers/TourStepsReducer";
|
||||||
|
export const store = configureStore({
|
||||||
|
reducer: {
|
||||||
|
appInfo: infoReducer,
|
||||||
|
TourSteps: TourStepsReducer,
|
||||||
|
ShowTenant
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@@ -101,4 +101,62 @@
|
|||||||
.validationlist {
|
.validationlist {
|
||||||
background-position: right 1rem top 50%;
|
background-position: right 1rem top 50%;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
position: absolute;
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid black;
|
||||||
|
background: white;
|
||||||
|
width: 250px;
|
||||||
|
border-radius: 5px;
|
||||||
|
animation: inAnimation 1s ease-in-out;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.defaultvalueWarning {
|
||||||
|
position: absolute;
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.defaultvalueWarning::before {
|
||||||
|
content: "";
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
border-style: outset;
|
||||||
|
border-width: 0px 10px 10px 10px;
|
||||||
|
border-color: transparent transparent black transparent;
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
top: -29%;
|
||||||
|
left: 0;
|
||||||
|
right: 75%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes inAnimation {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
25% {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
75% {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -18,27 +18,6 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nameWarning {
|
|
||||||
position: absolute;
|
|
||||||
bottom: -70px;
|
|
||||||
left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nameWarning::before {
|
|
||||||
content: "";
|
|
||||||
width: 0px;
|
|
||||||
height: 0px;
|
|
||||||
border-style: outset;
|
|
||||||
border-width: 0px 10px 10px 10px;
|
|
||||||
border-color: transparent transparent black transparent;
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
top: -29%;
|
|
||||||
left: 0;
|
|
||||||
right: 75%;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signWarning {
|
.signWarning {
|
||||||
bottom: 70px;
|
bottom: 70px;
|
||||||
left: 50px;
|
left: 50px;
|
||||||
|
|||||||
@@ -15,15 +15,8 @@
|
|||||||
border-width: 0.2px;
|
border-width: 0.2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdownContainer {
|
.dragCursor {
|
||||||
display: flex;
|
cursor: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAASElEQVR4nGNgwAMkJSUbpKSkOvCpIaT5PxSTbogUQjMYMwxeIIXmVFIxA8UGDDyQGg0DnIDi6JKUlCxHMqCeZAOghjSAMD5FAKfeaURdUFxCAAAAAElFTkSuQmCC"), auto;
|
||||||
flex-direction: column;
|
|
||||||
overflow-y: scroll;
|
|
||||||
max-height: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdownContainer::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-datepicker__input-container {
|
.react-datepicker__input-container {
|
||||||
@@ -503,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;
|
||||||
@@ -2,7 +2,8 @@ import axios from 'axios';
|
|||||||
export default async function getDrive(request) {
|
export default async function getDrive(request) {
|
||||||
const serverUrl = process.env.SERVER_URL;
|
const serverUrl = process.env.SERVER_URL;
|
||||||
const appId = process.env.APP_ID;
|
const appId = process.env.APP_ID;
|
||||||
|
const limit = request.params.limit;
|
||||||
|
const skip = request.params.skip;
|
||||||
const classUrl = serverUrl + '/classes/contracts_Document';
|
const classUrl = serverUrl + '/classes/contracts_Document';
|
||||||
const docId = request.params.docId;
|
const docId = request.params.docId;
|
||||||
try {
|
try {
|
||||||
@@ -16,9 +17,9 @@ export default async function getDrive(request) {
|
|||||||
if (userId) {
|
if (userId) {
|
||||||
let url;
|
let url;
|
||||||
if (docId) {
|
if (docId) {
|
||||||
url = `${classUrl}?where={"Folder":{"__type":"Pointer","className":"contracts_Document","objectId":"${docId}"},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,Signers,Folder`;
|
url = `${classUrl}?where={"Folder":{"__type":"Pointer","className":"contracts_Document","objectId":"${docId}"},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,Signers,Folder&skip=${skip}&limit=${limit}`;
|
||||||
} else {
|
} else {
|
||||||
url = `${classUrl}?where={"Folder":{"$exists":false},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,Signers`;
|
url = `${classUrl}?where={"Folder":{"$exists":false},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,Signers&skip=${skip}&limit=${limit}`;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const res = await axios.get(url, {
|
const res = await axios.get(url, {
|
||||||
|
|||||||
+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!' }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,7 @@ export default function reportJson(id, userId) {
|
|||||||
IsCompleted: { $ne: true },
|
IsCompleted: { $ne: true },
|
||||||
IsDeclined: { $ne: true },
|
IsDeclined: { $ne: true },
|
||||||
IsArchive: { $ne: true },
|
IsArchive: { $ne: true },
|
||||||
$or: [
|
SignedUrl: { $exists: false },
|
||||||
{ Signers: { $eq: [] } },
|
|
||||||
{ Signers: null },
|
|
||||||
{ Signers: { $exists: true }, Placeholders: null },
|
|
||||||
],
|
|
||||||
CreatedBy: {
|
CreatedBy: {
|
||||||
__type: 'Pointer',
|
__type: 'Pointer',
|
||||||
className: '_User',
|
className: '_User',
|
||||||
@@ -33,6 +29,7 @@ export default function reportJson(id, userId) {
|
|||||||
'Signers.Phone',
|
'Signers.Phone',
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Need your sign report
|
// Need your sign report
|
||||||
case '4Hhwbp482K':
|
case '4Hhwbp482K':
|
||||||
return {
|
return {
|
||||||
@@ -273,11 +270,7 @@ export default function reportJson(id, userId) {
|
|||||||
IsCompleted: { $ne: true },
|
IsCompleted: { $ne: true },
|
||||||
IsDeclined: { $ne: true },
|
IsDeclined: { $ne: true },
|
||||||
IsArchive: { $ne: true },
|
IsArchive: { $ne: true },
|
||||||
$or: [
|
SignedUrl: { $exists: false },
|
||||||
{ Signers: { $eq: [] } },
|
|
||||||
{ Signers: null },
|
|
||||||
{ Signers: { $exists: true }, Placeholders: null },
|
|
||||||
],
|
|
||||||
CreatedBy: {
|
CreatedBy: {
|
||||||
__type: 'Pointer',
|
__type: 'Pointer',
|
||||||
className: '_User',
|
className: '_User',
|
||||||
|
|||||||
+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;
|
||||||
@@ -63,13 +63,12 @@ export default async function (request) {
|
|||||||
sessionToken: user.sessionToken, //localStorage.getItem("accesstoken"),
|
sessionToken: user.sessionToken, //localStorage.getItem("accesstoken"),
|
||||||
};
|
};
|
||||||
let body = {
|
let body = {
|
||||||
appName: extClass, //props.appInfo.appname,
|
appName: extClass,
|
||||||
roleName: userDetails.role, //props.appInfo.defaultRole,
|
roleName: userDetails.role,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
};
|
};
|
||||||
let role = await axios.post(roleurl, body, { headers: headers });
|
let role = await axios.post(roleurl, body, { headers: headers });
|
||||||
// console.log("role ", role);
|
// console.log("role ", role);
|
||||||
// props.appInfo.defaultRole
|
|
||||||
const partnerCls = Parse.Object.extend("partners_Tenant");
|
const partnerCls = Parse.Object.extend("partners_Tenant");
|
||||||
const partnerQuery = new partnerCls();
|
const partnerQuery = new partnerCls();
|
||||||
partnerQuery.set("UserId", {
|
partnerQuery.set("UserId", {
|
||||||
@@ -111,7 +110,7 @@ export default async function (request) {
|
|||||||
className: "_User",
|
className: "_User",
|
||||||
objectId: user.id,
|
objectId: user.id,
|
||||||
});
|
});
|
||||||
newObj.set("UserRole", userDetails.role); // props.appInfo.defaultRole
|
newObj.set("UserRole", userDetails.role);
|
||||||
newObj.set("Email", userDetails.email);
|
newObj.set("Email", userDetails.email);
|
||||||
newObj.set("Name", userDetails.name);
|
newObj.set("Name", userDetails.name);
|
||||||
newObj.set("Phone", userDetails.phone);
|
newObj.set("Phone", userDetails.phone);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Generated
+3308
-581
File diff suppressed because it is too large
Load Diff
@@ -18,46 +18,43 @@
|
|||||||
"watch": "nodemon index.js"
|
"watch": "nodemon index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aws-sdk": "^2.1569.0",
|
"aws-sdk": "^2.1581.0",
|
||||||
"axios": "1.6.7",
|
"axios": "^1.6.8",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"crypto": "^1.0.1",
|
"dotenv": "^16.4.5",
|
||||||
"dotenv": "^16.0.3",
|
"express": "^4.18.3",
|
||||||
"express": "4.18.2",
|
|
||||||
"express-sse": "^0.5.3",
|
"express-sse": "^0.5.3",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"generate-api-key": "^1.0.2",
|
"generate-api-key": "^1.0.2",
|
||||||
"jsonschema": "^1.4.1",
|
"jsonschema": "^1.4.1",
|
||||||
"mailgun.js": "^9.3.0",
|
"mailgun.js": "^10.2.1",
|
||||||
"mongoose": "^8.2.0",
|
"mongoose": "^8.2.2",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"multer-s3": "^2.10.0",
|
"multer-s3": "^3.0.1",
|
||||||
"node-forge": "^1.3.1",
|
"node-forge": "^1.3.1",
|
||||||
"node-signpdf": "^1.5.1",
|
"node-signpdf": "^1.5.1",
|
||||||
"nodemailer": "^6.9.11",
|
"nodemailer": "^6.9.12",
|
||||||
"parse": "4.3.1",
|
"parse": "^5.0.0",
|
||||||
"parse-dbtool": "^1.2.0",
|
"parse-dbtool": "^1.2.0",
|
||||||
"parse-server": "6.5.0",
|
"parse-server": "^6.5.5",
|
||||||
"parse-server-api-mail-adapter": "^3.1.1",
|
"parse-server-api-mail-adapter": "^3.1.1",
|
||||||
"parse-server-fs-adapter": "1.0.1",
|
"parse-server-fs-adapter": "^1.0.1",
|
||||||
"parse-server-s3-adapter": "^1.2.0",
|
"parse-server-s3-adapter": "^1.2.0",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"pdfkit": "^0.13.0",
|
"pdfkit": "^0.14.0",
|
||||||
"posthog-node": "^3.6.2",
|
"posthog-node": "^3.6.3"
|
||||||
"razorpay": "^2.8.6",
|
|
||||||
"request": "^2.88.2"
|
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/eslint-parser": "7.21.3",
|
"@babel/eslint-parser": "^7.23.10",
|
||||||
"eslint": "8.38.0",
|
"eslint": "^8.57.0",
|
||||||
"jasmine": "4.6.0",
|
"jasmine": "^5.1.0",
|
||||||
"mongodb-runner": "5.5.3",
|
"mongodb-runner": "^5.5.4",
|
||||||
"nodemon": "^3.1.0",
|
"nodemon": "^3.1.0",
|
||||||
"nyc": "15.1.0",
|
"nyc": "15.1.0",
|
||||||
"prettier": "2.8.7"
|
"prettier": "^3.2.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.22.10 <19"
|
"node": ">=12.22.10 <21"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user