mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-03 16:28:56 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c20611b50b | ||
|
|
15d73ee62d | ||
|
|
a334cda9aa | ||
|
|
69d4254b44 | ||
|
|
95d2794754 | ||
|
|
65ce0d430c | ||
|
|
e7a98d55f0 | ||
|
|
d247c6d0e7 | ||
|
|
20e0277113 | ||
|
|
2ed3609c46 | ||
|
|
2e41dc20c1 | ||
|
|
50a8f93014 | ||
|
|
3803b29835 | ||
|
|
e18586887e | ||
|
|
d137c081ee | ||
|
|
62dfe32d32 | ||
|
|
f801192a8c | ||
|
|
13d161e3c8 | ||
|
|
a249baea66 | ||
|
|
f6f5b08d43 | ||
|
|
a1f4e9ea74 | ||
|
|
5eed145f4b | ||
|
|
546a0f8e87 | ||
|
|
975c4b079a | ||
|
|
09e0ac2415 | ||
|
|
6140aea31a | ||
|
|
c59c921a8b | ||
|
|
4b1e13d39a | ||
|
|
e33e0be735 | ||
|
|
2ff4e372d6 | ||
|
|
9cfffe3fbd | ||
|
|
82ef278a0e | ||
|
|
574d2d05a4 | ||
|
|
38f72c7415 | ||
|
|
e00704a43c | ||
|
|
778e28fae0 | ||
|
|
1574f86654 | ||
|
|
df17bdcd68 | ||
|
|
f290fd875f | ||
|
|
caeb055fc2 | ||
|
|
1eafc113e6 | ||
|
|
4e46795e0f | ||
|
|
f7087dfb29 | ||
|
|
e6a7cda3b6 | ||
|
|
db120ecda7 | ||
|
|
9bfe8b0e26 | ||
|
|
c1438be9e0 | ||
|
|
f4d7e33f97 | ||
|
|
4ec7fdb078 | ||
|
|
3413d0914d | ||
|
|
793b6a5550 | ||
|
|
77894f6754 | ||
|
|
812928a6a3 | ||
|
|
bb398d13a2 | ||
|
|
2d7a893424 | ||
|
|
62e943161a | ||
|
|
2604156c7f | ||
|
|
1e04bb4dbe | ||
|
|
0ac3a70a83 | ||
|
|
2f1ad45f92 | ||
|
|
8263e3247e | ||
|
|
9666e41880 | ||
|
|
e50f062a91 | ||
|
|
1c8f401060 | ||
|
|
a8e764a62c | ||
|
|
43bc1f3e17 | ||
|
|
eebed949cd | ||
|
|
c7cd9e56f8 | ||
|
|
1c9fb5ebcb | ||
|
|
1339259c3b | ||
|
|
27a069e1a2 | ||
|
|
7a69537255 | ||
|
|
9569b78e66 | ||
|
|
266b0f27f5 | ||
|
|
00e5c48828 | ||
|
|
c9e010e993 | ||
|
|
5b52825ea6 | ||
|
|
100b97cf1a | ||
|
|
7a3216a81c | ||
|
|
c6412be70d | ||
|
|
954dbb3375 | ||
|
|
c996825665 | ||
|
|
5fc1a58bdb | ||
|
|
5c947181a2 | ||
|
|
2e8b2fa525 | ||
|
|
1e6e5f9dba | ||
|
|
fa2e169df4 | ||
|
|
174023c62f | ||
|
|
1198460c97 | ||
|
|
07954c8bb6 | ||
|
|
d4d9521c31 | ||
|
|
d77477f3d1 | ||
|
|
ff36faa96c | ||
|
|
450de195a7 | ||
|
|
57b23d7f97 | ||
|
|
a246f74e11 | ||
|
|
89c687ed06 | ||
|
|
f7e2fa8aec | ||
|
|
8a2960511c | ||
|
|
832e5c2181 | ||
|
|
00d900c2b2 | ||
|
|
47ef685bcc | ||
|
|
9f4aff65f2 | ||
|
|
2eddb49b8e | ||
|
|
63f1bb9fc7 | ||
|
|
e73b055cc2 | ||
|
|
abd7cf9b71 | ||
|
|
2dbd41ce65 | ||
|
|
25ef7c9f39 | ||
|
|
81a4daa5e8 | ||
|
|
3f9e6d1f81 | ||
|
|
1507f113f4 | ||
|
|
d46ba8f307 | ||
|
|
2426e7484c | ||
|
|
17b9fc772e | ||
|
|
7b2b71fea5 | ||
|
|
70a3adebd7 | ||
|
|
9e012ef6c7 | ||
|
|
948e0d3270 | ||
|
|
6e4f9ba0e9 | ||
|
|
a816ceb04b | ||
|
|
f864f74f14 | ||
|
|
2c715a77a2 | ||
|
|
9b4cdde80a | ||
|
|
de2154e6fe | ||
|
|
76f4ccfcf3 | ||
|
|
af52bb30f5 |
@@ -2,7 +2,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'staging'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@@ -10,9 +10,9 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- image: amolshejole/OpenSign
|
||||
- image: opensign/opensign
|
||||
dockerfile: apps/OpenSign/Dockerhubfile
|
||||
- image: amolshejole/OpenSignServer
|
||||
- image: opensign/opensignserver
|
||||
dockerfile: apps/OpenSignServer/Dockerhubfile
|
||||
steps:
|
||||
-
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
|
||||
<a href="https://www.opensignlabs.com/">Website</a>
|
||||
<span> • </span>
|
||||
<a href="https://www.opensignlabs.com">Docs</a>
|
||||
<a href="https://docs.opensignlabs.com">Help Docs</a>
|
||||
<span> • </span>
|
||||
<a href="https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1">API Docs</a>
|
||||
<span> • </span>
|
||||
<a href="https://www.opensignlabs.com/blog">Blog</a>
|
||||
<span> • </span>
|
||||
@@ -22,7 +24,7 @@
|
||||
<a href="https://www.linkedin.com/company/opensign%E2%84%A2/about/">LinkedIn</a>
|
||||
|
||||
|
||||
## The open-source document e-signing solution
|
||||
## The premier open source document signing solution(DocuSign alternative)
|
||||
|
||||
---
|
||||
</div>
|
||||
@@ -42,29 +44,32 @@ Please star ⭐ the repo to support us! 😀
|
||||
|
||||
### 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 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.
|
||||
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 document signing process, making it accessible and straightforward for everyone.
|
||||
|
||||
---
|
||||
|
||||
### Features
|
||||
|
||||
- **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 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", "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 in e-signature space.
|
||||
- **Secure PDF E-Signing:** With the help of robust encryption algorithms, OpenSign™ ensures maximum security, privacy & compatibility. Now sign unlimited documents even on the [cloud hosted free version of OpenSign](https://www.opensignlabs.com/).
|
||||
- **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 open source document signing experience ever.
|
||||
- **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. OpenSign intends to provide the best document signing experience in the open source ecosystem.
|
||||
- **Multi-signer Support:** OpenSign's ability to invite multiple signers for signing along with the ability to invite by sharing signing links & 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.
|
||||
- **"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.
|
||||
- **"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 with a reason that will be promptly shared with the sender.
|
||||
- **Beautiful email templates:** All document signing invitations, completion notifications & reminders are formatted using great looking email templates. Not just this, you are even allowed to customise the email templates making your free document signing invitations look the way you always wanted them to be.
|
||||
- **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 digital 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 & archieving 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.
|
||||
- **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 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/86db91b7-6c2f-4885-a33c-58f4fd35ec89 height='200'>
|
||||
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/56835efd-c40e-42de-a206-20202c293876 height='200'>
|
||||
|
||||
- **API Support:** OpenSign™ API allows seamless integration into existing systems and software. You can generate an API key from the app and refer the [official API docs](https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1) to start integrating it in your existing applications.
|
||||
- **Integrations:** The open source document signing experience becomes even more seamless because of integrations with various Cloud storage systems, CRMs & enterprise platforms. We also have a Zapier integration that allows you to integrate it with virtually any application.
|
||||
<img alt="Login page" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/8016edb6-7d6e-4185-ab72-82d2c4a16032" height='200' >
|
||||
<img alt="Dash_board" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/6e7b96f7-3154-4c25-bc1e-caf33925cc47" height='200'>
|
||||
<img alt="Widgets" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/7edb65bd-c265-4b3d-9758-38e79766c5c2" height='200'>
|
||||
<img alt="Request Signature" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/1697ae46-dcac-41c9-a081-aded25693846" height='200'>
|
||||
<img alt="Create template" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/c2060fda-50f1-4116-a532-51b94b48463a" height='200'>
|
||||
<img alt="Manage_Template" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/90310c74-8271-49bd-8c5f-89daa5a623c4" height='200'>
|
||||
<img alt="Folders" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/a52207e7-3b0e-497c-b5f6-747bc4e67918" height='200'>
|
||||
<img alt="OpenSign_Confetti" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/8f4c6a6e-4a73-439c-9f34-f426044d0a7f" height='200'>
|
||||
|
||||
---
|
||||
|
||||
@@ -88,13 +93,13 @@ We welcome contributions from the open-source community. For more information on
|
||||
|
||||
### License
|
||||
|
||||
OpenSign is licensed under the AGPL License. For more details, see the [LICENSE](LICENSE) file.
|
||||
OpenSign is licensed under the AGPL-3 License. For more details, see the [LICENSE](LICENSE) file.
|
||||
|
||||
---
|
||||
|
||||
### Acknowledgments
|
||||
|
||||
We would like to thank all our contributors and users for their support and feedback. Special thanks to [OpenSignLabs](https://github.com/OpenSignLabs) for spearheading this initiative.
|
||||
We would like to thank all our contributors and users for their support and feedback. Special thanks to [OpenSignLabs](https://www.opensignlabs.com) for spearheading this initiative.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1 @@
|
||||
The community is working hard to put together a great usage guide.
|
||||
You will soon see one of the best usage guides here.
|
||||
|
||||
Till then you can view the quick promo video by clicking the link below -
|
||||
|
||||
[<img src="https://i.ytimg.com/vi/szYaBZhXZNo/maxresdefault.jpg" width="50%">](https://www.youtube.com/watch?v=szYaBZhXZNo "OpenSign promo")
|
||||
Please visit the official documentation [here](https://docs.opensignlabs.com).
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react"]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: ["@babel/preset-env", "@babel/preset-react"]
|
||||
};
|
||||
Generated
+5388
-599
File diff suppressed because it is too large
Load Diff
+33
-19
@@ -4,24 +4,24 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@formkit/auto-animate": "^0.8.2",
|
||||
"@lottiefiles/dotlottie-react": "^0.6.4",
|
||||
"@radix-ui/themes": "^3.0.5",
|
||||
"@lottiefiles/dotlottie-react": "^0.7.2",
|
||||
"@radix-ui/themes": "^3.1.1",
|
||||
"@react-pdf/renderer": "^3.4.4",
|
||||
"@reduxjs/toolkit": "^2.2.5",
|
||||
"@reduxjs/toolkit": "^2.2.6",
|
||||
"axios": "^1.7.2",
|
||||
"file-saver": "^2.0.5",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"moment": "^2.30.1",
|
||||
"nth-check": "^2.1.1",
|
||||
"parse": "^5.1.0",
|
||||
"parse": "^5.3.0",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"print-js": "^1.6.0",
|
||||
"radix-ui": "^1.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.10.2",
|
||||
"react-bootstrap": "^2.10.4",
|
||||
"react-confetti": "^6.1.0",
|
||||
"react-cookie": "^7.1.4",
|
||||
"react-datepicker": "^6.9.0",
|
||||
"react-datepicker": "^7.2.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dnd-multi-backend": "^8.0.3",
|
||||
@@ -30,16 +30,16 @@
|
||||
"react-gtm-module": "^2.0.11",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-konva": "^18.2.10",
|
||||
"react-pdf": "^9.0.0",
|
||||
"react-pdf": "^9.1.0",
|
||||
"react-quill": "^2.0.0",
|
||||
"react-redux": "^9.1.2",
|
||||
"react-rnd": "^10.4.11",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"react-router-dom": "^6.25.1",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-scrollbars-custom": "^4.1.1",
|
||||
"react-select": "^5.8.0",
|
||||
"react-signature-canvas": "^1.0.6",
|
||||
"react-tooltip": "^5.26.4",
|
||||
"react-tooltip": "^5.27.1",
|
||||
"react-web-share": "^2.0.2",
|
||||
"reactour": "^1.19.4",
|
||||
"redux": "^5.0.1",
|
||||
@@ -47,16 +47,18 @@
|
||||
"regex-parser": "^2.3.0",
|
||||
"serve": "^14.2.3",
|
||||
"styled-components": "^4.4.1",
|
||||
"web-vitals": "^4.0.1",
|
||||
"ws": "^8.17.1"
|
||||
"web-vitals": "^4.2.2",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build-webpack": "webpack --config webpack.config.js",
|
||||
"build": "npm run version && npm run build-webpack && react-scripts build",
|
||||
"build-watch": "webpack --config webpack.config.js --watch",
|
||||
"start-dev": "concurrently \"npm run build-watch\" \"react-scripts start\"",
|
||||
"start": "serve -s build",
|
||||
"start-dev": "react-scripts start",
|
||||
"version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
|
||||
"version-win": "powershell -Command \"Invoke-RestMethod -Uri 'https://api.github.com/repos/opensignlabs/opensign/releases/latest' | Select-Object -ExpandProperty tag_name | Out-File -FilePath ./public/version.txt\"",
|
||||
"build": "npm run version && react-scripts build",
|
||||
"build-win": "npm run version-win && react-scripts build",
|
||||
"build-win": "npm run version-win && npm run build-webpack && react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"release": "standard-version",
|
||||
@@ -86,21 +88,33 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.6",
|
||||
"@babel/preset-env": "^7.24.6",
|
||||
"@babel/preset-react": "^7.24.6",
|
||||
"@babel/runtime-corejs2": "^7.24.7",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"babel-loader": "^9.1.3",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"commitizen": "^4.3.0",
|
||||
"daisyui": "^4.12.2",
|
||||
"concurrently": "^8.2.2",
|
||||
"css-loader": "^7.1.2",
|
||||
"daisyui": "^4.12.10",
|
||||
"dotenv": "^16.4.5",
|
||||
"dotenv-webpack": "^8.1.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react": "^7.34.3",
|
||||
"lint-staged": "^15.2.7",
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "^3.3.2",
|
||||
"mini-css-extract-plugin": "^2.9.0",
|
||||
"postcss": "^8.4.39",
|
||||
"prettier": "^3.3.3",
|
||||
"pretty-quick": "^4.0.0",
|
||||
"tailwindcss": "^3.4.4"
|
||||
"tailwindcss": "^3.4.6",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"webpack-cli": "^5.1.4"
|
||||
},
|
||||
"overrides": {
|
||||
"nth-check": "$nth-check",
|
||||
"ws":"$ws"
|
||||
"ws": "$ws"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
|
||||
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" href="/css/fonts.css" />
|
||||
<link rel="stylesheet" href="https://cdn.opensignlabs.com/fonts.css" />
|
||||
<title>OpenSign™</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -18,6 +18,8 @@ import LazyPage from "./primitives/LazyPage";
|
||||
import { isEnableSubscription } from "./constant/const";
|
||||
import SSOVerify from "./pages/SSOVerify";
|
||||
import Loader from "./primitives/Loader";
|
||||
import TeamList from "./pages/TeamList";
|
||||
import UserList from "./pages/UserList";
|
||||
const DebugPdf = lazy(() => import("./pages/DebugPdf"));
|
||||
const ForgetPassword = lazy(() => import("./pages/ForgetPassword"));
|
||||
const GuestLogin = lazy(() => import("./pages/GuestLogin"));
|
||||
@@ -30,6 +32,8 @@ const Opensigndrive = lazy(() => import("./pages/Opensigndrive"));
|
||||
const ManageSign = lazy(() => import("./pages/Managesign"));
|
||||
const GenerateToken = lazy(() => import("./pages/GenerateToken"));
|
||||
const Webhook = lazy(() => import("./pages/Webhook"));
|
||||
const AddAdmin = lazy(() => import("./pages/AddAdmin"));
|
||||
const UpdateExistUserAdmin = lazy(() => import("./pages/UpdateExistUserAdmin"));
|
||||
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
|
||||
const AppLoader = () => {
|
||||
@@ -52,11 +56,9 @@ function App() {
|
||||
const baseurl = process.env.REACT_APP_SERVERURL
|
||||
? process.env.REACT_APP_SERVERURL
|
||||
: window.location.origin + "/api/app";
|
||||
const appName = "contracts";
|
||||
try {
|
||||
localStorage.setItem("baseUrl", `${baseurl}/`);
|
||||
localStorage.setItem("parseAppId", appId);
|
||||
localStorage.setItem("domain", appName);
|
||||
setIsLoading(false);
|
||||
} catch (error) {
|
||||
console.log("err ", error);
|
||||
@@ -72,7 +74,21 @@ function App() {
|
||||
<Routes>
|
||||
<Route element={<ValidateRoute />}>
|
||||
<Route exact path="/" element={<Login />} />
|
||||
<Route path="/signup" element={<LazyPage Page={Signup} />} />
|
||||
{isEnableSubscription && (
|
||||
<Route path="/signup" element={<LazyPage Page={Signup} />} />
|
||||
)}
|
||||
{!isEnableSubscription && (
|
||||
<>
|
||||
<Route
|
||||
path="/addadmin"
|
||||
element={<LazyPage Page={AddAdmin} />}
|
||||
/>
|
||||
<Route
|
||||
path="/upgrade-2.1"
|
||||
element={<LazyPage Page={UpdateExistUserAdmin} />}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Route>
|
||||
<Route element={<Validate />}>
|
||||
<Route
|
||||
@@ -139,11 +155,6 @@ function App() {
|
||||
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 />}
|
||||
@@ -164,11 +175,30 @@ function App() {
|
||||
path="/pdfRequestFiles/:docId"
|
||||
element={<PdfRequestFiles />}
|
||||
/>
|
||||
|
||||
{/* recipient signature route with no rowlevel data using docId from url */}
|
||||
<Route
|
||||
path="/recipientSignPdf/:docId/:contactBookId"
|
||||
element={<PdfRequestFiles />}
|
||||
/>
|
||||
<Route
|
||||
path="/recipientSignPdf/:docId"
|
||||
element={<PdfRequestFiles />}
|
||||
/>
|
||||
{isEnableSubscription && (
|
||||
<>
|
||||
<Route path="/teams" element={<TeamList />} />
|
||||
<Route
|
||||
path="/generatetoken"
|
||||
element={<LazyPage Page={GenerateToken} />}
|
||||
/>
|
||||
<Route
|
||||
path="/webhook"
|
||||
element={<LazyPage Page={Webhook} />}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Route path="/users" element={<UserList />} />
|
||||
</Route>
|
||||
<Route path="/sso" element={<SSOVerify />} />
|
||||
<Route path="*" element={<PageNotFound />} />
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -1,6 +1,5 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Parse from "parse";
|
||||
import axios from "axios";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
const AddSigner = (props) => {
|
||||
@@ -10,8 +9,6 @@ const AddSigner = (props) => {
|
||||
const [addYourself, setAddYourself] = useState(false);
|
||||
const [isLoader, setIsLoader] = useState(false);
|
||||
const [isUserExist, setIsUserExist] = useState(false);
|
||||
const parseBaseUrl = localStorage.getItem("baseUrl");
|
||||
const parseAppId = localStorage.getItem("parseAppId");
|
||||
|
||||
useEffect(() => {
|
||||
checkUserExist();
|
||||
@@ -85,18 +82,6 @@ const AddSigner = (props) => {
|
||||
}
|
||||
const user = await _user.save();
|
||||
if (user) {
|
||||
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseAppId,
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
};
|
||||
const body = {
|
||||
appName: localStorage.getItem("_appName"),
|
||||
roleName: "contracts_Guest",
|
||||
userId: user.id
|
||||
};
|
||||
await axios.post(roleurl, body, { headers: headers });
|
||||
const currentUser = Parse.User.current();
|
||||
contactQuery.set(
|
||||
"CreatedBy",
|
||||
@@ -140,18 +125,6 @@ const AddSigner = (props) => {
|
||||
if (err.code === 202) {
|
||||
const params = { email: email };
|
||||
const userRes = await Parse.Cloud.run("getUserId", params);
|
||||
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseAppId,
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
};
|
||||
const body = {
|
||||
appName: localStorage.getItem("_appName"),
|
||||
roleName: "contracts_Guest",
|
||||
userId: userRes.id
|
||||
};
|
||||
await axios.post(roleurl, body, { headers: headers });
|
||||
const currentUser = Parse.User.current();
|
||||
contactQuery.set(
|
||||
"CreatedBy",
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Parse from "parse";
|
||||
import Title from "./Title";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
const AddTeam = (props) => {
|
||||
const [formdata, setFormdata] = useState({
|
||||
name: "",
|
||||
team: ""
|
||||
});
|
||||
const [isLoader, setIsLoader] = useState(false);
|
||||
const [teamList, setTeamList] = useState([]);
|
||||
useEffect(() => {
|
||||
getTeamList();
|
||||
}, []);
|
||||
|
||||
const getTeamList = async () => {
|
||||
setIsLoader(true);
|
||||
try {
|
||||
const teams = await Parse.Cloud.run("getteams");
|
||||
const teamRes = JSON.parse(JSON.stringify(teams));
|
||||
if (teamRes.length > 0) {
|
||||
const _teamRes = JSON.parse(JSON.stringify(teamRes));
|
||||
const allUsersteam = _teamRes.find((x) => x.Name === "All Users");
|
||||
if (allUsersteam) {
|
||||
setFormdata({ team: allUsersteam.objectId });
|
||||
}
|
||||
setTeamList(_teamRes);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err in fetch top level teamList", err);
|
||||
} finally {
|
||||
setIsLoader(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDropdown = (e) => {
|
||||
setFormdata((prev) => ({ ...prev, [e.target.name]: e.target.value }));
|
||||
};
|
||||
// Define a function to handle form submission
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
// Extracting values except for the 'name' key
|
||||
let updatedAncestors = [];
|
||||
if (formdata.team) {
|
||||
const Ancestors = teamList.find(
|
||||
(x) => x.objectId === formdata.team
|
||||
)?.Ancestors;
|
||||
if (Ancestors && Ancestors.length > 0) {
|
||||
updatedAncestors = Ancestors.map((x) => ({
|
||||
__type: "Pointer",
|
||||
className: "contracts_Teams",
|
||||
objectId: x.objectId
|
||||
}));
|
||||
} else {
|
||||
const AllUser = teamList.find((x) => x.objectId === "All Users");
|
||||
updatedAncestors = [
|
||||
AllUser,
|
||||
{
|
||||
__type: "Pointer",
|
||||
className: "contracts_Teams",
|
||||
objectId: formdata.team
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
try {
|
||||
setIsLoader(true);
|
||||
let data = { Name: formdata.name };
|
||||
if (updatedAncestors.length > 0) {
|
||||
const ParentId = updatedAncestors[updatedAncestors.length - 1];
|
||||
data["ParentId"] = ParentId?.objectId;
|
||||
data["Ancestors"] = updatedAncestors;
|
||||
}
|
||||
const newTeamRes = await Parse.Cloud.run("addteam", data);
|
||||
// console.log("teamRes ", newTeamRes);
|
||||
if (updatedAncestors.length > 0) {
|
||||
const ParentId = teamList.find((x) => x.objectId === formdata.team);
|
||||
props.handleTeamInfo({
|
||||
objectId: newTeamRes.id,
|
||||
Name: formdata.name,
|
||||
ParentId: ParentId,
|
||||
Ancestors: updatedAncestors,
|
||||
IsActive: true
|
||||
});
|
||||
} else {
|
||||
props.handleTeamInfo({
|
||||
objectId: newTeamRes.id,
|
||||
Name: formdata.name,
|
||||
ParentId: "",
|
||||
Ancestors: "",
|
||||
IsActive: true
|
||||
});
|
||||
}
|
||||
if (props.closePopup) {
|
||||
props.closePopup();
|
||||
}
|
||||
setFormdata({ name: "", team: { name: "", objectId: "" } });
|
||||
props.setIsAlert({ type: "success", msg: "Team created successfully." });
|
||||
} catch (err) {
|
||||
console.log("err in save team", err);
|
||||
if (err.code === 137) {
|
||||
props.setIsAlert({ type: "danger", msg: "Teams already exists." });
|
||||
} else if (err.code === 102) {
|
||||
props.setIsAlert({ type: "warning", msg: "Provide team name." });
|
||||
} else {
|
||||
props.setIsAlert({ type: "danger", msg: "Something went wrong." });
|
||||
}
|
||||
} finally {
|
||||
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1500);
|
||||
setIsLoader(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Define a function to handle the "add yourself" checkbox
|
||||
const handleReset = () => {
|
||||
setFormdata({
|
||||
name: "",
|
||||
team: { name: "", objectId: "" }
|
||||
});
|
||||
};
|
||||
const handleChange = (e) => {
|
||||
setFormdata((prev) => ({ ...prev, [e.target.name]: e.target.value }));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="shadow-md rounded-box my-[1px] p-3 bg-[#ffffff]">
|
||||
<Title title="Add Team" />
|
||||
{isLoader && (
|
||||
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30 z-50 rounded-box">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full mx-auto">
|
||||
<form onSubmit={handleSubmit}>
|
||||
{/* <h1 className="text-[20px] font-semibold mb-4">Add User</h1> */}
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Name
|
||||
<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={formdata.name}
|
||||
onChange={(e) => handleChange(e)}
|
||||
required
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="phone"
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Parent Team
|
||||
</label>
|
||||
<select
|
||||
value={formdata.team}
|
||||
onChange={(e) => handleDropdown(e)}
|
||||
name="team"
|
||||
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
>
|
||||
{teamList.length > 0 &&
|
||||
teamList.map((x) => (
|
||||
<option key={x.objectId} value={x.objectId}>
|
||||
{x.Name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Submit
|
||||
</button>
|
||||
<div
|
||||
type="button"
|
||||
onClick={() => handleReset()}
|
||||
className="op-btn op-btn-secondary"
|
||||
>
|
||||
Reset
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddTeam;
|
||||
@@ -1,24 +1,63 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Parse from "parse";
|
||||
import axios from "axios";
|
||||
import Title from "./Title";
|
||||
import Alert from "../primitives/Alert";
|
||||
import Loader from "../primitives/Loader";
|
||||
import { copytoData } from "../constant/Utils";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
function generatePassword(length) {
|
||||
const characters =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let result = "";
|
||||
const charactersLength = characters.length;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const AddUser = (props) => {
|
||||
const [name, setName] = useState("");
|
||||
const [phone, setPhone] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [formdata, setFormdata] = useState({
|
||||
name: "",
|
||||
phone: "",
|
||||
email: "",
|
||||
team: "",
|
||||
password: "",
|
||||
role: ""
|
||||
});
|
||||
const [isLoader, setIsLoader] = useState(false);
|
||||
const [isUserExist, setIsUserExist] = useState(false);
|
||||
const parseBaseUrl = localStorage.getItem("baseUrl");
|
||||
const parseAppId = localStorage.getItem("parseAppId");
|
||||
const [teamList, setTeamList] = useState([]);
|
||||
const role = ["OrgAdmin", "Editor", "User"];
|
||||
|
||||
useEffect(() => {
|
||||
getTeamList();
|
||||
}, []);
|
||||
|
||||
const getTeamList = async () => {
|
||||
setFormdata((prev) => ({ ...prev, password: generatePassword(12) }));
|
||||
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||
const team = new Parse.Query("contracts_Teams");
|
||||
team.equalTo("OrganizationId", {
|
||||
__type: "Pointer",
|
||||
className: "contracts_Organizations",
|
||||
objectId: extUser.OrganizationId.objectId
|
||||
});
|
||||
team.notEqualTo("IsActive", false);
|
||||
const teamRes = await team.find();
|
||||
if (teamRes.length > 0) {
|
||||
const _teamRes = JSON.parse(JSON.stringify(teamRes));
|
||||
setTeamList(_teamRes);
|
||||
if (!isEnableSubscription) {
|
||||
const allUserId =
|
||||
_teamRes.find((x) => x.Name === "All Users")?.objectId || "";
|
||||
setFormdata((prev) => ({ ...prev, team: allUserId }));
|
||||
}
|
||||
}
|
||||
};
|
||||
const checkUserExist = async () => {
|
||||
try {
|
||||
const res = await Parse.Cloud.run("getUserDetails", {
|
||||
email: email,
|
||||
userId: Parse.User.current().id
|
||||
email: formdata.email
|
||||
});
|
||||
if (res) {
|
||||
return true;
|
||||
@@ -33,24 +72,46 @@ const AddUser = (props) => {
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const localUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||
setIsLoader(true);
|
||||
const res = await checkUserExist();
|
||||
if (res) {
|
||||
setIsUserExist(true);
|
||||
props.setIsAlert({ type: "danger", msg: "User already exist." });
|
||||
setIsLoader(false);
|
||||
setTimeout(() => {
|
||||
setIsUserExist(false);
|
||||
props.setIsAlert({ type: "success", msg: "" });
|
||||
}, 1000);
|
||||
} else {
|
||||
try {
|
||||
const contactQuery = new Parse.Object("contracts_Users");
|
||||
contactQuery.set("Name", name);
|
||||
contactQuery.set("Phone", phone);
|
||||
contactQuery.set("Email", email);
|
||||
contactQuery.set("UserRole", "contracts_User");
|
||||
const extUser = new Parse.Object("contracts_Users");
|
||||
extUser.set("Name", formdata.name);
|
||||
if (formdata.phone) {
|
||||
extUser.set("Phone", formdata.phone);
|
||||
}
|
||||
extUser.set("Email", formdata.email);
|
||||
extUser.set("UserRole", `contracts_${formdata.role}`);
|
||||
if (formdata?.team) {
|
||||
extUser.set("TeamIds", [
|
||||
{
|
||||
__type: "Pointer",
|
||||
className: "contracts_Teams",
|
||||
objectId: formdata.team
|
||||
}
|
||||
]);
|
||||
}
|
||||
if (localUser && localUser.OrganizationId) {
|
||||
extUser.set("OrganizationId", {
|
||||
__type: "Pointer",
|
||||
className: "contracts_Organizations",
|
||||
objectId: localUser.OrganizationId.objectId
|
||||
});
|
||||
}
|
||||
if (localUser && localUser.Company) {
|
||||
extUser.set("Company", localUser.Company);
|
||||
}
|
||||
|
||||
if (localStorage.getItem("TenantId")) {
|
||||
contactQuery.set("TenantId", {
|
||||
extUser.set("TenantId", {
|
||||
__type: "Pointer",
|
||||
className: "partners_Tenant",
|
||||
objectId: localStorage.getItem("TenantId")
|
||||
@@ -60,89 +121,69 @@ const AddUser = (props) => {
|
||||
try {
|
||||
const _users = Parse.Object.extend("User");
|
||||
const _user = new _users();
|
||||
_user.set("name", name);
|
||||
_user.set("username", email);
|
||||
_user.set("email", email);
|
||||
_user.set("password", email);
|
||||
if (phone) {
|
||||
_user.set("phone", phone);
|
||||
_user.set("name", formdata.name);
|
||||
_user.set("username", formdata.email);
|
||||
_user.set("email", formdata.email);
|
||||
_user.set("password", formdata.password);
|
||||
if (formdata.phone) {
|
||||
_user.set("phone", formdata.phone);
|
||||
}
|
||||
|
||||
const user = await _user.save();
|
||||
if (user) {
|
||||
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseAppId,
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
};
|
||||
const body = {
|
||||
appName: localStorage.getItem("_appName"),
|
||||
roleName: "contracts_User",
|
||||
userId: user.id
|
||||
};
|
||||
await axios.post(roleurl, body, { headers: headers });
|
||||
const currentUser = Parse.User.current();
|
||||
contactQuery.set(
|
||||
extUser.set(
|
||||
"CreatedBy",
|
||||
Parse.User.createWithoutData(currentUser.id)
|
||||
);
|
||||
|
||||
contactQuery.set("UserId", user);
|
||||
extUser.set("UserId", user);
|
||||
const acl = new Parse.ACL();
|
||||
acl.setPublicReadAccess(true);
|
||||
acl.setPublicWriteAccess(true);
|
||||
acl.setReadAccess(currentUser.id, true);
|
||||
acl.setWriteAccess(currentUser.id, true);
|
||||
|
||||
contactQuery.setACL(acl);
|
||||
extUser.setACL(acl);
|
||||
|
||||
const res = await contactQuery.save();
|
||||
const res = await extUser.save();
|
||||
|
||||
const parseData = JSON.parse(JSON.stringify(res));
|
||||
if (props.details) {
|
||||
props.details({
|
||||
value: parseData[props.valueKey],
|
||||
label: parseData[props.displayKey]
|
||||
});
|
||||
}
|
||||
|
||||
if (props.closePopup) {
|
||||
props.closePopup();
|
||||
}
|
||||
if (props.handleUserData) {
|
||||
if (formdata?.team) {
|
||||
const team = teamList.find((x) => x.objectId === formdata.team);
|
||||
parseData.TeamIds = parseData.TeamIds.map((y) =>
|
||||
y.objectId === team.objectId ? team : y
|
||||
);
|
||||
}
|
||||
props.handleUserData(parseData);
|
||||
}
|
||||
|
||||
setIsLoader(false);
|
||||
|
||||
setName("");
|
||||
setPhone("");
|
||||
setEmail("");
|
||||
setFormdata({
|
||||
name: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
team: "",
|
||||
role: ""
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err ", err);
|
||||
if (err.code === 202) {
|
||||
const params = { email: email };
|
||||
const params = { email: formdata.email };
|
||||
const userRes = await Parse.Cloud.run("getUserId", params);
|
||||
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseAppId,
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
};
|
||||
const body = {
|
||||
appName: localStorage.getItem("_appName"),
|
||||
roleName: "contracts_User",
|
||||
userId: userRes.id
|
||||
};
|
||||
await axios.post(roleurl, body, { headers: headers });
|
||||
const currentUser = Parse.User.current();
|
||||
contactQuery.set(
|
||||
extUser.set(
|
||||
"CreatedBy",
|
||||
Parse.User.createWithoutData(currentUser.id)
|
||||
);
|
||||
|
||||
contactQuery.set("UserId", {
|
||||
extUser.set("UserId", {
|
||||
__type: "Pointer",
|
||||
className: "_User",
|
||||
objectId: userRes.id
|
||||
@@ -153,55 +194,75 @@ const AddUser = (props) => {
|
||||
acl.setReadAccess(currentUser.id, true);
|
||||
acl.setWriteAccess(currentUser.id, true);
|
||||
|
||||
contactQuery.setACL(acl);
|
||||
const res = await contactQuery.save();
|
||||
extUser.setACL(acl);
|
||||
const res = await extUser.save();
|
||||
|
||||
const parseData = JSON.parse(JSON.stringify(res));
|
||||
if (props.details) {
|
||||
props.details({
|
||||
value: parseData[props.valueKey],
|
||||
label: parseData[props.displayKey]
|
||||
});
|
||||
}
|
||||
if (props.closePopup) {
|
||||
props.closePopup();
|
||||
}
|
||||
if (props.handleUserData) {
|
||||
if (formdata?.team) {
|
||||
const team = teamList.find((x) => x.objectId === formdata.team);
|
||||
parseData.TeamIds = parseData.TeamIds.map((y) =>
|
||||
y.objectId === team.objectId ? team : y
|
||||
);
|
||||
}
|
||||
props.handleUserData(parseData);
|
||||
}
|
||||
setIsLoader(false);
|
||||
setName("");
|
||||
setPhone("");
|
||||
setEmail("");
|
||||
setFormdata({
|
||||
name: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
team: "",
|
||||
role: ""
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// console.log("err", err);
|
||||
console.log("err", err);
|
||||
setIsLoader(false);
|
||||
alert("something went wrong!");
|
||||
props.setIsAlert({ type: "danger", msg: "something went wrong." });
|
||||
} finally {
|
||||
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1500);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Define a function to handle the "add yourself" checkbox
|
||||
const handleReset = () => {
|
||||
setName("");
|
||||
setPhone("");
|
||||
setEmail("");
|
||||
setFormdata({
|
||||
name: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
team: "",
|
||||
role: ""
|
||||
});
|
||||
if (props.closePopup) {
|
||||
props.closePopup();
|
||||
}
|
||||
};
|
||||
const handleChange = (e) => {
|
||||
setFormdata((prev) => ({ ...prev, [e.target.name]: e.target.value }));
|
||||
};
|
||||
|
||||
const copytoclipboard = (text) => {
|
||||
copytoData(text);
|
||||
props.setIsAlert({ type: "success", msg: "Copied" });
|
||||
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1500); // Reset copied state after 1.5 seconds
|
||||
};
|
||||
return (
|
||||
<div className="shadow-md rounded my-2 p-3 bg-[#ffffff] md:border-[1px] md:border-gray-600/50">
|
||||
<div className="shadow-md rounded-box my-[1px] p-3 bg-[#ffffff]">
|
||||
<Title title={"Add User"} />
|
||||
{isUserExist && <Alert type="danger">User already exists!</Alert>}
|
||||
{isLoader && (
|
||||
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30 z-50">
|
||||
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30 z-50 rounded-box">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full mx-auto">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<h1 className="text-[20px] font-semibold mb-4">Add User</h1>
|
||||
{/* <h1 className="text-[20px] font-semibold mb-4">Add User</h1> */}
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="name"
|
||||
@@ -212,9 +273,9 @@ const AddUser = (props) => {
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
name="name"
|
||||
value={formdata.name}
|
||||
onChange={(e) => handleChange(e)}
|
||||
required
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
@@ -229,44 +290,111 @@ const AddUser = (props) => {
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
name="email"
|
||||
value={formdata.email}
|
||||
onChange={(e) => handleChange(e)}
|
||||
required
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="email"
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Password
|
||||
</label>
|
||||
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm text-base-content w-full h-full text-[13px]">
|
||||
<div className="break-all">{formdata?.password}</div>
|
||||
<i
|
||||
onClick={() => copytoclipboard(formdata?.password)}
|
||||
className="fa-light fa-copy rounded-full hover:bg-base-300 p-[8px] cursor-pointer "
|
||||
></i>
|
||||
</div>
|
||||
<div className="text-[12px] ml-2 mb-0 text-[red] select-none">
|
||||
Password will only be generated once; make sure to copy it.
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="phone"
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Phone
|
||||
<span className="text-[red] text-[13px]"> *</span>
|
||||
{/* <span className="text-[red] text-[13px]"> *</span> */}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="phone"
|
||||
value={phone}
|
||||
onChange={(e) => setPhone(e.target.value)}
|
||||
required
|
||||
name="phone"
|
||||
placeholder="optional"
|
||||
value={formdata.phone}
|
||||
onChange={(e) => handleChange(e)}
|
||||
// required
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-[#1ab6ce] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 focus:outline-none"
|
||||
{isEnableSubscription && (
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="phone"
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Team<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<select
|
||||
value={formdata.team}
|
||||
onChange={(e) => handleChange(e)}
|
||||
name="team"
|
||||
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
required
|
||||
>
|
||||
<option defaultValue={""} value={""}>
|
||||
select
|
||||
</option>
|
||||
{teamList.length > 0 &&
|
||||
teamList.map((x) => (
|
||||
<option key={x.objectId} value={x.objectId}>
|
||||
{x.Name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="phone"
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Role<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<select
|
||||
value={formdata.role}
|
||||
onChange={(e) => handleChange(e)}
|
||||
name="role"
|
||||
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
required
|
||||
>
|
||||
<option defaultValue={""} value={""}>
|
||||
select
|
||||
</option>
|
||||
{role.length > 0 &&
|
||||
role.map((x) => (
|
||||
<option key={x} value={x}>
|
||||
{x}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Submit
|
||||
</button>
|
||||
<div
|
||||
type="button"
|
||||
onClick={() => handleReset()}
|
||||
className="bg-[#188ae2] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 text-center ml-[2px] focus:outline-none"
|
||||
className="op-btn op-btn-secondary"
|
||||
>
|
||||
Reset
|
||||
Cancel
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useNavigate } from "react-router-dom";
|
||||
import Parse from "parse";
|
||||
import { useWindowSize } from "../hook/useWindowSize";
|
||||
import { checkIsSubscribed, getAppLogo, openInNewTab } from "../constant/Utils";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { isEnableSubscription, isStaging } from "../constant/const";
|
||||
|
||||
const Header = ({ showSidebar }) => {
|
||||
const navigate = useNavigate();
|
||||
@@ -31,8 +31,8 @@ const Header = ({ showSidebar }) => {
|
||||
const getIsSubscribe = await checkIsSubscribed();
|
||||
if (getIsSubscribe) {
|
||||
const applogo = await getAppLogo();
|
||||
if (applogo) {
|
||||
setAppLogo(applogo);
|
||||
if (applogo?.logo) {
|
||||
setAppLogo(applogo?.logo);
|
||||
} else {
|
||||
setAppLogo(localStorage.getItem("appLogo") || "");
|
||||
}
|
||||
@@ -53,22 +53,16 @@ const Header = ({ showSidebar }) => {
|
||||
}
|
||||
let appdata = localStorage.getItem("userSettings");
|
||||
let applogo = localStorage.getItem("appLogo");
|
||||
let appName = localStorage.getItem("appName");
|
||||
let defaultmenuid = localStorage.getItem("defaultmenuid");
|
||||
let PageLanding = localStorage.getItem("PageLanding");
|
||||
let domain = localStorage.getItem("domain");
|
||||
let _appName = localStorage.getItem("_appName");
|
||||
let baseUrl = localStorage.getItem("baseUrl");
|
||||
let appid = localStorage.getItem("parseAppId");
|
||||
|
||||
localStorage.clear();
|
||||
|
||||
localStorage.setItem("appLogo", applogo);
|
||||
localStorage.setItem("appName", appName);
|
||||
localStorage.setItem("_appName", _appName);
|
||||
localStorage.setItem("defaultmenuid", defaultmenuid);
|
||||
localStorage.setItem("PageLanding", PageLanding);
|
||||
localStorage.setItem("domain", domain);
|
||||
localStorage.setItem("userSettings", appdata);
|
||||
localStorage.setItem("baseUrl", baseUrl);
|
||||
localStorage.setItem("parseAppId", appid);
|
||||
@@ -91,7 +85,13 @@ const Header = ({ showSidebar }) => {
|
||||
document.removeEventListener("click", closeMenuOnOutsideClick);
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
const handleConsoleRedirect = () => {
|
||||
if (isStaging) {
|
||||
window.open(" https://staging-console.opensignlabs.com/");
|
||||
} else {
|
||||
window.open("https://console.opensignlabs.com/");
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="op-navbar bg-base-100 shadow">
|
||||
<div className="flex-none">
|
||||
@@ -194,7 +194,7 @@ const Header = ({ showSidebar }) => {
|
||||
</li>
|
||||
<li
|
||||
onClick={() => {
|
||||
window.open("https://console.opensignlabs.com/");
|
||||
handleConsoleRedirect();
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
|
||||
@@ -51,14 +51,8 @@ const GoogleSignInBtn = ({
|
||||
let baseUrl = localStorage.getItem("baseUrl");
|
||||
let appid = localStorage.getItem("parseAppId");
|
||||
let applogo = localStorage.getItem("appLogo");
|
||||
let domain = localStorage.getItem("domain");
|
||||
let appversion = localStorage.getItem("appVersion");
|
||||
let appTitle = localStorage.getItem("appTitle");
|
||||
let defaultmenuid = localStorage.getItem("defaultmenuid");
|
||||
let PageLanding = localStorage.getItem("PageLanding");
|
||||
let _appName = localStorage.getItem("_appName");
|
||||
let _app_objectId = localStorage.getItem("_app_objectId");
|
||||
let appName = localStorage.getItem("appName");
|
||||
let userSettings = localStorage.getItem("userSettings");
|
||||
|
||||
localStorage.clear();
|
||||
@@ -66,14 +60,8 @@ const GoogleSignInBtn = ({
|
||||
localStorage.setItem("baseUrl", baseUrl);
|
||||
localStorage.setItem("parseAppId", appid);
|
||||
localStorage.setItem("appLogo", applogo);
|
||||
localStorage.setItem("domain", domain);
|
||||
localStorage.setItem("appversion", appversion);
|
||||
localStorage.setItem("appTitle", appTitle);
|
||||
localStorage.setItem("defaultmenuid", defaultmenuid);
|
||||
localStorage.setItem("PageLanding", PageLanding);
|
||||
localStorage.setItem("_appName", _appName);
|
||||
localStorage.setItem("_app_objectId", _app_objectId);
|
||||
localStorage.setItem("appName", appName);
|
||||
localStorage.setItem("userSettings", userSettings);
|
||||
localStorage.setItem("baseUrl", baseUrl);
|
||||
localStorage.setItem("parseAppId", appid);
|
||||
@@ -186,22 +174,16 @@ const GoogleSignInBtn = ({
|
||||
|
||||
let appdata = localStorage.getItem("userSettings");
|
||||
let applogo = localStorage.getItem("appLogo");
|
||||
let appName = localStorage.getItem("appName");
|
||||
let defaultmenuid = localStorage.getItem("defaultmenuid");
|
||||
let PageLanding = localStorage.getItem("PageLanding");
|
||||
let domain = localStorage.getItem("domain");
|
||||
let _appName = localStorage.getItem("_appName");
|
||||
let baseUrl = localStorage.getItem("baseUrl");
|
||||
let appid = localStorage.getItem("parseAppId");
|
||||
|
||||
localStorage.clear();
|
||||
|
||||
localStorage.setItem("appLogo", applogo);
|
||||
localStorage.setItem("appName", appName);
|
||||
localStorage.setItem("_appName", _appName);
|
||||
localStorage.setItem("defaultmenuid", defaultmenuid);
|
||||
localStorage.setItem("PageLanding", PageLanding);
|
||||
localStorage.setItem("domain", domain);
|
||||
localStorage.setItem("userSettings", appdata);
|
||||
localStorage.setItem("baseUrl", baseUrl);
|
||||
localStorage.setItem("parseAppId", appid);
|
||||
|
||||
@@ -31,7 +31,7 @@ const GetDashboard = (props) => {
|
||||
<div
|
||||
className={`${
|
||||
col?.widget?.bgColor ? col.widget.bgColor : "bg-[#2ed8b6]"
|
||||
} op-card w-full h-[140px] px-3 pt-4 mb-3 shadow-md"`}
|
||||
} op-card w-full h-[140px] px-3 pt-4 mb-3 shadow-md`}
|
||||
data-tut={col.widget.data.tourSection}
|
||||
>
|
||||
<Suspense
|
||||
|
||||
@@ -70,9 +70,9 @@ function DriveBody(props) {
|
||||
props.sortingData(null, null, updatedData);
|
||||
await axios
|
||||
.put(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Document/${docId}`,
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/contracts_Document/${docId}`,
|
||||
updateName,
|
||||
{
|
||||
headers: {
|
||||
@@ -104,7 +104,7 @@ function DriveBody(props) {
|
||||
const signedUrl = data.SignedUrl;
|
||||
//checking if document has completed and request signature flow
|
||||
if (data?.IsCompleted && signerExist?.length > 0) {
|
||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||
}
|
||||
//checking if document has completed and signyour-self flow
|
||||
else if (!signerExist && !isPlaceholder) {
|
||||
@@ -112,7 +112,7 @@ function DriveBody(props) {
|
||||
}
|
||||
//checking if document has declined by someone
|
||||
else if (isDecline) {
|
||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||
//checking draft type document
|
||||
} else if (
|
||||
signerExist?.length > 0 &&
|
||||
@@ -122,8 +122,8 @@ function DriveBody(props) {
|
||||
navigate(`/placeHolderSign/${data.objectId}`);
|
||||
}
|
||||
//Inprogress document
|
||||
else if (isPlaceholder?.length > 0 && signerExist?.length > 0) {
|
||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
||||
else if (isPlaceholder?.length > 0 && signedUrl) {
|
||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||
} //placeholder draft document
|
||||
else if (
|
||||
(signerExist?.length > 0 &&
|
||||
@@ -170,9 +170,7 @@ function DriveBody(props) {
|
||||
|
||||
await axios
|
||||
.put(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Document/${docId}`,
|
||||
`${localStorage.getItem("baseUrl")}classes/contracts_Document/${docId}`,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
@@ -219,7 +217,7 @@ function DriveBody(props) {
|
||||
updateData = {
|
||||
Folder: {
|
||||
__type: "Pointer",
|
||||
className: `${localStorage.getItem("_appName")}_Document`,
|
||||
className: "contracts_Document",
|
||||
objectId: moveFolderId
|
||||
}
|
||||
};
|
||||
@@ -231,9 +229,9 @@ function DriveBody(props) {
|
||||
|
||||
await axios
|
||||
.put(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Document/${updateDocId}`,
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/contracts_Document/${updateDocId}`,
|
||||
updateData,
|
||||
{
|
||||
headers: {
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import LoaderWithMsg from "../../primitives/LoaderWithMsg";
|
||||
import { contractDocument } from "../../constant/Utils";
|
||||
import HandleError from "../../primitives/HandleError";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
function useQuery() {
|
||||
return new URLSearchParams(useLocation().search);
|
||||
}
|
||||
function DraftDocument() {
|
||||
const navigate = useNavigate();
|
||||
const query = useQuery();
|
||||
const docId = query.get("docId");
|
||||
const [isLoading, setIsLoading] = useState({
|
||||
isLoader: true,
|
||||
message: "This might take some time"
|
||||
});
|
||||
|
||||
const rowLevel =
|
||||
localStorage.getItem("rowlevel") &&
|
||||
JSON.parse(localStorage.getItem("rowlevel"));
|
||||
const docId =
|
||||
rowLevel && rowLevel?.id
|
||||
? rowLevel.id
|
||||
: rowLevel?.objectId && rowLevel.objectId;
|
||||
|
||||
useEffect(() => {
|
||||
getDocumentDetails();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@@ -53,7 +49,7 @@ function DraftDocument() {
|
||||
const signedUrl = data.SignedUrl;
|
||||
//checking if document has completed and request signature flow
|
||||
if (data?.IsCompleted && signerExist?.length > 0) {
|
||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||
}
|
||||
//checking if document has completed and signyour-self flow
|
||||
else if (!signerExist && !isPlaceholder) {
|
||||
@@ -61,7 +57,7 @@ function DraftDocument() {
|
||||
}
|
||||
//checking if document has declined by someone
|
||||
else if (isDecline) {
|
||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||
//checking draft type document
|
||||
} else if (
|
||||
signerExist?.length > 0 &&
|
||||
@@ -71,8 +67,8 @@ function DraftDocument() {
|
||||
navigate(`/placeHolderSign/${data.objectId}`);
|
||||
}
|
||||
//Inprogress document
|
||||
else if (isPlaceholder?.length > 0 && signerExist?.length > 0) {
|
||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
||||
else if (isPlaceholder?.length > 0 && signedUrl) {
|
||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||
} //placeholder draft document
|
||||
else if (
|
||||
(signerExist?.length > 0 &&
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react";
|
||||
import { isEnableSubscription } from "../../constant/const";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
import { radioButtonWidget } from "../../constant/Utils";
|
||||
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
||||
import Upgrade from "../../primitives/Upgrade";
|
||||
function DropdownWidgetOption(props) {
|
||||
const [dropdownOptionList, setDropdownOptionList] = useState([
|
||||
@@ -214,55 +213,57 @@ function DropdownWidgetOption(props) {
|
||||
onClick={handleAddInput}
|
||||
className="fa-light fa-square-plus text-[25px] ml-[10px] op-text-primary cursor-pointer"
|
||||
></i>
|
||||
<div>
|
||||
{props.type === "checkbox" && !props.isSignYourself && (
|
||||
<>
|
||||
<label
|
||||
className={`${
|
||||
!props.isSubscribe ? "text-[gray]" : ""
|
||||
} text-[13px] font-semibold`}
|
||||
>
|
||||
Minimun check
|
||||
</label>
|
||||
{!props.isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
<input
|
||||
required
|
||||
defaultValue={0}
|
||||
value={minCount}
|
||||
onChange={(e) => {
|
||||
const count = handleSetMinMax(e);
|
||||
setMinCount(count);
|
||||
}}
|
||||
className={`${
|
||||
props.isSubscribe || !isEnableSubscription
|
||||
? ""
|
||||
: "pointer-events-none bg-opacity-50"
|
||||
} op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs`}
|
||||
/>
|
||||
<label
|
||||
className={`${
|
||||
!props.isSubscribe ? "text-[gray]" : ""
|
||||
} text-[13px] font-semibold`}
|
||||
>
|
||||
Maximum check
|
||||
</label>
|
||||
<input
|
||||
required
|
||||
defaultValue={0}
|
||||
value={maxCount}
|
||||
onChange={(e) => {
|
||||
const count = handleSetMinMax(e);
|
||||
setMaxCount(count);
|
||||
}}
|
||||
className={`${
|
||||
props.isSubscribe || !isEnableSubscription
|
||||
? ""
|
||||
: "pointer-events-none bg-opacity-50"
|
||||
} op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs`}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{isEnableSubscription && (
|
||||
<div>
|
||||
{props.type === "checkbox" && !props.isSignYourself && (
|
||||
<>
|
||||
<label
|
||||
className={`${
|
||||
!props.isSubscribe ? "text-[gray]" : ""
|
||||
} text-[13px] font-semibold`}
|
||||
>
|
||||
Minimun check
|
||||
</label>
|
||||
{!props.isSubscribe && isEnableSubscription && (
|
||||
<Upgrade />
|
||||
)}
|
||||
<input
|
||||
required
|
||||
defaultValue={0}
|
||||
value={minCount}
|
||||
disabled={props.isSubscribe ? false : true}
|
||||
onChange={(e) => {
|
||||
const count = handleSetMinMax(e);
|
||||
setMinCount(count);
|
||||
}}
|
||||
className={`${
|
||||
props.isSubscribe ? "" : "pointer-events-none"
|
||||
} op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs`}
|
||||
/>
|
||||
<label
|
||||
className={`${
|
||||
!props.isSubscribe ? "text-[gray]" : ""
|
||||
} text-[13px] font-semibold`}
|
||||
>
|
||||
Maximum check
|
||||
</label>
|
||||
<input
|
||||
required
|
||||
defaultValue={0}
|
||||
value={maxCount}
|
||||
disabled={props.isSubscribe ? false : true}
|
||||
onChange={(e) => {
|
||||
const count = handleSetMinMax(e);
|
||||
setMaxCount(count);
|
||||
}}
|
||||
className={`${
|
||||
props.isSubscribe ? "" : "pointer-events-none"
|
||||
} op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs`}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{["dropdown", radioButtonWidget].includes(props.type) && (
|
||||
<>
|
||||
@@ -344,15 +345,6 @@ function DropdownWidgetOption(props) {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{props.type === "checkbox" &&
|
||||
!props.isSignYourself &&
|
||||
!isEnableSubscription && (
|
||||
<PremiumAlertHeader
|
||||
message={
|
||||
"Field validations are free in beta, this feature will incur a fee later."
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
props.type === "checkbox" && !props.isSignYourself
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { checkIsSubscribed, getFileName } from "../../constant/Utils";
|
||||
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
||||
import Upgrade from "../../primitives/Upgrade";
|
||||
import { isEnableSubscription } from "../../constant/const";
|
||||
// import SelectFolder from "../../premitives/SelectFolder";
|
||||
@@ -134,39 +133,32 @@ const EditTemplate = ({ template, onSuccess }) => {
|
||||
<div className="text-[12px]">No</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-xs mt-2">
|
||||
{!isEnableSubscription && (
|
||||
<PremiumAlertHeader
|
||||
message={
|
||||
"Auto reminder is free in beta, this feature will incur a fee later."
|
||||
{isEnableSubscription && (
|
||||
<div className="text-xs mt-2">
|
||||
<span
|
||||
className={
|
||||
isSubscribe ? "font-semibold" : "font-semibold text-gray-300"
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
className={
|
||||
isSubscribe || !isEnableSubscription
|
||||
? "font-semibold"
|
||||
: "font-semibold text-gray-300"
|
||||
}
|
||||
>
|
||||
Auto reminder{" "}
|
||||
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
</span>
|
||||
<label
|
||||
className={`${
|
||||
isSubscribe || !isEnableSubscription
|
||||
? "cursor-pointer "
|
||||
: "pointer-events-none opacity-50"
|
||||
} relative block items-center mb-0`}
|
||||
>
|
||||
<input
|
||||
checked={formData.AutomaticReminders}
|
||||
onChange={handleAutoReminder}
|
||||
type="checkbox"
|
||||
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white mt-2"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
>
|
||||
Auto reminder{" "}
|
||||
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
</span>
|
||||
<label
|
||||
className={`${
|
||||
isSubscribe
|
||||
? "cursor-pointer "
|
||||
: "pointer-events-none opacity-50"
|
||||
} relative block items-center mb-0`}
|
||||
>
|
||||
<input
|
||||
checked={formData.AutomaticReminders}
|
||||
onChange={handleAutoReminder}
|
||||
type="checkbox"
|
||||
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white mt-2"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
{isSubscribe && formData?.AutomaticReminders === true && (
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState } from "react";
|
||||
import { saveAs } from "file-saver";
|
||||
import axios from "axios";
|
||||
import { getBase64FromUrl } from "../../constant/Utils";
|
||||
import { themeColor } from "../../constant/const";
|
||||
import { themeColor, emailRegex } from "../../constant/const";
|
||||
import printModule from "print-js";
|
||||
import Loader from "../../primitives/Loader";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
@@ -19,8 +19,9 @@ function EmailComponent({
|
||||
activeMailAdapter
|
||||
}) {
|
||||
const [emailList, setEmailList] = useState([]);
|
||||
const [emailValue, setEmailValue] = useState();
|
||||
const [emailValue, setEmailValue] = useState("");
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [emailErr, setEmailErr] = useState(false);
|
||||
//function for send email
|
||||
const sendEmail = async () => {
|
||||
setIsLoading(true);
|
||||
@@ -111,17 +112,30 @@ function EmailComponent({
|
||||
//function for get email value
|
||||
const handleEmailValue = (e) => {
|
||||
const value = e.target.value;
|
||||
setEmailErr(false);
|
||||
setEmailValue(value);
|
||||
};
|
||||
|
||||
//function for save email in array after press enter
|
||||
const handleEnterPress = (e) => {
|
||||
const pattern = emailRegex;
|
||||
const validate = emailValue?.match(pattern);
|
||||
if (e.key === "Enter" && emailValue) {
|
||||
setEmailList((prev) => [...prev, emailValue]);
|
||||
setEmailValue("");
|
||||
if (validate) {
|
||||
const emailLowerCase = emailValue?.toLowerCase();
|
||||
setEmailList((prev) => [...prev, emailLowerCase]);
|
||||
setEmailValue("");
|
||||
} else {
|
||||
setEmailErr(true);
|
||||
}
|
||||
} else if (e === "add" && emailValue) {
|
||||
setEmailList((prev) => [...prev, emailValue]);
|
||||
setEmailValue("");
|
||||
if (validate) {
|
||||
const emailLowerCase = emailValue?.toLowerCase();
|
||||
setEmailList((prev) => [...prev, emailLowerCase]);
|
||||
setEmailValue("");
|
||||
} else {
|
||||
setEmailErr(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -179,7 +193,6 @@ function EmailComponent({
|
||||
Successfully signed!
|
||||
</span>
|
||||
<div className="flex flex-row">
|
||||
<div></div>
|
||||
{!isAndroid && (
|
||||
<button
|
||||
onClick={handleToPrint}
|
||||
@@ -203,72 +216,63 @@ function EmailComponent({
|
||||
Recipients added here will get a copy of the signed document.
|
||||
</p>
|
||||
{emailList.length > 0 ? (
|
||||
<>
|
||||
<div className="p-0 border-[1.5px] op-border-primary rounded w-full text-[15px]">
|
||||
<div className="flex flex-row flex-wrap">
|
||||
{emailList.map((data, ind) => {
|
||||
return (
|
||||
<div
|
||||
className="flex flex-row items-center op-bg-primary m-[4px] rounded-md py-[5px] px-[10px]"
|
||||
key={ind}
|
||||
<div className="p-0 border-[1.5px] op-border-primary rounded w-full text-[15px]">
|
||||
<div className="flex flex-row flex-wrap">
|
||||
{emailList.map((data, ind) => {
|
||||
return (
|
||||
<div
|
||||
className="flex flex-row items-center op-bg-primary m-[4px] rounded-md py-[5px] px-[10px]"
|
||||
key={ind}
|
||||
>
|
||||
<span className="text-base-100 text-[13px]">
|
||||
{data}
|
||||
</span>
|
||||
<span
|
||||
className="text-base-100 text-[13px] font-semibold ml-[7px] cursor-pointer"
|
||||
onClick={() => removeChip(ind)}
|
||||
>
|
||||
<span className="text-base-100 text-[13px]">
|
||||
{data}
|
||||
</span>
|
||||
<span
|
||||
className="text-base-100 text-[13px] font-semibold ml-[7px] cursor-pointer"
|
||||
onClick={() => removeChip(ind)}
|
||||
>
|
||||
<i className="fa-light fa-xmark"></i>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{emailList.length <= 9 && (
|
||||
<input
|
||||
type="text"
|
||||
value={emailValue}
|
||||
className="p-[10px] pb-[20px] rounded w-full text-[15px] bg-transparent outline-none"
|
||||
onChange={handleEmailValue}
|
||||
onKeyDown={handleEnterPress}
|
||||
onBlur={() => {
|
||||
if (emailValue) {
|
||||
handleEnterPress("add");
|
||||
}
|
||||
}}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
<i className="fa-light fa-xmark"></i>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
{emailList.length <= 9 && (
|
||||
<input
|
||||
type="email"
|
||||
value={emailValue}
|
||||
className="p-[10px] pb-[20px] rounded w-full text-[15px] bg-transparent outline-none"
|
||||
onChange={handleEmailValue}
|
||||
onKeyDown={handleEnterPress}
|
||||
onBlur={() => emailValue && handleEnterPress("add")}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
type="email"
|
||||
value={emailValue}
|
||||
className="p-[10px] pb-[20px] rounded w-full text-[15px] outline-none bg-transparent border-[1.5px] op-border-primary"
|
||||
onChange={handleEmailValue}
|
||||
onKeyDown={handleEnterPress}
|
||||
placeholder="Add the email addresses"
|
||||
onBlur={() => {
|
||||
if (emailValue) {
|
||||
handleEnterPress("add");
|
||||
}
|
||||
}}
|
||||
placeholder="Add an email address and hit enter"
|
||||
onBlur={() => emailValue && handleEnterPress("add")}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{emailErr && (
|
||||
<p className="text-xs text-[red] ml-1.5 mt-0.5">
|
||||
please provide correct email address
|
||||
</p>
|
||||
)}
|
||||
<button
|
||||
className={`${
|
||||
emailValue ? "cursor-pointer" : "cursor-default"
|
||||
} op-btn op-btn-primary op-btn-sm m-2 shadow-md`}
|
||||
onClick={() => {
|
||||
if (emailValue) {
|
||||
handleEnterPress("add");
|
||||
}
|
||||
}}
|
||||
onClick={() => emailValue && handleEnterPress("add")}
|
||||
>
|
||||
<i className="fa-light fa-plus" aria-hidden="true"></i>
|
||||
</button>
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
} from "../../constant/Utils";
|
||||
import "../../styles/signature.css";
|
||||
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
import Loader from "../../primitives/Loader";
|
||||
|
||||
@@ -33,21 +32,18 @@ function Header({
|
||||
isSignYourself,
|
||||
setIsEmail,
|
||||
completeBtnTitle,
|
||||
setIsEditTemplate
|
||||
setIsEditTemplate,
|
||||
isPublicTemplate
|
||||
}) {
|
||||
const filterPrefill =
|
||||
signerPos && signerPos?.filter((data) => data.Role !== "prefill");
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const navigate = useNavigate();
|
||||
const [isDownloading, setIsDownloading] = useState("");
|
||||
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
||||
|
||||
//function for show decline alert
|
||||
const handleDeclinePdfAlert = async () => {
|
||||
const currentDecline = {
|
||||
currnt: "Sure",
|
||||
isDeclined: true
|
||||
};
|
||||
const currentDecline = { currnt: "Sure", isDeclined: true };
|
||||
setIsDecline(currentDecline);
|
||||
};
|
||||
|
||||
@@ -64,7 +60,7 @@ function Header({
|
||||
}}
|
||||
>
|
||||
<div className="flex justify-between items-center py-[5px] px-[10px] ">
|
||||
<div onClick={() => navigate(-1)}>
|
||||
<div onClick={() => window.history.go(-2)}>
|
||||
<i
|
||||
className="fa-light fa-arrow-left text-base-content"
|
||||
aria-hidden="true"
|
||||
@@ -209,7 +205,7 @@ function Header({
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content
|
||||
className="bg-white shadow-md rounded px-2 py-1"
|
||||
className="bg-white shadow-md rounded-full px-3 py-2"
|
||||
sideOffset={5}
|
||||
>
|
||||
<DropdownMenu.Item
|
||||
@@ -275,7 +271,7 @@ function Header({
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => navigate(-1)}
|
||||
onClick={() => window.history.go(-2)}
|
||||
type="button"
|
||||
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||
>
|
||||
@@ -298,6 +294,17 @@ function Header({
|
||||
) : isPdfRequestFiles ? (
|
||||
alreadySign ? (
|
||||
<div className="flex flex-row">
|
||||
<button
|
||||
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
|
||||
type="button"
|
||||
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
|
||||
>
|
||||
<i
|
||||
className="fa-light fa-print py-[3px]"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span className="hidden lg:block">Print</span>
|
||||
</button>
|
||||
{isCompleted && (
|
||||
<button
|
||||
type="button"
|
||||
@@ -313,19 +320,6 @@ function Header({
|
||||
<span className="hidden lg:block">Certificate</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
|
||||
type="button"
|
||||
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
|
||||
>
|
||||
<i
|
||||
className="fa-light fa-print py-[3px]"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span className="hidden lg:block">Print</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow"
|
||||
@@ -343,7 +337,7 @@ function Header({
|
||||
) : (
|
||||
<div className="flex" data-tut="reactourFifth">
|
||||
<button
|
||||
onClick={() => navigate(-1)}
|
||||
onClick={() => window.history.go(-2)}
|
||||
type="button"
|
||||
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||
>
|
||||
@@ -364,40 +358,16 @@ function Header({
|
||||
>
|
||||
Finish
|
||||
</button>
|
||||
<div className="op-dropdown op-dropdown-end">
|
||||
<div
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
className="op-btn op-btn-info op-btn-sm shadow"
|
||||
>
|
||||
<i
|
||||
className="fa-light fa-ellipsis-v"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</div>
|
||||
<ul
|
||||
tabIndex={0}
|
||||
className="op-dropdown-content z-[1] op-menu op-menu-sm p-1 shadow bg-base-100 rounded-box mt-1"
|
||||
>
|
||||
<li
|
||||
onClick={() =>
|
||||
handleDownloadPdf(
|
||||
pdfDetails,
|
||||
pdfUrl,
|
||||
setIsDownloading
|
||||
)
|
||||
}
|
||||
>
|
||||
<span className="font-semibold text-[12px]">
|
||||
<i
|
||||
className="fa-light fa-arrow-down"
|
||||
aria-hidden="true"
|
||||
></i>{" "}
|
||||
Download
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
|
||||
onClick={() =>
|
||||
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
|
||||
}
|
||||
>
|
||||
<i className="fa-light fa-arrow-down font-semibold lg:hidden"></i>
|
||||
<span className="hidden lg:block">Download</span>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@@ -443,10 +413,24 @@ function Header({
|
||||
<span className="hidden lg:block ml-1">Mail</span>
|
||||
</button>
|
||||
</div>
|
||||
) : isPublicTemplate ? (
|
||||
<>
|
||||
<div className="flex">
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-primary op-btn-sm shadow"
|
||||
onClick={() => {
|
||||
embedWidgetsData();
|
||||
}}
|
||||
>
|
||||
Sign Now
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="flex">
|
||||
<button
|
||||
onClick={() => navigate(-1)}
|
||||
onClick={() => window.history.go(-2)}
|
||||
type="button"
|
||||
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||
>
|
||||
|
||||
@@ -234,25 +234,29 @@ function Placeholder(props) {
|
||||
setDraggingEnabled(false);
|
||||
}
|
||||
if ((props.isNeedSign || props.isSignYourself) && !props.isDragging) {
|
||||
if (props.pos.type) {
|
||||
if (
|
||||
props.pos.type === "signature" ||
|
||||
props.pos.type === "stamp" ||
|
||||
props.pos.type === "image"
|
||||
) {
|
||||
props.setIsSignPad(true);
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setIsStamp(props.pos.isStamp);
|
||||
} else if (props.pos.type === "initials") {
|
||||
props.setIsSignPad(true);
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setIsStamp(props.pos.isStamp);
|
||||
props.setIsInitial(true);
|
||||
}
|
||||
if (props?.ispublicTemplate) {
|
||||
props.handleUserDetails();
|
||||
} else {
|
||||
props.setIsSignPad(true);
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setIsStamp(props.pos?.isStamp ? props.pos.isStamp : false);
|
||||
if (props.pos.type) {
|
||||
if (
|
||||
props.pos.type === "signature" ||
|
||||
props.pos.type === "stamp" ||
|
||||
props.pos.type === "image"
|
||||
) {
|
||||
props.setIsSignPad(true);
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setIsStamp(props.pos.isStamp);
|
||||
} else if (props.pos.type === "initials") {
|
||||
props.setIsSignPad(true);
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setIsStamp(props.pos.isStamp);
|
||||
props.setIsInitial(true);
|
||||
}
|
||||
} else {
|
||||
props.setIsSignPad(true);
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setIsStamp(props.pos?.isStamp ? props.pos.isStamp : false);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
props.isPlaceholder &&
|
||||
@@ -262,6 +266,10 @@ function Placeholder(props) {
|
||||
if (props.pos.key === props.selectWidgetId) {
|
||||
props.handleLinkUser(props.data.Id);
|
||||
props.setUniqueId(props.data.Id);
|
||||
const checkIndex = props.xyPostion.findIndex(
|
||||
(data) => data.Id === props.data.Id
|
||||
);
|
||||
props.setIsSelectId(checkIndex || 0);
|
||||
}
|
||||
} else if (!props.pos.type) {
|
||||
if (
|
||||
@@ -291,6 +299,12 @@ function Placeholder(props) {
|
||||
}
|
||||
if (props.isNeedSign && props.data?.signerObjId === props.signerObjId) {
|
||||
handleWidgetIdandPopup();
|
||||
} else if (
|
||||
props?.isNeedSign &&
|
||||
props?.uniqueId &&
|
||||
props.data?.Id === props?.uniqueId
|
||||
) {
|
||||
handleWidgetIdandPopup();
|
||||
} else if (props.isPlaceholder || props.isSignYourself) {
|
||||
handleWidgetIdandPopup();
|
||||
}
|
||||
@@ -303,7 +317,9 @@ function Placeholder(props) {
|
||||
props?.setShowDropdown(true);
|
||||
} else if (props.pos.type === "checkbox") {
|
||||
props?.setIsCheckbox(true);
|
||||
} else if (
|
||||
}
|
||||
//condition to handle setting icon for signyour-self flow for all type text widgets
|
||||
else if (
|
||||
[
|
||||
textInputWidget,
|
||||
textWidget,
|
||||
@@ -311,19 +327,33 @@ function Placeholder(props) {
|
||||
"company",
|
||||
"job title",
|
||||
"email"
|
||||
].includes(props.pos.type)
|
||||
].includes(props.pos.type) &&
|
||||
props.isSignYourself
|
||||
) {
|
||||
props.handleTextSettingModal(true);
|
||||
} else {
|
||||
props?.handleNameModal && props?.handleNameModal(true);
|
||||
}
|
||||
|
||||
//condition for only placeholder and template flow
|
||||
if (props.data && props?.pos?.type !== textWidget) {
|
||||
props.setSignerObjId(props?.data?.signerObjId);
|
||||
props.setUniqueId(props?.data?.Id);
|
||||
} else if (props.data && props.pos.type === textWidget) {
|
||||
const checkIndex = props.xyPostion.findIndex(
|
||||
(data) => data.Id === props.data.Id
|
||||
);
|
||||
|
||||
props.setIsSelectId(checkIndex || 0);
|
||||
}
|
||||
//condition to handle in placeholder and template flow for text widget signerId for text widgets i have to set uniqueId in tempSignerId because
|
||||
//it does not have any signer user and any signerobjId
|
||||
else if (props.data && props.pos.type === textWidget) {
|
||||
props.setTempSignerId(props.uniqueId);
|
||||
props.setUniqueId(props?.data?.Id);
|
||||
const checkIndex = props.xyPostion.findIndex(
|
||||
(data) => data.Id === props.data.Id
|
||||
);
|
||||
props.setIsSelectId(checkIndex || 0);
|
||||
}
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setWidgetType(props.pos.type);
|
||||
@@ -340,10 +370,19 @@ function Placeholder(props) {
|
||||
if (props.data && props?.pos?.type !== textWidget) {
|
||||
props.setSignerObjId(props?.data?.signerObjId);
|
||||
props.setUniqueId(props?.data?.Id);
|
||||
const checkIndex = props.xyPostion.findIndex(
|
||||
(data) => data.Id === props.data.Id
|
||||
);
|
||||
|
||||
props.setIsSelectId(checkIndex || 0);
|
||||
} else if (props.data && props.pos.type === textWidget) {
|
||||
props.setTempSignerId(props.uniqueId);
|
||||
props.setSignerObjId(props?.data?.signerObjId);
|
||||
props.setUniqueId(props?.data?.Id);
|
||||
const checkIndex = props.xyPostion.findIndex(
|
||||
(data) => data.Id === props.data.Id
|
||||
);
|
||||
props.setIsSelectId(checkIndex || 0);
|
||||
}
|
||||
|
||||
//checking widget's type and open widget copy modal for required widgets
|
||||
@@ -400,6 +439,9 @@ function Placeholder(props) {
|
||||
<>
|
||||
{(props.isPlaceholder || props.isSignYourself) && (
|
||||
<>
|
||||
{/* condition to add setting icon for signyour-self flow for particular text widgets
|
||||
and also it have diffrent position
|
||||
*/}
|
||||
{[
|
||||
"checkbox",
|
||||
textInputWidget,
|
||||
@@ -426,6 +468,7 @@ function Placeholder(props) {
|
||||
}}
|
||||
></i>
|
||||
) : (
|
||||
/* condition to add setting icon for placeholder & template flow for all widgets except signature and date */
|
||||
((!props?.pos?.type && props.pos.isStamp) ||
|
||||
(props?.pos?.type &&
|
||||
!["date", "signature"].includes(props.pos.type) &&
|
||||
@@ -448,7 +491,7 @@ function Placeholder(props) {
|
||||
></i>
|
||||
)
|
||||
)}
|
||||
|
||||
{/* condition for usericon for all widgets except text widgets and signyour-self flow */}
|
||||
{props.pos.type !== textWidget && !props.isSignYourself && (
|
||||
<i
|
||||
data-tut="assignSigner"
|
||||
@@ -457,17 +500,26 @@ function Placeholder(props) {
|
||||
e.stopPropagation();
|
||||
props.handleLinkUser(props.data.Id);
|
||||
props.setUniqueId(props.data.Id);
|
||||
const checkIndex = props.xyPostion.findIndex(
|
||||
(data) => data.Id === props.data.Id
|
||||
);
|
||||
props.setIsSelectId(checkIndex || 0);
|
||||
}}
|
||||
onTouchEnd={(e) => {
|
||||
e.stopPropagation();
|
||||
props.handleLinkUser(props.data.Id);
|
||||
props.setUniqueId(props.data.Id);
|
||||
const checkIndex = props.xyPostion.findIndex(
|
||||
(data) => data.Id === props.data.Id
|
||||
);
|
||||
props.setIsSelectId(checkIndex || 0);
|
||||
}}
|
||||
style={{ color: "#188ae2", right: "32px", top: "-18px" }}
|
||||
></i>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{/* setting icon only for date widgets */}
|
||||
{props.pos.type === "date" && selectDate && (
|
||||
<div
|
||||
id="menu-container"
|
||||
@@ -483,6 +535,10 @@ function Placeholder(props) {
|
||||
if (props.data) {
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setUniqueId(props.data.Id);
|
||||
const checkIndex = props.xyPostion.findIndex(
|
||||
(data) => data.Id === props.data.Id
|
||||
);
|
||||
props.setIsSelectId(checkIndex || 0);
|
||||
}
|
||||
}}
|
||||
onTouchEnd={(e) => {
|
||||
@@ -491,6 +547,10 @@ function Placeholder(props) {
|
||||
if (props.data) {
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setUniqueId(props.data.Id);
|
||||
const checkIndex = props.xyPostion.findIndex(
|
||||
(data) => data.Id === props.data.Id
|
||||
);
|
||||
props.setIsSelectId(checkIndex || 0);
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -532,29 +592,37 @@ function Placeholder(props) {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* copy icon for all widgets */}
|
||||
<i
|
||||
className="fa-light fa-copy icon"
|
||||
onClick={(e) => handleCopyPlaceholder(e)}
|
||||
onTouchEnd={(e) => handleCopyPlaceholder(e)}
|
||||
style={{ color: "#188ae2", right: "12px", top: "-18px" }}
|
||||
></i>
|
||||
{/* delete icon for all widgets */}
|
||||
<i
|
||||
className="fa-light fa-circle-xmark icon"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
//condition for template and placeholder flow
|
||||
if (props.data) {
|
||||
props.handleDeleteSign(props.pos.key, props.data.Id);
|
||||
} else {
|
||||
}
|
||||
//condition for signyour-self flow
|
||||
else {
|
||||
props.handleDeleteSign(props.pos.key);
|
||||
props.setIsStamp(false);
|
||||
}
|
||||
}}
|
||||
//for mobile and tablet touch event
|
||||
onTouchEnd={(e) => {
|
||||
e.stopPropagation();
|
||||
//condition for template and placeholder flow
|
||||
if (props.data) {
|
||||
props.handleDeleteSign(props.pos.key, props.data?.Id);
|
||||
} else {
|
||||
}
|
||||
//condition for signyour-self flow
|
||||
else {
|
||||
props.handleDeleteSign(props.pos.key);
|
||||
props.setIsStamp(false);
|
||||
}
|
||||
@@ -621,13 +689,25 @@ function Placeholder(props) {
|
||||
}
|
||||
};
|
||||
|
||||
const getCursor = () => {
|
||||
if (props.data && props.isNeedSign) {
|
||||
if (props?.signerObjId && props.data?.signerObjId === props.signerObjId) {
|
||||
return "pointer";
|
||||
} else if (props?.uniqueId && props.data?.Id === props.uniqueId) {
|
||||
return "pointer";
|
||||
} else {
|
||||
return "not-allowed";
|
||||
}
|
||||
} else {
|
||||
return "all-scroll";
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Rnd
|
||||
id={props.pos.key}
|
||||
data-tut={props.pos.key === props.unSignedWidgetId ? "IsSigned" : ""}
|
||||
key={props.pos.key}
|
||||
lockAspectRatio={
|
||||
// props.pos.type !== textWidget
|
||||
![
|
||||
textWidget,
|
||||
"email",
|
||||
@@ -671,12 +751,7 @@ function Placeholder(props) {
|
||||
props.pos.type !== "company" &&
|
||||
props.pos.type !== "job title" &&
|
||||
"center",
|
||||
cursor:
|
||||
props.data && props.isNeedSign
|
||||
? props.data?.signerObjId === props.signerObjId
|
||||
? "pointer"
|
||||
: "not-allowed"
|
||||
: "all-scroll",
|
||||
cursor: getCursor(),
|
||||
zIndex:
|
||||
props.pos.type === "date"
|
||||
? props.pos.key === props.selectWidgetId
|
||||
@@ -775,7 +850,6 @@ function Placeholder(props) {
|
||||
)}
|
||||
{isTabAndMobile ? (
|
||||
<div
|
||||
// className="sm:inline-block md:inline-block lg:hidden "
|
||||
className="flex items-stretch"
|
||||
style={{
|
||||
left: xPos(props.pos, props.isSignYourself),
|
||||
|
||||
@@ -51,8 +51,8 @@ function PlaceholderBorder(props) {
|
||||
style={{
|
||||
borderColor: themeColor,
|
||||
borderStyle: "dashed",
|
||||
minWidth: handleMinWidth(),
|
||||
minHeight: handleMinHeight(),
|
||||
minWidth: handleMinWidth() || 0,
|
||||
minHeight: handleMinHeight() || 0,
|
||||
borderWidth: "0.2px",
|
||||
overflow: "hidden"
|
||||
}}
|
||||
|
||||
@@ -189,9 +189,7 @@ function PlaceholderCopy(props) {
|
||||
<ModalUi
|
||||
isOpen={props.isPageCopy}
|
||||
title={"Copy to all pages"}
|
||||
handleClose={() => {
|
||||
props.setIsPageCopy(false);
|
||||
}}
|
||||
handleClose={() => handleUniqueId()}
|
||||
>
|
||||
<div className="h-full p-[20px] text-base-content">
|
||||
{copyType.map((data, key) => {
|
||||
|
||||
@@ -13,10 +13,11 @@ import DatePicker from "react-datepicker";
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import "../../styles/signature.css";
|
||||
import RegexParser from "regex-parser";
|
||||
import { emailRegex } from "../../constant/const";
|
||||
const textWidgetCls =
|
||||
"w-full h-full md:min-w-full md:min-h-full z-[999] text-[12px] rounded-[2px] border-[1px] border-[#007bff] overflow-hidden resize-none outline-none text-base-content item-center bg-base-100 whitespace-pre-wrap";
|
||||
"w-full h-full md:min-w-full md:min-h-full z-[999] text-[12px] rounded-[2px] border-[1px] border-[#007bff] overflow-hidden resize-none outline-none text-base-content item-center whitespace-pre-wrap";
|
||||
const selectWidgetCls =
|
||||
"w-full h-full absolute left-0 top-0 border-[1px] border-[#007bff] rounded-[2px] focus:outline-none bg-base-100 text-base-content";
|
||||
"w-full h-full absolute left-0 top-0 border-[1px] border-[#007bff] rounded-[2px] focus:outline-none text-base-content";
|
||||
function PlaceholderType(props) {
|
||||
const type = props?.pos?.type;
|
||||
const [selectOption, setSelectOption] = useState("");
|
||||
@@ -61,7 +62,7 @@ function PlaceholderType(props) {
|
||||
if (validateType && validateType !== "text") {
|
||||
switch (validateType) {
|
||||
case "email":
|
||||
regexValidation = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
regexValidation = emailRegex;
|
||||
validateExpression(regexValidation);
|
||||
break;
|
||||
case "number":
|
||||
@@ -423,8 +424,10 @@ function PlaceholderType(props) {
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
color: "black",
|
||||
fontSize: "12px"
|
||||
fontSize: props.pos.options?.fontSize
|
||||
? props.pos.options?.fontSize + "px"
|
||||
: "12px",
|
||||
color: props.pos.options?.fontColor || "black"
|
||||
}}
|
||||
>
|
||||
<span>{type}</span>
|
||||
@@ -522,8 +525,10 @@ function PlaceholderType(props) {
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
color: "black",
|
||||
fontSize: "12px"
|
||||
fontSize: props.pos.options?.fontSize
|
||||
? props.pos.options?.fontSize + "px"
|
||||
: "12px",
|
||||
color: props.pos.options?.fontColor || "black"
|
||||
}}
|
||||
>
|
||||
<span>{type}</span>
|
||||
@@ -562,8 +567,10 @@ function PlaceholderType(props) {
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
color: "black",
|
||||
fontSize: "12px"
|
||||
fontSize: props.pos.options?.fontSize
|
||||
? props.pos.options?.fontSize + "px"
|
||||
: "12px",
|
||||
color: props.pos.options?.fontColor || "black"
|
||||
}}
|
||||
>
|
||||
<span>{type}</span>
|
||||
@@ -602,15 +609,18 @@ function PlaceholderType(props) {
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
color: "black",
|
||||
fontSize: "12px"
|
||||
fontSize: props.pos.options?.fontSize
|
||||
? props.pos.options?.fontSize + "px"
|
||||
: "12px",
|
||||
color: props.pos.options?.fontColor || "black"
|
||||
}}
|
||||
>
|
||||
<span>{type}</span>
|
||||
</div>
|
||||
);
|
||||
case "date":
|
||||
return (
|
||||
return props.isSignYourself ||
|
||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||
<div>
|
||||
<DatePicker
|
||||
renderCustomHeader={({ date, changeYear, changeMonth }) => (
|
||||
@@ -667,6 +677,16 @@ function PlaceholderType(props) {
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-[12px] text-black uppercase items-center">
|
||||
<span>
|
||||
{props.selectDate
|
||||
? props.selectDate?.format
|
||||
: props.pos?.options?.validation?.format
|
||||
? props.pos?.options?.validation?.format
|
||||
: "MM/dd/yyyy"}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
case "image":
|
||||
return props.pos.SignUrl ? (
|
||||
@@ -720,8 +740,10 @@ function PlaceholderType(props) {
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
color: "black",
|
||||
fontSize: "12px"
|
||||
fontSize: props.pos.options?.fontSize
|
||||
? props.pos.options?.fontSize + "px"
|
||||
: "12px",
|
||||
color: props.pos.options?.fontColor || "black"
|
||||
}}
|
||||
>
|
||||
<span>{type}</span>
|
||||
|
||||
@@ -61,15 +61,27 @@ const RecipientList = (props) => {
|
||||
);
|
||||
//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);
|
||||
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);
|
||||
|
||||
//change order of placeholder's list using sorting method
|
||||
//`remainingItems` is correct order of signers after change order
|
||||
const changeOrderSignerList = props?.signerPos.sort((a, b) => {
|
||||
//`indexA` and `indexB` is to get element position using index in correct order array
|
||||
const indexA = remainingItems.findIndex((item) => item.Id === a.Id);
|
||||
const indexB = remainingItems.findIndex((item) => item.Id === b.Id);
|
||||
//and then compare `indexA - indexB` value
|
||||
//if positive it means indexB element comes before indexA then need to sorting
|
||||
//if negative it means indexA element is on correct position do not need to sorting
|
||||
return indexA - indexB;
|
||||
});
|
||||
props?.setSignerPos(changeOrderSignerList);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
@@ -101,7 +113,7 @@ const RecipientList = (props) => {
|
||||
} flex flex-row rounded-xl px-2 py-[10px] mt-1 mx-1 items-center last:mb-0.5`}
|
||||
style={{
|
||||
background:
|
||||
(!isMobile && isHover === ind) || props.isSelectListId === ind
|
||||
(!isMobile && isHover === ind) || props.uniqueId === obj.Id
|
||||
? obj?.blockColor
|
||||
? obj?.blockColor
|
||||
: color[ind % color.length]
|
||||
|
||||
@@ -10,7 +10,8 @@ function RenderAllPdfPage({
|
||||
setSignBtnPosition,
|
||||
pageNumber,
|
||||
signerPos,
|
||||
signerObjectId
|
||||
signerObjectId,
|
||||
containerWH
|
||||
}) {
|
||||
const [signPageNumber, setSignPageNumber] = useState([]);
|
||||
const [bookmarkColor, setBookmarkColor] = useState("");
|
||||
@@ -48,7 +49,7 @@ function RenderAllPdfPage({
|
||||
const timer = setTimeout(updateSize, 100); // match the transition duration
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [isHeader, pageContainer]);
|
||||
}, [isHeader, pageContainer, containerWH]);
|
||||
//'function `addSignatureBookmark` is used to display the page where the user's signature is located.
|
||||
const addSignatureBookmark = (index) => {
|
||||
const ispageNumber = signPageNumber.includes(index + 1);
|
||||
@@ -57,13 +58,12 @@ function RenderAllPdfPage({
|
||||
<div className="absolute z-20 top-[1px] -right-[13px] -translate-x-1/2 -translate-y-1/2">
|
||||
<i
|
||||
style={{ color: bookmarkColor || "red" }}
|
||||
className="fa-light fa-bookmark"
|
||||
className="fa-solid fa-bookmark"
|
||||
></i>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div ref={pageContainer} className="hidden w-[20%] bg-base-100 md:block">
|
||||
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
|
||||
|
||||
@@ -57,7 +57,10 @@ function RenderPdf({
|
||||
setTempSignerId,
|
||||
uniqueId,
|
||||
pdfOriginalWH,
|
||||
scale
|
||||
scale,
|
||||
setIsSelectId,
|
||||
ispublicTemplate,
|
||||
handleUserDetails
|
||||
}) {
|
||||
const isMobile = window.innerWidth < 767;
|
||||
//check isGuestSigner is present in local if yes than handle login flow header in mobile view
|
||||
@@ -194,6 +197,8 @@ function RenderPdf({
|
||||
containerWH={containerWH}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pageNumber={pageNumber}
|
||||
ispublicTemplate={ispublicTemplate}
|
||||
handleUserDetails={handleUserDetails}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)
|
||||
@@ -319,6 +324,7 @@ function RenderPdf({
|
||||
containerWH={containerWH}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pageNumber={pageNumber}
|
||||
setIsSelectId={setIsSelectId}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
@@ -428,7 +434,7 @@ function RenderPdf({
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: containerWH.width * scale
|
||||
width: containerWH?.width && containerWH?.width * scale
|
||||
}}
|
||||
ref={drop}
|
||||
id="container"
|
||||
@@ -501,6 +507,7 @@ function RenderPdf({
|
||||
containerWH={containerWH}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pageNumber={pageNumber}
|
||||
setIsSelectId={setIsSelectId}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
@@ -149,7 +149,6 @@ function SignPad({
|
||||
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) {
|
||||
@@ -164,8 +163,8 @@ function SignPad({
|
||||
}
|
||||
}
|
||||
|
||||
const trimmedName = currentUserName.trim();
|
||||
const firstCharacter = trimmedName.charAt(0);
|
||||
const trimmedName = currentUserName && currentUserName.trim();
|
||||
const firstCharacter = trimmedName?.charAt(0);
|
||||
const userName = isInitial ? firstCharacter : currentUserName;
|
||||
setSignValue(userName);
|
||||
setFontSelect("Fasthand");
|
||||
@@ -299,8 +298,9 @@ function SignPad({
|
||||
<div className="flex flex-row justify-between mt-[3px]">
|
||||
<div className="flex flex-row justify-between gap-[5px] md:gap-[8px] text-[11px] md:text-base">
|
||||
{isStamp ? (
|
||||
<span className="op-link-primary op-link">
|
||||
{widgetType === "image"
|
||||
<span className="text-base-content font-bold text-lg">
|
||||
{widgetType === "image" ||
|
||||
currWidgetsDetails?.type === "image"
|
||||
? "Upload image"
|
||||
: "Upload stamp image"}
|
||||
</span>
|
||||
|
||||
@@ -35,7 +35,9 @@ function SignerListComponent(props) {
|
||||
className="flex w-[30px] h-[30px] rounded-full justify-center items-center mx-1"
|
||||
>
|
||||
<span className="text-[12px] text-center font-bold text-black uppercase">
|
||||
{getFirstLetter(props?.obj?.Name || props?.obj?.Role)}
|
||||
{getFirstLetter(
|
||||
props.obj?.Name || props.obj?.email || props.obj?.Role
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
|
||||
@@ -9,9 +9,7 @@ function TextFontSetting(props) {
|
||||
isOpen={props.isTextSetting}
|
||||
reduceWidth={"max-w-[350px]"}
|
||||
title={"Text field"}
|
||||
handleClose={() => {
|
||||
props.setIsTextSetting(false);
|
||||
}}
|
||||
handleClose={() => props.setIsTextSetting(false)}
|
||||
>
|
||||
<div className="h-full p-[20px]">
|
||||
<div className="flex items-center">
|
||||
@@ -19,7 +17,9 @@ function TextFontSetting(props) {
|
||||
<select
|
||||
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
|
||||
value={
|
||||
props.fontSize || props.currWidgetsDetails?.options?.fontSize
|
||||
props.fontSize ||
|
||||
props.currWidgetsDetails?.options?.fontSize ||
|
||||
"12"
|
||||
}
|
||||
onChange={(e) => props.setFontSize(e.target.value)}
|
||||
>
|
||||
@@ -35,7 +35,9 @@ function TextFontSetting(props) {
|
||||
<span>color: </span>
|
||||
<select
|
||||
value={
|
||||
props.fontColor || props.currWidgetsDetails?.options?.fontColor
|
||||
props.fontColor ||
|
||||
props.currWidgetsDetails?.options?.fontColor ||
|
||||
"black"
|
||||
}
|
||||
onChange={(e) => props.setFontColor(e.target.value)}
|
||||
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
|
||||
|
||||
@@ -37,11 +37,10 @@ function WidgetComponent({
|
||||
sendInOrder,
|
||||
isTemplateFlow,
|
||||
setBlockColor,
|
||||
blockColor,
|
||||
setIsAddSigner
|
||||
setIsAddSigner,
|
||||
uniqueId
|
||||
}) {
|
||||
const [isSignersModal, setIsSignersModal] = useState(false);
|
||||
|
||||
const [, dropdown] = useDrag({
|
||||
type: "BOX",
|
||||
item: {
|
||||
@@ -187,7 +186,6 @@ function WidgetComponent({
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const scrollContainerRef = useRef(null);
|
||||
const [widget, setWidget] = useState([]);
|
||||
|
||||
const color = [
|
||||
"#93a3db",
|
||||
"#e6c3db",
|
||||
@@ -245,86 +243,66 @@ function WidgetComponent({
|
||||
? textWidgetData
|
||||
: widget;
|
||||
|
||||
const handleSelectRecipient = () => {
|
||||
if (
|
||||
signersdata[isSelectListId]?.Email ||
|
||||
signersdata[isSelectListId]?.Role
|
||||
) {
|
||||
const userData =
|
||||
signersdata[isSelectListId]?.Name || signersdata[isSelectListId]?.Role;
|
||||
const name =
|
||||
userData?.length > 20 ? `${userData.slice(0, 20)}...` : userData;
|
||||
return name;
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{isMobile ? (
|
||||
!isMailSend && (
|
||||
<div
|
||||
id="navbar"
|
||||
className="fixed z-[99] bottom-0 right-0"
|
||||
style={{ width: window.innerWidth + "px" }}
|
||||
>
|
||||
<div className="mx-1">
|
||||
{isSigners && (
|
||||
<div
|
||||
data-tut="recipientArea"
|
||||
className="py-[10px] flex justify-center items-center op-card"
|
||||
style={{
|
||||
background: blockColor
|
||||
? blockColor
|
||||
: isSelectListId
|
||||
<div id="navbar" className="fixed z-[99] bottom-0 right-0 w-full">
|
||||
{isSigners && (
|
||||
<div className="w-full mb-[5px] flex justify-center items-center gap-1">
|
||||
<div className="w-full ml-[5px]" onClick={() => handleModal()}>
|
||||
<select
|
||||
data-tut="recipientArea"
|
||||
className="w-full op-select op-select-bordered pointer-events-none"
|
||||
value={handleSelectRecipient()}
|
||||
style={{
|
||||
backgroundColor: isSelectListId
|
||||
? color[isSelectListId % color.length]
|
||||
: color[0]
|
||||
}}
|
||||
onClick={() => handleModal()}
|
||||
>
|
||||
<span className="text-[13px] font-bold flex items-center">
|
||||
{title ? title : "Recipient"}
|
||||
{signersdata[isSelectListId]?.Role && (
|
||||
<div>
|
||||
{signersdata[isSelectListId]?.Name ? (
|
||||
<>
|
||||
:{" "}
|
||||
{signersdata[isSelectListId]?.Name?.length > 12
|
||||
? `${signersdata[isSelectListId].Name.slice(
|
||||
0,
|
||||
12
|
||||
)}...`
|
||||
: signersdata[isSelectListId]?.Name}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
:{" "}
|
||||
{signersdata[isSelectListId]?.Role?.length > 12
|
||||
? `${signersdata[isSelectListId].Role.slice(
|
||||
0,
|
||||
12
|
||||
)}...`
|
||||
: signersdata[isSelectListId]?.Role}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="ml-[6px] text-[16px]">
|
||||
<i className="fa-light fa-angle-down"></i>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="mx-1">
|
||||
{handleAddSigner ? (
|
||||
<div
|
||||
data-tut="reactourAddbtn"
|
||||
className="op-btn op-btn-accent w-full my-[2px]"
|
||||
onClick={() => handleAddSigner()}
|
||||
>
|
||||
<i className="fa-light fa-plus"></i>
|
||||
<span>Add role</span>
|
||||
</div>
|
||||
) : (
|
||||
setIsAddSigner && (
|
||||
<div
|
||||
data-tut="addRecipient"
|
||||
className="op-btn op-btn-accent w-full my-[2px]"
|
||||
onClick={() => setIsAddSigner(true)}
|
||||
}}
|
||||
>
|
||||
<i className="fa-light fa-plus"></i>
|
||||
<span>Add recipients</span>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
<option value={handleSelectRecipient()}>
|
||||
{handleSelectRecipient()}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="w-[18%]">
|
||||
{handleAddSigner ? (
|
||||
<button
|
||||
data-tut="reactourAddbtn"
|
||||
onClick={() => handleAddSigner()}
|
||||
className="op-btn op-btn-accent"
|
||||
>
|
||||
<i className="fa-light fa-plus "></i>
|
||||
</button>
|
||||
) : (
|
||||
setIsAddSigner && (
|
||||
<button
|
||||
data-tut="addRecipient"
|
||||
onClick={() => setIsAddSigner(true)}
|
||||
className="op-btn op-btn-accent"
|
||||
>
|
||||
<i className="fa-light fa-plus"></i>
|
||||
</button>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
data-tut="addWidgets"
|
||||
ref={scrollContainerRef}
|
||||
@@ -392,6 +370,7 @@ function WidgetComponent({
|
||||
sendInOrder={sendInOrder}
|
||||
setSignersData={setSignersData}
|
||||
setBlockColor={setBlockColor}
|
||||
uniqueId={uniqueId}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
|
||||
@@ -2,11 +2,11 @@ import React, { useEffect, useState } from "react";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
import "../../styles/AddUser.css";
|
||||
import RegexParser from "regex-parser";
|
||||
import { textInputWidget } from "../../constant/Utils";
|
||||
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
||||
import { textInputWidget, textWidget } from "../../constant/Utils";
|
||||
import Upgrade from "../../primitives/Upgrade";
|
||||
import { isEnableSubscription } from "../../constant/const";
|
||||
import Tooltip from "../../primitives/Tooltip";
|
||||
import { fontColorArr, fontsizeArr } from "../../constant/Utils";
|
||||
|
||||
const WidgetNameModal = (props) => {
|
||||
const [formdata, setFormdata] = useState({
|
||||
@@ -23,7 +23,7 @@ const WidgetNameModal = (props) => {
|
||||
useEffect(() => {
|
||||
if (props.defaultdata) {
|
||||
setFormdata({
|
||||
name: props.defaultdata?.options?.name || props?.widgetName || "",
|
||||
name: props.defaultdata?.options?.name || "",
|
||||
defaultValue: props.defaultdata?.options?.defaultValue || "",
|
||||
status: props.defaultdata?.options?.status || "required",
|
||||
hint: props.defaultdata?.options?.hint || "",
|
||||
@@ -35,11 +35,11 @@ const WidgetNameModal = (props) => {
|
||||
} else {
|
||||
setFormdata({
|
||||
...formdata,
|
||||
name: props.defaultdata?.options?.name || props?.widgetName || ""
|
||||
name: props.defaultdata?.options?.name || ""
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, [props.defaultdata, props.widgetName]);
|
||||
}, [props.defaultdata]);
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
if (props.handleData) {
|
||||
@@ -106,22 +106,10 @@ const WidgetNameModal = (props) => {
|
||||
handleClose={props.handleClose && props.handleClose}
|
||||
title={"Widget info"}
|
||||
>
|
||||
{(props.defaultdata?.type === textInputWidget ||
|
||||
props.widgetName === textInputWidget) &&
|
||||
!isEnableSubscription && (
|
||||
<PremiumAlertHeader
|
||||
message={
|
||||
"Field validations are free in beta, this feature will incur a fee later."
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className={`${
|
||||
props.defaultdata?.type === textInputWidget ||
|
||||
props.widgetName === textInputWidget
|
||||
? "pt-0"
|
||||
: ""
|
||||
props.defaultdata?.type === textInputWidget ? "pt-0" : ""
|
||||
} p-[20px] text-base-content`}
|
||||
>
|
||||
<div className="mb-[0.75rem] text-[13px]">
|
||||
@@ -137,67 +125,71 @@ const WidgetNameModal = (props) => {
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
{(props.defaultdata?.type === textInputWidget ||
|
||||
props.widgetName === textInputWidget) && (
|
||||
{props.defaultdata?.type === textInputWidget && (
|
||||
<>
|
||||
<div className="mb-[0.75rem]">
|
||||
<div className="flex items-center gap-1">
|
||||
<label
|
||||
htmlFor="textvalidate"
|
||||
{isEnableSubscription && (
|
||||
<div className="mb-[0.75rem]">
|
||||
<div className="flex items-center gap-1">
|
||||
<label
|
||||
htmlFor="textvalidate"
|
||||
className={`${
|
||||
!props.isSubscribe && isEnableSubscription
|
||||
? "bg-opacity-50 pointer-events-none"
|
||||
: ""
|
||||
} text-[13px]`}
|
||||
>
|
||||
Validation
|
||||
</label>
|
||||
<Tooltip
|
||||
url={"https://www.w3schools.com/jsref/jsref_obj_regexp.asp"}
|
||||
/>
|
||||
{!props.isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
</div>
|
||||
<div
|
||||
className={`${
|
||||
!props.isSubscribe && isEnableSubscription
|
||||
? "bg-opacity-50 pointer-events-none"
|
||||
: ""
|
||||
} text-[13px]`}
|
||||
} flex flex-row gap-[10px] mb-[0.5rem]`}
|
||||
>
|
||||
Validation
|
||||
</label>
|
||||
<Tooltip
|
||||
url={"https://www.w3schools.com/jsref/jsref_obj_regexp.asp"}
|
||||
/>
|
||||
{!props.isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
</div>
|
||||
<div
|
||||
className={`${
|
||||
!props.isSubscribe && isEnableSubscription
|
||||
? "bg-opacity-50 pointer-events-none"
|
||||
: ""
|
||||
} flex flex-row gap-[10px] mb-[0.5rem]`}
|
||||
>
|
||||
<div className="w-full relative group">
|
||||
<input
|
||||
className="z-20 relative op-input op-input-bordered rounded-r-none op-input-sm focus:outline-none group-hover:border-base-content w-[87%] md:w-[92%] text-xs"
|
||||
name="textvalidate"
|
||||
placeholder="Enter custom regular expression"
|
||||
value={formdata.textvalidate}
|
||||
onChange={(e) => handleChange(e)}
|
||||
// onBlur={() => handleBlurRegex()}
|
||||
/>
|
||||
<select
|
||||
className="validationlist op-input op-input-bordered op-input-sm focus:outline-none group-hover:border-base-content w-full text-xs"
|
||||
name="textvalidate"
|
||||
value={formdata.textvalidate}
|
||||
onChange={(e) => handleChange(e)}
|
||||
onBlur={() => handleBlurRegex()}
|
||||
>
|
||||
<option
|
||||
disabled={formdata?.textvalidate}
|
||||
className="text-[13px]"
|
||||
<div className="w-full relative group">
|
||||
<input
|
||||
className="z-20 relative op-input op-input-bordered rounded-r-none op-input-sm focus:outline-none group-hover:border-base-content w-[87%] md:w-[92%] text-xs"
|
||||
name="textvalidate"
|
||||
placeholder="Enter custom regular expression"
|
||||
value={formdata.textvalidate}
|
||||
onChange={(e) => handleChange(e)}
|
||||
// onBlur={() => handleBlurRegex()}
|
||||
/>
|
||||
<select
|
||||
className="validationlist op-input op-input-bordered op-input-sm focus:outline-none group-hover:border-base-content w-full text-xs"
|
||||
name="textvalidate"
|
||||
value={formdata.textvalidate}
|
||||
onChange={(e) => handleChange(e)}
|
||||
onBlur={() => handleBlurRegex()}
|
||||
>
|
||||
Select...
|
||||
</option>
|
||||
{inputOpt.map((data, ind) => {
|
||||
return (
|
||||
<option className="text-[13px]" key={ind} value={data}>
|
||||
{data}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
<option
|
||||
disabled={formdata?.textvalidate}
|
||||
className="text-[13px]"
|
||||
>
|
||||
Select...
|
||||
</option>
|
||||
{inputOpt.map((data, ind) => {
|
||||
return (
|
||||
<option
|
||||
className="text-[13px]"
|
||||
key={ind}
|
||||
value={data}
|
||||
>
|
||||
{data}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
)}
|
||||
<div className="mb-[0.75rem]">
|
||||
<label htmlFor="name" className="text-[13px]">
|
||||
Default value
|
||||
@@ -252,8 +244,7 @@ const WidgetNameModal = (props) => {
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
{(props.defaultdata?.type === textInputWidget ||
|
||||
props?.widgetName === textInputWidget) && (
|
||||
{props.defaultdata?.type === textInputWidget && (
|
||||
<div className="mb-[0.75rem]">
|
||||
<label htmlFor="hint" className="text-[13px]">
|
||||
Hint
|
||||
@@ -266,6 +257,63 @@ const WidgetNameModal = (props) => {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{[
|
||||
textInputWidget,
|
||||
textWidget,
|
||||
"name",
|
||||
"company",
|
||||
"job title",
|
||||
"email"
|
||||
].includes(props.defaultdata?.type) && (
|
||||
<div className="flex items-center mb-[0.75rem]">
|
||||
<span>Font size:</span>
|
||||
<select
|
||||
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
|
||||
value={
|
||||
props.fontSize || props.defaultdata?.options?.fontSize || "12"
|
||||
}
|
||||
onChange={(e) => props.setFontSize(e.target.value)}
|
||||
>
|
||||
{fontsizeArr.map((size, ind) => {
|
||||
return (
|
||||
<option className="text-[13px]" value={size} key={ind}>
|
||||
{size}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
<div className="flex flex-row gap-1 items-center ml-4">
|
||||
<span>color: </span>
|
||||
<select
|
||||
value={
|
||||
props.fontColor ||
|
||||
props.defaultdata?.options?.fontColor ||
|
||||
"black"
|
||||
}
|
||||
onChange={(e) => props.setFontColor(e.target.value)}
|
||||
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
|
||||
>
|
||||
{fontColorArr.map((color, ind) => {
|
||||
return (
|
||||
<option value={color} key={ind}>
|
||||
{color}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
<span
|
||||
style={{
|
||||
background:
|
||||
props.fontColor ||
|
||||
props.defaultdata?.options?.fontColor ||
|
||||
"black"
|
||||
}}
|
||||
className="w-5 h-[19px] ml-1"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="h-[1px] w-full mb-[16px] bg-[#b7b3b3]"></div>
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Save
|
||||
|
||||
@@ -4,11 +4,14 @@ import Submenu from "./SubMenu";
|
||||
import SocialMedia from "./SocialMedia";
|
||||
import dp from "../../assets/images/dp.png";
|
||||
import sidebarList from "../../json/menuJson";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { isEnableSubscription } from "../../constant/const";
|
||||
|
||||
const Sidebar = ({ isOpen, closeSidebar }) => {
|
||||
const navigate = useNavigate();
|
||||
const [menuList, setmenuList] = useState([]);
|
||||
const [submenuOpen, setSubmenuOpen] = useState(false);
|
||||
let username = localStorage.getItem("username");
|
||||
const username = localStorage.getItem("username");
|
||||
const image = localStorage.getItem("profileImg") || dp;
|
||||
const tenantname = localStorage.getItem("Extand_Class")
|
||||
? JSON.parse(localStorage.getItem("Extand_Class"))?.[0]?.Company
|
||||
@@ -23,29 +26,76 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
|
||||
const menuItem = async () => {
|
||||
try {
|
||||
if (localStorage.getItem("defaultmenuid")) {
|
||||
const menuId = localStorage.getItem("defaultmenuid") !== "VPh91h0ZHk";
|
||||
if (menuId) {
|
||||
setmenuList(sidebarList);
|
||||
} else {
|
||||
const addUserForm = {
|
||||
icon: "fa-light fa-user",
|
||||
title: "Add User",
|
||||
target: "_self",
|
||||
pageType: "form",
|
||||
description: "",
|
||||
objectId: "lM0xRnM3iE"
|
||||
};
|
||||
const Extand_Class = localStorage.getItem("Extand_Class");
|
||||
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
||||
// console.log("extClass ", extClass);
|
||||
let userRole = "contracts_User";
|
||||
if (extClass && extClass.length > 0) {
|
||||
userRole = extClass[0].UserRole;
|
||||
}
|
||||
if (
|
||||
userRole === "contracts_Admin" ||
|
||||
userRole === "contracts_OrgAdmin"
|
||||
) {
|
||||
const newSidebarList = sidebarList.map((item) => {
|
||||
if (item.title === "Settings") {
|
||||
// Make a shallow copy of the item
|
||||
const newItem = { ...item };
|
||||
// Insert addUserForm at the second position
|
||||
newItem.children.splice(1, 0, addUserForm);
|
||||
if (isEnableSubscription) {
|
||||
newItem.children = [
|
||||
...newItem.children,
|
||||
{
|
||||
icon: "fa-light fa-building-memo",
|
||||
title: "Teams",
|
||||
target: "_self",
|
||||
pageType: "",
|
||||
description: "",
|
||||
objectId: "teams"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-users fa-fw",
|
||||
title: "Users",
|
||||
target: "_self",
|
||||
pageType: "",
|
||||
description: "",
|
||||
objectId: "users"
|
||||
}
|
||||
];
|
||||
} else {
|
||||
const arr = newItem.children.slice(0, 1);
|
||||
newItem.children = [
|
||||
...arr,
|
||||
{
|
||||
icon: "fa-light fa-users fa-fw",
|
||||
title: "Users",
|
||||
target: "_self",
|
||||
pageType: "",
|
||||
description: "",
|
||||
objectId: "users"
|
||||
}
|
||||
];
|
||||
}
|
||||
return newItem;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
setmenuList(newSidebarList);
|
||||
} else {
|
||||
if (!isEnableSubscription) {
|
||||
const newSidebarList = sidebarList.map((item) => {
|
||||
if (item.title === "Settings") {
|
||||
// Make a shallow copy of the item
|
||||
const newItem = { ...item };
|
||||
const arr = newItem.children.slice(0, 1);
|
||||
newItem.children = arr;
|
||||
return newItem;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
setmenuList(newSidebarList);
|
||||
} else {
|
||||
setmenuList(sidebarList);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -61,13 +111,19 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
|
||||
closeSidebar();
|
||||
setSubmenuOpen({});
|
||||
};
|
||||
const handleProfile = () => {
|
||||
navigate("/profile");
|
||||
};
|
||||
return (
|
||||
<aside
|
||||
className={`absolute lg:relative bg-base-100 h-screen overflow-y-auto transition-all z-[999] shadow-lg hide-scrollbar
|
||||
className={`absolute lg:relative bg-base-100 h-screen overflow-y-auto transition-all z-[500] shadow-lg hide-scrollbar
|
||||
${isOpen ? "w-full md:w-[300px]" : "w-0"}`}
|
||||
>
|
||||
<div className="flex px-2 py-3 gap-2 items-center shadow-md">
|
||||
<div className="w-[75px] h-[75px] rounded-full ring-[2px] ring-offset-2 ring-gray-400 overflow-hidden">
|
||||
<div
|
||||
onClick={() => handleProfile()}
|
||||
className="w-[75px] h-[75px] rounded-full ring-[2px] ring-offset-2 ring-gray-400 overflow-hidden cursor-pointer"
|
||||
>
|
||||
<img
|
||||
className="w-full h-full object-contain"
|
||||
src={image}
|
||||
@@ -75,9 +131,15 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-[14px] font-bold text-base-content">{username}</p>
|
||||
<p
|
||||
className={`text-[12px] text-base-content ${
|
||||
onClick={handleProfile}
|
||||
className="text-[14px] font-bold text-base-content cursor-pointer"
|
||||
>
|
||||
{username}
|
||||
</p>
|
||||
<p
|
||||
onClick={handleProfile}
|
||||
className={`cursor-pointer text-[12px] text-base-content ${
|
||||
tenantname ? "mt-2" : ""
|
||||
}`}
|
||||
>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import axios from "axios";
|
||||
import moment from "moment";
|
||||
import { isEnableSubscription } from "./const";
|
||||
import React from "react";
|
||||
import { rgb } from "pdf-lib";
|
||||
import Parse from "parse";
|
||||
@@ -63,7 +62,7 @@ export async function fetchSubscription(
|
||||
return { plan: "", billingDate: "" };
|
||||
}
|
||||
}
|
||||
//function to get subcripition details from Extand user class
|
||||
//function to get subcripition details from subscription class
|
||||
export async function checkIsSubscribed() {
|
||||
try {
|
||||
const res = await fetchSubscription();
|
||||
@@ -84,6 +83,34 @@ export async function checkIsSubscribed() {
|
||||
}
|
||||
}
|
||||
|
||||
//function to get subcripition details from subscription class
|
||||
export async function checkIsSubscribedTeam() {
|
||||
try {
|
||||
const res = await fetchSubscription();
|
||||
if (res.plan === "freeplan") {
|
||||
return false;
|
||||
} else if (res.billingDate) {
|
||||
const plan =
|
||||
res.plan === "team-weekly" ||
|
||||
res.plan === "team-yearly" ||
|
||||
res.plan === "teams-monthly" ||
|
||||
res.plan === "teams-yearly" ||
|
||||
res.plan === "enterprise-monthly" ||
|
||||
res.plan === "enterprise-yearly";
|
||||
if (plan && new Date(res.billingDate) > new Date()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err in fetch subscription", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const color = [
|
||||
"#93a3db",
|
||||
"#e6c3db",
|
||||
@@ -151,7 +178,7 @@ export const getDrive = async (documentId, skip = 0, limit = 100) => {
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Err ", err);
|
||||
console.log("Err in getDrive cloud function", err);
|
||||
return "Error: Something went wrong!";
|
||||
});
|
||||
|
||||
@@ -186,7 +213,7 @@ export const contractUsers = async (email) => {
|
||||
return data;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Err ", err);
|
||||
console.log("Err in getUserDetails cloud function", err);
|
||||
return "Error: Something went wrong!";
|
||||
});
|
||||
|
||||
@@ -326,7 +353,7 @@ export const getDate = () => {
|
||||
};
|
||||
export const addWidgetOptions = (type) => {
|
||||
const defaultOpt = {
|
||||
name: "",
|
||||
name: type,
|
||||
status: "required"
|
||||
};
|
||||
switch (type) {
|
||||
@@ -541,7 +568,7 @@ export const signPdfFun = async (
|
||||
if (
|
||||
tenantDetails?.CompletionBody &&
|
||||
tenantDetails?.CompletionSubject &&
|
||||
(!isEnableSubscription || isSubscribed)
|
||||
isSubscribed
|
||||
) {
|
||||
isCustomCompletionMail = true;
|
||||
}
|
||||
@@ -599,7 +626,7 @@ export const signPdfFun = async (
|
||||
return res;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Err ", err);
|
||||
console.log("Err in signPdf cloud function ", err);
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "something went wrong"
|
||||
@@ -669,9 +696,7 @@ export const createDocument = async (template, placeholders, signerData) => {
|
||||
|
||||
try {
|
||||
const res = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Document`,
|
||||
`${localStorage.getItem("baseUrl")}classes/contracts_Document`,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
@@ -1618,9 +1643,9 @@ export const placeholderHeight = (pos) => {
|
||||
export const contactBook = async (objectId) => {
|
||||
const result = await axios
|
||||
.get(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Contactbook?where={"objectId":"${objectId}"}`,
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/contracts_Contactbook?where={"objectId":"${objectId}"}`,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@@ -1636,7 +1661,7 @@ export const contactBook = async (objectId) => {
|
||||
})
|
||||
|
||||
.catch((err) => {
|
||||
console.log("Err ", err);
|
||||
console.log("Err in contracts_Contactbook class ", err);
|
||||
return "Error: Something went wrong!";
|
||||
});
|
||||
return result;
|
||||
@@ -1668,7 +1693,7 @@ export const contractDocument = async (documentId) => {
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Err ", err);
|
||||
console.log("Err in getDocument cloud function ", err);
|
||||
return "Error: Something went wrong!";
|
||||
});
|
||||
|
||||
@@ -1830,18 +1855,21 @@ export const getFileName = (fileUrl) => {
|
||||
|
||||
//fetch tenant app logo from `partners_Tenant` class by domain name
|
||||
export const getAppLogo = async () => {
|
||||
const domainName = window.location.host;
|
||||
try {
|
||||
const tenantCreditsQuery = new Parse.Query("partners_Tenant");
|
||||
tenantCreditsQuery.equalTo("Domain", domainName);
|
||||
const res = await tenantCreditsQuery.first();
|
||||
|
||||
if (res) {
|
||||
const updateRes = JSON.parse(JSON.stringify(res));
|
||||
return updateRes?.Logo;
|
||||
if (window.location.host === "app.opensignlabs.com") {
|
||||
return { logo: appInfo.applogo, user: "exist" };
|
||||
} else {
|
||||
const domain = window.location.host;
|
||||
try {
|
||||
const tenant = await Parse.Cloud.run("getlogobydomain", {
|
||||
domain: domain
|
||||
});
|
||||
if (tenant) {
|
||||
return { logo: tenant?.logo, user: tenant?.user };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err in getlogo ", err);
|
||||
return { logo: appInfo.applogo, user: "exist" };
|
||||
}
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1940,12 +1968,12 @@ export const handleDownloadPdf = async (
|
||||
try {
|
||||
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
|
||||
const axiosRes = await axios.post(
|
||||
`${appInfo.baseUrl}/functions/getsignedurl`,
|
||||
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
||||
{ url: pdfUrl },
|
||||
{
|
||||
headers: {
|
||||
"content-type": "Application/json",
|
||||
"X-Parse-Application-Id": appInfo.appId,
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
@@ -1970,13 +1998,15 @@ export const handleToPrint = async (event, pdfUrl, setIsDownloading) => {
|
||||
setIsDownloading("pdf");
|
||||
try {
|
||||
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
|
||||
//`localStorage.getItem("baseUrl")` is also use in public-profile flow for public-sign
|
||||
//if we give this `appInfo.baseUrl` as a base url then in public-profile it will create base url of it's window.location.origin ex- opensign.me which is not base url
|
||||
const axiosRes = await axios.post(
|
||||
`${appInfo.baseUrl}/functions/getsignedurl`,
|
||||
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
||||
{ url: pdfUrl },
|
||||
{
|
||||
headers: {
|
||||
"content-type": "Application/json",
|
||||
"X-Parse-Application-Id": appInfo.appId,
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import logo from "../assets/images/logo.png";
|
||||
export const appInfo = {
|
||||
appTitle: "contracts",
|
||||
applogo: logo,
|
||||
appname: "contracts",
|
||||
appId: process.env.REACT_APP_APPID ? process.env.REACT_APP_APPID : "opensign",
|
||||
baseUrl: process.env.REACT_APP_SERVERURL
|
||||
? process.env.REACT_APP_SERVERURL
|
||||
@@ -18,22 +16,34 @@ export const appInfo = {
|
||||
: "",
|
||||
metaDescription:
|
||||
"The fastest way to sign PDFs & request signatures from others.",
|
||||
objectId: "aIPmIvMzGM",
|
||||
settings: [
|
||||
{
|
||||
role: "contracts_User",
|
||||
menuId: "H9vRfEYKhT",
|
||||
pageType: "dashboard",
|
||||
pageId: "35KBoSgoAK",
|
||||
extended_class: "contracts_Users"
|
||||
},
|
||||
{
|
||||
role: "contracts_Admin",
|
||||
menuId: "VPh91h0ZHk",
|
||||
pageType: "dashboard",
|
||||
pageId: "35KBoSgoAK",
|
||||
extended_class: "contracts_Users"
|
||||
},
|
||||
{
|
||||
role: "contracts_OrgAdmin",
|
||||
menuId: "VPh91h0ZHk",
|
||||
pageType: "dashboard",
|
||||
pageId: "35KBoSgoAK",
|
||||
extended_class: "contracts_Users"
|
||||
},
|
||||
{
|
||||
role: "contracts_Editor",
|
||||
menuId: "H9vRfEYKhT",
|
||||
pageType: "dashboard",
|
||||
pageId: "35KBoSgoAK",
|
||||
extended_class: "contracts_Users"
|
||||
},
|
||||
{
|
||||
role: "contracts_User",
|
||||
menuId: "H9vRfEYKhT",
|
||||
pageType: "dashboard",
|
||||
pageId: "35KBoSgoAK",
|
||||
extended_class: "contracts_Users"
|
||||
}
|
||||
],
|
||||
version: "0.1"
|
||||
]
|
||||
};
|
||||
|
||||
@@ -3,4 +3,11 @@ export const templateCls = "contracts_Template";
|
||||
export const documentCls = "contracts_Document";
|
||||
export const themeColor = "#47a3ad";
|
||||
export const iconColor = "#686968";
|
||||
export const isEnableSubscription = process.env.REACT_APP_ENABLE_SUBSCRIPTION;
|
||||
export const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
export const isEnableSubscription = true;
|
||||
// process.env.REACT_APP_ENABLE_SUBSCRIPTION &&
|
||||
// process.env.REACT_APP_ENABLE_SUBSCRIPTION?.toLowerCase() === "true"
|
||||
// ? true
|
||||
// : false;
|
||||
export const isStaging = "http://localhost:3001";
|
||||
// window.location.origin === "https://staging-app.opensignlabs.com";
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
export default function reportJson(id) {
|
||||
// console.log("json ", json);
|
||||
const head = ["Sr.No", "Title", "Note", "Folder", "File", "Owner", "Signers"];
|
||||
const declineHead = [
|
||||
"Sr.No",
|
||||
"Title",
|
||||
"Reason",
|
||||
"Folder",
|
||||
"File",
|
||||
"Owner",
|
||||
"Signers"
|
||||
];
|
||||
const contactbook = ["Sr.No", "Title", "Email", "Phone"];
|
||||
const dashboardReportHead = ["Title", "File", "Owner", "Signers"];
|
||||
const templateReport = ["Sr.No", "Title", "File", "Owner", "Signers"];
|
||||
@@ -43,7 +52,7 @@ export default function reportJson(id) {
|
||||
hoverLabel: "Sign",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-signature",
|
||||
redirectUrl: "pdfRequestFiles",
|
||||
redirectUrl: "draftDocument",
|
||||
action: "redirect"
|
||||
}
|
||||
],
|
||||
@@ -69,7 +78,7 @@ export default function reportJson(id) {
|
||||
hoverLabel: "View",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-eye",
|
||||
redirectUrl: "pdfRequestFiles",
|
||||
redirectUrl: "draftDocument",
|
||||
action: "redirect"
|
||||
},
|
||||
{
|
||||
@@ -140,7 +149,7 @@ export default function reportJson(id) {
|
||||
case "UPr2Fm5WY3":
|
||||
return {
|
||||
reportName: "Declined Documents",
|
||||
heading: head,
|
||||
heading: declineHead,
|
||||
actions: [
|
||||
{
|
||||
btnId: "1458",
|
||||
@@ -207,7 +216,7 @@ export default function reportJson(id) {
|
||||
hoverLabel: "View",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-eye",
|
||||
redirectUrl: "pdfRequestFiles",
|
||||
redirectUrl: "draftDocument",
|
||||
action: "redirect"
|
||||
},
|
||||
{
|
||||
@@ -258,7 +267,7 @@ export default function reportJson(id) {
|
||||
hoverLabel: "Sign",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-signature",
|
||||
redirectUrl: "pdfRequestFiles",
|
||||
redirectUrl: "draftDocument",
|
||||
action: "redirect"
|
||||
}
|
||||
]
|
||||
@@ -306,68 +315,99 @@ export default function reportJson(id) {
|
||||
"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
|
||||
case "6TeaPr321t":
|
||||
case "6TeaPr321t": {
|
||||
const templateAct = [
|
||||
{
|
||||
btnId: "2234",
|
||||
btnLabel: "Use",
|
||||
hoverLabel: "Use",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-plus",
|
||||
redirectUrl: "placeHolderSign",
|
||||
action: "redirect",
|
||||
selector: "reactourSecond",
|
||||
message:
|
||||
"Click the 'Use' button to create a new document from an existing template. "
|
||||
},
|
||||
{
|
||||
btnId: "1631",
|
||||
btnLabel: "Quick send",
|
||||
hoverLabel: "Quick send",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-envelope",
|
||||
redirectUrl: "",
|
||||
action: "bulksend",
|
||||
selector: "tourbulksend",
|
||||
message:
|
||||
"To quickly create and send multiple documents using an existing template, click the 'Quick Send' button."
|
||||
},
|
||||
{
|
||||
btnId: "2234",
|
||||
hoverLabel: "option",
|
||||
btnColor: "",
|
||||
textColor: "black",
|
||||
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
|
||||
action: "option",
|
||||
selector: "reactourThird",
|
||||
message:
|
||||
"This menu reveals more options such as Edit & Delete. Use the 'Edit' button to add signer roles, modify fields, and update your template. Changes will apply to all future documents created from this template but won’t affect existing documents.Use the Delete button you can delete template. ",
|
||||
subaction: [
|
||||
{
|
||||
btnId: "2434",
|
||||
btnLabel: "Edit",
|
||||
hoverLabel: "Edit",
|
||||
btnIcon: "fa-light fa-pen",
|
||||
redirectUrl: "template",
|
||||
action: "redirect"
|
||||
},
|
||||
{
|
||||
btnId: "1834",
|
||||
btnLabel: "Delete",
|
||||
hoverLabel: "Delete",
|
||||
btnIcon: "fa-light fa-trash",
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
const Extand_Class = localStorage.getItem("Extand_Class");
|
||||
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
||||
// console.log("extClass ", extClass);
|
||||
let templateActions = templateAct;
|
||||
if (extClass && extClass.length > 0) {
|
||||
if (extClass?.[0]?.UserRole !== "contracts_User") {
|
||||
templateActions = templateAct.map((item) => {
|
||||
if (item.action === "option") {
|
||||
// Make a shallow copy of the item
|
||||
const newItem = { ...item };
|
||||
newItem.subaction = [
|
||||
{
|
||||
btnId: "1873",
|
||||
btnLabel: "Share with team",
|
||||
hoverLabel: "Share with team",
|
||||
btnIcon: "fa-light fa-share-nodes",
|
||||
redirectUrl: "",
|
||||
action: "sharewith"
|
||||
},
|
||||
...newItem.subaction
|
||||
];
|
||||
|
||||
return newItem;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
reportName: "Templates",
|
||||
heading: templateReport,
|
||||
actions: [
|
||||
{
|
||||
btnId: "2234",
|
||||
btnLabel: "Use",
|
||||
hoverLabel: "Use",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-plus",
|
||||
redirectUrl: "placeHolderSign",
|
||||
action: "redirect",
|
||||
selector: "reactourSecond",
|
||||
message:
|
||||
"Click the 'Use' button to create a new document from an existing template. "
|
||||
},
|
||||
{
|
||||
btnId: "1631",
|
||||
btnLabel: "Quick send",
|
||||
hoverLabel: "Quick send",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-envelope",
|
||||
redirectUrl: "",
|
||||
action: "bulksend",
|
||||
selector: "tourbulksend",
|
||||
message:
|
||||
"To quickly create and send multiple documents using an existing template, click the 'Quick Send' button."
|
||||
},
|
||||
{
|
||||
btnId: "2234",
|
||||
hoverLabel: "option",
|
||||
btnColor: "",
|
||||
textColor: "black",
|
||||
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
|
||||
action: "option",
|
||||
selector: "reactourThird",
|
||||
message:
|
||||
"This menu reveals more options such as Edit & Delete. Use the 'Edit' button to add signer roles, modify fields, and update your template. Changes will apply to all future documents created from this template but won’t affect existing documents.Use the Delete button you can delete template. ",
|
||||
subaction: [
|
||||
{
|
||||
btnId: "2434",
|
||||
btnLabel: "Edit",
|
||||
hoverLabel: "Edit",
|
||||
btnIcon: "fa-light fa-pen",
|
||||
redirectUrl: "template",
|
||||
action: "redirect"
|
||||
},
|
||||
{
|
||||
btnId: "1834",
|
||||
btnLabel: "Delete",
|
||||
hoverLabel: "Delete",
|
||||
btnIcon: "fa-light fa-trash",
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
actions: templateActions,
|
||||
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:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -143,17 +143,17 @@ const sidebarList = [
|
||||
icon: "fa-light fa-key",
|
||||
title: "API Token",
|
||||
target: "_self",
|
||||
pageType: "generatetoken",
|
||||
pageType: "",
|
||||
description: "",
|
||||
objectId: ""
|
||||
objectId: "generatetoken"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-globe",
|
||||
title: "Webhook",
|
||||
target: "_self",
|
||||
pageType: "webhook",
|
||||
pageType: "",
|
||||
description: "",
|
||||
objectId: ""
|
||||
objectId: "webhook"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { isStaging } from "../constant/const";
|
||||
|
||||
const plans = [
|
||||
{
|
||||
planName: "OPENSIGN™ FREE",
|
||||
img: "free.png",
|
||||
currency: "",
|
||||
monthlyPrice: "Free",
|
||||
yearlyPrice: "Free",
|
||||
subtitle: "Free Unlimited E-signatures, Forever.",
|
||||
btnText: "Subscribe",
|
||||
btn: { text: "Subscribe", color: "op-btn-primary" },
|
||||
url: "",
|
||||
target: "_blank",
|
||||
benefits: [
|
||||
@@ -28,19 +31,18 @@ const plans = [
|
||||
},
|
||||
{
|
||||
planName: "OPENSIGN™ PROFESSIONAL",
|
||||
img: "professional.png",
|
||||
currency: "$",
|
||||
monthlyPrice: "29.99",
|
||||
yearlyPrice: "329.99",
|
||||
yearlyPrice: `10 <sup style="font-size: 17px;">/month/user</sup>`,
|
||||
subtitle: "Exclusive Access to advanced features.",
|
||||
btnText: "Subscribe",
|
||||
url:
|
||||
window.location.origin === "https://staging-app.opensignlabs.com"
|
||||
? "https://billing.zoho.in/subscribe/9627f62a09df1c8ce500f2f4dc8328dd84ecda20eeae13878ce581d60240f206/pro-weekly"
|
||||
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d1a09dfa8085585cdd4ec4d7f32137f3/professional-monthly",
|
||||
yearlyUrl:
|
||||
window.location.origin === "https://staging-app.opensignlabs.com"
|
||||
? "https://billing.zoho.in/subscribe/9627f62a09df1c8ce500f2f4dc8328ddc184411129224f1f29ed84f6cef3b862/pro-yearly"
|
||||
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d8ad1135190dff951330360e47585a71/professional-yearly",
|
||||
btn: { text: "Subscribe", color: "op-btn-primary" },
|
||||
url: isStaging
|
||||
? "https://billing.zoho.in/subscribe/9627f62a09df1c8ce500f2f4dc8328dd84ecda20eeae13878ce581d60240f206/pro-weekly"
|
||||
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d1a09dfa8085585cdd4ec4d7f32137f3/professional-monthly",
|
||||
yearlyUrl: isStaging
|
||||
? "https://billing.zoho.in/subscribe/9627f62a09df1c8ce500f2f4dc8328ddc184411129224f1f29ed84f6cef3b862/pro-yearly"
|
||||
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d8ad1135190dff951330360e47585a71/professional-yearly",
|
||||
target: "_self",
|
||||
benefits: [
|
||||
"Everything in OpenSign™ free",
|
||||
@@ -58,11 +60,12 @@ const plans = [
|
||||
},
|
||||
{
|
||||
planName: "OPENSIGN™ ENTERPRISE",
|
||||
img: "enterprise.png",
|
||||
currency: "",
|
||||
monthlyPrice: "Request Price",
|
||||
yearlyPrice: "Request Price",
|
||||
monthlyPrice: `<p style="font-size: 22px;">Request Price</p>`,
|
||||
yearlyPrice: `<p style="font-size: 22px;">Request Price</p>`,
|
||||
subtitle: "Scalable Features with priority support.",
|
||||
btnText: "Contact us",
|
||||
btn: { text: "Contact us", color: "op-btn-primary" },
|
||||
url: "https://www.opensignlabs.com/contact-us",
|
||||
target: "_blank",
|
||||
benefits: [
|
||||
@@ -75,5 +78,33 @@ const plans = [
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export const stagingPlan = {
|
||||
planName: "OPENSIGN™ TEAMS",
|
||||
img: "teams.png",
|
||||
currency: "$",
|
||||
monthlyPrice: "40",
|
||||
yearlyPrice: `20 <sup style="font-size: 17px;">/month/user</sup>`,
|
||||
subtitle: "Exclusive Access to advanced features.",
|
||||
btn: { text: "Subscribe", color: "op-btn-accent" },
|
||||
url: isStaging
|
||||
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/team-weekly"
|
||||
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d1a09dfa8085585cdd4ec4d7f32137f3/professional-monthly",
|
||||
yearlyUrl: isStaging
|
||||
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/team-weekly"
|
||||
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d8ad1135190dff951330360e47585a71/professional-yearly",
|
||||
target: "_self",
|
||||
benefits: [
|
||||
"Everything in OpenSign™ free, professional",
|
||||
"Field validations",
|
||||
"Regular expression validations",
|
||||
"Organize docs in OpenSign™ Drive",
|
||||
"Webhooks",
|
||||
"Zapier integration",
|
||||
"API Access",
|
||||
"100 API signatures included",
|
||||
"DocumentId removal from signed docs",
|
||||
"Custom email templates",
|
||||
"Auto reminders"
|
||||
]
|
||||
};
|
||||
export default plans;
|
||||
|
||||
@@ -67,6 +67,8 @@ const HomeLayout = () => {
|
||||
const indexOfFirstDot = domainName.indexOf(".");
|
||||
// Remove the first dot and get the substring starting from the next character
|
||||
const updateDomain = domainName.substring(indexOfFirstDot); //.opensignlabs.com
|
||||
const serverUrl = localStorage.getItem("baseUrl");
|
||||
const parseAppId = localStorage.getItem("parseAppId");
|
||||
setCookie("accesstoken", localStorage.getItem("accesstoken"), {
|
||||
secure: true,
|
||||
domain: updateDomain
|
||||
@@ -75,6 +77,14 @@ const HomeLayout = () => {
|
||||
secure: true,
|
||||
domain: updateDomain
|
||||
});
|
||||
setCookie("server_url", serverUrl, {
|
||||
secure: true,
|
||||
domain: updateDomain
|
||||
});
|
||||
setCookie("parse_app_id", parseAppId, {
|
||||
secure: true,
|
||||
domain: updateDomain
|
||||
});
|
||||
};
|
||||
|
||||
async function checkIsSubscribed() {
|
||||
@@ -109,11 +119,7 @@ const HomeLayout = () => {
|
||||
}, [width]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
localStorage.getItem("domain") === "contracts" &&
|
||||
arr &&
|
||||
arr.length > 0
|
||||
) {
|
||||
if (arr && arr.length > 0) {
|
||||
handleDynamicSteps();
|
||||
} else {
|
||||
setIsTour(false);
|
||||
@@ -171,7 +177,6 @@ const HomeLayout = () => {
|
||||
setIsTour(false);
|
||||
const serverUrl = localStorage.getItem("baseUrl");
|
||||
const appId = localStorage.getItem("parseAppId");
|
||||
const extUserClass = localStorage.getItem("extended_class");
|
||||
const json = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||
const extUserId = json && json.length > 0 && json[0].objectId;
|
||||
// console.log("extUserId ", extUserId)
|
||||
@@ -193,7 +198,7 @@ const HomeLayout = () => {
|
||||
|
||||
// console.log("updatedTourStatus ", updatedTourStatus);
|
||||
await axios.put(
|
||||
serverUrl + "classes/" + extUserClass + "/" + extUserId,
|
||||
serverUrl + "classes/contracts_Users/" + extUserId,
|
||||
{
|
||||
TourStatus: updatedTourStatus
|
||||
},
|
||||
@@ -251,7 +256,7 @@ const HomeLayout = () => {
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<div className="sticky top-0 z-[101]">
|
||||
<div className="sticky top-0 z-[501]">
|
||||
{!isLoader && <Header showSidebar={showSidebar} />}
|
||||
</div>
|
||||
{isUserValid ? (
|
||||
|
||||
@@ -0,0 +1,454 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Parse from "parse";
|
||||
import { appInfo } from "../constant/appinfo";
|
||||
import { NavLink, useNavigate } from "react-router-dom";
|
||||
import { getAppLogo, openInNewTab } from "../constant/Utils";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||
import Loader from "../primitives/Loader";
|
||||
import Title from "../components/Title";
|
||||
|
||||
const AddAdmin = () => {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [name, setName] = useState("");
|
||||
const [phone, setPhone] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [company, setCompany] = useState("");
|
||||
const [jobTitle, setJobTitle] = useState("");
|
||||
const [lengthValid, setLengthValid] = useState(false);
|
||||
const [caseDigitValid, setCaseDigitValid] = useState(false);
|
||||
const [specialCharValid, setSpecialCharValid] = useState(false);
|
||||
const [isAuthorize, setIsAuthorize] = useState(false);
|
||||
const [isSubscribeNews, setIsSubscribeNews] = useState(false);
|
||||
const [errMsg, setErrMsg] = useState("");
|
||||
const [state, setState] = useState({
|
||||
loading: false,
|
||||
alertType: "success",
|
||||
alertMsg: ""
|
||||
});
|
||||
const togglePasswordVisibility = () => setShowPassword(!showPassword);
|
||||
|
||||
useEffect(() => {
|
||||
checkUserExist();
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
const checkUserExist = async () => {
|
||||
setState((prev) => ({ ...prev, loading: true }));
|
||||
try {
|
||||
const app = await getAppLogo();
|
||||
if (app?.user === "exist") {
|
||||
setErrMsg("Admin already exist.");
|
||||
}
|
||||
} catch (err) {
|
||||
setErrMsg("Something went wrong.");
|
||||
console.log("err in check user exist", err);
|
||||
} finally {
|
||||
setState((prev) => ({ ...prev, loading: false }));
|
||||
}
|
||||
};
|
||||
const clearStorage = async () => {
|
||||
if (Parse.User.current()) {
|
||||
await Parse.User.logOut();
|
||||
}
|
||||
const baseUrl = localStorage.getItem("baseUrl");
|
||||
const appid = localStorage.getItem("parseAppId");
|
||||
const applogo = localStorage.getItem("appLogo");
|
||||
const defaultmenuid = localStorage.getItem("defaultmenuid");
|
||||
const PageLanding = localStorage.getItem("PageLanding");
|
||||
const userSettings = localStorage.getItem("userSettings");
|
||||
|
||||
localStorage.clear();
|
||||
localStorage.setItem("baseUrl", baseUrl);
|
||||
localStorage.setItem("parseAppId", appid);
|
||||
localStorage.setItem("appLogo", applogo);
|
||||
localStorage.setItem("defaultmenuid", defaultmenuid);
|
||||
localStorage.setItem("PageLanding", PageLanding);
|
||||
localStorage.setItem("userSettings", userSettings);
|
||||
localStorage.setItem("baseUrl", baseUrl);
|
||||
localStorage.setItem("parseAppId", appid);
|
||||
};
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
if (lengthValid && caseDigitValid && specialCharValid) {
|
||||
clearStorage();
|
||||
setState({ loading: true });
|
||||
const userDetails = {
|
||||
name: name,
|
||||
email: email,
|
||||
phone: phone,
|
||||
company: company,
|
||||
jobTitle: jobTitle
|
||||
};
|
||||
localStorage.setItem("userDetails", JSON.stringify(userDetails));
|
||||
try {
|
||||
event.preventDefault();
|
||||
const user = new Parse.User();
|
||||
user.set("name", name);
|
||||
user.set("email", email);
|
||||
user.set("password", password);
|
||||
user.set("phone", phone);
|
||||
user.set("username", email);
|
||||
const userRes = await user.save();
|
||||
if (userRes) {
|
||||
const params = {
|
||||
userDetails: {
|
||||
jobTitle: jobTitle,
|
||||
company: company,
|
||||
name: name,
|
||||
email: email,
|
||||
phone: phone,
|
||||
role: "contracts_Admin"
|
||||
}
|
||||
};
|
||||
try {
|
||||
const usersignup = await Parse.Cloud.run("addadmin", params);
|
||||
if (usersignup) {
|
||||
if (isSubscribeNews) {
|
||||
subscribeNewsletter();
|
||||
}
|
||||
handleNavigation(userRes.getSessionToken());
|
||||
}
|
||||
} catch (err) {
|
||||
alert(err.message);
|
||||
setState({ loading: false });
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("err ", error);
|
||||
if (error.code === 202) {
|
||||
const params = { email: email };
|
||||
const res = await Parse.Cloud.run("getUserDetails", params);
|
||||
// console.log("Res ", res);
|
||||
if (res) {
|
||||
alert("User already exists with this username!");
|
||||
setState({ loading: false });
|
||||
} else {
|
||||
// console.log("state.email ", email);
|
||||
try {
|
||||
await Parse.User.requestPasswordReset(email).then(
|
||||
async function (res) {
|
||||
if (res.data === undefined) {
|
||||
alert("Verification mail has been sent to your E-mail!");
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
setState({ loading: false });
|
||||
}
|
||||
} else {
|
||||
alert(error.message);
|
||||
setState({ loading: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleNavigation = async (sessionToken) => {
|
||||
const res = await Parse.User.become(sessionToken);
|
||||
if (res) {
|
||||
const _user = JSON.parse(JSON.stringify(res));
|
||||
// console.log("_user ", _user);
|
||||
localStorage.setItem("accesstoken", sessionToken);
|
||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
||||
localStorage.setItem("scriptId", true);
|
||||
if (_user.ProfilePic) {
|
||||
localStorage.setItem("profileImg", _user.ProfilePic);
|
||||
} else {
|
||||
localStorage.setItem("profileImg", "");
|
||||
}
|
||||
// Check extended class user role and tenentId
|
||||
try {
|
||||
const userSettings = appInfo.settings;
|
||||
const currentUser = Parse.User.current();
|
||||
const extUser = await Parse.Cloud.run("getUserDetails", {
|
||||
email: currentUser.get("email")
|
||||
});
|
||||
if (extUser) {
|
||||
const IsDisabled = extUser?.get("IsDisabled") || false;
|
||||
if (!IsDisabled) {
|
||||
const userRole = extUser?.get("UserRole");
|
||||
const menu =
|
||||
userRole && userSettings.find((menu) => menu.role === userRole);
|
||||
if (menu) {
|
||||
const _currentRole = userRole;
|
||||
const _role = _currentRole.replace("contracts_", "");
|
||||
localStorage.setItem("_user_role", _role);
|
||||
const extInfo_stringify = JSON.stringify([extUser]);
|
||||
localStorage.setItem("Extand_Class", extInfo_stringify);
|
||||
const extInfo = JSON.parse(JSON.stringify(extUser));
|
||||
localStorage.setItem("userEmail", extInfo?.Email);
|
||||
localStorage.setItem("username", extInfo?.Name);
|
||||
if (extInfo?.TenantId) {
|
||||
const tenant = {
|
||||
Id: extInfo?.TenantId?.objectId || "",
|
||||
Name: extInfo?.TenantId?.TenantName || ""
|
||||
};
|
||||
localStorage.setItem("TenantId", tenant?.Id);
|
||||
dispatch(showTenant(tenant?.Name));
|
||||
localStorage.setItem("TenantName", tenant?.Name);
|
||||
}
|
||||
localStorage.setItem("PageLanding", menu.pageId);
|
||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||
localStorage.setItem("pageType", menu.pageType);
|
||||
setState({
|
||||
loading: false,
|
||||
alertType: "success",
|
||||
alertMsg: "Registered user successfully."
|
||||
});
|
||||
navigate(`/${menu.pageType}/${menu.pageId}`);
|
||||
} else {
|
||||
setState({
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: "Role not found."
|
||||
});
|
||||
}
|
||||
} else {
|
||||
setState({
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: "You don't have access, please contact the admin."
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("error in fetch extuser", error);
|
||||
const msg = error.message || "Something went wrong.";
|
||||
setState({ loading: false, alertType: "danger", alertMsg: msg });
|
||||
} finally {
|
||||
setTimeout(() => setState({ loading: false, alertMsg: "" }), 2000);
|
||||
}
|
||||
}
|
||||
};
|
||||
const handlePasswordChange = (e) => {
|
||||
const newPassword = e.target.value;
|
||||
setPassword(newPassword);
|
||||
// Check conditions separately
|
||||
setLengthValid(newPassword.length >= 8);
|
||||
setCaseDigitValid(
|
||||
/[a-z]/.test(newPassword) &&
|
||||
/[A-Z]/.test(newPassword) &&
|
||||
/\d/.test(newPassword)
|
||||
);
|
||||
setSpecialCharValid(/[!@#$%^&*()\-_=+{};:,<.>]/.test(newPassword));
|
||||
};
|
||||
const subscribeNewsletter = async () => {
|
||||
try {
|
||||
const params = { name: name, email: email, domain: window.location.host };
|
||||
await Parse.Cloud.run("newsletter", params);
|
||||
// console.log("newsletter ", newsletter);
|
||||
} catch (err) {
|
||||
console.log("err in subscribeNewsletter", err);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="h-screen flex justify-center">
|
||||
<Title title={"Add admin"} />
|
||||
{state.loading ? (
|
||||
<div className="text-[grey] flex justify-center items-center text-lg md:text-2xl">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{errMsg ? (
|
||||
<div className="text-[grey] flex justify-center items-center text-lg md:text-2xl">
|
||||
{errMsg}
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-[95%] md:w-[500px]">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="w-full my-4 op-card bg-base-100 shadow-md outline outline-1 outline-slate-300/50">
|
||||
<h2 className="text-[30px] text-center mt-3 font-medium">
|
||||
Opensign Setup
|
||||
</h2>
|
||||
<NavLink
|
||||
to="https://discord.com/invite/xe9TDuyAyj"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-center text-sm mt-1 text-[blue] cursor-pointer"
|
||||
>
|
||||
Join our discord server
|
||||
<i
|
||||
aria-hidden="true"
|
||||
className="fa-brands fa-discord ml-1"
|
||||
></i>
|
||||
{/* <span className="fa-sr-only">OpenSign's Discord</span> */}
|
||||
</NavLink>
|
||||
<div className="px-6 py-3 text-xs">
|
||||
<label className="block ">
|
||||
Name <span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<hr className="my-2 border-none" />
|
||||
<label>
|
||||
Email <span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value?.toLowerCase())}
|
||||
required
|
||||
/>
|
||||
<hr className="my-2 border-none" />
|
||||
<label>
|
||||
Phone <span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="tel"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={phone}
|
||||
onChange={(e) => setPhone(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<hr className="my-2 border-none" />
|
||||
<label>
|
||||
Company <span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={company}
|
||||
onChange={(e) => setCompany(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<hr className="my-2 border-none" />
|
||||
<label>
|
||||
Job Title{" "}
|
||||
<span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={jobTitle}
|
||||
onChange={(e) => setJobTitle(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<hr className="my-2 border-none" />
|
||||
<label>
|
||||
Password <span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={showPassword ? "text" : "password"}
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
name="password"
|
||||
value={password}
|
||||
onChange={(e) => handlePasswordChange(e)}
|
||||
required
|
||||
/>
|
||||
<span
|
||||
className={`absolute top-[50%] right-[10px] -translate-y-[50%] cursor-pointer text-base-content`}
|
||||
onClick={togglePasswordVisibility}
|
||||
>
|
||||
{showPassword ? (
|
||||
<i className="fa fa-eye-slash" /> // Close eye icon
|
||||
) : (
|
||||
<i className="fa fa-eye" /> // Open eye icon
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{password.length > 0 && (
|
||||
<div className="mt-1 text-[11px]">
|
||||
<p
|
||||
className={`${
|
||||
lengthValid ? "text-green-600" : "text-red-600"
|
||||
}`}
|
||||
>
|
||||
{lengthValid ? "✓" : "✗"} Password should be 8
|
||||
characters long
|
||||
</p>
|
||||
<p
|
||||
className={`${
|
||||
caseDigitValid ? "text-green-600" : "text-red-600"
|
||||
}`}
|
||||
>
|
||||
{caseDigitValid ? "✓" : "✗"} Password should contain
|
||||
uppercase letter, lowercase letter, digit
|
||||
</p>
|
||||
<p
|
||||
className={`${
|
||||
specialCharValid ? "text-green-600" : "text-red-600"
|
||||
}`}
|
||||
>
|
||||
{specialCharValid ? "✓" : "✗"} Password should contain
|
||||
special character
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-2.5 ml-1 flex flex-row items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="op-checkbox op-checkbox-sm"
|
||||
id="termsandcondition"
|
||||
checked={isAuthorize}
|
||||
onChange={(e) => setIsAuthorize(e.target.checked)}
|
||||
required
|
||||
/>
|
||||
<label
|
||||
className="text-xs cursor-pointer ml-1 mb-0"
|
||||
htmlFor="termsandcondition"
|
||||
>
|
||||
I agree to the
|
||||
</label>
|
||||
<span
|
||||
className="underline cursor-pointer ml-1"
|
||||
onClick={() =>
|
||||
openInNewTab(
|
||||
"https://www.opensignlabs.com/terms-and-conditions"
|
||||
)
|
||||
}
|
||||
>
|
||||
Terms of Service
|
||||
</span>
|
||||
<span>.</span>
|
||||
</div>
|
||||
<div className="mt-2.5 ml-1 flex flex-row items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="op-checkbox op-checkbox-sm"
|
||||
id="termsandcondition"
|
||||
checked={isSubscribeNews}
|
||||
onChange={(e) => setIsSubscribeNews(e.target.checked)}
|
||||
/>
|
||||
<label
|
||||
className="text-xs cursor-pointer ml-1 mb-0"
|
||||
htmlFor="termsandcondition"
|
||||
>
|
||||
Subscribe to OpenSign newsletter
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx-4 text-center text-xs font-bold mb-3">
|
||||
<button
|
||||
type="submit"
|
||||
className="op-btn op-btn-primary w-full"
|
||||
disabled={state.loading}
|
||||
>
|
||||
{state.loading ? "Loading..." : "Next"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddAdmin;
|
||||
@@ -21,7 +21,12 @@ function ChangePassword() {
|
||||
user.set("password", newpassword);
|
||||
user
|
||||
.save()
|
||||
.then(() => {
|
||||
.then(async () => {
|
||||
let _user = user.toJSON();
|
||||
if (_user) {
|
||||
await Parse.User.become(_user.sessionToken);
|
||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
||||
}
|
||||
alert("Password updated successfully.");
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -32,7 +37,6 @@ function ChangePassword() {
|
||||
} else {
|
||||
alert("Your current password is missing or incorrect.");
|
||||
}
|
||||
console.log("Logged in user", user);
|
||||
})
|
||||
.catch((error) => {
|
||||
alert("Your current password is missing or incorrect.");
|
||||
|
||||
@@ -36,9 +36,6 @@ function ForgotPassword() {
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
localStorage.setItem("appLogo", appInfo.applogo);
|
||||
localStorage.setItem("appName", appInfo.appname);
|
||||
// localStorage.setItem("defaultmenuid", props.appInfo.defaultmenuid);
|
||||
// localStorage.setItem("PageLanding", props.appInfo.LandingPageId);
|
||||
localStorage.setItem("userSettings", JSON.stringify(appInfo.settings));
|
||||
if (state.email) {
|
||||
const username = state.email;
|
||||
@@ -64,9 +61,9 @@ function ForgotPassword() {
|
||||
}, []);
|
||||
const saveLogo = async () => {
|
||||
if (isEnableSubscription) {
|
||||
const logo = await getAppLogo();
|
||||
if (logo) {
|
||||
setImage(logo);
|
||||
const app = await getAppLogo();
|
||||
if (app?.logo) {
|
||||
setImage(app?.logo);
|
||||
} else {
|
||||
setImage(appInfo?.applogo || undefined);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import { isEnableSubscription } from "../constant/const";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
import Upgrade from "../primitives/Upgrade";
|
||||
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
// `Form` render all type of Form on this basis of their provided in path
|
||||
@@ -645,8 +644,8 @@ const Forms = (props) => {
|
||||
</label>
|
||||
{fileupload.length > 0 ? (
|
||||
<div className="flex gap-2 justify-center items-center">
|
||||
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm w-full h-full text-x text-[13px]">
|
||||
<div className="break-all ">
|
||||
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm w-full h-full text-[13px]">
|
||||
<div className="break-all">
|
||||
file selected: {getFileName(fileupload)}
|
||||
</div>
|
||||
<div
|
||||
@@ -830,39 +829,34 @@ const Forms = (props) => {
|
||||
<div className="text-center">No</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-xs mt-2">
|
||||
{!isEnableSubscription && (
|
||||
<PremiumAlertHeader
|
||||
message={
|
||||
"Auto reminder is free in beta, this feature will incur a fee later."
|
||||
{isEnableSubscription && (
|
||||
<div className="text-xs mt-2">
|
||||
<span
|
||||
className={
|
||||
isSubscribe
|
||||
? "font-semibold"
|
||||
: "font-semibold text-gray-300"
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
className={
|
||||
isSubscribe || !isEnableSubscription
|
||||
? "font-semibold"
|
||||
: "font-semibold text-gray-300"
|
||||
}
|
||||
>
|
||||
Auto reminder{" "}
|
||||
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
</span>
|
||||
<label
|
||||
className={`${
|
||||
isSubscribe || !isEnableSubscription
|
||||
? "cursor-pointer "
|
||||
: "pointer-events-none opacity-50"
|
||||
} relative block items-center mb-0`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
|
||||
checked={formData.autoreminder}
|
||||
onChange={handleAutoReminder}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
>
|
||||
Auto reminder{" "}
|
||||
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
</span>
|
||||
<label
|
||||
className={`${
|
||||
isSubscribe
|
||||
? "cursor-pointer "
|
||||
: "pointer-events-none opacity-50"
|
||||
} relative block items-center mb-0`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
|
||||
checked={formData.autoreminder}
|
||||
onChange={handleAutoReminder}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
{formData?.autoreminder === true && (
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
|
||||
@@ -5,7 +5,6 @@ import Alert from "../primitives/Alert";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { checkIsSubscribed, copytoData, openInNewTab } from "../constant/Utils";
|
||||
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||
import Tooltip from "../primitives/Tooltip";
|
||||
import Loader from "../primitives/Loader";
|
||||
import SubscribeCard from "../primitives/SubscribeCard";
|
||||
@@ -45,7 +44,7 @@ function GenerateToken() {
|
||||
};
|
||||
const res = await axios.post(url, {}, { headers: headers });
|
||||
if (res) {
|
||||
SetApiToken(res.data.result.result);
|
||||
SetApiToken(res.data?.result?.result);
|
||||
}
|
||||
setIsLoader(false);
|
||||
} catch (err) {
|
||||
@@ -112,7 +111,6 @@ function GenerateToken() {
|
||||
) : (
|
||||
<>
|
||||
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box mb-3">
|
||||
{!isEnableSubscription && <PremiumAlertHeader />}
|
||||
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||
OpenSign™ API{" "}
|
||||
<Tooltip
|
||||
@@ -122,19 +120,14 @@ function GenerateToken() {
|
||||
isSubscribe={true}
|
||||
/>
|
||||
</h1>
|
||||
<ul
|
||||
className={"w-full flex flex-col p-2 text-sm"}
|
||||
// isSubscribe || !isEnableSubscription
|
||||
// ? "w-full flex flex-col p-2 text-sm "
|
||||
// : "w-full flex flex-col p-2 text-sm opacity-20 pointer-events-none select-none"
|
||||
>
|
||||
<ul className="w-full flex flex-col p-2 text-sm">
|
||||
<li className="flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2">
|
||||
<div className="w-full md:w-[70%] flex-col md:flex-row text-xs md:text-[15px] flex items-center gap-x-5">
|
||||
<span className="ml-1">API Token:</span>{" "}
|
||||
<span
|
||||
id="token"
|
||||
className={`${
|
||||
isSubscribe || !isEnableSubscription
|
||||
isSubscribe
|
||||
? ""
|
||||
: "bg-white/20 pointer-events-none select-none"
|
||||
} md:text-end py-2 md:py-0`}
|
||||
|
||||
@@ -29,9 +29,9 @@ function GuestLogin() {
|
||||
//function generate serverUrl and parseAppId from url and save it in local storage
|
||||
const handleServerUrl = async () => {
|
||||
if (isEnableSubscription) {
|
||||
const applogo = await getAppLogo();
|
||||
if (applogo) {
|
||||
setAppLogo(applogo);
|
||||
const app = await getAppLogo();
|
||||
if (app?.logo) {
|
||||
setAppLogo(app?.logo);
|
||||
} else {
|
||||
setAppLogo(logo);
|
||||
}
|
||||
@@ -42,10 +42,8 @@ function GuestLogin() {
|
||||
localStorage.clear();
|
||||
const parseId = appInfo.appId;
|
||||
const newServer = `${appInfo.baseUrl}/`;
|
||||
const appName = appInfo.appname;
|
||||
localStorage.setItem("baseUrl", newServer);
|
||||
localStorage.setItem("parseAppId", parseId);
|
||||
localStorage.setItem("_appName", appName);
|
||||
//this condition is used decode base64 to string and get userEmail,documentId, contactBoookId data.
|
||||
if (!id) {
|
||||
//`atob` function is used to decode base64
|
||||
|
||||
+352
-801
File diff suppressed because it is too large
Load Diff
@@ -4,12 +4,10 @@ import "../styles/managesign.css";
|
||||
import "../styles/signature.css";
|
||||
import { toDataUrl } from "../constant/Utils";
|
||||
import Parse from "parse";
|
||||
import { appInfo } from "../constant/appinfo";
|
||||
import { SaveFileSize } from "../constant/saveFileSize";
|
||||
import Alert from "../primitives/Alert";
|
||||
import Loader from "../primitives/Loader";
|
||||
const ManageSign = () => {
|
||||
const appName = appInfo.appname;
|
||||
const [penColor, setPenColor] = useState("blue");
|
||||
const [initialPen, setInitialPen] = useState("blue");
|
||||
const [image, setImage] = useState();
|
||||
@@ -39,7 +37,7 @@ const ManageSign = () => {
|
||||
objectId: User.id
|
||||
};
|
||||
try {
|
||||
const signCls = `${appName}_Signature`;
|
||||
const signCls = "contracts_Signature";
|
||||
const signQuery = new Parse.Query(signCls);
|
||||
signQuery.equalTo("UserId", userId);
|
||||
const signRes = await signQuery.first();
|
||||
@@ -174,7 +172,7 @@ const ManageSign = () => {
|
||||
};
|
||||
|
||||
const saveEntry = async (obj) => {
|
||||
const signCls = `${appName}_Signature`;
|
||||
const signCls = "contracts_Signature";
|
||||
const User = Parse.User.current().id;
|
||||
const userId = { __type: "Pointer", className: "_User", objectId: User };
|
||||
if (id) {
|
||||
@@ -265,7 +263,7 @@ const ManageSign = () => {
|
||||
<div className="relative">
|
||||
<div>
|
||||
{image ? (
|
||||
<div className="signatureCanvas relative border-[2px] border-[#888] rounded-box">
|
||||
<div className="signatureCanvas relative border-[2px] border-[#888] rounded-box overflow-hidden">
|
||||
<img
|
||||
alt="signature"
|
||||
src={image}
|
||||
|
||||
@@ -272,7 +272,7 @@ function Opensigndrive() {
|
||||
setIsFolderLoader(true);
|
||||
const getParentObjId = folderName[folderName.length - 1];
|
||||
const parentId = getParentObjId && getParentObjId.objectId;
|
||||
const foldercls = `${localStorage.getItem("_appName")}_Document`;
|
||||
const foldercls = "contracts_Document";
|
||||
const folderPtr = {
|
||||
__type: "Pointer",
|
||||
className: foldercls,
|
||||
@@ -465,7 +465,6 @@ function Opensigndrive() {
|
||||
if (isDontShow) {
|
||||
const serverUrl = localStorage.getItem("baseUrl");
|
||||
const appId = localStorage.getItem("parseAppId");
|
||||
const extUserClass = localStorage.getItem("extended_class");
|
||||
const json = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||
const extUserId = json && json.length > 0 && json[0].objectId;
|
||||
let updatedTourStatus = [];
|
||||
@@ -483,7 +482,7 @@ function Opensigndrive() {
|
||||
updatedTourStatus = [{ driveTour: true }];
|
||||
}
|
||||
await axios.put(
|
||||
serverUrl + "classes/" + extUserClass + "/" + extUserId,
|
||||
serverUrl + "classes/contracts_Users/" + extUserId,
|
||||
{
|
||||
TourStatus: updatedTourStatus
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -70,6 +70,19 @@ const PgSignUp = () => {
|
||||
});
|
||||
if (res) {
|
||||
localStorage.removeItem("userDetails");
|
||||
try {
|
||||
const extUser = await Parse.Cloud.run("getUserDetails", {
|
||||
email: userDetails.email
|
||||
});
|
||||
const userRole = extUser?.get("UserRole");
|
||||
const _currentRole = userRole;
|
||||
const _role = _currentRole.replace("contracts_", "");
|
||||
localStorage.setItem("_user_role", _role);
|
||||
const extInfo_stringify = JSON.stringify([extUser]);
|
||||
localStorage.setItem("Extand_Class", extInfo_stringify);
|
||||
} catch (err) {
|
||||
console.log("Err in fetching extuser", err);
|
||||
}
|
||||
navigate(
|
||||
"/" + userSettings[0].pageType + "/" + userSettings[0].pageId
|
||||
);
|
||||
@@ -107,8 +120,6 @@ const PgSignUp = () => {
|
||||
}
|
||||
};
|
||||
const saveUser = async (obj) => {
|
||||
// const domain = localStorage.getItem("domain");
|
||||
// console.log("domain", domain)
|
||||
try {
|
||||
const zohoRes = await axios.post(
|
||||
parseBaseUrl + "functions/zohodetails",
|
||||
@@ -209,8 +220,6 @@ const PgSignUp = () => {
|
||||
if (res.data) {
|
||||
let _user = res.data;
|
||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
||||
localStorage.setItem("userEmail", _user.email);
|
||||
localStorage.setItem("username", _user.name);
|
||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
||||
localStorage.setItem("scriptId", true);
|
||||
if (_user.ProfilePic) {
|
||||
@@ -220,190 +229,52 @@ const PgSignUp = () => {
|
||||
}
|
||||
// Check extended class user role and tenentId
|
||||
try {
|
||||
let userRoles = [];
|
||||
if (appInfo.settings) {
|
||||
let userSettings = appInfo.settings;
|
||||
|
||||
//Get Current user roles
|
||||
let url = `${baseUrl}functions/UserGroups`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseAppId,
|
||||
sessionToken: _user.sessionToken
|
||||
};
|
||||
|
||||
let body = {
|
||||
appname: localStorage.getItem("_appName")
|
||||
};
|
||||
await axios
|
||||
.post(url, JSON.stringify(body), { headers: headers })
|
||||
.then((roles) => {
|
||||
if (roles) {
|
||||
userRoles = roles.data.result;
|
||||
let _currentRole = "";
|
||||
if (userRoles.length > 1) {
|
||||
if (
|
||||
userRoles[0] ===
|
||||
`${localStorage.getItem("_appName")}_appeditor`
|
||||
) {
|
||||
_currentRole = userRoles[1];
|
||||
} else {
|
||||
_currentRole = userRoles[0];
|
||||
}
|
||||
} else {
|
||||
_currentRole = userRoles[0];
|
||||
}
|
||||
if (
|
||||
_currentRole !==
|
||||
`${localStorage.getItem("_appName")}_appeditor`
|
||||
) {
|
||||
userSettings.forEach(async (element) => {
|
||||
if (element.role === _currentRole) {
|
||||
let _role = _currentRole.replace(
|
||||
`${localStorage.getItem("_appName")}_`,
|
||||
""
|
||||
);
|
||||
localStorage.setItem("_user_role", _role);
|
||||
// Get TenentID from Extendend Class
|
||||
localStorage.setItem(
|
||||
"extended_class",
|
||||
element.extended_class
|
||||
);
|
||||
const currentUser = Parse.User.current();
|
||||
await Parse.Cloud.run("getUserDetails", {
|
||||
email: currentUser.get("email")
|
||||
}).then(
|
||||
(result) => {
|
||||
const results = [result];
|
||||
let tenentInfo = [];
|
||||
if (results) {
|
||||
let extendedInfo_stringify =
|
||||
JSON.stringify(results);
|
||||
localStorage.setItem(
|
||||
"Extand_Class",
|
||||
extendedInfo_stringify
|
||||
);
|
||||
let extendedInfo = JSON.parse(
|
||||
extendedInfo_stringify
|
||||
);
|
||||
if (extendedInfo.length > 1) {
|
||||
extendedInfo.forEach((x) => {
|
||||
if (x.TenantId) {
|
||||
let obj = {
|
||||
tenentId: x.TenantId.objectId,
|
||||
tenentName: x.TenantId.TenantName || ""
|
||||
};
|
||||
tenentInfo.push(obj);
|
||||
}
|
||||
});
|
||||
if (tenentInfo.length) {
|
||||
dispatch(
|
||||
showTenant(tenentInfo[0].tenentName || "")
|
||||
);
|
||||
localStorage.setItem(
|
||||
"TenantName",
|
||||
tenentInfo[0].tenentName || ""
|
||||
);
|
||||
}
|
||||
|
||||
localStorage.setItem("showpopup", true);
|
||||
localStorage.setItem(
|
||||
"PageLanding",
|
||||
element.pageId
|
||||
);
|
||||
localStorage.setItem(
|
||||
"defaultmenuid",
|
||||
element.menuId
|
||||
);
|
||||
localStorage.setItem(
|
||||
"pageType",
|
||||
element.pageType
|
||||
);
|
||||
setIsLoader(false);
|
||||
navigate("/", { replace: true });
|
||||
} else {
|
||||
extendedInfo.forEach((x) => {
|
||||
if (x.TenantId) {
|
||||
let obj = {
|
||||
tenentId: x.TenantId.objectId,
|
||||
tenentName: x.TenantId.TenantName || ""
|
||||
};
|
||||
localStorage.setItem(
|
||||
"TenantId",
|
||||
x.TenantId.objectId
|
||||
);
|
||||
tenentInfo.push(obj);
|
||||
}
|
||||
});
|
||||
if (tenentInfo.length) {
|
||||
dispatch(
|
||||
showTenant(tenentInfo[0].tenentName || "")
|
||||
);
|
||||
localStorage.setItem(
|
||||
"TenantName",
|
||||
tenentInfo[0].tenentName || ""
|
||||
);
|
||||
}
|
||||
localStorage.setItem(
|
||||
"PageLanding",
|
||||
element.pageId
|
||||
);
|
||||
localStorage.setItem(
|
||||
"defaultmenuid",
|
||||
element.menuId
|
||||
);
|
||||
localStorage.setItem(
|
||||
"pageType",
|
||||
element.pageType
|
||||
);
|
||||
setIsLoader(false);
|
||||
alert("Registered user successfully");
|
||||
const redirectUrl =
|
||||
location?.state?.from ||
|
||||
`/${element.pageType}/${element.pageId}`;
|
||||
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
}
|
||||
} else {
|
||||
alert("Registered user successfully");
|
||||
localStorage.setItem("PageLanding", element.pageId);
|
||||
localStorage.setItem(
|
||||
"defaultmenuid",
|
||||
element.menuId
|
||||
);
|
||||
localStorage.setItem("pageType", element.pageType);
|
||||
setIsLoader(false);
|
||||
const redirectUrl =
|
||||
location?.state?.from ||
|
||||
`/${element.pageType}/${element.pageId}`;
|
||||
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
setIsLoader(false);
|
||||
console.error("Error while fetching Follow", error);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setIsLoader(false);
|
||||
}
|
||||
} else {
|
||||
setIsLoader(false);
|
||||
const userSettings = appInfo.settings;
|
||||
const currentUser = Parse.User.current();
|
||||
const extUser = await Parse.Cloud.run("getUserDetails", {
|
||||
email: currentUser.get("email")
|
||||
});
|
||||
if (extUser) {
|
||||
const IsDisabled = extUser?.get("IsDisabled") || false;
|
||||
if (!IsDisabled) {
|
||||
const userRole = extUser?.get("UserRole");
|
||||
const menu =
|
||||
userRole && userSettings.find((menu) => menu.role === userRole);
|
||||
if (menu) {
|
||||
const _currentRole = userRole;
|
||||
const _role = _currentRole.replace("contracts_", "");
|
||||
localStorage.setItem("_user_role", _role);
|
||||
const extInfo_stringify = JSON.stringify([extUser]);
|
||||
localStorage.setItem("Extand_Class", extInfo_stringify);
|
||||
const extInfo = JSON.parse(JSON.stringify(extUser));
|
||||
localStorage.setItem("userEmail", extInfo?.Email);
|
||||
localStorage.setItem("username", extInfo?.Name);
|
||||
if (extInfo?.TenantId) {
|
||||
const tenant = {
|
||||
Id: extInfo?.TenantId?.objectId || "",
|
||||
Name: extInfo?.TenantId?.TenantName || ""
|
||||
};
|
||||
localStorage.setItem("TenantId", tenant?.Id);
|
||||
dispatch(showTenant(tenant?.Name));
|
||||
localStorage.setItem("TenantName", tenant?.Name);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("err", err);
|
||||
localStorage.setItem("PageLanding", menu.pageId);
|
||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||
localStorage.setItem("pageType", menu.pageType);
|
||||
setIsLoader(false);
|
||||
});
|
||||
alert("Registered user successfully");
|
||||
const redirectUrl =
|
||||
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
||||
// Redirect to the appropriate URL after successful login
|
||||
navigate(redirectUrl);
|
||||
}
|
||||
} else {
|
||||
setIsLoader(false);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
setIsLoader(false);
|
||||
console.log(error);
|
||||
console.log("Err in fetch extuser", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -50,7 +50,6 @@ import Upgrade from "../primitives/Upgrade";
|
||||
import Alert from "../primitives/Alert";
|
||||
import Loader from "../primitives/Loader";
|
||||
import { useSelector } from "react-redux";
|
||||
import TextFontSetting from "../components/pdf/TextFontSetting";
|
||||
import PdfZoom from "../components/pdf/PdfZoom";
|
||||
import LottieWithLoader from "../primitives/DotLottieReact";
|
||||
|
||||
@@ -170,16 +169,7 @@ function PlaceHolderSign() {
|
||||
isDragStamp: !!monitor.isDragging()
|
||||
})
|
||||
});
|
||||
|
||||
const rowLevel =
|
||||
localStorage.getItem("rowlevel") &&
|
||||
JSON.parse(localStorage.getItem("rowlevel"));
|
||||
const objectId =
|
||||
rowLevel && rowLevel.id
|
||||
? rowLevel.id
|
||||
: rowLevel?.objectId && rowLevel.objectId;
|
||||
|
||||
const documentId = docId ? docId : objectId && objectId;
|
||||
const documentId = docId;
|
||||
useEffect(() => {
|
||||
if (documentId) {
|
||||
getDocumentDetails();
|
||||
@@ -454,7 +444,6 @@ function PlaceHolderSign() {
|
||||
const addPositionOfSignature = (item, monitor) => {
|
||||
getSignerPos(item, monitor);
|
||||
};
|
||||
// console.log("signerpos", signerPos);
|
||||
const getSignerPos = (item, monitor) => {
|
||||
// setSignerObjId("");
|
||||
// setContractName("");
|
||||
@@ -679,6 +668,8 @@ function PlaceHolderSign() {
|
||||
|
||||
//function for set and update x and y postion after drag and drop signature tab
|
||||
const handleStop = (event, dragElement, signerId, key) => {
|
||||
setFontColor();
|
||||
setFontSize();
|
||||
if (!isResize && isDragging) {
|
||||
const dataNewPlace = addZIndex(signerPos, key, setZIndex);
|
||||
let updateSignPos = [...signerPos];
|
||||
@@ -751,7 +742,6 @@ function PlaceHolderSign() {
|
||||
setIsDragging(false);
|
||||
}, 200);
|
||||
};
|
||||
|
||||
//function for delete signature block
|
||||
const handleDeleteSign = (key, Id) => {
|
||||
const updateData = [];
|
||||
@@ -1007,9 +997,9 @@ function PlaceHolderSign() {
|
||||
}
|
||||
await axios
|
||||
.put(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Document/${documentId}`,
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/contracts_Document/${documentId}`,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
@@ -1145,12 +1135,7 @@ function PlaceHolderSign() {
|
||||
const senderName = `${pdfDetails?.[0].ExtUserPtr.Name}`;
|
||||
const documentName = `${pdfDetails?.[0].Name}`;
|
||||
let replaceVar;
|
||||
if (
|
||||
requestBody &&
|
||||
requestSubject &&
|
||||
isCustomize &&
|
||||
(isSubscribe || !isEnableSubscription)
|
||||
) {
|
||||
if (requestBody && requestSubject && isCustomize && isSubscribe) {
|
||||
const replacedRequestBody = requestBody.replace(/"/g, "'");
|
||||
htmlReqBody =
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
|
||||
@@ -1218,12 +1203,7 @@ function PlaceHolderSign() {
|
||||
setMailStatus("success");
|
||||
try {
|
||||
let data;
|
||||
if (
|
||||
requestBody &&
|
||||
requestSubject &&
|
||||
isCustomize &&
|
||||
(isSubscribe || !isEnableSubscription)
|
||||
) {
|
||||
if (requestBody && requestSubject && isCustomize && isSubscribe) {
|
||||
data = {
|
||||
RequestBody: htmlReqBody,
|
||||
RequestSubject: requestSubject,
|
||||
@@ -1237,9 +1217,9 @@ function PlaceHolderSign() {
|
||||
|
||||
await axios
|
||||
.put(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Document/${documentId}`,
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/contracts_Document/${documentId}`,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
@@ -1488,13 +1468,19 @@ function PlaceHolderSign() {
|
||||
hint: defaultdata?.hint || "",
|
||||
defaultValue: defaultdata?.defaultValue || "",
|
||||
validation:
|
||||
(isSubscribe || !isEnableSubscription) && inputype
|
||||
isSubscribe && inputype
|
||||
? {
|
||||
type: inputype,
|
||||
pattern:
|
||||
inputype === "regex" ? defaultdata.textvalidate : ""
|
||||
}
|
||||
: {}
|
||||
: {},
|
||||
fontSize:
|
||||
fontSize || currWidgetsDetails?.options?.fontSize || "12",
|
||||
fontColor:
|
||||
fontColor ||
|
||||
currWidgetsDetails?.options?.fontColor ||
|
||||
"black"
|
||||
}
|
||||
};
|
||||
} else {
|
||||
@@ -1504,7 +1490,13 @@ function PlaceHolderSign() {
|
||||
...position.options,
|
||||
name: defaultdata.name,
|
||||
status: defaultdata.status,
|
||||
defaultValue: defaultdata.defaultValue
|
||||
defaultValue: defaultdata.defaultValue,
|
||||
fontSize:
|
||||
fontSize || currWidgetsDetails?.options?.fontSize || "12",
|
||||
fontColor:
|
||||
fontColor ||
|
||||
currWidgetsDetails?.options?.fontColor ||
|
||||
"black"
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1528,6 +1520,8 @@ function PlaceHolderSign() {
|
||||
}
|
||||
}
|
||||
setCurrWidgetsDetails({});
|
||||
setFontSize();
|
||||
setFontColor();
|
||||
handleNameModal();
|
||||
};
|
||||
|
||||
@@ -1537,12 +1531,19 @@ function PlaceHolderSign() {
|
||||
setShowDropdown(false);
|
||||
setIsRadio(false);
|
||||
setIsCheckbox(false);
|
||||
setIsPageCopy(false);
|
||||
//condition for text widget type after set all values for text widget
|
||||
//change setUniqueId which is set in tempsignerId
|
||||
//because textwidget do not have signer user so for selected signers we have to do
|
||||
if (currWidgetsDetails.type === textWidget) {
|
||||
setUniqueId(tempSignerId);
|
||||
setTempSignerId("");
|
||||
}
|
||||
};
|
||||
//function for update TourStatus
|
||||
const closeTour = async () => {
|
||||
setPlaceholderTour(false);
|
||||
if (isDontShow) {
|
||||
const extUserClass = localStorage.getItem("extended_class");
|
||||
let updatedTourStatus = [];
|
||||
if (tourStatus.length > 0) {
|
||||
updatedTourStatus = [...tourStatus];
|
||||
@@ -1561,7 +1562,7 @@ function PlaceHolderSign() {
|
||||
.put(
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/${extUserClass}/${signerUserId}`,
|
||||
)}classes/contracts_Users/${signerUserId}`,
|
||||
{
|
||||
TourStatus: updatedTourStatus
|
||||
},
|
||||
@@ -1620,13 +1621,11 @@ function PlaceHolderSign() {
|
||||
setCurrentId(getCurrentUserDeatils[0].Email);
|
||||
}
|
||||
}
|
||||
|
||||
setSignersData(updateSigner);
|
||||
const index = signersdata.findIndex((x) => x.Id === uniqueId);
|
||||
setIsSelectId(index);
|
||||
}
|
||||
};
|
||||
|
||||
//function to add new signer in document signers list
|
||||
const handleAddNewRecipients = (data) => {
|
||||
const newId = randomId();
|
||||
@@ -1689,60 +1688,6 @@ function PlaceHolderSign() {
|
||||
setSignerPos(updatePlaceholderUser);
|
||||
setIsMailSend(false);
|
||||
};
|
||||
|
||||
const handleSaveFontSize = () => {
|
||||
const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
|
||||
if (filterSignerPos.length > 0) {
|
||||
const getPlaceHolder = filterSignerPos[0].placeHolder;
|
||||
|
||||
const getPageNumer = getPlaceHolder.filter(
|
||||
(data) => data.pageNumber === pageNumber
|
||||
);
|
||||
|
||||
if (getPageNumer.length > 0) {
|
||||
const getXYdata = getPageNumer[0].pos;
|
||||
const getPosData = getXYdata;
|
||||
const addSignPos = getPosData.map((position) => {
|
||||
if (position.key === signKey) {
|
||||
return {
|
||||
...position,
|
||||
options: {
|
||||
...position.options,
|
||||
fontSize: fontSize,
|
||||
fontColor: fontColor
|
||||
}
|
||||
};
|
||||
}
|
||||
return position;
|
||||
});
|
||||
|
||||
const newUpdateSignPos = getPlaceHolder.map((obj) => {
|
||||
if (obj.pageNumber === pageNumber) {
|
||||
return { ...obj, pos: addSignPos };
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
const newUpdateSigner = signerPos.map((obj) => {
|
||||
if (obj.Id === uniqueId) {
|
||||
return { ...obj, placeHolder: newUpdateSignPos };
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
setSignerPos(newUpdateSigner);
|
||||
}
|
||||
}
|
||||
setFontSize();
|
||||
setFontColor();
|
||||
if (currWidgetsDetails.type === textWidget) {
|
||||
setUniqueId(tempSignerId);
|
||||
setTempSignerId("");
|
||||
}
|
||||
|
||||
handleTextSettingModal(false);
|
||||
};
|
||||
const handleTextSettingModal = (value) => {
|
||||
setIsTextSetting(value);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Title title={state?.title ? state.title : "New Document"} />
|
||||
@@ -1813,7 +1758,6 @@ function PlaceHolderSign() {
|
||||
: isSendAlert.mssg === "confirm" && "Send Mail"
|
||||
}
|
||||
handleClose={() => setIsSendAlert({})}
|
||||
showHeaderMessage={isSendAlert.mssg === "confirm"}
|
||||
>
|
||||
<div className="max-h-96 overflow-y-scroll scroll-hide p-[20px] text-base-content">
|
||||
{isSendAlert.mssg === "sure" ? (
|
||||
@@ -1828,86 +1772,69 @@ function PlaceHolderSign() {
|
||||
) : (
|
||||
isSendAlert.mssg === "confirm" && (
|
||||
<>
|
||||
<>
|
||||
{!isCustomize && (
|
||||
<span>
|
||||
Are you sure you want to send out this
|
||||
document for signatures?
|
||||
</span>
|
||||
)}
|
||||
{isCustomize &&
|
||||
(!isEnableSubscription || isSubscribe) && (
|
||||
<>
|
||||
<EmailBody
|
||||
editorRef={editorRef}
|
||||
requestBody={requestBody}
|
||||
requestSubject={requestSubject}
|
||||
handleOnchangeRequest={
|
||||
handleOnchangeRequest
|
||||
}
|
||||
setRequestSubject={setRequestSubject}
|
||||
/>
|
||||
<div
|
||||
className="flex justify-end items-center gap-1 mt-2 op-link op-link-primary"
|
||||
onClick={() => {
|
||||
setRequestBody(defaultBody);
|
||||
setRequestSubject(defaultSubject);
|
||||
}}
|
||||
>
|
||||
<span>Reset to default</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div
|
||||
className={
|
||||
"flex flex-row md:items-center gap-2 md:gap-6 mt-2 "
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row gap-2">
|
||||
<button
|
||||
onClick={() => sendEmailToSigners()}
|
||||
className="op-btn op-btn-primary font-[500] text-sm shadow"
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
{isCustomize && (
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsCustomize(false);
|
||||
}}
|
||||
className="op-btn op-btn-ghost font-[500] text-sm"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
)}
|
||||
{!isCustomize && (
|
||||
<span>
|
||||
Are you sure you want to send out this document
|
||||
for signatures?
|
||||
</span>
|
||||
)}
|
||||
{isCustomize && isSubscribe && (
|
||||
<>
|
||||
<EmailBody
|
||||
editorRef={editorRef}
|
||||
requestBody={requestBody}
|
||||
requestSubject={requestSubject}
|
||||
handleOnchangeRequest={handleOnchangeRequest}
|
||||
setRequestSubject={setRequestSubject}
|
||||
/>
|
||||
<div
|
||||
className="flex justify-end items-center gap-1 mt-2 op-link op-link-primary"
|
||||
onClick={() => {
|
||||
setRequestBody(defaultBody);
|
||||
setRequestSubject(defaultSubject);
|
||||
}}
|
||||
>
|
||||
<span>Reset to default</span>
|
||||
</div>
|
||||
|
||||
{!isCustomize &&
|
||||
(isSubscribe || !isEnableSubscription) && (
|
||||
<span
|
||||
className="op-link op-link-accent text-sm"
|
||||
onClick={() => {
|
||||
setIsCustomize(!isCustomize);
|
||||
}}
|
||||
>
|
||||
Cutomize Email
|
||||
</span>
|
||||
)}
|
||||
|
||||
{!isSubscribe && isEnableSubscription && (
|
||||
<div className="mt-2">
|
||||
<Upgrade
|
||||
message="Upgrade to customize Email"
|
||||
newWindow={true}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className="flex flex-row md:items-center gap-2 md:gap-6 mt-2">
|
||||
<div className="flex flex-row gap-2">
|
||||
<button
|
||||
onClick={() => sendEmailToSigners()}
|
||||
className="op-btn op-btn-primary font-[500] text-sm shadow"
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
{isCustomize && (
|
||||
<button
|
||||
onClick={() => setIsCustomize(false)}
|
||||
className="op-btn op-btn-ghost font-[500] text-sm"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
{!isCustomize && isSubscribe && (
|
||||
<span
|
||||
className="op-link op-link-accent text-sm"
|
||||
onClick={() => setIsCustomize(!isCustomize)}
|
||||
>
|
||||
Cutomize Email
|
||||
</span>
|
||||
)}
|
||||
{!isSubscribe && isEnableSubscription && (
|
||||
<div className="mt-2">
|
||||
<Upgrade
|
||||
message="Upgrade to customize Email"
|
||||
newWindow={true}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
)}
|
||||
|
||||
{isSendAlert.mssg === "confirm" && (
|
||||
<>
|
||||
<div className="flex justify-center items-center mt-3">
|
||||
@@ -1948,29 +1875,37 @@ function PlaceHolderSign() {
|
||||
{!mailStatus && (
|
||||
<div className="w-full h-[1px] bg-[#9f9f9f] my-[15px]"></div>
|
||||
)}
|
||||
{isCurrUser && (
|
||||
<div
|
||||
className={
|
||||
mailStatus === "success"
|
||||
? "flex justify-center mt-1"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
{isCurrUser && (
|
||||
<button
|
||||
onClick={() => {
|
||||
handleRecipientSign();
|
||||
}}
|
||||
type="button"
|
||||
className="op-btn op-btn-primary mr-1"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
handleRecipientSign();
|
||||
setIsSend(false);
|
||||
setSignerPos([]);
|
||||
navigate("/report/1MwEuxLEkF");
|
||||
}}
|
||||
type="button"
|
||||
className="op-btn op-btn-primary mr-1"
|
||||
className="op-btn op-btn-ghost"
|
||||
>
|
||||
Yes
|
||||
{isCurrUser ? "No" : "Close"}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsSend(false);
|
||||
setSignerPos([]);
|
||||
navigate("/report/1MwEuxLEkF");
|
||||
}}
|
||||
type="button"
|
||||
className="op-btn op-btn-ghost"
|
||||
>
|
||||
{isCurrUser ? "No" : "Close"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalUi>
|
||||
<ModalUi
|
||||
@@ -2095,10 +2030,10 @@ function PlaceHolderSign() {
|
||||
handleNameModal={setIsNameModal}
|
||||
setTempSignerId={setTempSignerId}
|
||||
uniqueId={uniqueId}
|
||||
handleTextSettingModal={handleTextSettingModal}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
setIsSelectId={setIsSelectId}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -2142,6 +2077,7 @@ function PlaceHolderSign() {
|
||||
setBlockColor={setBlockColor}
|
||||
setIsAddSigner={setIsAddSigner}
|
||||
handleDeleteUser={handleDeleteUser}
|
||||
uniqueId={uniqueId}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
@@ -2151,6 +2087,7 @@ function PlaceHolderSign() {
|
||||
aria-disabled
|
||||
>
|
||||
<SignerListPlace
|
||||
setSignerPos={setSignerPos}
|
||||
signerPos={signerPos}
|
||||
signersdata={signersdata}
|
||||
isSelectListId={isSelectListId}
|
||||
@@ -2167,6 +2104,7 @@ function PlaceHolderSign() {
|
||||
setIsAddSigner={setIsAddSigner}
|
||||
handleDeleteUser={handleDeleteUser}
|
||||
roleName={roleName}
|
||||
uniqueId={uniqueId}
|
||||
// handleAddSigner={handleAddSigner}
|
||||
/>
|
||||
<div data-tut="addWidgets">
|
||||
@@ -2211,17 +2149,6 @@ function PlaceHolderSign() {
|
||||
</button>
|
||||
</div>
|
||||
</ModalUi>
|
||||
<TextFontSetting
|
||||
isTextSetting={isTextSetting}
|
||||
setIsTextSetting={setIsTextSetting}
|
||||
fontSize={fontSize}
|
||||
setFontSize={setFontSize}
|
||||
fontColor={fontColor}
|
||||
setFontColor={setFontColor}
|
||||
handleSaveFontSize={handleSaveFontSize}
|
||||
currWidgetsDetails={currWidgetsDetails}
|
||||
/>
|
||||
|
||||
<LinkUserModal
|
||||
handleAddUser={handleAddUser}
|
||||
isAddUser={isAddUser}
|
||||
@@ -2242,6 +2169,12 @@ function PlaceHolderSign() {
|
||||
handleClose={handleNameModal}
|
||||
handleData={handleWidgetdefaultdata}
|
||||
isSubscribe={isSubscribe}
|
||||
isTextSetting={isTextSetting}
|
||||
setIsTextSetting={setIsTextSetting}
|
||||
fontSize={fontSize}
|
||||
setFontSize={setFontSize}
|
||||
fontColor={fontColor}
|
||||
setFontColor={setFontColor}
|
||||
/>
|
||||
</DndProvider>
|
||||
</>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { NavLink, useNavigate } from "react-router-dom";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import checkmark from "../assets/images/checkmark.png";
|
||||
import plansArr from "../json/plansArr";
|
||||
import plansArr, { stagingPlan } from "../json/plansArr";
|
||||
import Title from "../components/Title";
|
||||
import Parse from "parse";
|
||||
import { openInNewTab } from "../constant/Utils";
|
||||
import Loader from "../primitives/Loader";
|
||||
import { isStaging } from "../constant/const";
|
||||
const listItemStyle = {
|
||||
paddingLeft: "20px", // Add padding to create space for the image
|
||||
backgroundImage: `url(${checkmark})`, // Set your image as the list style image
|
||||
@@ -16,7 +17,8 @@ const listItemStyle = {
|
||||
|
||||
const PlanSubscriptions = () => {
|
||||
const navigate = useNavigate();
|
||||
const [yearlyVisible, setYearlyVisible] = useState(false);
|
||||
const isTeamPlan = plansArr.some((x) => x.planName === "OPENSIGN™ TEAMS");
|
||||
const [yearlyVisible, setYearlyVisible] = useState(true);
|
||||
const [isLoader, setIsLoader] = useState(true);
|
||||
const extUser =
|
||||
localStorage.getItem("Extand_Class") &&
|
||||
@@ -29,10 +31,15 @@ const PlanSubscriptions = () => {
|
||||
};
|
||||
const userDetails = JSON.parse(localStorage.getItem("userDetails")) || user;
|
||||
// console.log("userDetails ", userDetails);
|
||||
const name =
|
||||
userDetails && userDetails.name
|
||||
? "first_name=" + encodeURIComponent(userDetails.name)
|
||||
: "";
|
||||
const fullname =
|
||||
userDetails && userDetails.name ? userDetails.name.split(" ") : "";
|
||||
const firstname = fullname?.[0]
|
||||
? "first_name=" + encodeURIComponent(fullname?.[0])
|
||||
: "";
|
||||
const lastname = fullname?.[1]
|
||||
? "&last_name=" + encodeURIComponent(fullname?.[1])
|
||||
: "";
|
||||
const name = firstname ? firstname + lastname : "";
|
||||
const email =
|
||||
userDetails && userDetails.email
|
||||
? "&email=" + encodeURIComponent(userDetails.email)
|
||||
@@ -53,33 +60,40 @@ const PlanSubscriptions = () => {
|
||||
company +
|
||||
phone;
|
||||
useEffect(() => {
|
||||
// if (localStorage.getItem("accesstoken")) {
|
||||
setIsLoader(false);
|
||||
// } else {
|
||||
// navigate("/", { replace: true });
|
||||
// }
|
||||
if (!isTeamPlan && isStaging) {
|
||||
plansArr.splice(2, 0, stagingPlan);
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
const handleFreePlan = async () => {
|
||||
setIsLoader(true);
|
||||
try {
|
||||
const params = { userId: Parse.User.current().id };
|
||||
const res = await Parse.Cloud.run("freesubscription", params);
|
||||
if (res.status === "success" && res.result === "already subscribed!") {
|
||||
setIsLoader(false);
|
||||
alert("You have already subscribed to plan!");
|
||||
} else if (res.status === "success") {
|
||||
setIsLoader(false);
|
||||
navigate("/");
|
||||
} else if (res.status === "error") {
|
||||
setIsLoader(false);
|
||||
alert(res.result);
|
||||
const handleFreePlan = async (item) => {
|
||||
if (item.url) {
|
||||
const url = yearlyVisible ? item.yearlyUrl + details : item.url + details;
|
||||
if (user) {
|
||||
localStorage.setItem("userDetails", JSON.stringify(user));
|
||||
}
|
||||
openInNewTab(url, item?.target);
|
||||
} else {
|
||||
setIsLoader(true);
|
||||
try {
|
||||
const params = { userId: Parse.User.current().id };
|
||||
const res = await Parse.Cloud.run("freesubscription", params);
|
||||
if (res.status === "success" && res.result === "already subscribed!") {
|
||||
setIsLoader(false);
|
||||
alert("You have already subscribed to plan!");
|
||||
} else if (res.status === "success") {
|
||||
setIsLoader(false);
|
||||
navigate("/");
|
||||
} else if (res.status === "error") {
|
||||
setIsLoader(false);
|
||||
alert(res.result);
|
||||
}
|
||||
} catch (err) {
|
||||
setIsLoader(false);
|
||||
console.log("err in free subscribe", err.message);
|
||||
alert("Somenthing went wrong, please try again later!");
|
||||
}
|
||||
} catch (err) {
|
||||
setIsLoader(false);
|
||||
console.log("err in free subscribe", err.message);
|
||||
alert("Somenthing went wrong, please try again later!");
|
||||
}
|
||||
};
|
||||
return (
|
||||
@@ -122,19 +136,43 @@ const PlanSubscriptions = () => {
|
||||
<h3 className="text-[#002862] uppercase">
|
||||
{item.planName}
|
||||
</h3>
|
||||
<div className="w-[150px] h-[150px]">
|
||||
<div className="w-[120px] h-[120px] overflow-hidden">
|
||||
<img
|
||||
className="icon-basic mx-auto"
|
||||
src="https://js.zohostatic.com/books/zfwidgets/assets/images/plan.png"
|
||||
alt="freeimg"
|
||||
className="w-full h-full object-contain"
|
||||
src={require(`../assets/images/${item?.img}`)}
|
||||
alt="img"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-3xl">
|
||||
{item.currency && <small>{item.currency}</small>}
|
||||
{yearlyVisible
|
||||
? item?.yearlyPrice
|
||||
: item.monthlyPrice}
|
||||
{yearlyVisible ? (
|
||||
<>
|
||||
{item?.yearlyPrice.includes("<") ? (
|
||||
<div
|
||||
className="inline-block"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item?.yearlyPrice
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span>{item?.yearlyPrice}</span>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{item?.monthlyPrice.includes("<") ? (
|
||||
<div
|
||||
className="inline-block"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item?.monthlyPrice
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span>{item?.monthlyPrice}</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
<p className="font-semibold pt-2 text-sm">
|
||||
{yearlyVisible ? "Billed Yearly" : "Billed Monthly"}
|
||||
@@ -160,28 +198,14 @@ const PlanSubscriptions = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{item.url ? (
|
||||
<NavLink
|
||||
to={
|
||||
item.btnText === "Subscribe"
|
||||
? yearlyVisible
|
||||
? item.yearlyUrl + details
|
||||
: item.url + details
|
||||
: item.url
|
||||
}
|
||||
className="bg-[#002862] w-full text-white py-2 rounded uppercase hover:no-underline hover:text-white cursor-pointer"
|
||||
target={item.target}
|
||||
>
|
||||
{item.btnText}
|
||||
</NavLink>
|
||||
) : (
|
||||
<button
|
||||
className="bg-[#002862] w-full text-white py-2 rounded uppercase hover:text-white cursor-pointer"
|
||||
onClick={() => handleFreePlan()}
|
||||
>
|
||||
{item.btnText}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
className={`${
|
||||
item?.btn?.color ? item?.btn?.color : "op-btn-primary"
|
||||
} w-full text-white py-2 op-btn uppercase hover:text-white cursor-pointer`}
|
||||
onClick={() => handleFreePlan(item)}
|
||||
>
|
||||
{item?.btn?.text}
|
||||
</button>
|
||||
</div>
|
||||
<hr className="w-full bg-gray-300 h-[0.5px]" />
|
||||
<ul className="mx-1 p-3 text-left break-words text-sm list-none">
|
||||
|
||||
@@ -22,6 +22,7 @@ const Report = () => {
|
||||
const [form, setForm] = useState("");
|
||||
const [tourData, setTourData] = useState([]);
|
||||
const [isDontShow, setIsDontShow] = useState(false);
|
||||
const [isPublic, setIsPublic] = useState({});
|
||||
const abortController = new AbortController();
|
||||
const docPerPage = 10;
|
||||
|
||||
@@ -156,6 +157,13 @@ const Report = () => {
|
||||
? [...prevRecord, ...res.data.result]
|
||||
: res.data.result
|
||||
);
|
||||
const listData = res.data.result;
|
||||
setIsPublic(
|
||||
listData.reduce((acc, item) => {
|
||||
acc[item.objectId] = item?.IsPublic || false;
|
||||
return acc;
|
||||
}, {})
|
||||
);
|
||||
}
|
||||
}
|
||||
setIsLoader(false);
|
||||
@@ -193,6 +201,8 @@ const Report = () => {
|
||||
report_help={reporthelp}
|
||||
tourData={tourData}
|
||||
isDontShow={isDontShow}
|
||||
setIsPublic={setIsPublic}
|
||||
isPublic={isPublic}
|
||||
/>
|
||||
) : (
|
||||
<PageNotFound prefix={"Report"} />
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import Parse from "parse";
|
||||
import axios from "axios";
|
||||
import { appInfo } from "../constant/appinfo";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { fetchSubscription } from "../constant/Utils";
|
||||
@@ -136,8 +135,6 @@ const SSOVerify = () => {
|
||||
};
|
||||
// `thirdpartyLoginfn` is used to save necessary parameters locally for the logged-in user
|
||||
const thirdpartyLoginfn = async (sessionToken) => {
|
||||
const baseUrl = localStorage.getItem("baseUrl");
|
||||
const parseAppId = localStorage.getItem("parseAppId");
|
||||
try {
|
||||
const validUser = await Parse.User.become(sessionToken);
|
||||
if (validUser) {
|
||||
@@ -151,76 +148,44 @@ const SSOVerify = () => {
|
||||
}
|
||||
// Check extended class user role and tenentId
|
||||
try {
|
||||
let userRoles = [];
|
||||
const userSettings = appInfo.settings;
|
||||
//Get Current user roles
|
||||
const url = `${baseUrl}functions/UserGroups`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseAppId,
|
||||
sessionToken: _user.sessionToken
|
||||
};
|
||||
const body = { appname: appInfo.appname };
|
||||
const UserGroupsRes = await axios.post(url, JSON.stringify(body), {
|
||||
headers: headers
|
||||
});
|
||||
userRoles = (UserGroupsRes.data && UserGroupsRes.data.result) || [];
|
||||
if (userRoles) {
|
||||
let _currentRole = "";
|
||||
const excludeRoles = ["contracts_Guest", `contracts_appeditor`];
|
||||
const filteredRole = userRoles.filter(
|
||||
(x) => !excludeRoles.includes(x)
|
||||
);
|
||||
if (filteredRole?.length > 1) {
|
||||
console.log("user has two roles");
|
||||
// _currentRole = filteredRole.filter((x) => x === "contracts_User");
|
||||
} else {
|
||||
_currentRole = filteredRole?.[0] || "";
|
||||
}
|
||||
if (_currentRole) {
|
||||
const roleSetting = userSettings?.find(
|
||||
(setting) => setting.role === _currentRole
|
||||
);
|
||||
const redirectUrl =
|
||||
location?.state?.from ||
|
||||
`/${roleSetting.pageType}/${roleSetting.pageId}`;
|
||||
const _role = _currentRole.replace(`${appInfo.appname}_`, "");
|
||||
localStorage.setItem("_user_role", _role);
|
||||
// Get TenentID from Extendend Class
|
||||
localStorage.setItem(
|
||||
"extended_class",
|
||||
roleSetting.extended_class
|
||||
);
|
||||
try {
|
||||
const extUser = await Parse.Cloud.run("getUserDetails", {
|
||||
email: _user.email
|
||||
});
|
||||
if (extUser) {
|
||||
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||
localStorage.setItem("userEmail", _extUser.Email);
|
||||
localStorage.setItem("username", _extUser.Name);
|
||||
localStorage.setItem("scriptId", true);
|
||||
let tenentInfo = [];
|
||||
const results = [extUser];
|
||||
if (results) {
|
||||
let extendedInfo_stringify = JSON.stringify(results);
|
||||
localStorage.setItem(
|
||||
"Extand_Class",
|
||||
extendedInfo_stringify
|
||||
);
|
||||
const currentUser = Parse.User.current();
|
||||
await Parse.Cloud.run("getUserDetails", {
|
||||
email: currentUser.get("email")
|
||||
})
|
||||
.then(async (extUser) => {
|
||||
if (extUser) {
|
||||
const IsDisabled = extUser?.get("IsDisabled") || false;
|
||||
if (!IsDisabled) {
|
||||
const userRole = extUser?.get("UserRole");
|
||||
const menu =
|
||||
userRole &&
|
||||
userSettings.find((menu) => menu.role === userRole);
|
||||
if (menu) {
|
||||
const _currentRole = userRole;
|
||||
const redirectUrl =
|
||||
location?.state?.from ||
|
||||
`/${menu.pageType}/${menu.pageId}`;
|
||||
const _role = _currentRole.replace("contracts_", "");
|
||||
localStorage.setItem("_user_role", _role);
|
||||
const extUser_stringify = JSON.stringify([extUser]);
|
||||
localStorage.setItem("Extand_Class", extUser_stringify);
|
||||
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||
localStorage.setItem("userEmail", _extUser.Email);
|
||||
localStorage.setItem("username", _extUser.Name);
|
||||
localStorage.setItem("scriptId", true);
|
||||
if (_extUser.TenantId) {
|
||||
const obj = {
|
||||
tenentId: _extUser.TenantId.objectId,
|
||||
tenentName: _extUser.TenantId.TenantName || ""
|
||||
const tenant = {
|
||||
Id: _extUser?.TenantId?.objectId || "",
|
||||
Name: _extUser?.TenantId?.TenantName || ""
|
||||
};
|
||||
localStorage.setItem("TenantId", obj.tenentId);
|
||||
tenentInfo.push(obj);
|
||||
dispatch(showTenant(obj.tenentName || ""));
|
||||
localStorage.setItem("TenantName", obj.tenentName || "");
|
||||
localStorage.setItem("TenantId", tenant?.Id);
|
||||
dispatch(showTenant(tenant?.Name));
|
||||
localStorage.setItem("TenantName", tenant?.Name);
|
||||
}
|
||||
localStorage.setItem("PageLanding", roleSetting.pageId);
|
||||
localStorage.setItem("defaultmenuid", roleSetting.menuId);
|
||||
localStorage.setItem("pageType", roleSetting.pageType);
|
||||
localStorage.setItem("PageLanding", menu.pageId);
|
||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||
localStorage.setItem("pageType", menu.pageType);
|
||||
if (isEnableSubscription) {
|
||||
const res = await fetchSubscription();
|
||||
const plan = res.plan;
|
||||
@@ -232,35 +197,32 @@ const SSOVerify = () => {
|
||||
localStorage.removeItem("userDetails");
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
navigate(`/subscription`, {
|
||||
replace: true
|
||||
});
|
||||
navigate(`/subscription`, { replace: true });
|
||||
}
|
||||
} else {
|
||||
navigate(`/subscription`, {
|
||||
replace: true
|
||||
});
|
||||
navigate(`/subscription`, { replace: true });
|
||||
}
|
||||
} else {
|
||||
navigate(redirectUrl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
alert(
|
||||
"Error: You don't have access, please contact the admin."
|
||||
);
|
||||
setMessage(
|
||||
"Error: You don't have access, please contact the admin."
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
alert("user not exist.");
|
||||
setMessage("Error: User not exist.");
|
||||
console.log("err in get extUser", err);
|
||||
}
|
||||
} else {
|
||||
alert("Role does not exists.");
|
||||
setMessage("Error: Role does not exists.");
|
||||
}
|
||||
} else {
|
||||
alert("Role does not exists.");
|
||||
setMessage("Error: Role does not exists.");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Err in fetch extuser", error);
|
||||
alert("user not exist.");
|
||||
setMessage("Error: User not exist.");
|
||||
});
|
||||
} catch (err) {
|
||||
console.log("err in usergroups", err);
|
||||
console.log("err in getuserdetails", err);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@@ -44,14 +44,8 @@ const Signup = () => {
|
||||
let baseUrl = localStorage.getItem("baseUrl");
|
||||
let appid = localStorage.getItem("parseAppId");
|
||||
let applogo = localStorage.getItem("appLogo");
|
||||
let domain = localStorage.getItem("domain");
|
||||
let appversion = localStorage.getItem("appVersion");
|
||||
let appTitle = localStorage.getItem("appTitle");
|
||||
let defaultmenuid = localStorage.getItem("defaultmenuid");
|
||||
let PageLanding = localStorage.getItem("PageLanding");
|
||||
let _appName = localStorage.getItem("_appName");
|
||||
let _app_objectId = localStorage.getItem("_app_objectId");
|
||||
let appName = localStorage.getItem("appName");
|
||||
let userSettings = localStorage.getItem("userSettings");
|
||||
|
||||
localStorage.clear();
|
||||
@@ -59,14 +53,8 @@ const Signup = () => {
|
||||
localStorage.setItem("baseUrl", baseUrl);
|
||||
localStorage.setItem("parseAppId", appid);
|
||||
localStorage.setItem("appLogo", applogo);
|
||||
localStorage.setItem("domain", domain);
|
||||
localStorage.setItem("appversion", appversion);
|
||||
localStorage.setItem("appTitle", appTitle);
|
||||
localStorage.setItem("defaultmenuid", defaultmenuid);
|
||||
localStorage.setItem("PageLanding", PageLanding);
|
||||
localStorage.setItem("_appName", _appName);
|
||||
localStorage.setItem("_app_objectId", _app_objectId);
|
||||
localStorage.setItem("appName", appName);
|
||||
localStorage.setItem("userSettings", userSettings);
|
||||
localStorage.setItem("baseUrl", baseUrl);
|
||||
localStorage.setItem("parseAppId", appid);
|
||||
@@ -194,8 +182,6 @@ const Signup = () => {
|
||||
if (res.data) {
|
||||
let _user = res.data;
|
||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
||||
localStorage.setItem("userEmail", _user.email);
|
||||
localStorage.setItem("username", _user.name);
|
||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
||||
localStorage.setItem("scriptId", true);
|
||||
if (_user.ProfilePic) {
|
||||
@@ -205,252 +191,84 @@ const Signup = () => {
|
||||
}
|
||||
// Check extended class user role and tenentId
|
||||
try {
|
||||
let userRoles = [];
|
||||
if (appInfo.settings) {
|
||||
let userSettings = appInfo.settings;
|
||||
|
||||
//Get Current user roles
|
||||
let url = `${baseUrl}functions/UserGroups`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseAppId,
|
||||
sessionToken: _user.sessionToken
|
||||
};
|
||||
|
||||
let body = {
|
||||
appname: localStorage.getItem("_appName")
|
||||
};
|
||||
await axios
|
||||
.post(url, JSON.stringify(body), { headers: headers })
|
||||
.then((roles) => {
|
||||
if (roles) {
|
||||
userRoles = roles.data.result;
|
||||
let _currentRole = "";
|
||||
if (userRoles.length > 1) {
|
||||
if (
|
||||
userRoles[0] ===
|
||||
`${localStorage.getItem("_appName")}_appeditor`
|
||||
) {
|
||||
_currentRole = userRoles[1];
|
||||
} else {
|
||||
_currentRole = userRoles[0];
|
||||
const userSettings = appInfo.settings;
|
||||
const currentUser = Parse.User.current();
|
||||
await Parse.Cloud.run("getUserDetails", {
|
||||
email: currentUser.get("email")
|
||||
})
|
||||
.then(async (extUser) => {
|
||||
if (extUser) {
|
||||
const IsDisabled = extUser?.get("IsDisabled") || false;
|
||||
if (!IsDisabled) {
|
||||
const userRole = extUser?.get("UserRole");
|
||||
const menu =
|
||||
userRole &&
|
||||
userSettings.find((menu) => menu.role === userRole);
|
||||
if (menu) {
|
||||
const _currentRole = userRole;
|
||||
const _role = _currentRole.replace("contracts_", "");
|
||||
localStorage.setItem("_user_role", _role);
|
||||
const extInfo_stringify = JSON.stringify([extUser]);
|
||||
localStorage.setItem("Extand_Class", extInfo_stringify);
|
||||
const extInfo = JSON.parse(JSON.stringify(extUser));
|
||||
localStorage.setItem("userEmail", extInfo?.Email);
|
||||
localStorage.setItem("username", extInfo?.Name);
|
||||
if (extInfo?.TenantId) {
|
||||
const tenant = {
|
||||
Id: extInfo?.TenantId?.objectId || "",
|
||||
Name: extInfo?.TenantId?.TenantName || ""
|
||||
};
|
||||
localStorage.setItem("TenantId", tenant?.Id);
|
||||
dispatch(showTenant(tenant?.Name));
|
||||
localStorage.setItem("TenantName", tenant?.Name);
|
||||
}
|
||||
} else {
|
||||
_currentRole = userRoles[0];
|
||||
}
|
||||
if (
|
||||
_currentRole !==
|
||||
`${localStorage.getItem("_appName")}_appeditor`
|
||||
) {
|
||||
userSettings.forEach(async (element) => {
|
||||
if (element.role === _currentRole) {
|
||||
let _role = _currentRole.replace(
|
||||
`${localStorage.getItem("_appName")}_`,
|
||||
""
|
||||
);
|
||||
localStorage.setItem("_user_role", _role);
|
||||
// Get TenentID from Extendend Class
|
||||
localStorage.setItem(
|
||||
"extended_class",
|
||||
element.extended_class
|
||||
);
|
||||
await Parse.Cloud.run("getUserDetails", {
|
||||
email: email
|
||||
}).then(
|
||||
(result) => {
|
||||
let tenentInfo = [];
|
||||
const results = [result];
|
||||
if (results) {
|
||||
let extendedInfo_stringify =
|
||||
JSON.stringify(results);
|
||||
localStorage.setItem(
|
||||
"Extand_Class",
|
||||
extendedInfo_stringify
|
||||
);
|
||||
let extendedInfo = JSON.parse(
|
||||
extendedInfo_stringify
|
||||
);
|
||||
if (extendedInfo.length > 1) {
|
||||
extendedInfo.forEach((x) => {
|
||||
if (x.TenantId) {
|
||||
let obj = {
|
||||
tenentId: x.TenantId.objectId,
|
||||
tenentName: x.TenantId.TenantName || ""
|
||||
};
|
||||
tenentInfo.push(obj);
|
||||
}
|
||||
});
|
||||
if (tenentInfo.length) {
|
||||
dispatch(
|
||||
showTenant(tenentInfo[0].tenentName || "")
|
||||
);
|
||||
localStorage.setItem(
|
||||
"TenantName",
|
||||
tenentInfo[0].tenentName || ""
|
||||
);
|
||||
}
|
||||
|
||||
localStorage.setItem("showpopup", true);
|
||||
localStorage.setItem(
|
||||
"IncludedApps",
|
||||
JSON.stringify(tenentInfo)
|
||||
);
|
||||
|
||||
localStorage.setItem(
|
||||
"PageLanding",
|
||||
element.pageId
|
||||
);
|
||||
localStorage.setItem(
|
||||
"defaultmenuid",
|
||||
element.menuId
|
||||
);
|
||||
localStorage.setItem(
|
||||
"pageType",
|
||||
element.pageType
|
||||
);
|
||||
setState({ loading: false });
|
||||
navigate("/");
|
||||
} else {
|
||||
extendedInfo.forEach((x) => {
|
||||
if (x.TenantId) {
|
||||
let obj = {
|
||||
tenentId: x.TenantId.objectId,
|
||||
tenentName: x.TenantId.TenantName || ""
|
||||
};
|
||||
localStorage.setItem(
|
||||
"TenantId",
|
||||
x.TenantId.objectId
|
||||
);
|
||||
tenentInfo.push(obj);
|
||||
}
|
||||
});
|
||||
if (tenentInfo.length) {
|
||||
dispatch(
|
||||
showTenant(tenentInfo[0].tenentName || "")
|
||||
);
|
||||
localStorage.setItem(
|
||||
"TenantName",
|
||||
tenentInfo[0].tenentName || ""
|
||||
);
|
||||
}
|
||||
localStorage.setItem(
|
||||
"PageLanding",
|
||||
element.pageId
|
||||
);
|
||||
localStorage.setItem(
|
||||
"defaultmenuid",
|
||||
element.menuId
|
||||
);
|
||||
localStorage.setItem(
|
||||
"pageType",
|
||||
element.pageType
|
||||
);
|
||||
setState({ loading: false });
|
||||
if (isEnableSubscription) {
|
||||
if (isFreeplan) {
|
||||
navigate(
|
||||
`/${element.pageType}/${element.pageId}`
|
||||
);
|
||||
} else {
|
||||
navigate(`/subscription`, { replace: true });
|
||||
}
|
||||
} else {
|
||||
alert("Registered user successfully");
|
||||
navigate(
|
||||
`/${element.pageType}/${element.pageId}`
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
alert("Registered user successfully");
|
||||
localStorage.setItem("PageLanding", element.pageId);
|
||||
localStorage.setItem(
|
||||
"defaultmenuid",
|
||||
element.menuId
|
||||
);
|
||||
localStorage.setItem("pageType", element.pageType);
|
||||
setState({ loading: false });
|
||||
if (isEnableSubscription) {
|
||||
if (isFreeplan) {
|
||||
navigate(
|
||||
`/${element.pageType}/${element.pageId}`
|
||||
);
|
||||
} else {
|
||||
navigate(`/subscription`, { replace: true });
|
||||
}
|
||||
} else {
|
||||
navigate(
|
||||
`/${element.pageType}/${element.pageId}`
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
setState({
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg:
|
||||
"You dont have access to this application!"
|
||||
});
|
||||
setTimeout(function () {
|
||||
setState({
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: ""
|
||||
});
|
||||
}, 2000);
|
||||
localStorage.setItem("accesstoken", null);
|
||||
console.error("Error while fetching Follow", error);
|
||||
}
|
||||
);
|
||||
localStorage.setItem("PageLanding", menu.pageId);
|
||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||
localStorage.setItem("pageType", menu.pageType);
|
||||
setState({ loading: false });
|
||||
if (isEnableSubscription) {
|
||||
if (isFreeplan) {
|
||||
navigate(`/${menu.pageType}/${menu.pageId}`);
|
||||
} else {
|
||||
navigate(`/subscription`, { replace: true });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
alert("Registered user successfully");
|
||||
navigate(`/${menu.pageType}/${menu.pageId}`);
|
||||
}
|
||||
} else {
|
||||
setState({
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: "User Role Not Found!"
|
||||
alertMsg: "Role not found."
|
||||
});
|
||||
setTimeout(function () {
|
||||
setState({
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: ""
|
||||
});
|
||||
setTimeout(() => {
|
||||
setState({ loading: false, alertMsg: "" });
|
||||
}, 2000);
|
||||
}
|
||||
} else {
|
||||
setState({
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: "User Role Not Found!"
|
||||
alertMsg: "You don't have access, please contact the admin."
|
||||
});
|
||||
setTimeout(function () {
|
||||
setState({
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: ""
|
||||
});
|
||||
setTimeout(() => {
|
||||
setState({ loading: false, alertMsg: "" });
|
||||
}, 2000);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("err", err);
|
||||
setState({
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg:
|
||||
"Does not have permissions to access this application!"
|
||||
});
|
||||
setTimeout(function () {
|
||||
setState({
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: ""
|
||||
});
|
||||
}, 2000);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("error in fetch extuser", error);
|
||||
setState({
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: "You don't have access, please contact the admin."
|
||||
});
|
||||
}
|
||||
setTimeout(() => {
|
||||
setState({ loading: false, alertMsg: "" });
|
||||
}, 2000);
|
||||
});
|
||||
} catch (error) {
|
||||
// alert(`${error.message}`);
|
||||
setState({
|
||||
@@ -458,12 +276,8 @@ const Signup = () => {
|
||||
alertType: "danger",
|
||||
alertMsg: `${error.message}`
|
||||
});
|
||||
setTimeout(function () {
|
||||
setState({
|
||||
loading: false,
|
||||
alertType: "danger",
|
||||
alertMsg: ""
|
||||
});
|
||||
setTimeout(() => {
|
||||
setState({ loading: false, alertMsg: "" });
|
||||
}, 2000);
|
||||
console.log(error);
|
||||
}
|
||||
@@ -477,9 +291,9 @@ const Signup = () => {
|
||||
|
||||
const saveLogo = async () => {
|
||||
if (isEnableSubscription) {
|
||||
const logo = await getAppLogo();
|
||||
if (logo) {
|
||||
setImage(logo);
|
||||
const app = await getAppLogo();
|
||||
if (app?.logo) {
|
||||
setImage(app?.logo);
|
||||
} else {
|
||||
setImage(appInfo?.applogo || undefined);
|
||||
}
|
||||
@@ -601,9 +415,9 @@ const Signup = () => {
|
||||
onClick={togglePasswordVisibility}
|
||||
>
|
||||
{showPassword ? (
|
||||
<i className="fa fa-eye-slash" /> // Close eye icon
|
||||
<i className="fa-light fa-eye-slash" /> // Close eye icon
|
||||
) : (
|
||||
<i className="fa fa-eye" /> // Open eye icon
|
||||
<i className="fa-light fa-eye" /> // Open eye icon
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useState, useRef, useEffect } from "react";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
import "../styles/signature.css";
|
||||
import Parse from "parse";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import Confetti from "react-confetti";
|
||||
import axios from "axios";
|
||||
import LoaderWithMsg from "../primitives/LoaderWithMsg";
|
||||
@@ -71,8 +70,8 @@ function SignYourSelf() {
|
||||
const signRef = useRef(null);
|
||||
const dragRef = useRef(null);
|
||||
const [dragKey, setDragKey] = useState();
|
||||
const [fontSize, setFontSize] = useState(11);
|
||||
const [fontColor, setFontColor] = useState("black");
|
||||
const [fontSize, setFontSize] = useState();
|
||||
const [fontColor, setFontColor] = useState();
|
||||
const [signKey, setSignKey] = useState();
|
||||
const [imgWH, setImgWH] = useState({});
|
||||
const [pdfNewWidth, setPdfNewWidth] = useState();
|
||||
@@ -264,9 +263,9 @@ function SignYourSelf() {
|
||||
}
|
||||
await axios
|
||||
.get(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Signature?where={"UserId": {"__type": "Pointer","className": "_User", "objectId":"${
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/contracts_Signature?where={"UserId": {"__type": "Pointer","className": "_User", "objectId":"${
|
||||
jsonSender.objectId
|
||||
}"}}`,
|
||||
{
|
||||
@@ -739,7 +738,7 @@ function SignYourSelf() {
|
||||
if (
|
||||
tenantDetails?.CompletionBody &&
|
||||
tenantDetails?.CompletionSubject &&
|
||||
(!isEnableSubscription || getIsSubscribe)
|
||||
getIsSubscribe
|
||||
) {
|
||||
isCustomCompletionMail = true;
|
||||
}
|
||||
@@ -809,6 +808,8 @@ function SignYourSelf() {
|
||||
};
|
||||
//function for set and update x and y postion after drag and drop signature tab
|
||||
const handleStop = (event, dragElement) => {
|
||||
setFontSize();
|
||||
setFontColor();
|
||||
if (isDragging && dragElement) {
|
||||
event.preventDefault();
|
||||
const getPdfPageWidth = pdfOriginalWH.find(
|
||||
@@ -1028,9 +1029,9 @@ function SignYourSelf() {
|
||||
}
|
||||
await axios
|
||||
.put(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}${contractName}/${signerUserId}`,
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/contracts${contractName}/${signerUserId}`,
|
||||
{
|
||||
TourStatus: updatedTourStatus
|
||||
},
|
||||
@@ -1134,8 +1135,10 @@ function SignYourSelf() {
|
||||
...position,
|
||||
options: {
|
||||
...position.options,
|
||||
fontSize: fontSize || currWidgetsDetails?.options?.fontSize,
|
||||
fontColor: fontColor || currWidgetsDetails?.options?.fontColor
|
||||
fontSize:
|
||||
fontSize || currWidgetsDetails?.options?.fontSize || "12",
|
||||
fontColor:
|
||||
fontColor || currWidgetsDetails?.options?.fontColor || "black"
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1153,7 +1156,6 @@ function SignYourSelf() {
|
||||
handleTextSettingModal(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<Title title={"Self Sign"} />
|
||||
|
||||
@@ -0,0 +1,465 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Parse from "parse";
|
||||
import Alert from "../primitives/Alert";
|
||||
import Loader from "../primitives/Loader";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import Tooltip from "../primitives/Tooltip";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import pad from "../assets/images/pad.svg";
|
||||
import AddTeam from "../components/AddTeam";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { checkIsSubscribedTeam } from "../constant/Utils";
|
||||
import SubscribeCard from "../primitives/SubscribeCard";
|
||||
import Title from "../components/Title";
|
||||
|
||||
const heading = ["Sr.No", "Name", "Parent Team", "Active"];
|
||||
const actions = [
|
||||
{
|
||||
btnId: "1231",
|
||||
hoverLabel: "Edit",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-pen",
|
||||
redirectUrl: "",
|
||||
action: "edit"
|
||||
}
|
||||
];
|
||||
|
||||
const TeamList = () => {
|
||||
const recordperPage = 10;
|
||||
const [teamList, setTeamList] = useState([]);
|
||||
const [isLoader, setIsLoader] = useState(false);
|
||||
const [isModal, setIsModal] = useState(false);
|
||||
const location = useLocation();
|
||||
const isDashboard =
|
||||
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [isActiveModal, setIsActiveModal] = useState({});
|
||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||
const [isActLoader, setIsActLoader] = useState({});
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
const [isEditModal, setIsEditModal] = useState({});
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
const startIndex = (currentPage - 1) * recordperPage; // user per page
|
||||
|
||||
const getPaginationRange = () => {
|
||||
const totalPageNumbers = 7; // Adjust this value to show more/less page numbers
|
||||
const pages = [];
|
||||
const totalPages = Math.ceil(teamList.length / recordperPage);
|
||||
if (totalPages <= totalPageNumbers) {
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
} else {
|
||||
const leftSiblingIndex = Math.max(currentPage - 1, 1);
|
||||
const rightSiblingIndex = Math.min(currentPage + 1, totalPages);
|
||||
|
||||
const showLeftDots = leftSiblingIndex > 2;
|
||||
const showRightDots = rightSiblingIndex < totalPages - 2;
|
||||
|
||||
const firstPageIndex = 1;
|
||||
const lastPageIndex = totalPages;
|
||||
|
||||
if (!showLeftDots && showRightDots) {
|
||||
let leftItemCount = 3;
|
||||
let leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1);
|
||||
|
||||
pages.push(...leftRange);
|
||||
pages.push("...");
|
||||
pages.push(totalPages);
|
||||
} else if (showLeftDots && !showRightDots) {
|
||||
let rightItemCount = 3;
|
||||
let rightRange = Array.from(
|
||||
{ length: rightItemCount },
|
||||
(_, i) => totalPages - rightItemCount + i + 1
|
||||
);
|
||||
|
||||
pages.push(firstPageIndex);
|
||||
pages.push("...");
|
||||
pages.push(...rightRange);
|
||||
} else if (showLeftDots && showRightDots) {
|
||||
let middleRange = Array.from(
|
||||
{ length: 3 },
|
||||
(_, i) => leftSiblingIndex + i
|
||||
);
|
||||
|
||||
pages.push(firstPageIndex);
|
||||
pages.push("...");
|
||||
pages.push(...middleRange);
|
||||
pages.push("...");
|
||||
pages.push(lastPageIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return pages;
|
||||
};
|
||||
const pageNumbers = getPaginationRange();
|
||||
useEffect(() => {
|
||||
fetchTeamList();
|
||||
}, []);
|
||||
async function fetchTeamList() {
|
||||
try {
|
||||
setIsLoader(true);
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribedTeam();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
}
|
||||
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||
if (extUser) {
|
||||
const admin =
|
||||
extUser?.UserRole &&
|
||||
(extUser?.UserRole === "contracts_Admin" ||
|
||||
extUser?.UserRole === "contracts_OrgAdmin")
|
||||
? true
|
||||
: false;
|
||||
setIsAdmin(admin);
|
||||
}
|
||||
const teams = await Parse.Cloud.run("getteams");
|
||||
if (teams.length > 0) {
|
||||
const _teamRes = JSON.parse(JSON.stringify(teams));
|
||||
setTeamList(_teamRes);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err in fetch teamlist", err);
|
||||
setIsAlert({ type: "danger", msg: "Something went wrong." });
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
setIsAlert({ type: "success", msg: "" });
|
||||
}, 1500);
|
||||
setIsLoader(false);
|
||||
}
|
||||
}
|
||||
const handleFormModal = () => {
|
||||
setIsModal(!isModal);
|
||||
};
|
||||
// Get current list
|
||||
const indexOfLastDoc = currentPage * recordperPage;
|
||||
const indexOfFirstDoc = indexOfLastDoc - recordperPage;
|
||||
const currentList = teamList?.slice(indexOfFirstDoc, indexOfLastDoc);
|
||||
|
||||
const handleClose = () => {
|
||||
setIsActiveModal({});
|
||||
setIsEditModal({});
|
||||
};
|
||||
|
||||
// Change page
|
||||
const paginateFront = () => setCurrentPage(currentPage + 1);
|
||||
const paginateBack = () => setCurrentPage(currentPage - 1);
|
||||
const handleActionBtn = (act, item) => {
|
||||
if (act.action === "edit") {
|
||||
setIsEditModal({ [item.objectId]: true });
|
||||
}
|
||||
};
|
||||
const handleToggleBtn = (team) => {
|
||||
setIsActiveModal({ [team.objectId]: true });
|
||||
};
|
||||
const handleToggleSubmit = async (team) => {
|
||||
const index = teamList.findIndex((obj) => obj.objectId === team.objectId);
|
||||
if (index !== -1) {
|
||||
setIsActiveModal({});
|
||||
setIsActLoader({ [team.objectId]: true });
|
||||
const newArray = [...teamList];
|
||||
const IsActive = newArray[index].IsActive;
|
||||
newArray[index] = { ...newArray[index], IsActive: !IsActive };
|
||||
setTeamList(newArray);
|
||||
try {
|
||||
await Parse.Cloud.run("updateteam", {
|
||||
IsActive: !IsActive,
|
||||
TeamId: team.objectId
|
||||
});
|
||||
// console.log("teamRes ", teamRes);
|
||||
setIsAlert({
|
||||
type: !IsActive === false ? "danger" : "success",
|
||||
msg: !IsActive === false ? "Team disabled." : "Team enabled."
|
||||
});
|
||||
} catch (err) {
|
||||
setIsAlert({ type: "danger", msg: "something went wrong." });
|
||||
console.log("err in disable team", err);
|
||||
} finally {
|
||||
setIsActLoader({});
|
||||
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleTeamInfo = (team) => {
|
||||
setTeamList((prev) => [team, ...prev]);
|
||||
};
|
||||
const handleEditChange = (e, team) => {
|
||||
const index = teamList.findIndex((obj) => obj.objectId === team.objectId);
|
||||
if (index !== -1) {
|
||||
const newArray = [...teamList];
|
||||
newArray[index] = { ...newArray[index], Name: e.target.value };
|
||||
setTeamList(newArray);
|
||||
}
|
||||
};
|
||||
const updateTeamName = async (e, team) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsActLoader({ [team.objectId]: true });
|
||||
setIsEditModal({});
|
||||
try {
|
||||
const data = { Name: team.Name, TeamId: team.objectId };
|
||||
await Parse.Cloud.run("updateteam", data);
|
||||
// console.log("updateTeamRes ", updateTeamRes);
|
||||
setIsAlert({ type: "success", msg: "Team Update successfully." });
|
||||
} catch (Err) {
|
||||
console.log("Err in update team name"), Err;
|
||||
setIsAlert({ type: "danger", msg: "Something went wrong." });
|
||||
} finally {
|
||||
setIsActLoader({});
|
||||
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="relative">
|
||||
<Title title={"Teams"} />
|
||||
{isLoader && (
|
||||
<div className="absolute w-full h-[300px] md:h-[400px] flex justify-center items-center z-30 rounded-box">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
{Object.keys(isActLoader)?.length > 0 && (
|
||||
<div className="absolute w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-30 rounded-box">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
{isSubscribe && isEnableSubscription && !isLoader && (
|
||||
<>
|
||||
{isAdmin ? (
|
||||
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
|
||||
{isAlert.msg && (
|
||||
<Alert type={isAlert.type}>
|
||||
<div className="ml-3">{isAlert.msg}</div>
|
||||
</Alert>
|
||||
)}
|
||||
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
||||
<div className="font-light">
|
||||
Teams{" "}
|
||||
<span className="text-xs md:text-[13px] font-normal">
|
||||
<Tooltip message={"Teams"} />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="cursor-pointer"
|
||||
onClick={() => handleFormModal()}
|
||||
>
|
||||
<i className="fa-light fa-square-plus text-accent text-[40px]"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div className={` overflow-x-auto w-full`}>
|
||||
<table className="op-table border-collapse w-full">
|
||||
<thead className="text-[14px]">
|
||||
<tr className="border-y-[1px]">
|
||||
{heading?.map((item, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<th className="px-4 py-2">{item}</th>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-[12px]">
|
||||
{teamList?.length > 0 && (
|
||||
<>
|
||||
{currentList.map((item, index) => (
|
||||
<tr className="border-y-[1px]" key={index}>
|
||||
{heading.includes("Sr.No") && (
|
||||
<th className="px-4 py-2">
|
||||
{startIndex + index + 1}
|
||||
</th>
|
||||
)}
|
||||
<td className="px-4 py-2 font-semibold">
|
||||
{item?.Name}
|
||||
</td>
|
||||
<td className="px-4 py-2 font-semibold">
|
||||
{item?.ParentId?.Name || "-"}
|
||||
</td>
|
||||
<td className="px-4 py-2 font-semibold">
|
||||
{item?.Name !== "All Users" && (
|
||||
<>
|
||||
<label className="cursor-pointer relative block items-center mb-0">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="op-toggle transition-all op-toggle-secondary"
|
||||
checked={item?.IsActive}
|
||||
onChange={() => handleToggleBtn(item)}
|
||||
/>
|
||||
</label>
|
||||
{isActiveModal[item.objectId] && (
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={"Team status"}
|
||||
handleClose={handleClose}
|
||||
>
|
||||
<div className="m-[20px]">
|
||||
<div className="text-lg font-normal text-black">
|
||||
Are you sure you want to{" "}
|
||||
{item?.IsActive
|
||||
? "disable"
|
||||
: "enable"}{" "}
|
||||
this team?
|
||||
</div>
|
||||
<hr className="bg-[#ccc] mt-4 " />
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<button
|
||||
onClick={() =>
|
||||
handleToggleSubmit(item)
|
||||
}
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
onClick={handleClose}
|
||||
className="op-btn op-btn-secondary"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalUi>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-3 py-2 text-white flex flex-wrap gap-1">
|
||||
{item?.Name !== "All Users" && (
|
||||
<>
|
||||
{actions?.length > 0 &&
|
||||
actions.map((act, index) => (
|
||||
<button
|
||||
key={index}
|
||||
onClick={() =>
|
||||
handleActionBtn(act, item)
|
||||
}
|
||||
title={act.hoverLabel}
|
||||
className={`${
|
||||
act?.btnColor ? act.btnColor : ""
|
||||
} op-btn op-btn-sm w-[50px]`}
|
||||
>
|
||||
<i className={act.btnIcon}></i>
|
||||
</button>
|
||||
))}
|
||||
{isEditModal[item.objectId] && (
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={"Edit Team"}
|
||||
handleClose={handleClose}
|
||||
>
|
||||
<form
|
||||
className="m-[20px]"
|
||||
onSubmit={(e) =>
|
||||
updateTeamName(e, item)
|
||||
}
|
||||
>
|
||||
<label className="text-xs font-semibold text-base-content ml-1">
|
||||
Name of Team{" "}
|
||||
<span className="text-[red] text-[13px]">
|
||||
*
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-base-content w-full text-xs"
|
||||
value={item.Name}
|
||||
onChange={(e) =>
|
||||
handleEditChange(e, item)
|
||||
}
|
||||
required
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="op-btn op-btn-primary mt-3"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</form>
|
||||
</ModalUi>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="op-join flex flex-wrap items-center p-2">
|
||||
{teamList.length > recordperPage && (
|
||||
<button
|
||||
onClick={() => paginateBack()}
|
||||
className="op-join-item op-btn op-btn-sm"
|
||||
>
|
||||
Prev
|
||||
</button>
|
||||
)}
|
||||
{pageNumbers.map((x, i) => (
|
||||
<button
|
||||
key={i}
|
||||
onClick={() => setCurrentPage(x)}
|
||||
disabled={x === "..."}
|
||||
className={`${
|
||||
x === currentPage ? "op-btn-active" : ""
|
||||
} op-join-item op-btn op-btn-sm`}
|
||||
>
|
||||
{x}
|
||||
</button>
|
||||
))}
|
||||
{teamList.length > recordperPage && (
|
||||
<button
|
||||
onClick={() => paginateFront()}
|
||||
className="op-join-item op-btn op-btn-sm"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{teamList?.length <= 0 && (
|
||||
<div
|
||||
className={`${
|
||||
isDashboard ? "h-[317px]" : ""
|
||||
} flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`}
|
||||
>
|
||||
<div className="w-[60px] h-[60px] overflow-hidden">
|
||||
<img
|
||||
className="w-full h-full object-contain"
|
||||
src={pad}
|
||||
alt="img"
|
||||
/>
|
||||
</div>
|
||||
<div className="text-sm font-semibold">No Data Available</div>
|
||||
</div>
|
||||
)}
|
||||
<ModalUi
|
||||
title={"Add Team"}
|
||||
isOpen={isModal}
|
||||
handleClose={handleFormModal}
|
||||
>
|
||||
<AddTeam
|
||||
setIsAlert={setIsAlert}
|
||||
handleTeamInfo={handleTeamInfo}
|
||||
closePopup={handleFormModal}
|
||||
/>
|
||||
</ModalUi>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
|
||||
<div className="text-center">
|
||||
<h1 className="text-[60px] lg:text-[120px] font-semibold">
|
||||
404
|
||||
</h1>
|
||||
<p className="text-[30px] lg:text-[50px]">Page Not Found</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!isSubscribe && isEnableSubscription && !isLoader && (
|
||||
<div data-tut="apisubscribe">
|
||||
<SubscribeCard plan={"TEAMS"} price={"20"} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TeamList;
|
||||
@@ -38,7 +38,6 @@ import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
||||
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
||||
import Parse from "parse";
|
||||
import { useSelector } from "react-redux";
|
||||
import TextFontSetting from "../components/pdf/TextFontSetting";
|
||||
import PdfZoom from "../components/pdf/PdfZoom";
|
||||
const TemplatePlaceholder = () => {
|
||||
const navigate = useNavigate();
|
||||
@@ -389,7 +388,6 @@ const TemplatePlaceholder = () => {
|
||||
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
|
||||
key: key,
|
||||
scale: containerScale,
|
||||
// isMobile: isMobile,
|
||||
zIndex: posZIndex,
|
||||
type: dragTypeValue,
|
||||
options: addWidgetOptions(dragTypeValue),
|
||||
@@ -501,6 +499,8 @@ const TemplatePlaceholder = () => {
|
||||
setShowDropdown(true);
|
||||
} else if (dragTypeValue === "checkbox") {
|
||||
setIsCheckbox(true);
|
||||
} else if (dragTypeValue === radioButtonWidget) {
|
||||
setIsRadio(true);
|
||||
} else if (
|
||||
[textInputWidget, "name", "company", "job title", "email"].includes(
|
||||
dragTypeValue
|
||||
@@ -508,8 +508,6 @@ const TemplatePlaceholder = () => {
|
||||
) {
|
||||
setFontSize(12);
|
||||
setFontColor("black");
|
||||
} else if (dragTypeValue === radioButtonWidget) {
|
||||
setIsRadio(true);
|
||||
}
|
||||
setCurrWidgetsDetails({});
|
||||
setWidgetType(dragTypeValue);
|
||||
@@ -555,6 +553,8 @@ const TemplatePlaceholder = () => {
|
||||
|
||||
//function for set and update x and y postion after drag and drop signature tab
|
||||
const handleStop = (event, dragElement, signerId, key) => {
|
||||
setFontColor();
|
||||
setFontSize();
|
||||
if (!isResize && isDragging) {
|
||||
const dataNewPlace = addZIndex(signerPos, key, setZIndex);
|
||||
let updateSignPos = [...signerPos];
|
||||
@@ -615,7 +615,6 @@ const TemplatePlaceholder = () => {
|
||||
setIsDragging(false);
|
||||
}, 200);
|
||||
};
|
||||
|
||||
//function for delete signature block
|
||||
const handleDeleteSign = (key, Id) => {
|
||||
const updateData = [];
|
||||
@@ -851,7 +850,6 @@ const TemplatePlaceholder = () => {
|
||||
const closeTour = async () => {
|
||||
setTemplateTour(false);
|
||||
if (isDontShow) {
|
||||
const extUserClass = localStorage.getItem("extended_class");
|
||||
let updatedTourStatus = [];
|
||||
if (tourStatus.length > 0) {
|
||||
updatedTourStatus = [...tourStatus];
|
||||
@@ -870,7 +868,7 @@ const TemplatePlaceholder = () => {
|
||||
.put(
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}classes/${extUserClass}/${signerUserId}`,
|
||||
)}classes/contracts_Users/${signerUserId}`,
|
||||
{
|
||||
TourStatus: updatedTourStatus
|
||||
},
|
||||
@@ -1199,13 +1197,19 @@ const TemplatePlaceholder = () => {
|
||||
hint: defaultdata?.hint || "",
|
||||
defaultValue: defaultdata?.defaultValue || "",
|
||||
validation:
|
||||
(isSubscribe || !isEnableSubscription) && inputype
|
||||
isSubscribe && inputype
|
||||
? {
|
||||
type: inputype,
|
||||
pattern:
|
||||
inputype === "regex" ? defaultdata.textvalidate : ""
|
||||
}
|
||||
: {}
|
||||
: {},
|
||||
fontSize:
|
||||
fontSize || currWidgetsDetails?.options?.fontSize || "12",
|
||||
fontColor:
|
||||
fontColor ||
|
||||
currWidgetsDetails?.options?.fontColor ||
|
||||
"black"
|
||||
}
|
||||
};
|
||||
} else {
|
||||
@@ -1215,7 +1219,13 @@ const TemplatePlaceholder = () => {
|
||||
...position.options,
|
||||
name: defaultdata.name,
|
||||
status: defaultdata.status,
|
||||
defaultValue: defaultdata.defaultValue
|
||||
defaultValue: defaultdata.defaultValue,
|
||||
fontSize:
|
||||
fontSize || currWidgetsDetails?.options?.fontSize || "12",
|
||||
fontColor:
|
||||
fontColor ||
|
||||
currWidgetsDetails?.options?.fontColor ||
|
||||
"black"
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1238,6 +1248,8 @@ const TemplatePlaceholder = () => {
|
||||
setSignerPos(newUpdateSigner);
|
||||
}
|
||||
}
|
||||
setFontSize();
|
||||
setFontColor();
|
||||
setCurrWidgetsDetails({});
|
||||
handleNameModal();
|
||||
};
|
||||
@@ -1249,55 +1261,6 @@ const TemplatePlaceholder = () => {
|
||||
setIsCheckbox(false);
|
||||
};
|
||||
|
||||
const handleSaveFontSize = () => {
|
||||
const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
|
||||
if (filterSignerPos.length > 0) {
|
||||
const getPlaceHolder = filterSignerPos[0].placeHolder;
|
||||
|
||||
const getPageNumer = getPlaceHolder.filter(
|
||||
(data) => data.pageNumber === pageNumber
|
||||
);
|
||||
|
||||
if (getPageNumer.length > 0) {
|
||||
const getXYdata = getPageNumer[0].pos;
|
||||
const getPosData = getXYdata;
|
||||
const addSignPos = getPosData.map((position) => {
|
||||
if (position.key === signKey) {
|
||||
return {
|
||||
...position,
|
||||
options: {
|
||||
...position.options,
|
||||
fontSize: fontSize,
|
||||
fontColor: fontColor
|
||||
}
|
||||
};
|
||||
}
|
||||
return position;
|
||||
});
|
||||
|
||||
const newUpdateSignPos = getPlaceHolder.map((obj) => {
|
||||
if (obj.pageNumber === pageNumber) {
|
||||
return { ...obj, pos: addSignPos };
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
const newUpdateSigner = signerPos.map((obj) => {
|
||||
if (obj.Id === uniqueId) {
|
||||
return { ...obj, placeHolder: newUpdateSignPos };
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
setSignerPos(newUpdateSigner);
|
||||
}
|
||||
}
|
||||
setFontSize();
|
||||
setFontColor();
|
||||
|
||||
handleTextSettingModal(false);
|
||||
};
|
||||
const handleTextSettingModal = (value) => {
|
||||
setIsTextSetting(value);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Title title={"Template"} />
|
||||
@@ -1399,6 +1362,7 @@ const TemplatePlaceholder = () => {
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsCreateDocModal(false);
|
||||
navigate("/report/6TeaPr321t");
|
||||
}}
|
||||
type="button"
|
||||
className="op-btn op-btn-secondary ml-2"
|
||||
@@ -1532,10 +1496,10 @@ const TemplatePlaceholder = () => {
|
||||
selectWidgetId={selectWidgetId}
|
||||
setIsCheckbox={setIsCheckbox}
|
||||
handleNameModal={setIsNameModal}
|
||||
handleTextSettingModal={handleTextSettingModal}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
setIsSelectId={setIsSelectId}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -1591,6 +1555,7 @@ const TemplatePlaceholder = () => {
|
||||
<SignerListPlace
|
||||
isMailSend={isMailSend}
|
||||
signerPos={signerPos}
|
||||
setSignerPos={setSignerPos}
|
||||
signersdata={signersdata}
|
||||
isSelectListId={isSelectListId}
|
||||
setSignerObjId={setSignerObjId}
|
||||
@@ -1607,6 +1572,7 @@ const TemplatePlaceholder = () => {
|
||||
setSignersData={setSignersData}
|
||||
blockColor={blockColor}
|
||||
setBlockColor={setBlockColor}
|
||||
uniqueId={uniqueId}
|
||||
/>
|
||||
<div data-tut="addWidgets">
|
||||
<WidgetComponent
|
||||
@@ -1669,16 +1635,12 @@ const TemplatePlaceholder = () => {
|
||||
handleClose={handleNameModal}
|
||||
handleData={handleWidgetdefaultdata}
|
||||
isSubscribe={isSubscribe}
|
||||
/>
|
||||
<TextFontSetting
|
||||
isTextSetting={isTextSetting}
|
||||
setIsTextSetting={setIsTextSetting}
|
||||
fontSize={fontSize}
|
||||
setFontSize={setFontSize}
|
||||
fontColor={fontColor}
|
||||
setFontColor={setFontColor}
|
||||
handleSaveFontSize={handleSaveFontSize}
|
||||
currWidgetsDetails={currWidgetsDetails}
|
||||
/>
|
||||
</DndProvider>
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Loader from "../primitives/Loader";
|
||||
import Parse from "parse";
|
||||
import { NavLink, useNavigate } from "react-router-dom";
|
||||
import Alert from "../primitives/Alert";
|
||||
import Title from "../components/Title";
|
||||
|
||||
const UpdateExistUserAdmin = () => {
|
||||
const navigate = useNavigate();
|
||||
const [formdata, setFormdata] = useState({ email: "", masterkey: "" });
|
||||
const [loader, setLoader] = useState(true);
|
||||
const [errMsg, setErrMsg] = useState("");
|
||||
const [isSubmitLoading, setIsSubmitLoading] = useState(false);
|
||||
const [isAlert, setIsAlert] = useState({ type: "danger", msg: "" });
|
||||
useEffect(() => {
|
||||
checkIsAdminExist();
|
||||
}, []);
|
||||
|
||||
const checkIsAdminExist = async () => {
|
||||
try {
|
||||
const isAdminExist = await Parse.Cloud.run("checkadminexist");
|
||||
if (isAdminExist !== "not_exist") {
|
||||
console.log("isAdminExist ", isAdminExist);
|
||||
setErrMsg("Admin already exists.");
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err in checkadminexist", err);
|
||||
setErrMsg("Something went wrong.");
|
||||
} finally {
|
||||
setLoader(false);
|
||||
}
|
||||
};
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsSubmitLoading(true);
|
||||
try {
|
||||
const updateUserAsAdmin = await Parse.Cloud.run(
|
||||
"updateuserasadmin",
|
||||
formdata
|
||||
);
|
||||
// console.log("updateUserAsAdmin ", updateUserAsAdmin);
|
||||
if (updateUserAsAdmin === "admin_created") {
|
||||
setIsAlert({ type: "success", msg: "Admin created" });
|
||||
navigate("/");
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err in updateuserasadmin", err.code);
|
||||
if (err.code === 404) {
|
||||
setIsAlert((prev) => ({ ...prev, msg: "Invalid masterkey" }));
|
||||
} else if (err.code === 101) {
|
||||
setIsAlert((prev) => ({ ...prev, msg: "User not found" }));
|
||||
} else if (err.code === 137) {
|
||||
setIsAlert((prev) => ({ ...prev, msg: "Admin already exist" }));
|
||||
} else {
|
||||
setErrMsg("Something went wrong.");
|
||||
}
|
||||
} finally {
|
||||
setIsSubmitLoading(false);
|
||||
setTimeout(() => {
|
||||
setIsAlert(() => ({ type: "danger", msg: "" }));
|
||||
}, 2000);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="h-screen flex justify-center">
|
||||
<Title title={"Add Admin"} />
|
||||
{isAlert.msg && (
|
||||
<Alert type={isAlert.type}>
|
||||
<div className="ml-3">{isAlert.msg}</div>
|
||||
</Alert>
|
||||
)}
|
||||
{loader ? (
|
||||
<div className="text-[grey] flex justify-center items-center text-lg md:text-2xl">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{errMsg ? (
|
||||
<div className="text-[grey] flex justify-center items-center text-lg md:text-2xl">
|
||||
{errMsg}
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-[95%] md:w-[500px]">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="w-full my-4 op-card bg-base-100 shadow-md outline outline-1 outline-slate-300/50 overflow-hidden">
|
||||
{isSubmitLoading && (
|
||||
<div className="absolute z-40 w-full h-full flex justify-center bg-black/30">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
<h2 className="text-[30px] text-center mt-3 font-medium">
|
||||
Opensign Setup
|
||||
</h2>
|
||||
<NavLink
|
||||
to="https://discord.com/invite/xe9TDuyAyj"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-center text-sm mt-1 text-[blue] cursor-pointer"
|
||||
>
|
||||
Join our discord server
|
||||
<i
|
||||
aria-hidden="true"
|
||||
className="fa-brands fa-discord ml-1"
|
||||
></i>
|
||||
{/* <span className="fa-sr-only">OpenSign's Discord</span> */}
|
||||
</NavLink>
|
||||
<div className="px-6 py-3 text-xs">
|
||||
<label>
|
||||
Email <span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={formdata.email}
|
||||
onChange={(e) =>
|
||||
setFormdata((prev) => ({
|
||||
...prev,
|
||||
email: e.target.value?.toLowerCase()
|
||||
}))
|
||||
}
|
||||
required
|
||||
/>
|
||||
<hr className="my-2 border-none" />
|
||||
<label>
|
||||
Master key{" "}
|
||||
<span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={formdata.masterkey}
|
||||
onChange={(e) =>
|
||||
setFormdata((prev) => ({
|
||||
...prev,
|
||||
masterkey: e.target.value
|
||||
}))
|
||||
}
|
||||
required
|
||||
/>
|
||||
|
||||
{/*
|
||||
<div className="mt-2.5 ml-1 flex flex-row items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="op-checkbox op-checkbox-sm"
|
||||
id="termsandcondition"
|
||||
checked={isSubscribeNews}
|
||||
onChange={(e) => setIsSubscribeNews(e.target.checked)}
|
||||
/>
|
||||
<label
|
||||
className="text-xs cursor-pointer ml-1 mb-0"
|
||||
htmlFor="termsandcondition"
|
||||
>
|
||||
Subscribe to OpenSign newsletter
|
||||
</label>
|
||||
</div> */}
|
||||
</div>
|
||||
<div className="mx-4 text-center text-xs font-bold mb-3">
|
||||
<button
|
||||
type="submit"
|
||||
className="op-btn op-btn-primary w-full"
|
||||
disabled={loader}
|
||||
>
|
||||
{loader ? "Loading..." : "Next"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateExistUserAdmin;
|
||||
@@ -0,0 +1,426 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Parse from "parse";
|
||||
import Alert from "../primitives/Alert";
|
||||
import Loader from "../primitives/Loader";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import pad from "../assets/images/pad.svg";
|
||||
import Tooltip from "../primitives/Tooltip";
|
||||
import AddUser from "../components/AddUser";
|
||||
import SubscribeCard from "../primitives/SubscribeCard";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { checkIsSubscribedTeam } from "../constant/Utils";
|
||||
import Title from "../components/Title";
|
||||
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"];
|
||||
// const actions = [];
|
||||
const UserList = () => {
|
||||
const [userList, setUserList] = useState([]);
|
||||
const [isLoader, setIsLoader] = useState(false);
|
||||
const [isModal, setIsModal] = useState(false);
|
||||
const location = useLocation();
|
||||
const isDashboard =
|
||||
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||
const [isActiveModal, setIsActiveModal] = useState({});
|
||||
const [isActLoader, setIsActLoader] = useState({});
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
const recordperPage = 10;
|
||||
const startIndex = (currentPage - 1) * recordperPage; // user per page
|
||||
|
||||
const getPaginationRange = () => {
|
||||
const totalPageNumbers = 7; // Adjust this value to show more/less page numbers
|
||||
const pages = [];
|
||||
const totalPages = Math.ceil(userList.length / recordperPage);
|
||||
if (totalPages <= totalPageNumbers) {
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
} else {
|
||||
const leftSiblingIndex = Math.max(currentPage - 1, 1);
|
||||
const rightSiblingIndex = Math.min(currentPage + 1, totalPages);
|
||||
|
||||
const showLeftDots = leftSiblingIndex > 2;
|
||||
const showRightDots = rightSiblingIndex < totalPages - 2;
|
||||
|
||||
const firstPageIndex = 1;
|
||||
const lastPageIndex = totalPages;
|
||||
|
||||
if (!showLeftDots && showRightDots) {
|
||||
let leftItemCount = 3;
|
||||
let leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1);
|
||||
|
||||
pages.push(...leftRange);
|
||||
pages.push("...");
|
||||
pages.push(totalPages);
|
||||
} else if (showLeftDots && !showRightDots) {
|
||||
let rightItemCount = 3;
|
||||
let rightRange = Array.from(
|
||||
{ length: rightItemCount },
|
||||
(_, i) => totalPages - rightItemCount + i + 1
|
||||
);
|
||||
|
||||
pages.push(firstPageIndex);
|
||||
pages.push("...");
|
||||
pages.push(...rightRange);
|
||||
} else if (showLeftDots && showRightDots) {
|
||||
let middleRange = Array.from(
|
||||
{ length: 3 },
|
||||
(_, i) => leftSiblingIndex + i
|
||||
);
|
||||
|
||||
pages.push(firstPageIndex);
|
||||
pages.push("...");
|
||||
pages.push(...middleRange);
|
||||
pages.push("...");
|
||||
pages.push(lastPageIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return pages;
|
||||
};
|
||||
const pageNumbers = getPaginationRange();
|
||||
useEffect(() => {
|
||||
fetchUserList();
|
||||
}, []);
|
||||
async function fetchUserList() {
|
||||
try {
|
||||
setIsLoader(true);
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribedTeam();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
} else {
|
||||
setIsSubscribe(true);
|
||||
}
|
||||
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||
if (extUser) {
|
||||
const admin =
|
||||
extUser?.UserRole &&
|
||||
(extUser?.UserRole === "contracts_Admin" ||
|
||||
extUser?.UserRole === "contracts_OrgAdmin")
|
||||
? true
|
||||
: false;
|
||||
setIsAdmin(admin);
|
||||
}
|
||||
const res = await Parse.Cloud.run("getuserlistbyorg", {
|
||||
organizationId: extUser.OrganizationId.objectId
|
||||
});
|
||||
const _userRes = JSON.parse(JSON.stringify(res));
|
||||
setUserList(_userRes);
|
||||
} catch (err) {
|
||||
console.log("Err in fetch userlist", err);
|
||||
setIsAlert({ type: "danger", msg: "Something went wrong." });
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
setIsAlert({ type: "success", msg: "" });
|
||||
}, 1500);
|
||||
setIsLoader(false);
|
||||
}
|
||||
}
|
||||
const handleFormModal = () => {
|
||||
setIsModal(!isModal);
|
||||
};
|
||||
|
||||
// Change page
|
||||
const paginateFront = () => setCurrentPage(currentPage + 1);
|
||||
const paginateBack = () => setCurrentPage(currentPage - 1);
|
||||
// const handleActionBtn = (act, item) => {
|
||||
// if (act.action === "delete") {
|
||||
// setIsDeleteModal({ [item.objectId]: true });
|
||||
// }
|
||||
// };
|
||||
const handleUserData = (userData) => {
|
||||
setUserList((prev) => [userData, ...prev]);
|
||||
};
|
||||
// `formatRow` is used to show data in poper manner like
|
||||
// if data is of array type then it will join array items with ","
|
||||
// if data is of object type then it Name values will be show in row
|
||||
// if no data available it will show hyphen "-"
|
||||
const formatRow = (row) => {
|
||||
if (Array.isArray(row)) {
|
||||
let updateArr = row.map((x) => x.Name);
|
||||
return updateArr.join(", ");
|
||||
} else if (typeof row === "object" && row !== null) {
|
||||
return row?.Name || "-";
|
||||
} else {
|
||||
return "-";
|
||||
}
|
||||
};
|
||||
const handleClose = () => {
|
||||
setIsActiveModal({});
|
||||
};
|
||||
const handleToggleSubmit = async (user) => {
|
||||
const index = userList.findIndex((obj) => obj.objectId === user.objectId);
|
||||
if (index !== -1) {
|
||||
setIsActiveModal({});
|
||||
setIsActLoader({ [user.objectId]: true });
|
||||
const newArray = [...userList];
|
||||
const IsDisabled = newArray[index]?.IsDisabled;
|
||||
newArray[index] = { ...newArray[index], IsDisabled: !IsDisabled };
|
||||
setUserList(newArray);
|
||||
try {
|
||||
const extUser = new Parse.Object("contracts_Users");
|
||||
extUser.id = user.objectId;
|
||||
extUser.set("IsDisabled", !IsDisabled);
|
||||
await extUser.save();
|
||||
setIsAlert({
|
||||
type: !IsDisabled === true ? "danger" : "success",
|
||||
msg: !IsDisabled === true ? "User deactivated." : "User activated."
|
||||
});
|
||||
} catch (err) {
|
||||
setIsAlert({ type: "danger", msg: "something went wrong." });
|
||||
console.log("err in disable team", err);
|
||||
} finally {
|
||||
setIsActLoader({});
|
||||
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleToggleBtn = (user) => {
|
||||
setIsActiveModal({ [user.objectId]: true });
|
||||
};
|
||||
return (
|
||||
<div className="relative">
|
||||
<Title title={isAdmin ? "Users" : "Page not found"} />
|
||||
{isLoader && (
|
||||
<div className="absolute w-full h-[300px] md:h-[400px] flex justify-center items-center z-30 rounded-box">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
{Object.keys(isActLoader)?.length > 0 && (
|
||||
<div className="absolute w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-30 rounded-box">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
{isSubscribe && !isLoader && (
|
||||
<>
|
||||
{isAdmin ? (
|
||||
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
|
||||
{isAlert.msg && (
|
||||
<Alert type={isAlert.type}>
|
||||
<div className="ml-3">{isAlert.msg}</div>
|
||||
</Alert>
|
||||
)}
|
||||
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
||||
<div className="font-light">
|
||||
Users{" "}
|
||||
<span className="text-xs md:text-[13px] font-normal">
|
||||
<Tooltip message={"users from Teams"} />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="cursor-pointer"
|
||||
onClick={() => handleFormModal()}
|
||||
>
|
||||
<i className="fa-light fa-square-plus text-accent text-[40px]"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div className={` overflow-x-auto w-full`}>
|
||||
<table className="op-table border-collapse w-full">
|
||||
<thead className="text-[14px]">
|
||||
<tr className="border-y-[1px]">
|
||||
{heading?.map((item, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<th className="px-4 py-2">{item}</th>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-[12px]">
|
||||
{userList?.length > 0 && (
|
||||
<>
|
||||
{userList.map((item, index) => (
|
||||
<tr className="border-y-[1px]" key={index}>
|
||||
{heading.includes("Sr.No") && (
|
||||
<th className="px-4 py-2">
|
||||
{startIndex + index + 1}
|
||||
</th>
|
||||
)}
|
||||
<td className="px-4 py-2 font-semibold">
|
||||
{item?.Name}{" "}
|
||||
</td>
|
||||
<td className="px-4 py-2 ">{item?.Email || "-"}</td>
|
||||
<td className="px-4 py-2">{item?.Phone || "-"}</td>
|
||||
<td className="px-4 py-2">
|
||||
{item?.UserRole?.split("_").pop() || "-"}
|
||||
</td>
|
||||
<td className="px-4 py-2">
|
||||
{formatRow(item.TeamIds)}
|
||||
</td>
|
||||
{item.UserRole !== "contracts_Admin" && (
|
||||
<td className="px-4 py-2 font-semibold">
|
||||
<label className="cursor-pointer relative block items-center mb-0">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="op-toggle transition-all op-toggle-secondary"
|
||||
checked={item?.IsDisabled !== true}
|
||||
onChange={() => handleToggleBtn(item)}
|
||||
/>
|
||||
</label>
|
||||
{isActiveModal[item.objectId] && (
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={"User status"}
|
||||
handleClose={handleClose}
|
||||
>
|
||||
<div className="m-[20px]">
|
||||
<div className="text-lg font-normal text-black">
|
||||
Are you sure you want to{" "}
|
||||
{item?.IsDisabled
|
||||
? "activate"
|
||||
: "deactivate"}{" "}
|
||||
this user?
|
||||
</div>
|
||||
<hr className="bg-[#ccc] mt-4 " />
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<button
|
||||
onClick={() =>
|
||||
handleToggleSubmit(item)
|
||||
}
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
onClick={handleClose}
|
||||
className="op-btn op-btn-secondary"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalUi>
|
||||
)}
|
||||
</td>
|
||||
)}
|
||||
{/* <td className="px-3 py-2 text-white grid grid-cols-2">
|
||||
{actions?.length > 0 &&
|
||||
actions.map((act, index) => (
|
||||
<button
|
||||
key={index}
|
||||
onClick={() => handleActionBtn(act, item)}
|
||||
title={act.hoverLabel}
|
||||
className={`${
|
||||
act?.btnColor ? act.btnColor : ""
|
||||
} op-btn op-btn-sm`}
|
||||
>
|
||||
<i className={act.btnIcon}></i>
|
||||
</button>
|
||||
))}
|
||||
{isDeleteModal[item.objectId] && (
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={"Delete User"}
|
||||
handleClose={handleClose}
|
||||
>
|
||||
<div className="m-[20px]">
|
||||
<div className="text-lg font-normal text-black">
|
||||
Are you sure you want to delete this user?
|
||||
</div>
|
||||
<hr className="bg-[#ccc] mt-4 " />
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<button
|
||||
onClick={() => handleDelete(item)}
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
onClick={handleClose}
|
||||
className="op-btn op-btn-secondary"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalUi>
|
||||
)}
|
||||
</td> */}
|
||||
</tr>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="op-join flex flex-wrap items-center p-2">
|
||||
{userList.length > recordperPage && (
|
||||
<button
|
||||
onClick={() => paginateBack()}
|
||||
className="op-join-item op-btn op-btn-sm"
|
||||
>
|
||||
Prev
|
||||
</button>
|
||||
)}
|
||||
{pageNumbers.map((x, i) => (
|
||||
<button
|
||||
key={i}
|
||||
onClick={() => setCurrentPage(x)}
|
||||
disabled={x === "..."}
|
||||
className={`${
|
||||
x === currentPage ? "op-btn-active" : ""
|
||||
} op-join-item op-btn op-btn-sm`}
|
||||
>
|
||||
{x}
|
||||
</button>
|
||||
))}
|
||||
{userList.length > recordperPage && (
|
||||
<button
|
||||
onClick={() => paginateFront()}
|
||||
className="op-join-item op-btn op-btn-sm"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{userList?.length <= 0 && (
|
||||
<div
|
||||
className={`${
|
||||
isDashboard ? "h-[317px]" : ""
|
||||
} flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`}
|
||||
>
|
||||
<div className="w-[60px] h-[60px] overflow-hidden">
|
||||
<img
|
||||
className="w-full h-full object-contain"
|
||||
src={pad}
|
||||
alt="img"
|
||||
/>
|
||||
</div>
|
||||
<div className="text-sm font-semibold">No Data Available</div>
|
||||
</div>
|
||||
)}
|
||||
<ModalUi
|
||||
title={"Add User"}
|
||||
isOpen={isModal}
|
||||
handleClose={handleFormModal}
|
||||
>
|
||||
<AddUser
|
||||
setIsAlert={setIsAlert}
|
||||
handleUserData={handleUserData}
|
||||
closePopup={handleFormModal}
|
||||
/>
|
||||
</ModalUi>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
|
||||
<div className="text-center">
|
||||
<h1 className="text-[60px] lg:text-[120px] font-semibold">
|
||||
404
|
||||
</h1>
|
||||
<p className="text-[30px] lg:text-[50px]">Page Not Found</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!isSubscribe && isEnableSubscription && !isLoader && (
|
||||
<div data-tut="apisubscribe">
|
||||
<SubscribeCard plan={"TEAMS"} price={"20"} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserList;
|
||||
@@ -1,8 +1,4 @@
|
||||
import React, {
|
||||
useState,
|
||||
useEffect
|
||||
// useRef
|
||||
} from "react";
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { Navigate, useNavigate } from "react-router-dom";
|
||||
import Parse from "parse";
|
||||
import { SaveFileSize } from "../constant/saveFileSize";
|
||||
@@ -10,7 +6,6 @@ import dp from "../assets/images/dp.png";
|
||||
import Title from "../components/Title";
|
||||
import sanitizeFileName from "../primitives/sanitizeFileName";
|
||||
import axios from "axios";
|
||||
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||
import Tooltip from "../primitives/Tooltip";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { checkIsSubscribed, handleSendOTP } from "../constant/Utils";
|
||||
@@ -32,10 +27,11 @@ function UserProfile() {
|
||||
const [percentage, setpercentage] = useState(0);
|
||||
const [isDisableDocId, setIsDisableDocId] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
// const [publicUserName, setPublicUserName] = useState(
|
||||
// extendUser && extendUser?.[0]?.UserName
|
||||
// );
|
||||
// const previousPublicUserName = useRef(publicUserName);
|
||||
const [isUpgrade, setIsUpgrade] = useState(false);
|
||||
const [publicUserName, setPublicUserName] = useState(
|
||||
extendUser && extendUser?.[0]?.UserName
|
||||
);
|
||||
const previousPublicUserName = useRef(publicUserName);
|
||||
const [company, setCompany] = useState(
|
||||
extendUser && extendUser?.[0]?.Company
|
||||
);
|
||||
@@ -46,7 +42,10 @@ function UserProfile() {
|
||||
const [otp, setOtp] = useState("");
|
||||
const [otpLoader, setOtpLoader] = useState(false);
|
||||
const [isEmailVerified, setIsEmailVerified] = useState(false);
|
||||
// const [userNameError, setUserNameError] = useState("");
|
||||
const [userNameError, setUserNameError] = useState("");
|
||||
const [tagLine, setTagLine] = useState(
|
||||
extendUser && extendUser?.[0]?.Tagline
|
||||
);
|
||||
useEffect(() => {
|
||||
getUserDetail();
|
||||
}, []);
|
||||
@@ -85,31 +84,31 @@ function UserProfile() {
|
||||
}
|
||||
};
|
||||
//function to check public username already exist
|
||||
// const handleCheckPublicUserName = async () => {
|
||||
// try {
|
||||
// const res = await Parse.Cloud.run("getpublicusername", {
|
||||
// username: publicUserName
|
||||
// });
|
||||
// if (res) {
|
||||
// setIsLoader(false);
|
||||
// setUserNameError("user name already exist");
|
||||
// setTimeout(() => {
|
||||
// setUserNameError("");
|
||||
// }, 3000);
|
||||
// return res;
|
||||
// }
|
||||
// } catch (e) {
|
||||
// console.log("error in getpublicusername cloud function");
|
||||
// }
|
||||
// };
|
||||
const handleCheckPublicUserName = async () => {
|
||||
try {
|
||||
const res = await Parse.Cloud.run("getpublicusername", {
|
||||
username: publicUserName
|
||||
});
|
||||
if (res) {
|
||||
setIsLoader(false);
|
||||
setUserNameError("user name already exist");
|
||||
setTimeout(() => {
|
||||
setUserNameError("");
|
||||
}, 3000);
|
||||
return res;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("error in getpublicusername cloud function");
|
||||
}
|
||||
};
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
let phn = Phone,
|
||||
res = "";
|
||||
//condition to call cloud function when user change publicUserName
|
||||
// if (previousPublicUserName.current !== publicUserName) {
|
||||
// res = await handleCheckPublicUserName();
|
||||
// }
|
||||
if (publicUserName && previousPublicUserName.current !== publicUserName) {
|
||||
res = await handleCheckPublicUserName();
|
||||
}
|
||||
if (!res) {
|
||||
setIsLoader(true);
|
||||
try {
|
||||
@@ -155,7 +154,6 @@ function UserProfile() {
|
||||
|
||||
// `updateExtUser` is used to update user details in extended class
|
||||
const updateExtUser = async (obj) => {
|
||||
const extClass = localStorage.getItem("extended_class");
|
||||
const extData = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||
const ExtUserId = extData[0].objectId;
|
||||
const body = {
|
||||
@@ -163,12 +161,13 @@ function UserProfile() {
|
||||
Name: obj.Name,
|
||||
HeaderDocId: isDisableDocId,
|
||||
JobTitle: jobTitle,
|
||||
Company: company
|
||||
// UserName: publicUserName || ""
|
||||
Company: company,
|
||||
UserName: publicUserName || "",
|
||||
Tagline: tagLine || ""
|
||||
};
|
||||
|
||||
await axios.put(
|
||||
parseBaseUrl + "classes/" + extClass + "/" + ExtUserId,
|
||||
parseBaseUrl + "classes/contracts_Users/" + ExtUserId,
|
||||
body,
|
||||
{
|
||||
headers: {
|
||||
@@ -185,6 +184,7 @@ function UserProfile() {
|
||||
const json = JSON.parse(JSON.stringify([res]));
|
||||
const extRes = JSON.stringify(json);
|
||||
localStorage.setItem("Extand_Class", extRes);
|
||||
previousPublicUserName.current = publicUserName;
|
||||
// console.log("updateRes ", updateRes);
|
||||
};
|
||||
// file upload function
|
||||
@@ -278,23 +278,20 @@ function UserProfile() {
|
||||
alert("OTP sent on you email");
|
||||
};
|
||||
//function to handle onchange username and restrict 6-characters username for free users
|
||||
// const handleOnchangeUserName = (e) => {
|
||||
// const value = e.target.value;
|
||||
// if (value.length > 6 && !isSubscribe) {
|
||||
// setUserNameError("Please upgrade to allow more than 6 characters.");
|
||||
// setTimeout(() => {
|
||||
// setUserNameError("");
|
||||
// }, 2000);
|
||||
// } else {
|
||||
// setPublicUserName(e.target.value);
|
||||
// }
|
||||
// };
|
||||
const handleOnchangeUserName = (e) => {
|
||||
const newValue = e.target.value.replace(/\s+/g, "");
|
||||
setPublicUserName(newValue);
|
||||
};
|
||||
|
||||
const handleOnchangeTagLine = (e) => {
|
||||
setTagLine(e.target.value);
|
||||
};
|
||||
const handleCancel = () => {
|
||||
setEditMode(false);
|
||||
SetName(localStorage.getItem("username"));
|
||||
SetPhone(UserProfile && UserProfile.phone);
|
||||
setImage(localStorage.getItem("profileImg"));
|
||||
// setPublicUserName(extendUser && extendUser?.[0]?.UserName);
|
||||
setPublicUserName(extendUser && extendUser?.[0]?.UserName);
|
||||
setCompany(extendUser && extendUser?.[0]?.Company);
|
||||
setJobTitle(extendUser?.[0]?.JobTitle);
|
||||
setIsDisableDocId(extendUser?.[0]?.HeaderDocId);
|
||||
@@ -308,13 +305,13 @@ function UserProfile() {
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex justify-center items-center w-full relative">
|
||||
{/* {userNameError && (
|
||||
{userNameError && (
|
||||
<div
|
||||
className={`z-[1000] fixed top-[50%] transform border-[1px] text-sm border-[#f0a8a8] bg-[#f4bebe] text-[#c42121] rounded py-[.75rem] px-[1.25rem]`}
|
||||
>
|
||||
{userNameError}
|
||||
</div>
|
||||
)} */}
|
||||
)}
|
||||
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box w-[450px]">
|
||||
<div className="flex flex-col justify-center items-center my-4">
|
||||
<div className="w-[200px] h-[200px] overflow-hidden rounded-full">
|
||||
@@ -442,85 +439,128 @@ function UserProfile() {
|
||||
)}
|
||||
</span>
|
||||
</li>
|
||||
{/* {isEnableSubscription && (
|
||||
<li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all">
|
||||
<span className="font-semibold">
|
||||
Public profile :{" "}
|
||||
<Tooltip
|
||||
message={`this is your public URL. Copy or share it
|
||||
with the signer, and you will be able to see
|
||||
all your publicly set templates.`}
|
||||
/>
|
||||
</span>
|
||||
<div className="flex text-xs items-center">
|
||||
<span>opensign-me.vercel.app/</span>
|
||||
{editmode ? (
|
||||
<input
|
||||
onChange={handleOnchangeUserName}
|
||||
value={publicUserName}
|
||||
disabled={!editmode}
|
||||
placeholder="enter user name"
|
||||
className="op-input op-input-bordered focus:outline-none hover:border-base-content op-input-xs"
|
||||
{isEnableSubscription && (
|
||||
<>
|
||||
<li className="flex md:flex-row flex-col md:justify-between md:items-center border-t-[1px] border-gray-300 py-2 break-all">
|
||||
<span className="font-semibold flex gap-1">
|
||||
Public profile :{" "}
|
||||
<Tooltip
|
||||
maxWidth="max-w-[250px]"
|
||||
message={`This is your public URL. Copy or share it with the signer, and you will be able to see all your publicly set templates.`}
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
value={extendUser?.[0]?.UserName}
|
||||
disabled
|
||||
placeholder="enter user name"
|
||||
className="op-input op-input-bordered op-input-xs"
|
||||
</span>
|
||||
<div className="flex md:flex-row flex-col md:items-center">
|
||||
<span className="mb-1 md:mb-1">opensign.me/</span>
|
||||
{editmode ? (
|
||||
<input
|
||||
maxLength={40}
|
||||
style={{
|
||||
border:
|
||||
!isSubscribe &&
|
||||
publicUserName?.length > 0 &&
|
||||
publicUserName?.length < 9 &&
|
||||
"solid red"
|
||||
}}
|
||||
onChange={handleOnchangeUserName}
|
||||
value={publicUserName}
|
||||
disabled={!editmode}
|
||||
placeholder="enter user name"
|
||||
className="op-input op-input-bordered focus:outline-none hover:border-base-content op-input-xs"
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
value={extendUser?.[0]?.UserName}
|
||||
disabled
|
||||
placeholder="enter user name"
|
||||
className="op-input op-input-bordered op-input-xs"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
<li className="flex md:flex-row flex-col md:justify-between md:items-center border-t-[1px] border-gray-300 py-2 break-all">
|
||||
<span className="font-semibold flex gap-1">
|
||||
Tagline :{" "}
|
||||
<Tooltip
|
||||
maxWidth="max-w-[250px]"
|
||||
message={`This Tagline will appear on your OpenSign public profile for ex. https://opensign.me/alex`}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
<div className="flex md:flex-row flex-col md:items-center">
|
||||
{editmode ? (
|
||||
<input
|
||||
onChange={handleOnchangeTagLine}
|
||||
value={tagLine}
|
||||
disabled={!editmode}
|
||||
placeholder="enter tagline"
|
||||
className="op-input op-input-bordered focus:outline-none hover:border-base-content op-input-xs"
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
value={extendUser?.[0]?.Tagline}
|
||||
disabled
|
||||
placeholder="enter tagline"
|
||||
className="op-input op-input-bordered op-input-xs"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
</>
|
||||
)}
|
||||
{isEnableSubscription && (
|
||||
<li className="border-y-[1px] border-gray-300 break-all">
|
||||
<div className="flex justify-between items-center py-2">
|
||||
<span
|
||||
className={
|
||||
isSubscribe
|
||||
? "font-semibold"
|
||||
: "font-semibold text-gray-300"
|
||||
}
|
||||
>
|
||||
Disable DocumentId :{" "}
|
||||
<Tooltip
|
||||
url={
|
||||
"https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid"
|
||||
}
|
||||
/>
|
||||
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
</span>
|
||||
<label
|
||||
className={`${
|
||||
isSubscribe
|
||||
? `${editmode ? "cursor-pointer" : ""}`
|
||||
: "pointer-events-none opacity-50"
|
||||
} relative block items-center mb-0`}
|
||||
>
|
||||
<input
|
||||
disabled={editmode ? false : true}
|
||||
type="checkbox"
|
||||
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
|
||||
checked={isDisableDocId}
|
||||
onChange={handleDisableDocId}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
)} */}
|
||||
<li className="border-y-[1px] border-gray-300 break-all">
|
||||
<div className="flex justify-between items-center py-2">
|
||||
<span
|
||||
className={
|
||||
isSubscribe || !isEnableSubscription
|
||||
? "font-semibold"
|
||||
: "font-semibold text-gray-300"
|
||||
}
|
||||
>
|
||||
Disable DocumentId :{" "}
|
||||
<Tooltip
|
||||
url={
|
||||
"https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid"
|
||||
}
|
||||
/>
|
||||
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
</span>
|
||||
<label
|
||||
className={`${
|
||||
isSubscribe || !isEnableSubscription
|
||||
? `${editmode ? "cursor-pointer" : ""}`
|
||||
: "pointer-events-none opacity-50"
|
||||
} relative block items-center mb-0`}
|
||||
>
|
||||
<input
|
||||
disabled={editmode ? false : true}
|
||||
type="checkbox"
|
||||
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
|
||||
checked={isDisableDocId}
|
||||
onChange={handleDisableDocId}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
{!isEnableSubscription && (
|
||||
<PremiumAlertHeader
|
||||
message={
|
||||
"Disable documentId is free in beta, this feature will incur a fee later."
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
<div className="flex justify-center gap-2 pt-2 pb-3 md:pt-3 md:pb-4">
|
||||
<div
|
||||
className={`${
|
||||
!isEnableSubscription ? "border-t-[1px] border-gray-300" : ""
|
||||
} flex justify-center gap-2 pt-2 pb-3 md:pt-3 md:pb-4`}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) =>
|
||||
editmode ? handleSubmit(e) : setEditMode(true)
|
||||
}
|
||||
onClick={(e) => {
|
||||
if (
|
||||
!isSubscribe &&
|
||||
publicUserName?.length > 0 &&
|
||||
publicUserName?.length < 9
|
||||
) {
|
||||
setIsUpgrade(true);
|
||||
} else {
|
||||
editmode ? handleSubmit(e) : setEditMode(true);
|
||||
}
|
||||
}}
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
{editmode ? "Save" : "Edit"}
|
||||
@@ -577,6 +617,38 @@ function UserProfile() {
|
||||
)}
|
||||
</ModalUi>
|
||||
)}
|
||||
{isUpgrade && (
|
||||
<div className="op-modal op-modal-open">
|
||||
<div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative">
|
||||
<>
|
||||
<div
|
||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-primary-content absolute right-2 top-2 z-40"
|
||||
onClick={() => setIsUpgrade(false)}
|
||||
>
|
||||
✕
|
||||
</div>
|
||||
|
||||
<div className="op-card op-bg-primary text-primary-content w-full shadow-lg">
|
||||
<div className="op-card-body">
|
||||
<h2 className="op-card-title">Upgrade to Plan</h2>
|
||||
<p>
|
||||
To have a username less than 8 character please
|
||||
subscribe
|
||||
</p>
|
||||
<div className="op-card-actions justify-end">
|
||||
<button
|
||||
onClick={() => navigate("/subscription")}
|
||||
className="op-btn op-btn-accent"
|
||||
>
|
||||
Upgrade Now
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
|
||||
@@ -6,7 +6,6 @@ import ModalUi from "../primitives/ModalUi";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { checkIsSubscribed, openInNewTab } from "../constant/Utils";
|
||||
import Parse from "parse";
|
||||
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||
import Tooltip from "../primitives/Tooltip";
|
||||
import Loader from "../primitives/Loader";
|
||||
import SubscribeCard from "../primitives/SubscribeCard";
|
||||
@@ -107,7 +106,6 @@ function Webhook() {
|
||||
) : (
|
||||
<>
|
||||
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box mb-3">
|
||||
{!isEnableSubscription && <PremiumAlertHeader />}
|
||||
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||
OpenSign™ Webhook{" "}
|
||||
<Tooltip
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Parse from "parse";
|
||||
import axios from "axios";
|
||||
import Loader from "./Loader";
|
||||
const AddContact = (props) => {
|
||||
const [name, setName] = useState("");
|
||||
@@ -9,8 +8,6 @@ const AddContact = (props) => {
|
||||
const [addYourself, setAddYourself] = useState(false);
|
||||
const [isLoader, setIsLoader] = useState(false);
|
||||
const [isUserExist, setIsUserExist] = useState(false);
|
||||
const parseBaseUrl = localStorage.getItem("baseUrl");
|
||||
const parseAppId = localStorage.getItem("parseAppId");
|
||||
useEffect(() => {
|
||||
checkUserExist();
|
||||
}, []);
|
||||
@@ -77,18 +74,6 @@ const AddContact = (props) => {
|
||||
|
||||
const user = await _user.save();
|
||||
if (user) {
|
||||
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseAppId,
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
};
|
||||
const body = {
|
||||
appName: localStorage.getItem("_appName"),
|
||||
roleName: "contracts_Guest",
|
||||
userId: user.id
|
||||
};
|
||||
await axios.post(roleurl, body, { headers: headers });
|
||||
const currentUser = Parse.User.current();
|
||||
contactQuery.set(
|
||||
"CreatedBy",
|
||||
@@ -124,18 +109,6 @@ const AddContact = (props) => {
|
||||
if (err.code === 202) {
|
||||
const params = { email: email };
|
||||
const userRes = await Parse.Cloud.run("getUserId", params);
|
||||
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseAppId,
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
};
|
||||
const body = {
|
||||
appName: localStorage.getItem("_appName"),
|
||||
roleName: "contracts_Guest",
|
||||
userId: userRes.id
|
||||
};
|
||||
await axios.post(roleurl, body, { headers: headers });
|
||||
const currentUser = Parse.User.current();
|
||||
contactQuery.set(
|
||||
"CreatedBy",
|
||||
|
||||
@@ -30,8 +30,7 @@ const LottieWithLoader = () => {
|
||||
return (
|
||||
<div>
|
||||
{!isLoaded && !hasError && (
|
||||
<div className="loader">
|
||||
{" "}
|
||||
<div className="w-[120px] h-[120px] mx-auto">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
@@ -39,9 +38,8 @@ const LottieWithLoader = () => {
|
||||
{isLoaded && animationSrc && (
|
||||
<DotLottieReact
|
||||
src={animationSrc}
|
||||
loop
|
||||
autoplay
|
||||
style={{ display: "block" }}
|
||||
className="w-[120px] h-[120px] md:w-[200px] md:h-[200px] mx-auto"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,4 @@
|
||||
import React from "react";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import PremiumAlertHeader from "./PremiumAlertHeader";
|
||||
|
||||
const ModalUi = ({
|
||||
children,
|
||||
@@ -9,8 +7,7 @@ const ModalUi = ({
|
||||
handleClose,
|
||||
showHeader = true,
|
||||
showClose = true,
|
||||
reduceWidth,
|
||||
showHeaderMessage
|
||||
reduceWidth
|
||||
}) => {
|
||||
const width = reduceWidth;
|
||||
return (
|
||||
@@ -37,13 +34,6 @@ const ModalUi = ({
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!isEnableSubscription && showHeaderMessage && (
|
||||
<PremiumAlertHeader
|
||||
message={
|
||||
"Cutomize Email is free in beta, this feature will incur a fee later."
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import "../styles/signature.css";
|
||||
|
||||
function CustomModal({
|
||||
@@ -9,11 +9,12 @@ function CustomModal({
|
||||
declineDoc,
|
||||
setIsDecline
|
||||
}) {
|
||||
const [reason, setReason] = useState("");
|
||||
return (
|
||||
show && (
|
||||
<dialog className="op-modal op-modal-open absolute z-[998]">
|
||||
<div className="w-[80%] md:w-[40%] op-modal-box p-0 overflow-y-auto hide-scrollbar text-sm">
|
||||
<h3 className="text-[#de4337] font-bold text-lg pt-[15px] px-[20px]">
|
||||
<dialog className="op-modal op-modal-open absolute z-[448]">
|
||||
<div className="w-[95%] md:w-[60%] lg:w-[40%] op-modal-box p-0 overflow-y-auto hide-scrollbar text-sm">
|
||||
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||
{headMsg && headMsg}
|
||||
</h3>
|
||||
<div className="p-[10px] px-[20px]">
|
||||
@@ -21,19 +22,34 @@ function CustomModal({
|
||||
</div>
|
||||
{footerMessage && (
|
||||
<>
|
||||
<div className="h-[1px] bg-[#9f9f9f] w-full"></div>
|
||||
<div className="m-[15px] ">
|
||||
<div className="mx-3">
|
||||
<textarea
|
||||
rows={3}
|
||||
placeholder="Reason (optional)"
|
||||
className="px-4 op-textarea op-textarea-bordered focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={reason}
|
||||
onChange={(e) => setReason(e.target.value)}
|
||||
></textarea>
|
||||
</div>
|
||||
{/* <div className="h-[1px] bg-[#9f9f9f] w-full"></div> */}
|
||||
<div className="m-[15px]">
|
||||
<button
|
||||
className="op-btn op-btn-primary mr-2"
|
||||
className="op-btn op-btn-primary mr-2 px-6"
|
||||
type="button"
|
||||
onClick={() => declineDoc()}
|
||||
onClick={() => {
|
||||
setReason("");
|
||||
declineDoc(reason);
|
||||
}}
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-secondary"
|
||||
onClick={() => setIsDecline({ isDeclined: false })}
|
||||
onClick={() => {
|
||||
setReason("");
|
||||
setIsDecline({ isDeclined: false });
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
const PremiumAlertHeader = ({ message }) => (
|
||||
<marquee className="bg-yellow-300 text-black px-2">
|
||||
{message
|
||||
? message
|
||||
: "Currently free in Beta, this feature will incur a fee later."}
|
||||
</marquee>
|
||||
);
|
||||
|
||||
export default PremiumAlertHeader;
|
||||
@@ -1,13 +1,16 @@
|
||||
import React from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const SubscribeCard = () => {
|
||||
const SubscribeCard = ({ plan, price }) => {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<div className="op-card op-bg-primary text-primary-content w-full shadow-lg">
|
||||
<div className="op-card-body">
|
||||
<h2 className="op-card-title">Upgrade to PRO Plan</h2>
|
||||
<p>$29.99/month: Sign 100 docs using API. Only $0.15/doc after that.</p>
|
||||
<h2 className="op-card-title">Upgrade to {plan ? plan : "PRO"} Plan</h2>
|
||||
<p>
|
||||
${price ? price : "29.99"}/month: Sign 100 docs using API. Only
|
||||
$0.15/doc after that.
|
||||
</p>
|
||||
<div className="op-card-actions justify-end">
|
||||
<button
|
||||
onClick={() => navigate("/subscription")}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { Tooltip as ReactTooltip } from "react-tooltip";
|
||||
import { openInNewTab } from "../constant/Utils";
|
||||
const Tooltip = ({ id, message, url, iconColor }) =>
|
||||
const Tooltip = ({ id, message, url, iconColor, maxWidth }) =>
|
||||
url ? (
|
||||
<button onClick={() => openInNewTab(url)} className={"text-center"}>
|
||||
<sup>
|
||||
@@ -33,7 +33,7 @@ const Tooltip = ({ id, message, url, iconColor }) =>
|
||||
</a>
|
||||
<ReactTooltip
|
||||
id={id ? id : "my-tooltip"}
|
||||
className="max-w-[200px] z-[200]"
|
||||
className={`${maxWidth ? maxWidth : "max-w-[200px]"} z-[200]`}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -6,15 +6,11 @@ const infoSlice = createSlice({
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import React, { useState } from "react";
|
||||
import Parse from "parse";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import PdfRequestFiles from "../pages/PdfRequestFiles";
|
||||
import { pdfjs } from "react-pdf";
|
||||
import { Provider } from "react-redux";
|
||||
import { store } from "../redux/store";
|
||||
import "../index.css";
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.mjs`;
|
||||
|
||||
// Wrapper component to manage props
|
||||
const PublicScriptFileWrapper = ({ initialProps }) => {
|
||||
const [props, setProps] = useState(initialProps);
|
||||
|
||||
// Make the setProps function globally accessible
|
||||
window.updatePublicTemplateProps = setProps;
|
||||
|
||||
return <PdfRequestFiles {...props} />;
|
||||
};
|
||||
|
||||
const appId = "legadranaxn";
|
||||
// "opensign";
|
||||
const serverUrl = "https://app.opensignlabs.com/api/app";
|
||||
// "https://staging-app.opensignlabs.com/api/app";
|
||||
localStorage.setItem("baseUrl", `${serverUrl}/`);
|
||||
localStorage.setItem("parseAppId", appId);
|
||||
Parse.initialize(appId);
|
||||
Parse.serverURL = serverUrl;
|
||||
// Create a new div element and append it to the body
|
||||
const scriptComponent = document.createElement("div");
|
||||
scriptComponent.id = "script-component";
|
||||
document.body.appendChild(scriptComponent);
|
||||
const link = document.createElement("link");
|
||||
link.href = "https://cdn.opensignlabs.com/fonts.css";
|
||||
link.rel = "stylesheet";
|
||||
document.head.appendChild(link);
|
||||
|
||||
//add the Tailwind CSS file
|
||||
const tailwindCssLink = document.createElement("link");
|
||||
tailwindCssLink.href =
|
||||
"https://app.opensignlabs.com/static/js/public-template.bundle.css"; // css bundle file
|
||||
// "https://staging-app.opensignlabs.com/static/js/public-template.bundle.css"; // css bundle file
|
||||
tailwindCssLink.rel = "stylesheet";
|
||||
document.head.appendChild(tailwindCssLink);
|
||||
// Create a root and render the wrapper component with initial props
|
||||
const root = ReactDOM.createRoot(document.getElementById("script-component"));
|
||||
root.render(
|
||||
<div>
|
||||
<Provider store={store}>
|
||||
<PublicScriptFileWrapper initialProps={{ text: "templateId" }} />
|
||||
</Provider>
|
||||
</div>
|
||||
);
|
||||
@@ -1,6 +1,6 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./src/**/*.{js,jsx,ts,tsx}"],
|
||||
content: ["./src/**/*.{js,jsx,ts,tsx}", "./src/script/PublicTemplate.js"],
|
||||
theme: {
|
||||
extend: {}
|
||||
},
|
||||
@@ -60,8 +60,8 @@ module.exports = {
|
||||
"success-content": "#f5f5f4",
|
||||
warning: "#ffbe00",
|
||||
"warning-content": "#ccd9e8",
|
||||
error: "#ff0000",
|
||||
"error-content": "#f3f4f6",
|
||||
error: "#ffa1a7",
|
||||
"error-content": "#16090a",
|
||||
"--rounded-btn": "1.9rem",
|
||||
"--tab-border": "2px",
|
||||
"--tab-radius": "0.7rem"
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
const path = require("path");
|
||||
const Dotenv = require("dotenv-webpack");
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin"); //used to clean directory
|
||||
const TerserPlugin = require("terser-webpack-plugin"); //used to minify and optimize JavaScript files
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //used to extract css file into separate files
|
||||
|
||||
const isProduction = process.env.NODE_ENV;
|
||||
module.exports = {
|
||||
mode: isProduction ? "production" : "development",
|
||||
entry: "./src/script/PublicTemplate.js",
|
||||
output: {
|
||||
path: path.resolve(__dirname, "public", "static", "js"),
|
||||
filename: "public-template.bundle.js",
|
||||
libraryTarget: "umd",
|
||||
umdNamedDefine: true,
|
||||
library: "PublicTemplate",
|
||||
globalObject: "this"
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: ["@babel/preset-react"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
isProduction ? MiniCssExtractPlugin.loader : "style-loader",
|
||||
"css-loader",
|
||||
"postcss-loader"
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: "file-loader",
|
||||
options: {
|
||||
name: "assets/images/[name].[hash].[ext]"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".js", ".jsx"]
|
||||
},
|
||||
plugins: [
|
||||
new Dotenv(),
|
||||
new CleanWebpackPlugin(),
|
||||
...(isProduction
|
||||
? [
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "public-template.bundle.css"
|
||||
})
|
||||
]
|
||||
: [])
|
||||
],
|
||||
optimization: {
|
||||
minimize: isProduction ? true : false,
|
||||
minimizer: [new TerserPlugin()]
|
||||
},
|
||||
devtool: isProduction ? "source-map" : "inline-source-map"
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
# Use an official Node runtime as the base image
|
||||
FROM node:18
|
||||
FROM node:20
|
||||
|
||||
# Set the working directory inside the container
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
@@ -143,13 +143,13 @@ export const updateMailCount = async extUserId => {
|
||||
await contractUser.save(null, { useMasterKey: true });
|
||||
} else {
|
||||
// Create new entry if not found
|
||||
const ContractsUsers = Parse.Object.extend('contracts_users');
|
||||
const ContractsUsers = Parse.Object.extend('contracts_Users');
|
||||
const newContractUser = new ContractsUsers();
|
||||
newContractUser.set('EmailCount', 1);
|
||||
await newContractUser.save(null, { useMasterKey: true });
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('Error updating EmailCount in contracts_users: ' + error.message);
|
||||
console.log('Error updating EmailCount in contracts_Users: ' + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import axios from 'axios';
|
||||
export default async function createContact(request, response) {
|
||||
const serverUrl = process.env.SERVER_URL;
|
||||
const appId = process.env.APP_ID;
|
||||
const name = request.body.name;
|
||||
const phone = request.body?.phone;
|
||||
const email = request.body.email;
|
||||
@@ -74,18 +71,6 @@ export default async function createContact(request, response) {
|
||||
|
||||
const user = await _user.save();
|
||||
if (user) {
|
||||
const roleurl = `${serverUrl}/functions/AddUserToRole`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': appId,
|
||||
// sessionToken: localStorage.getItem('accesstoken'),
|
||||
};
|
||||
const body = {
|
||||
appName: 'contracts',
|
||||
roleName: 'contracts_Guest',
|
||||
userId: user.id,
|
||||
};
|
||||
await axios.post(roleurl, body, { headers: headers });
|
||||
const currentUser = userPtr;
|
||||
contactQuery.set('CreatedBy', currentUser);
|
||||
contactQuery.set('UserId', user);
|
||||
@@ -120,18 +105,6 @@ export default async function createContact(request, response) {
|
||||
if (err.code === 202) {
|
||||
const params = { email: email };
|
||||
const userRes = await Parse.Cloud.run('getUserId', params);
|
||||
const roleurl = `${serverUrl}/functions/AddUserToRole`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': appId,
|
||||
// sessionToken: localStorage.getItem('accesstoken'),
|
||||
};
|
||||
const body = {
|
||||
appName: 'contracts',
|
||||
roleName: 'contracts_Guest',
|
||||
userId: userRes.objectId,
|
||||
};
|
||||
await axios.post(roleurl, body, { headers: headers });
|
||||
contactQuery.set('CreatedBy', userPtr);
|
||||
contactQuery.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
|
||||
@@ -4,11 +4,9 @@ import GoogleSign from './parsefunction/GoogleSign.js';
|
||||
import ZohoDetails from './parsefunction/ZohoDetails.js';
|
||||
import usersignup from './parsefunction/usersignup.js';
|
||||
import FacebookSign from './parsefunction/FacebookSign.js';
|
||||
import { addUserToGroups } from './parsefunction/AddUserToRole.js';
|
||||
import { getUserGroups } from './parsefunction/UserGroups.js';
|
||||
import DocumentAftersave from './parsefunction/DocumentAftersave.js';
|
||||
import ContactbookAftersave from './parsefunction/ContactBookAftersave.js';
|
||||
import ContractUsersAftersave from './parsefunction/ContractUsersAftersave.js';
|
||||
// import ContractUsersAftersave from './parsefunction/ContractUsersAftersave.js';
|
||||
import sendMailOTPv1 from './parsefunction/SendMailOTPv1.js';
|
||||
import AuthLoginAsMail from './parsefunction/AuthLoginAsMail.js';
|
||||
import getUserId from './parsefunction/getUserId.js';
|
||||
@@ -44,13 +42,30 @@ import GetPublicUserName from './parsefunction/GetPublicUserName.js';
|
||||
import GetPublicTemplate from './parsefunction/GetPublicTemplate.js';
|
||||
import ssoSignin from './parsefunction/ssoSignin.js';
|
||||
import isextenduser from './parsefunction/isextenduser.js';
|
||||
import getUserByOrg from './parsefunction/getUserByOrg.js';
|
||||
import getUserListByOrg from './parsefunction/getUserListByOrg.js';
|
||||
import TeamsAftersave from './parsefunction/TeamsAftersave.js';
|
||||
import SubscriptionAftersave from './parsefunction/SubscriptionAftersave.js';
|
||||
import PublicUserLinkContactToDoc from './parsefunction/PublicUserLinkContactToDoc.js';
|
||||
import GetLogoByDomain from './parsefunction/GetLogobyDomain.js';
|
||||
import AddAdmin from './parsefunction/AddAdmin.js';
|
||||
import CheckAdminExist from './parsefunction/CheckAdminExist.js';
|
||||
import UpdateExistUserAsAdmin from './parsefunction/UpdateExistUserAsAdmin.js';
|
||||
import Newsletter from './parsefunction/Newsletter.js';
|
||||
import getOrganizations from './parsefunction/getOrganizations.js';
|
||||
import addOrganization from './parsefunction/addOrganization.js';
|
||||
import updateOrganization from './parsefunction/updateOrganization.js';
|
||||
import getTeams from './parsefunction/getTeams.js';
|
||||
import addTeam from './parsefunction/addTeam.js';
|
||||
import updateTeam from './parsefunction/updateTeam.js';
|
||||
|
||||
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
|
||||
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
|
||||
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
|
||||
Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
|
||||
// Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
|
||||
Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave);
|
||||
|
||||
Parse.Cloud.afterSave('contracts_Teams', TeamsAftersave);
|
||||
Parse.Cloud.afterSave('contracts_Subscriptions', SubscriptionAftersave);
|
||||
// This beforeSave function triggers before an object is added or updated in the specified class, allowing for validation or modification.
|
||||
Parse.Cloud.beforeSave('contracts_Document', DocumentBeforesave);
|
||||
Parse.Cloud.beforeSave('contracts_Template', TemplateBeforeSave);
|
||||
@@ -63,8 +78,6 @@ Parse.Cloud.afterFind('contracts_Signature', SignatureAfterFind);
|
||||
Parse.Cloud.afterFind('partners_Tenant', TenantAterFind);
|
||||
|
||||
// This define function creates a custom Cloud Function that can be called from the client-side, enabling custom business logic on the server.
|
||||
Parse.Cloud.define('AddUserToRole', addUserToGroups);
|
||||
Parse.Cloud.define('UserGroups', getUserGroups);
|
||||
Parse.Cloud.define('signPdf', PDF);
|
||||
Parse.Cloud.define('sendmailv3', sendmailv3);
|
||||
Parse.Cloud.define('googlesign', GoogleSign);
|
||||
@@ -98,3 +111,17 @@ Parse.Cloud.define('getpublicusername', GetPublicUserName);
|
||||
Parse.Cloud.define('getpublictemplate', GetPublicTemplate);
|
||||
Parse.Cloud.define('ssosign', ssoSignin);
|
||||
Parse.Cloud.define('isextenduser', isextenduser);
|
||||
Parse.Cloud.define('getuserbyorg', getUserByOrg);
|
||||
Parse.Cloud.define('getuserlistbyorg', getUserListByOrg);
|
||||
Parse.Cloud.define('publicuserlinkcontacttodoc', PublicUserLinkContactToDoc);
|
||||
Parse.Cloud.define('getlogobydomain', GetLogoByDomain);
|
||||
Parse.Cloud.define('addadmin', AddAdmin);
|
||||
Parse.Cloud.define('checkadminexist', CheckAdminExist);
|
||||
Parse.Cloud.define('updateuserasadmin', UpdateExistUserAsAdmin);
|
||||
Parse.Cloud.define('newsletter', Newsletter);
|
||||
Parse.Cloud.define('getorganizations', getOrganizations);
|
||||
Parse.Cloud.define('addorganization', addOrganization);
|
||||
Parse.Cloud.define('updateorganization', updateOrganization);
|
||||
Parse.Cloud.define('getteams', getTeams);
|
||||
Parse.Cloud.define('addteam', addTeam);
|
||||
Parse.Cloud.define('updateteam', updateTeam);
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
import axios from 'axios';
|
||||
const serverUrl = process.env.SERVER_URL;
|
||||
const APPID = process.env.APP_ID;
|
||||
const masterKEY = process.env.MASTER_KEY;
|
||||
async function addTeamAndOrg(extUser) {
|
||||
try {
|
||||
const orgCls = new Parse.Object('contracts_Organizations');
|
||||
orgCls.set('Name', extUser.Company);
|
||||
orgCls.set('IsActive', true);
|
||||
orgCls.set('ExtUserId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser?.objectId,
|
||||
});
|
||||
orgCls.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: extUser?.UserId?.objectId,
|
||||
});
|
||||
orgCls.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: extUser?.TenantId?.objectId,
|
||||
});
|
||||
|
||||
const orgRes = await orgCls.save(null, { useMasterKey: true });
|
||||
const teamCls = new Parse.Object('contracts_Teams');
|
||||
teamCls.set('Name', 'All Users');
|
||||
teamCls.set('OrganizationId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: orgRes.id,
|
||||
});
|
||||
teamCls.set('IsActive', true);
|
||||
const teamRes = await teamCls.save(null, { useMasterKey: true });
|
||||
const updateUser = new Parse.Object('contracts_Users');
|
||||
updateUser.id = extUser.objectId;
|
||||
updateUser.set('UserRole', 'contracts_Admin');
|
||||
updateUser.set('OrganizationId', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Organizations',
|
||||
objectId: orgRes.id,
|
||||
});
|
||||
updateUser.set('TeamIds', [
|
||||
{
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Teams',
|
||||
objectId: teamRes.id,
|
||||
},
|
||||
]);
|
||||
const extUserRes = await updateUser.save(null, { useMasterKey: true });
|
||||
} catch (err) {
|
||||
console.log('err in add team, role, org', err);
|
||||
}
|
||||
}
|
||||
|
||||
async function saveUser(userDetails) {
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
userQuery.equalTo('username', userDetails.email);
|
||||
const userRes = await userQuery.first({ useMasterKey: true });
|
||||
|
||||
if (userRes) {
|
||||
const url = `${serverUrl}/loginAs`;
|
||||
const axiosRes = await axios({
|
||||
method: 'POST',
|
||||
url: url,
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8',
|
||||
'X-Parse-Application-Id': APPID,
|
||||
'X-Parse-Master-Key': masterKEY,
|
||||
},
|
||||
params: {
|
||||
userId: userRes.id,
|
||||
},
|
||||
});
|
||||
const login = await axiosRes.data;
|
||||
// console.log("login ", login);
|
||||
return { id: login.objectId, sessionToken: login.sessionToken };
|
||||
} else {
|
||||
const user = new Parse.User();
|
||||
user.set('username', userDetails.email);
|
||||
user.set('password', userDetails.password);
|
||||
user.set('email', userDetails.email);
|
||||
if (userDetails?.phone) {
|
||||
user.set('phone', userDetails.phone);
|
||||
}
|
||||
user.set('name', userDetails.name);
|
||||
|
||||
const res = await user.signUp();
|
||||
// console.log("res ", res);
|
||||
return { id: res.id, sessionToken: res.getSessionToken() };
|
||||
}
|
||||
}
|
||||
export default async function AddAdmin(request) {
|
||||
const userDetails = request.params.userDetails;
|
||||
// const subscription = request.params.subscription;
|
||||
const user = await saveUser(userDetails);
|
||||
|
||||
try {
|
||||
const extQuery = new Parse.Query('contracts_Users');
|
||||
extQuery.equalTo('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: user.id,
|
||||
});
|
||||
const extUser = await extQuery.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
return { message: 'User already exist' };
|
||||
} else {
|
||||
// console.log("role ", role);
|
||||
const partnerQuery = new Parse.Object('partners_Tenant');
|
||||
partnerQuery.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: user.id,
|
||||
});
|
||||
|
||||
if (userDetails?.phone) {
|
||||
partnerQuery.set('ContactNumber', userDetails.phone);
|
||||
}
|
||||
partnerQuery.set('TenantName', userDetails.company);
|
||||
partnerQuery.set('EmailAddress', userDetails.email);
|
||||
partnerQuery.set('IsActive', true);
|
||||
partnerQuery.set('CreatedBy', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: user.id,
|
||||
});
|
||||
if (userDetails && userDetails.pincode) {
|
||||
partnerQuery.set('PinCode', userDetails.pincode);
|
||||
}
|
||||
if (userDetails && userDetails.country) {
|
||||
partnerQuery.set('Country', userDetails.country);
|
||||
}
|
||||
if (userDetails && userDetails.state) {
|
||||
partnerQuery.set('State', userDetails.state);
|
||||
}
|
||||
if (userDetails && userDetails.city) {
|
||||
partnerQuery.set('City', userDetails.city);
|
||||
}
|
||||
if (userDetails && userDetails.address) {
|
||||
partnerQuery.set('Address', userDetails.address);
|
||||
}
|
||||
const tenantRes = await partnerQuery.save(null, { useMasterKey: true });
|
||||
// console.log("tenantRes ", tenantRes);
|
||||
const newObj = new Parse.Object('contracts_Users');
|
||||
newObj.set('UserId', {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: user.id,
|
||||
});
|
||||
newObj.set('UserRole', userDetails.role);
|
||||
newObj.set('Email', userDetails.email);
|
||||
newObj.set('Name', userDetails.name);
|
||||
if (userDetails?.phone) {
|
||||
newObj.set('Phone', userDetails?.phone);
|
||||
}
|
||||
newObj.set('TenantId', {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: tenantRes.id,
|
||||
});
|
||||
if (userDetails && userDetails.company) {
|
||||
newObj.set('Company', userDetails.company);
|
||||
}
|
||||
if (userDetails && userDetails.jobTitle) {
|
||||
newObj.set('JobTitle', userDetails.jobTitle);
|
||||
}
|
||||
const extRes = await newObj.save(null, { useMasterKey: true });
|
||||
// if (subscription) {
|
||||
const extUser = {
|
||||
objectId: extRes.id,
|
||||
Name: userDetails.name,
|
||||
Email: userDetails.email,
|
||||
Phone: userDetails?.phone ? userDetails.phone : '',
|
||||
TenantId: { objectId: tenantRes.id },
|
||||
UserId: { objectId: user.id },
|
||||
UserRole: userDetails.role,
|
||||
Company: userDetails.company,
|
||||
JobTitle: userDetails.jobTitle,
|
||||
};
|
||||
await addTeamAndOrg(extUser);
|
||||
// await saveSubscription(extRes.id, user.id, tenantRes.id, subscription);
|
||||
// }
|
||||
return { message: 'User sign up', sessionToken: user.sessionToken };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err ', err);
|
||||
}
|
||||
}
|
||||
|
||||
// async function saveSubscription(extUserId, UserId, tenantId, subscription) {
|
||||
// const SubscriptionId = subscription?.data?.subscription?.subscription_id || '';
|
||||
// const Next_billing_date = subscription?.data?.subscription?.next_billing_at || '';
|
||||
// const planCode = subscription?.data?.subscription?.plan?.plan_code || '';
|
||||
// try {
|
||||
// const createSubscription = new Parse.Object('contracts_Subscriptions');
|
||||
// createSubscription.set('SubscriptionId', SubscriptionId);
|
||||
// createSubscription.set('SubscriptionDetails', subscription);
|
||||
// createSubscription.set('ExtUserPtr', {
|
||||
// __type: 'Pointer',
|
||||
// className: 'contracts_Users',
|
||||
// objectId: extUserId,
|
||||
// });
|
||||
// createSubscription.set('CreatedBy', {
|
||||
// __type: 'Pointer',
|
||||
// className: '_User',
|
||||
// objectId: UserId,
|
||||
// });
|
||||
// createSubscription.set('TenantId', {
|
||||
// __type: 'Pointer',
|
||||
// className: 'partners_Tenant',
|
||||
// objectId: tenantId,
|
||||
// });
|
||||
// createSubscription.set('Next_billing_date', new Date(Next_billing_date));
|
||||
// createSubscription.set('PlanCode', planCode);
|
||||
// await createSubscription.save(null, { useMasterKey: true });
|
||||
// } catch (err) {
|
||||
// console.log('err in save subscription pgsignup', err);
|
||||
// }
|
||||
// }
|
||||
@@ -1,262 +0,0 @@
|
||||
/* --Description :cloud function to add or attach user in given role */
|
||||
|
||||
//-- Export Modules
|
||||
import 'dotenv/config.js';
|
||||
import axios from 'axios';
|
||||
|
||||
export async function addUserToGroups(request) {
|
||||
try {
|
||||
var roleName = request.params.roleName;
|
||||
if (roleName == undefined) {
|
||||
return Promise.reject('Error:roleName not found!');
|
||||
}
|
||||
var appName = request.params.appName;
|
||||
if (appName == undefined) {
|
||||
return Promise.reject('Error:appName not found!');
|
||||
}
|
||||
var chkappName = appName + '_';
|
||||
//console.log("roleName " + roleName);
|
||||
var userId = request.params.userId;
|
||||
//console.log("userId " + userId);
|
||||
console.log('addUserToGroups');
|
||||
var response = {};
|
||||
var rolelist = {};
|
||||
var user = {
|
||||
users: {
|
||||
__op: 'AddRelation',
|
||||
objects: [{ __type: 'Pointer', className: '_User', objectId: userId }],
|
||||
},
|
||||
};
|
||||
var Role = roleName;
|
||||
var chkappnam = Role.split('_')[0];
|
||||
chkappnam = chkappnam + '_';
|
||||
// if (!chkappnam == chkappName) {
|
||||
// return Promise.reject("Error:Please check role it should belong to current appllication");
|
||||
// }
|
||||
function getAccessType(request) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
const options = {
|
||||
url: process.env.SERVER_URL + '/classes/w_appinfo?where={"appname":"' + appName + '"}',
|
||||
method: 'get',
|
||||
headers: {
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
||||
},
|
||||
};
|
||||
|
||||
axios(options)
|
||||
.then(x => {
|
||||
const body = x.data;
|
||||
var accessType;
|
||||
if (body['results'].length !== 0) {
|
||||
accessType = body['results'][0]['accessType'];
|
||||
} else {
|
||||
reject('Error:app not found!');
|
||||
}
|
||||
var error = accessType == '' ? true : false;
|
||||
if (error) {
|
||||
reject('result not found!');
|
||||
} else {
|
||||
resolve(accessType);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
var role = appName + 'appeditor';
|
||||
var appaccessType = await getAccessType(request);
|
||||
//console.log("appaccessType");
|
||||
//console.log(appaccessType);
|
||||
if (appaccessType == 'public') {
|
||||
adduserToRole();
|
||||
} else {
|
||||
//--function to get the userid from session token
|
||||
function getuserid(request) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
const options = {
|
||||
url: process.env.SERVER_URL + '/users/me',
|
||||
method: 'get',
|
||||
headers: {
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
};
|
||||
|
||||
axios(options)
|
||||
.then(x => {
|
||||
const body = x.data;
|
||||
var error = body == '' ? true : false;
|
||||
if (error) {
|
||||
reject('result not found!');
|
||||
} else {
|
||||
resolve(body);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
var userData = await getuserid(request);
|
||||
if (userData.objectId == undefined) {
|
||||
return Promise.reject('Error:user not found!');
|
||||
}
|
||||
var chkuserid = userData.objectId;
|
||||
//console.log("chkuserid "+chkuserid);
|
||||
var url =
|
||||
process.env.SERVER_URL +
|
||||
'/roles?where={"users":{"__type":"Pointer","className":"_User","objectId":"' +
|
||||
chkuserid +
|
||||
'"},"name": {"$regex": "' +
|
||||
chkappName +
|
||||
'"}}';
|
||||
|
||||
//-- check user role
|
||||
function getRoleList(chkuserid) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
const options = {
|
||||
url: url,
|
||||
method: 'get',
|
||||
headers: {
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
},
|
||||
};
|
||||
|
||||
axios(options)
|
||||
.then(x => {
|
||||
const body = x.data;
|
||||
if (body['results'].length == 0) {
|
||||
reject('Error:user not found');
|
||||
}
|
||||
var error = body == '' ? true : false;
|
||||
if (error) {
|
||||
reject('result not found!');
|
||||
} else {
|
||||
resolve(body);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
rolelist = await getRoleList(chkuserid);
|
||||
//console.log("rolelist");
|
||||
// console.log(rolelist);
|
||||
var roleres = [];
|
||||
var result;
|
||||
for (var i = 0; i < rolelist['results'].length; i++) {
|
||||
var rolenum = rolelist['results'][i]['name'];
|
||||
var appnam = rolenum.split('_')[0];
|
||||
appnam = appnam + '_';
|
||||
if (appnam == chkappName) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == true) {
|
||||
adduserToRole();
|
||||
} else {
|
||||
return Promise.reject('Error:user of this app can only add user to Role');
|
||||
}
|
||||
}
|
||||
|
||||
//--after validation call adduserToRole function
|
||||
async function adduserToRole() {
|
||||
var roleNam = roleName;
|
||||
var roleid = await getroleobjId(roleNam);
|
||||
console.log('roleid');
|
||||
console.log(roleid);
|
||||
var response = await adduserid(roleid);
|
||||
/*process.stdin.resume();
|
||||
// listen to the event
|
||||
process.on('SIGTERM', () => {
|
||||
process.emit('cleanup');
|
||||
})*/
|
||||
return response;
|
||||
}
|
||||
//--function to get the role objId
|
||||
function getroleobjId(roleNam) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
const options = {
|
||||
url: process.env.SERVER_URL + '/roles?where={"name":"' + roleNam + '"}',
|
||||
method: 'get',
|
||||
headers: {
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
},
|
||||
};
|
||||
axios(options)
|
||||
.then(x => {
|
||||
const body = x.data;
|
||||
var roleid;
|
||||
if (body['results'].length !== 0) {
|
||||
roleid = body['results'][0]['objectId'];
|
||||
} else {
|
||||
reject('Error:Role not found!');
|
||||
}
|
||||
var error = roleid == '' ? true : false;
|
||||
if (error) {
|
||||
reject('result not found!');
|
||||
} else {
|
||||
resolve(roleid);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//--function to add the userid to role
|
||||
function adduserid(roleid) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
const options = {
|
||||
url: process.env.SERVER_URL + '/roles/' + roleid,
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: user,
|
||||
};
|
||||
|
||||
axios(options)
|
||||
.then(x => {
|
||||
const body = x.data;
|
||||
var error = body == '' ? true : false;
|
||||
if (error) {
|
||||
reject('result not found!');
|
||||
} else {
|
||||
console.log('user added to role');
|
||||
resolve(body);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in AddUserToRole');
|
||||
console.log(err);
|
||||
return Promise.reject('Error:exception in query,Result not Found');
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,23 @@ async function AuthLoginAsMail(request) {
|
||||
|
||||
if (resOtp === otp) {
|
||||
var result = await getToken(request);
|
||||
return result;
|
||||
if (result && !result?.emailVerified) {
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
const user = await userQuery.get(result?.objectId, {
|
||||
sessionToken: result.sessionToken,
|
||||
});
|
||||
// Update the emailVerified field to true
|
||||
user.set('emailVerified', true);
|
||||
// Save the user object
|
||||
const res = await user.save(null, { useMasterKey: true });
|
||||
if (res) {
|
||||
return result;
|
||||
} else {
|
||||
reject('user not found!');
|
||||
}
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
|
||||
async function getToken(request) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
@@ -56,6 +72,7 @@ async function AuthLoginAsMail(request) {
|
||||
.catch(err => {
|
||||
reject('user not found!');
|
||||
});
|
||||
|
||||
// user couldn't find lets sign up!
|
||||
})
|
||||
.catch(() => {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// `CheckAdminExist` is used to check is admin with org exist or not in db
|
||||
export default async function CheckAdminExist() {
|
||||
try {
|
||||
const extClsQuery = new Parse.Query('contracts_Users');
|
||||
extClsQuery.equalTo('UserRole', 'contracts_Admin');
|
||||
extClsQuery.notEqualTo('IsDisabled', true);
|
||||
const extAdminRes = await extClsQuery.find({ useMasterKey: true });
|
||||
// must be only one admin
|
||||
if (extAdminRes && extAdminRes.length === 1 && extAdminRes?.[0]?.get('OrganizationId')) {
|
||||
return 'exist';
|
||||
} else {
|
||||
return 'not_exist';
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in isAdminExist', err);
|
||||
const code = err?.code || 400;
|
||||
const msg = err?.message || 'something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ async function DocumentAftersave(request) {
|
||||
const ip = request?.headers?.['x-real-ip'] || '';
|
||||
if (createdAt && Folder === undefined) {
|
||||
// console.log("IN If condition")
|
||||
const TimeToCompleteDays = request.object.get('TimeToCompleteDays');
|
||||
const TimeToCompleteDays = request.object.get('TimeToCompleteDays') || 15;
|
||||
const ExpiryDate = new Date(createdAt);
|
||||
ExpiryDate.setDate(ExpiryDate.getDate() + TimeToCompleteDays);
|
||||
const documentQuery = new Parse.Query('contracts_Document');
|
||||
|
||||
@@ -17,13 +17,13 @@ async function DocumentBeforesave(request) {
|
||||
await contractUser.save(null, { useMasterKey: true });
|
||||
} else {
|
||||
// Create new entry if not found
|
||||
const ContractsUsers = Parse.Object.extend('contracts_users');
|
||||
const ContractsUsers = Parse.Object.extend('contracts_Users');
|
||||
const newContractUser = new ContractsUsers();
|
||||
newContractUser.set('DocumentCount', 1);
|
||||
await newContractUser.save(null, { useMasterKey: true });
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('Error updating document count in contracts_users: ' + error.message);
|
||||
console.log('Error updating document count in contracts_Users: ' + error.message);
|
||||
}
|
||||
if (document?.get('Signers') && document.get('Signers').length > 0) {
|
||||
document.set('DocSentAt', new Date());
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// `GetLogoByDomain` is used to get logo by domain as well as check any tenant exist or not in db
|
||||
export default async function GetLogoByDomain(request) {
|
||||
const domain = request.params.domain;
|
||||
try {
|
||||
const tenantCreditsQuery = new Parse.Query('partners_Tenant');
|
||||
tenantCreditsQuery.equalTo('Domain', domain);
|
||||
const res = await tenantCreditsQuery.first();
|
||||
if (res) {
|
||||
const updateRes = JSON.parse(JSON.stringify(res));
|
||||
return { logo: updateRes?.Logo, user: 'exist' };
|
||||
} else {
|
||||
const tenantCreditsQuery = new Parse.Query('partners_Tenant');
|
||||
const tenantRes = await tenantCreditsQuery.first();
|
||||
if (tenantRes) {
|
||||
return { logo: '', user: 'exist' };
|
||||
} else {
|
||||
return { logo: '', user: 'not_exist' };
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
const code = err.code || 400;
|
||||
const msg = err.message || 'Something went wrong.';
|
||||
throw new Parse.Error(code, msg);
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,12 @@ async function GetPublicTemplate(request) {
|
||||
if (username) {
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
extUserQuery.equalTo('UserName', username);
|
||||
const res = await extUserQuery.first({ useMasterKey: true });
|
||||
const userId = res.get('UserId').id;
|
||||
const userRes = await extUserQuery.first({ useMasterKey: true });
|
||||
const userId = userRes.get('UserId').id;
|
||||
|
||||
//get _user details
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
const user = await userQuery.get(userId, { useMasterKey: true });
|
||||
if (userId) {
|
||||
const templatQuery = new Parse.Query('contracts_Template');
|
||||
templatQuery.equalTo('CreatedBy', {
|
||||
@@ -13,11 +17,20 @@ async function GetPublicTemplate(request) {
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
templatQuery.descending('updatedAt');
|
||||
templatQuery.equalTo('IsPublic', true);
|
||||
const getTemplate = await templatQuery.find({ useMasterKey: true });
|
||||
return getTemplate;
|
||||
|
||||
const extend_Res = await Parse.Cloud.run('getUserDetails', {
|
||||
email: user.get('email'),
|
||||
});
|
||||
if (extend_Res) {
|
||||
return { template: getTemplate, user: user, extend_User: extend_Res };
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found');
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found');
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User does not exist');
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Please provide required parameters!');
|
||||
|
||||
@@ -3,35 +3,75 @@ import axios from 'axios';
|
||||
export default async function GetTemplate(request) {
|
||||
const serverUrl = process.env.SERVER_URL;
|
||||
const templateId = request.params.templateId;
|
||||
const ispublic = request.params.ispublic;
|
||||
|
||||
try {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
const userId = userRes.data && userRes.data.objectId;
|
||||
// console.log("templateId ", templateId)
|
||||
// console.log("userId ",userId)
|
||||
if (templateId && userId) {
|
||||
if (!ispublic) {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
const userId = userRes.data && userRes.data.objectId;
|
||||
if (templateId && userId) {
|
||||
try {
|
||||
let template = new Parse.Query('contracts_Template');
|
||||
template.equalTo('objectId', templateId);
|
||||
template.include('ExtUserPtr');
|
||||
template.include('Signers');
|
||||
template.include('CreatedBy');
|
||||
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
extUserQuery.equalTo('Email', userRes.data.email);
|
||||
extUserQuery.include('TeamIds');
|
||||
const extUser = await extUserQuery.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||
if (_extUser?.TeamIds && _extUser.TeamIds?.length > 0) {
|
||||
let teamsArr = [];
|
||||
_extUser?.TeamIds?.forEach(x => (teamsArr = [...teamsArr, ...x.Ancestors]));
|
||||
// Create the first query
|
||||
const sharedWithQuery = new Parse.Query('contracts_Template');
|
||||
sharedWithQuery.containedIn('SharedWith', teamsArr);
|
||||
|
||||
// Create the second query
|
||||
const createdByQuery = new Parse.Query('contracts_Template');
|
||||
createdByQuery.equalTo('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser.id,
|
||||
});
|
||||
template = Parse.Query.or(sharedWithQuery, createdByQuery);
|
||||
template.equalTo('objectId', templateId);
|
||||
template.include('ExtUserPtr');
|
||||
template.include('Signers');
|
||||
template.include('CreatedBy');
|
||||
}
|
||||
}
|
||||
const res = await template.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
// console.log("res ",res)
|
||||
return res;
|
||||
} else {
|
||||
return { error: "You don't have access of this document!" };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err', err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
} else if (templateId && ispublic) {
|
||||
try {
|
||||
const template = new Parse.Query('contracts_Template');
|
||||
template.equalTo('objectId', templateId);
|
||||
template.include('ExtUserPtr');
|
||||
template.include('Signers');
|
||||
template.include('CreateBy');
|
||||
template.include('CreatedBy');
|
||||
const res = await template.first({ useMasterKey: true });
|
||||
// console.log("res ", res)
|
||||
if (res) {
|
||||
// console.log("res ",res)
|
||||
const acl = res.getACL();
|
||||
// console.log("acl", acl.getReadAccess(userId))
|
||||
if (acl && acl.getReadAccess(userId)) {
|
||||
return res;
|
||||
} else {
|
||||
return { error: "You don't have access of this document!" };
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return { error: "You don't have access of this document!" };
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user