Compare commits

...
69 Commits
Author SHA1 Message Date
AndrewandGitHub 0bf07c2703 Update README.md 2024-03-30 13:26:13 +05:30
prafull-opensignlabsandGitHub 10a0c60056 Merge pull request #540 from OpenSignLabs/opensign_drive_move
fix: document list sorting issue on scroll down in opensign-drive issue, disable recipient's list and field after send request
2024-03-28 13:55:06 +05:30
RaktimaNXG 036c9b8d4a fix: open-sign drive sorting issue by name 2024-03-28 12:46:15 +05:30
RaktimaNXG 1f50368259 fix: open-sign drive sorting issue by date and name 2024-03-28 12:30:28 +05:30
RaktimaNXG 6d5e07dac7 fix: sorting issue in open-sign drive 2024-03-28 11:03:54 +05:30
RaktimaNXG 3656175f11 fix: drive details sorting, signature and intial widgets signature url isuue 2024-03-27 20:31:30 +05:30
RaktimaNXG febb50c3cd fix: expired document message 2024-03-27 18:09:06 +05:30
RaktimaNXG f8ba0d357b fix: mismatch between signature URL in the signature widget and the initial widget on the signature pad. 2024-03-27 17:31:11 +05:30
RaktimaNXG 5a25b2d874 fix: disable tour message for completed document 2024-03-27 13:54:12 +05:30
RaktimaNXG d1e7b9a2ab fix: document list sorting issue on scroll down in opensign-drive issue, disable recipient's list and field after send request 2024-03-27 12:19:17 +05:30
AmolandGitHub 60140885e0 Merge pull request #537 from OpenSignLabs/tooltip_pos 2024-03-27 11:12:18 +05:30
prafull-opensignlabs a06723ff3f refactor: reduce size of tooltip and adjust it's position 2024-03-27 11:05:24 +05:30
AmolandGitHub 12a6a84450 Merge pull request #535 from OpenSignLabs/premium_alert 2024-03-26 20:49:51 +05:30
prafull-opensignlabs 1f350fc459 fix: move document to folder in opensigndrive not working 2024-03-26 20:48:41 +05:30
AmolandGitHub d9fd2a5531 Merge pull request #533 from OpenSignLabs/premium_alert 2024-03-26 20:14:41 +05:30
prafull-opensignlabs cd4fd6e3de refactor: change help message of contact report 2024-03-26 19:12:38 +05:30
prafull-opensignlabs 49cd30de96 refactor: update help message 2024-03-26 19:00:51 +05:30
prafull-opensignlabsandGitHub a24ebe25a8 Merge pull request #534 from OpenSignLabs/widget_copy
feat: implement feature of copy widget to next of that widget for any widgets except `signature,text,stamp,initial` widgets.
2024-03-26 18:36:11 +05:30
RaktimaNXG 3e664bf677 fix: checkbox position issue 2024-03-26 17:29:26 +05:30
prafull-opensignlabs 6161e975fb refactor: add help buttons for all sections 2024-03-26 17:03:08 +05:30
RaktimaNXG c2a45c230b fix: widget copy issue in sign-yourself flow 2024-03-26 16:02:03 +05:30
RaktimaNXG a629aa0bff Merge branch 'widget_copy' of https://github.com/OpenSignLabs/OpenSign into widget_copy 2024-03-26 14:42:54 +05:30
RaktimaNXG 899678d98a feat: implement feature of copy widget to next of that widget for any widgets except signature,text,stamp,initial widgets 2024-03-26 14:31:48 +05:30
prafull-opensignlabsandGitHub 076a0f54c5 Merge pull request #522 from OpenSignLabs/signature_pad
fix: change dashboard icon of signyour-self & request sign, add pen color for text signature
2024-03-26 10:48:22 +05:30
RaktimaNXG a94e67cd7c fix:signature pad pen color issue 2024-03-26 10:12:07 +05:30
RaktimaNXG e78a3991f0 fix: remoove unnecessary code 2024-03-26 09:50:46 +05:30
prafull-opensignlabs 593a8499f4 refactor: add premium features warning 2024-03-25 22:12:58 +05:30
AndrewandGitHub 70d643a5e2 Merge pull request #524 from OpenSignLabs/prafull-opensignlabs-patch-5 2024-03-23 19:35:07 +05:30
prafull-opensignlabsandGitHub f2b1a54695 change mongdb url in .env.local_dev 2024-03-23 19:33:14 +05:30
AndrewandGitHub 4353a4f732 Merge pull request #523 from OpenSignLabs/fix_localdocker 2024-03-23 17:38:39 +05:30
RaktimaNXG 34c99edf1a fix: increase text area height on press enter and fix text widget embeding issue on finished button 2024-03-23 17:08:09 +05:30
prafull-opensignlabs 91f3bdb299 fix: issue of cannot post /login in local docker setup 2024-03-23 17:06:40 +05:30
RaktimaNXG 276fc974fa fix: change dashboard icon of signyour-self & request sign,other minor issue fixed 2024-03-22 21:20:49 +05:30
prafull-opensignlabsandGitHub 081e11f9af Merge pull request #518 from OpenSignLabs/send_In_Order
feat: implement of draggable recipient's list to modify recipient's sequence when enable send-in-order during edit document
2024-03-22 18:08:34 +05:30
RaktimaandGitHub 4f056cc9d3 Update RecipientList.js 2024-03-22 18:06:18 +05:30
RaktimaNXG d9da25e908 fix: increase gap between up and down arrow icon 2024-03-22 16:42:51 +05:30
RaktimaNXG 99b3436c8c feat: add up and down key to change sequence of recipient's list 2024-03-22 16:29:08 +05:30
prafull-opensignlabsandGitHub 452d4d7a1d Merge pull request #519 from OpenSignLabs/signyourself-textinput
fix: change text-input widget to text in signyour-self flow
2024-03-22 12:46:52 +05:30
RaktimaNXG ed613c3424 fix: set default option field value oftextInput widget issue in signyourself 2024-03-22 12:30:53 +05:30
RaktimaNXG bf70fa0b11 fix: drag icon image select issue in ios 2024-03-22 12:01:27 +05:30
RaktimaNXG 8684197d49 fix: drag icon image select issue in ios 2024-03-22 11:55:55 +05:30
RaktimaNXG 648d1224b3 fix: disable default menu open on press on drag icon in mobile view 2024-03-21 18:30:46 +05:30
RaktimaNXG 126b6ad355 fix: change text-input widget to text in signyour-self flow 2024-03-21 18:01:02 +05:30
RaktimaNXG 0512f27e2e change drag icon 2024-03-21 17:41:48 +05:30
prafull-opensignlabsandGitHub 2c61630017 Update signature.css 2024-03-21 17:19:25 +05:30
prafull-opensignlabsandGitHub 72c2b2dde6 change size of custom cursor icon 2024-03-21 17:11:56 +05:30
prafull-opensignlabsandGitHub 29eb78c960 Update signature.css 2024-03-21 17:01:18 +05:30
prafull-opensignlabsandGitHub aa9ba05dde Update move cursor icon 2024-03-21 16:45:28 +05:30
RaktimaNXG 365b074f62 fix: change default value of send in order,dragging functionality to change sequence of signers list in mobile 2024-03-21 16:08:07 +05:30
RaktimaNXG af6cb4c17d feat: implement dragging functionality on recipient's list to modify sequence of send-in-order during edit document 2024-03-21 12:39:00 +05:30
prafull-opensignlabsandGitHub 6bcad91b0f Merge pull request #517 from OpenSignLabs/openSign_drive
feat: updated draft document query
2024-03-20 19:16:46 +05:30
RaktimaNXG 1aa2b003b2 feat: updated draft document query 2024-03-20 19:14:20 +05:30
prafull-opensignlabsandGitHub 1a27e9addf Merge pull request #515 from OpenSignLabs/openSign_drive
fix: data fetching issue in openSign_drive
2024-03-20 18:21:20 +05:30
RaktimaNXG c2891a0858 refactor code 2024-03-20 16:43:56 +05:30
RaktimaNXG c1b226db96 fix: handle condition of fetching opensign details 2024-03-20 15:59:06 +05:30
RaktimaNXG 62e1a1bd9b fix: refactor code 2024-03-20 15:02:08 +05:30
RaktimaNXG 58eb71c52d fix: refactor code 2024-03-20 14:50:48 +05:30
RaktimaNXG c1e6f2b5ab add comment 2024-03-20 12:49:07 +05:30
RaktimaNXG ba0c18b591 fix: data fetching issue in openSign_drive 2024-03-20 12:38:34 +05:30
prafull-opensignlabsandGitHub c3a902dcc7 Merge pull request #514 from OpenSignLabs/unuse_package
Refactor: remove warning
2024-03-20 11:40:46 +05:30
prafull-opensignlabs 5ece3c0694 Refactor: remov warning 2024-03-20 11:38:15 +05:30
AmolandGitHub 1053540410 Merge pull request #513 from OpenSignLabs/unuse_package 2024-03-20 11:14:09 +05:30
prafull-opensignlabs 24773759c2 Refactor: Add LazyPage Component for Lazy Loading of Pages & update dependcies 2024-03-20 11:11:37 +05:30
AmolandGitHub 7a6de70169 Merge pull request #510 from OpenSignLabs/unuse_package 2024-03-19 19:52:34 +05:30
prafull-opensignlabs 04b2c7c4da build(deps): update dependencies 2024-03-19 19:51:20 +05:30
AmolandGitHub d11171e91c Merge pull request #508 from OpenSignLabs/migrate_redux 2024-03-19 18:52:44 +05:30
prafull-opensignlabs a4a78cb96c fix: stuck on loader in login screen after guest login 2024-03-19 18:51:04 +05:30
prafull-opensignlabs dfdcde8fcc Refactor: Implement Lazy Loading for OpenSign Drive 2024-03-19 18:03:13 +05:30
prafull-opensignlabs 5e1b84d2e6 refactor: migrate redux to redux-toolkit 2024-03-19 17:29:48 +05:30
62 changed files with 5718 additions and 2511 deletions
+1 -1
View File
@@ -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 -1
View File
@@ -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:
+11 -11
View File
@@ -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).
--- ---
+1 -1
View File
@@ -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
+632 -710
View File
File diff suppressed because it is too large Load Diff
+16 -19
View File
@@ -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"
} }
} }
+95 -72
View File
@@ -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,12 @@ 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";
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 +23,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 +79,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} />}
/>
{process.env.REACT_APP_ENABLE_SUBSCRIPTION && (
<>
<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>
@@ -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
@@ -2,6 +2,7 @@ import React, { useEffect, useState } from "react";
import { themeColor } from "../../constant/const"; import { 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";
function DropdownWidgetOption(props) { function DropdownWidgetOption(props) {
const [dropdownOptionList, setDropdownOptionList] = useState([ const [dropdownOptionList, setDropdownOptionList] = useState([
"option-1", "option-1",
@@ -144,21 +145,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>
@@ -383,17 +378,22 @@ function DropdownWidgetOption(props) {
</div> </div>
)} )}
</div> </div>
{props.type === "checkbox" && !props.isSignYourself && (
<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,
@@ -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%",
+132 -48
View File
@@ -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>
) )
+102 -60
View File
@@ -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>
</> </>
@@ -23,6 +23,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,7 @@ 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";
const WidgetNameModal = (props) => { const WidgetNameModal = (props) => {
const [formdata, setFormdata] = useState({ const [formdata, setFormdata] = useState({
@@ -14,7 +15,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 +71,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 +99,23 @@ 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) && (
<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
@@ -170,25 +187,22 @@ 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 className="warning defaultvalueWarning" style={{ fontSize: 12 }}>
<i
className="fas fa-exclamation-circle"
style={{ color: "#fab005", fontSize: 15 }}
></i>{" "}
invalid default value invalid default value
</p> </div>
) : (
<p
style={{
color: "transparent",
fontSize: 10,
margin: "3px 8px"
}}
>
.
</p>
)} )}
</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%" }}>
+1 -1
View File
@@ -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}
+214 -15
View File
@@ -12,6 +12,35 @@ export const openInNewTab = (url) => {
window.open(url, "_blank", "noopener,noreferrer"); window.open(url, "_blank", "noopener,noreferrer");
}; };
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 +51,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 +760,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 +935,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 +976,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 +1187,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 +1257,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 +1285,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 +1313,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 +1338,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 +1465,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 +1705,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);
}
};
+19 -8
View File
@@ -18,7 +18,8 @@ export default function reportJson(id) {
btnIcon: "fa fa-plus", btnIcon: "fa fa-plus",
redirectUrl: "draftDocument" redirectUrl: "draftDocument"
} }
] ],
helpMsg: "This 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;
+4 -1
View File
@@ -224,7 +224,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 className="relative h-screen flex flex-col justify-between w-full overflow-y-auto"> <div
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 />
+6 -7
View File
@@ -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);
+14 -20
View File
@@ -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
);
+14 -5
View File
@@ -35,7 +35,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 +51,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);
@@ -165,7 +166,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 +236,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 +330,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"
+9 -1
View File
@@ -5,6 +5,8 @@ import Alert from "../primitives/Alert";
import ModalUi from "../primitives/ModalUi"; import ModalUi from "../primitives/ModalUi";
import { rejectBtn, submitBtn } from "../constant/const"; import { rejectBtn, submitBtn } from "../constant/const";
import { openInNewTab } from "../constant/Utils"; import { openInNewTab } from "../constant/Utils";
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
import Tooltip from "../primitives/Tooltip";
function GenerateToken() { function GenerateToken() {
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
@@ -115,7 +117,13 @@ 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> <PremiumAlertHeader />
<h1 className="ml-4 mt-3 mb-2 font-semibold">
API Token{" "}
<Tooltip
url={"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"}
/>
</h1>
<ul className="w-full flex flex-col p-2 text-sm"> <ul className="w-full flex flex-col p-2 text-sm">
<li <li
className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`} className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
+110 -121
View File
@@ -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";
@@ -13,10 +12,13 @@ import { useWindowSize } from "../hook/useWindowSize";
import ModalUi from "../primitives/ModalUi"; import ModalUi from "../primitives/ModalUi";
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const"; import { 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 +39,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 +63,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 +83,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 +174,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",
@@ -212,8 +216,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",
@@ -412,8 +418,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 +509,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",
@@ -543,8 +549,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",
@@ -730,94 +736,90 @@ 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 await Parse.Cloud.run("getUserDetails", {
localStorage.setItem( email: currentUser.get("email")
"extended_class", }).then(
element.extended_class (result) => {
); let tenentInfo = [];
const results = [result];
const currentUser = Parse.User.current(); if (results) {
await Parse.Cloud.run("getUserDetails", { let extendedInfo_stringify = JSON.stringify(results);
email: currentUser.get("email") let extendedInfo = JSON.parse(extendedInfo_stringify);
}).then( if (extendedInfo.length > 1) {
(result) => { extendedInfo.forEach((x) => {
let tenentInfo = []; if (x.TenantId) {
const results = [result]; let obj = {
if (results) { tenentId: x.TenantId.objectId,
let extendedInfo_stringify = JSON.stringify(results); tenentName: x.TenantId.TenantName || ""
let extendedInfo = JSON.parse(extendedInfo_stringify); };
if (extendedInfo.length > 1) { tenentInfo.push(obj);
extendedInfo.forEach((x) => { }
if (x.TenantId) { });
let obj = { localStorage.setItem("showpopup", true);
tenentId: x.TenantId.objectId, localStorage.setItem("PageLanding", item.pageId);
tenentName: x.TenantId.TenantName || "" localStorage.setItem("defaultmenuid", item.menuId);
}; localStorage.setItem("pageType", item.pageType);
tenentInfo.push(obj); navigate("/");
} } else {
}); extendedInfo.forEach((x) => {
if (x.TenantId) {
localStorage.setItem("showpopup", true); let obj = {
localStorage.setItem("PageLanding", element.pageId); tenentId: x.TenantId.objectId,
localStorage.setItem("defaultmenuid", element.menuId); tenentName: x.TenantId.TenantName || ""
localStorage.setItem("pageType", element.pageType); };
navigate("/"); localStorage.setItem(
"TenetId",
x.TenantId.objectId
);
tenentInfo.push(obj);
}
});
localStorage.setItem("PageLanding", item.pageId);
localStorage.setItem("defaultmenuid", item.menuId);
localStorage.setItem("pageType", item.pageType);
navigate(`/${item.pageType}/${item.pageId}`);
}
} else { } else {
extendedInfo.forEach((x) => { localStorage.setItem("PageLanding", item.pageId);
if (x.TenantId) { localStorage.setItem("defaultmenuid", item.menuId);
let obj = { localStorage.setItem("pageType", item.pageType);
tenentId: x.TenantId.objectId, navigate(`/${item.pageType}/${item.pageId}`);
tenentName: x.TenantId.TenantName || ""
};
localStorage.setItem(
"TenetId",
x.TenantId.objectId
);
tenentInfo.push(obj);
}
});
localStorage.setItem("PageLanding", element.pageId);
localStorage.setItem("defaultmenuid", element.menuId);
localStorage.setItem("pageType", element.pageType);
navigate(`/${element.pageType}/${element.pageId}`);
} }
} 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 +945,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 ">
@@ -1051,7 +1053,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 +1084,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 +1102,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 +1214,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);
+17 -85
View File
@@ -13,7 +13,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 +104,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 {
@@ -222,26 +219,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 +253,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&apos;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 +361,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 +469,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) {
+176 -193
View File
@@ -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>
)} )}
</> </>
)} )}
+24 -4
View File
@@ -10,6 +10,7 @@ import { useParams } from "react-router-dom";
import SignPad from "../components/pdf/SignPad"; import SignPad from "../components/pdf/SignPad";
import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage"; import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage";
import Tour from "reactour"; import Tour from "reactour";
import moment from "moment";
import { import {
contractDocument, contractDocument,
multiSignEmbed, multiSignEmbed,
@@ -65,6 +66,7 @@ function PdfRequestFiles() {
const [currentSigner, setCurrentSigner] = useState(false); const [currentSigner, setCurrentSigner] = useState(false);
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" }); const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
const [unSignedWidgetId, setUnSignedWidgetId] = useState(""); const [unSignedWidgetId, setUnSignedWidgetId] = useState("");
const [expiredDate, setExpiredDate] = useState("");
const [defaultSignAlert, setDefaultSignAlert] = useState({ const [defaultSignAlert, setDefaultSignAlert] = useState({
isShow: false, isShow: false,
alertMessage: "" alertMessage: ""
@@ -87,6 +89,7 @@ function PdfRequestFiles() {
const [widgetsTour, setWidgetsTour] = useState(false); const [widgetsTour, setWidgetsTour] = useState(false);
const [minRequiredCount, setminRequiredCount] = useState(); const [minRequiredCount, setminRequiredCount] = useState();
const [sendInOrder, setSendInOrder] = useState(false); const [sendInOrder, setSendInOrder] = useState(false);
const [currWidgetsDetails, setCurrWidgetsDetails] = useState({});
const divRef = useRef(null); const divRef = useRef(null);
const isMobile = window.innerWidth < 767; const isMobile = window.innerWidth < 767;
const rowLevel = const rowLevel =
@@ -167,7 +170,11 @@ function PdfRequestFiles() {
}; };
setIsDecline(currentDecline); setIsDecline(currentDecline);
} else if (currDate > expireUpdateDate) { } else if (currDate > expireUpdateDate) {
const expireDateFormat = moment(new Date(expireDate)).format(
"MMM DD, YYYY"
);
setIsExpired(true); setIsExpired(true);
setExpiredDate(expireDateFormat);
} }
if (documentData.length > 0) { if (documentData.length > 0) {
@@ -367,7 +374,6 @@ function PdfRequestFiles() {
return true; return true;
} }
}; };
//function for embed signature or image url in pdf //function for embed signature or image url in pdf
async function embedWidgetsData() { async function embedWidgetsData() {
const validateSigning = checkSendInOrder(); const validateSigning = checkSendInOrder();
@@ -731,7 +737,7 @@ function PdfRequestFiles() {
}; };
//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"
@@ -767,6 +773,7 @@ function PdfRequestFiles() {
const placeholderPosition = currentSigner[0].placeHolder; const placeholderPosition = currentSigner[0].placeHolder;
//function of save signature image and get updated position with signature image url //function of save signature image and get updated position with signature image url
const getUpdatePosition = onSaveSign( const getUpdatePosition = onSaveSign(
type,
placeholderPosition, placeholderPosition,
getIndex, getIndex,
signKey, signKey,
@@ -926,7 +933,17 @@ function PdfRequestFiles() {
</div> </div>
)} )}
<div className="signatureContainer" ref={divRef}> <div
className="signatureContainer"
style={{
pointerEvents:
isExpired ||
(isDecline.isDeclined && isDecline.currnt === "another")
? "none"
: "auto"
}}
ref={divRef}
>
<ModalUi <ModalUi
headerColor={"#dc3545"} headerColor={"#dc3545"}
isOpen={isAlert.isShow} isOpen={isAlert.isShow}
@@ -999,7 +1016,7 @@ function PdfRequestFiles() {
containerWH={containerWH} containerWH={containerWH}
show={isExpired} show={isExpired}
headMsg="Document Expired!" headMsg="Document Expired!"
bodyMssg="This Document is no longer available." bodyMssg={`This document expired on ${expiredDate} and is no longer available to sign.`}
/> />
<ModalUi <ModalUi
@@ -1133,6 +1150,8 @@ function PdfRequestFiles() {
isInitial={isInitial} isInitial={isInitial}
setIsInitial={setIsInitial} setIsInitial={setIsInitial}
setIsStamp={setIsStamp} setIsStamp={setIsStamp}
currWidgetsDetails={currWidgetsDetails}
setCurrWidgetsDetails={setCurrWidgetsDetails}
/> />
{/* pdf header which contain funish back button */} {/* pdf header which contain funish back button */}
<Header <Header
@@ -1179,6 +1198,7 @@ function PdfRequestFiles() {
unSignedWidgetId={unSignedWidgetId} unSignedWidgetId={unSignedWidgetId}
setSelectWidgetId={setSelectWidgetId} setSelectWidgetId={setSelectWidgetId}
selectWidgetId={selectWidgetId} selectWidgetId={selectWidgetId}
setCurrWidgetsDetails={setCurrWidgetsDetails}
/> />
)} )}
</div> </div>
+14 -23
View File
@@ -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",
@@ -358,8 +360,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",
@@ -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);
+25 -23
View File
@@ -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";
@@ -80,6 +81,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,7 +97,7 @@ 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);
@@ -106,20 +108,6 @@ function PlaceHolderSign() {
status: false, status: false,
message: "" message: ""
}); });
const color = [
"#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({
@@ -276,14 +264,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 +294,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 (
@@ -1034,7 +1026,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 +1364,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 +1450,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>
@@ -1717,13 +1708,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 +1732,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}
+3
View File
@@ -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"} />
+20 -27
View File
@@ -1,17 +1,19 @@
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 } 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";
const Signup = () => {
const { width } = useWindowSize(); const { width } = useWindowSize();
const navigate = useNavigate(); const navigate = useNavigate();
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 +31,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()) {
@@ -90,7 +92,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 +101,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 {
@@ -181,8 +183,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 +258,10 @@ 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",
@@ -300,8 +304,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",
@@ -433,7 +437,7 @@ const Signup = (props) => {
} }
}; };
useEffect(() => { useEffect(() => {
props.fetchAppInfo(); dispatch(fetchAppInfo());
// eslint-disable-next-line // eslint-disable-next-line
}, []); }, []);
@@ -479,7 +483,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">
@@ -657,15 +661,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);
+19 -12
View File
@@ -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({
@@ -180,14 +180,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);
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 +263,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 +271,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 +292,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 +301,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 +346,7 @@ function SignYourSelf() {
return { return {
name: "checkbox" name: "checkbox"
}; };
case textWidget:
case textInputWidget:
return { return {
name: "text" name: "text"
}; };
@@ -528,7 +531,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 +589,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 +708,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 +731,7 @@ function SignYourSelf() {
} }
} }
const getUpdatePosition = onSaveSign( const getUpdatePosition = onSaveSign(
type,
xyPostion, xyPostion,
index, index,
signKey, signKey,
@@ -764,6 +768,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 +1107,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
+18 -2
View File
@@ -77,6 +77,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({
@@ -223,6 +224,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 +233,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 +252,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 +450,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 +858,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 +875,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);
@@ -1443,6 +1450,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 +1464,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 +1478,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}
+21 -7
View File
@@ -6,6 +6,8 @@ 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";
function UserProfile() { function UserProfile() {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -250,7 +252,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 +260,17 @@ 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 className="font-semibold">
<label className="relative inline-flex items-center cursor-pointer mb-0"> Disable DocumentId :{" "}
<Tooltip url={"https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid"} />{" "}
</span>{" "}
<label
className={`${
editmode ? "cursor-pointer" : ""
} relative inline-flex items-center mb-0`}
>
<input <input
disabled={editmode ? false : true} disabled={editmode ? false : true}
checked={isDisableDocId} checked={isDisableDocId}
@@ -270,9 +279,14 @@ 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>
<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">
+9 -1
View File
@@ -6,6 +6,8 @@ import ModalUi from "../primitives/ModalUi";
import { rejectBtn, submitBtn } from "../constant/const"; import { rejectBtn, submitBtn } from "../constant/const";
import { openInNewTab } from "../constant/Utils"; import { 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 [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
@@ -101,7 +103,13 @@ 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> <PremiumAlertHeader />
<h1 className="ml-4 mt-3 mb-2 font-semibold">
Webhook{" "}
<Tooltip
url={"https://docs.opensignlabs.com/docs/API-docs/get-webhook"}
/>
</h1>
<ul className="w-full flex flex-col p-2 text-sm"> <ul className="w-full flex flex-col p-2 text-sm">
<li <li
className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`} className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
@@ -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")}
+30
View File
@@ -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;
+40 -14
View File
@@ -1,18 +1,44 @@
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";
<> const Tooltip = ({ id, message, url, iconColor }) =>
<a data-tooltip-id="my-tooltip" data-tooltip-content={message}> url ? (
{children ? ( <button onClick={() => openInNewTab(url)} className="text-center">
children <sup>
) : ( <i
<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="fa-solid fa-question rounded-full"
)} style={{
</a> borderColor: iconColor ? iconColor : "#33bbff",
<ReactTooltip id="my-tooltip" className="max-w-[200px]" /> 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;
-200
View File
@@ -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: [] });
};
+13 -8
View File
@@ -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;
+2 -4
View File
@@ -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;
+15 -4
View File
@@ -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
}
});
+58
View File
@@ -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;
}
} }
-21
View File
@@ -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;
+7 -10
View File
@@ -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;
@@ -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, {
@@ -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',
@@ -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);
+3308 -581
View File
File diff suppressed because it is too large Load Diff
+19 -22
View File
@@ -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"
} }
} }