mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-03 16:28:56 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc398d68e4 | ||
|
|
cd4844863e | ||
|
|
6d4ebf7be5 | ||
|
|
18992e0334 | ||
|
|
0580a18b0d | ||
|
|
5a4114b786 | ||
|
|
4fdf2299f8 | ||
|
|
f15aa39588 | ||
|
|
694312812a | ||
|
|
2606b58434 | ||
|
|
943f9a0673 | ||
|
|
77622ebea9 | ||
|
|
6fb714d565 | ||
|
|
f6170e01f6 | ||
|
|
1e857b615f | ||
|
|
b982ca5218 | ||
|
|
c83817800e | ||
|
|
d1992839a8 | ||
|
|
bfb7136c89 | ||
|
|
52b2cc6af4 | ||
|
|
94d386541d | ||
|
|
d85d76c8aa | ||
|
|
ade97b972f | ||
|
|
532780629b | ||
|
|
1f2298f192 | ||
|
|
ae5d527e4f | ||
|
|
e59a7e0028 | ||
|
|
1d6655eafe | ||
|
|
09b39a467b | ||
|
|
e0e7dd5298 | ||
|
|
56d5091b96 | ||
|
|
0b28e64111 | ||
|
|
482b75c6a7 | ||
|
|
cdff7e252d | ||
|
|
a18aee0be1 | ||
|
|
89f67bfeeb | ||
|
|
e4f0e9cef3 | ||
|
|
12599c1e5a | ||
|
|
6bb3203417 | ||
|
|
0eb2c5ecc4 | ||
|
|
01ab19b235 | ||
|
|
ba6b0ce7e5 | ||
|
|
b99d3f643b | ||
|
|
fea174c48d | ||
|
|
1aa1a602b3 | ||
|
|
37b7e50b4c | ||
|
|
e9fab26ef3 | ||
|
|
3216a1d4ae | ||
|
|
eb0941f087 | ||
|
|
0a315ef9c7 | ||
|
|
134babd070 | ||
|
|
954ba13f22 | ||
|
|
66718fd416 | ||
|
|
f4358c5004 | ||
|
|
63f888b3ec | ||
|
|
e066d1d273 | ||
|
|
daddb10030 | ||
|
|
6d9090d414 | ||
|
|
795e8a8ec9 | ||
|
|
e8b0b333a1 | ||
|
|
93d9a761ca | ||
|
|
3642d4f3a3 | ||
|
|
08387fc406 | ||
|
|
d1d0f40b00 | ||
|
|
ad4a9e7141 | ||
|
|
d46cb7dc10 | ||
|
|
50b9717cb9 | ||
|
|
4e83734c5c | ||
|
|
6eeaea137a | ||
|
|
2c91499232 | ||
|
|
e6085eb2c0 | ||
|
|
6fa4c4759b | ||
|
|
f8d6547c24 | ||
|
|
ffdd952440 | ||
|
|
9594e9438e | ||
|
|
08d1e9a360 | ||
|
|
74a9d08550 | ||
|
|
6fc86e026b | ||
|
|
72da56a916 | ||
|
|
4ba7ffbb1a | ||
|
|
0d9a0b8bb1 | ||
|
|
084aa69702 | ||
|
|
597635800f | ||
|
|
8da2c7fad4 | ||
|
|
2b0276ead9 | ||
|
|
45a96ece54 | ||
|
|
729d19dfd3 | ||
|
|
29aa123669 | ||
|
|
f69caf016a | ||
|
|
48e0e0ee15 | ||
|
|
a71278f95c | ||
|
|
f7bb11ede1 | ||
|
|
6a365f7734 | ||
|
|
e4d946e519 | ||
|
|
149a16f150 | ||
|
|
d8ff3d9faa | ||
|
|
fe34001e42 | ||
|
|
fcdd7e2758 | ||
|
|
025c30b685 | ||
|
|
e742e85f0e | ||
|
|
476a99feae | ||
|
|
29464585b8 | ||
|
|
cdd078699b | ||
|
|
9ef1e22fda | ||
|
|
655401e04b | ||
|
|
b550c07ca8 | ||
|
|
fd72094b8a | ||
|
|
4d7348abc2 | ||
|
|
ec68479e98 | ||
|
|
ac05942e58 | ||
|
|
b387b6b402 | ||
|
|
e13baeb2fc | ||
|
|
52eb8e4a68 | ||
|
|
71189783a8 | ||
|
|
aec9396524 | ||
|
|
d74390b974 | ||
|
|
998fe013c8 | ||
|
|
06d4c9aeaf | ||
|
|
bc77a9b0a1 | ||
|
|
07c0390401 | ||
|
|
c50d753d74 | ||
|
|
65eef5739d | ||
|
|
01eed3664b | ||
|
|
685e09d406 | ||
|
|
7bacca1f78 | ||
|
|
3764ab5c30 | ||
|
|
2f7a1d67b6 | ||
|
|
8726efb0aa | ||
|
|
e073e83ad6 | ||
|
|
69140d2139 | ||
|
|
aeed48c0ef | ||
|
|
1f9504b9cc | ||
|
|
5518d6932e | ||
|
|
f14e301b6c | ||
|
|
901ddf35bb | ||
|
|
9aa3166528 | ||
|
|
a90e679228 | ||
|
|
90b5e3c860 | ||
|
|
74f6612271 | ||
|
|
2862a97c4e | ||
|
|
5c3f967128 | ||
|
|
6fde71e947 | ||
|
|
2900464272 | ||
|
|
10bac3c11f | ||
|
|
302f38d472 | ||
|
|
8ecdbc43a3 | ||
|
|
6721b334cf | ||
|
|
454f557d14 | ||
|
|
635693b394 | ||
|
|
0be1816046 | ||
|
|
feb162e03e | ||
|
|
c8801846fa | ||
|
|
a793fc3722 | ||
|
|
ffdabe4a00 | ||
|
|
5536c99052 | ||
|
|
ba1c3145f3 | ||
|
|
0fbe6aeb6c | ||
|
|
4898c4a851 | ||
|
|
85aa6b2947 | ||
|
|
3b02d2bcdb | ||
|
|
ed01f4a7a0 | ||
|
|
1f395cf25f | ||
|
|
cf98e73d13 | ||
|
|
10112ac20d | ||
|
|
9a0183274f | ||
|
|
6b2e16c21d | ||
|
|
3c51baf1c9 | ||
|
|
3f4be1c4f3 | ||
|
|
62b36f58f7 | ||
|
|
ba3591c7bc | ||
|
|
1ec11b8733 | ||
|
|
ab89d3b71f | ||
|
|
1811173648 | ||
|
|
b218e96107 | ||
|
|
64a0be8776 | ||
|
|
414e2d819c | ||
|
|
0769101f28 | ||
|
|
5dc86119d3 | ||
|
|
4999dc2b18 | ||
|
|
962d36c088 | ||
|
|
d071986aac | ||
|
|
afb4de9d0c | ||
|
|
bc5c8cac33 | ||
|
|
be93e6a214 | ||
|
|
37748057e3 | ||
|
|
eb3bb77692 | ||
|
|
df0ce3f086 | ||
|
|
0a99b5181e | ||
|
|
8a5d3a0368 | ||
|
|
c00406e401 | ||
|
|
aeead23c86 | ||
|
|
83fe88911f | ||
|
|
527bca32d2 | ||
|
|
9bf4940c2e | ||
|
|
a653df6935 | ||
|
|
dfc6da388c | ||
|
|
3e2c822bbc | ||
|
|
1a20841a94 | ||
|
|
c6be81923b | ||
|
|
6b47f6a27b | ||
|
|
33b0111ed0 | ||
|
|
48fd9e52b3 | ||
|
|
d85074b127 | ||
|
|
5ada9a411b | ||
|
|
6f50de1ef1 | ||
|
|
612150cf4b | ||
|
|
634db83e8e | ||
|
|
b32c8068ef | ||
|
|
ae464274b0 | ||
|
|
c5ceba8d57 | ||
|
|
903d626c27 | ||
|
|
e5b4fb123f | ||
|
|
116893c1b4 | ||
|
|
592254a9a3 | ||
|
|
f52c6e24fe | ||
|
|
70ae1e24fc | ||
|
|
c491595fc8 | ||
|
|
6875135ede | ||
|
|
662049d878 | ||
|
|
1764d7f9ba | ||
|
|
07933b56b1 | ||
|
|
f6ba4db62d | ||
|
|
5bd36f91d9 | ||
|
|
c199c3019e | ||
|
|
facbc8e76e | ||
|
|
c3c6f6bab3 | ||
|
|
f5e216fedc | ||
|
|
c40a923388 | ||
|
|
a86f4fd9b7 | ||
|
|
59f6d022cf | ||
|
|
b7beeee260 | ||
|
|
31c861cbe4 | ||
|
|
6a9408b7b4 | ||
|
|
a9fd264a01 | ||
|
|
6c77bbfe75 | ||
|
|
890c3d2b1f | ||
|
|
3ede441f54 | ||
|
|
2433ad5957 | ||
|
|
fffd907d63 | ||
|
|
51edc339cd | ||
|
|
bf307abe9a | ||
|
|
08a97707b7 | ||
|
|
d99fecd46e | ||
|
|
6c59c0ec9a | ||
|
|
32c75d1fc3 | ||
|
|
7f0f81c334 | ||
|
|
a882f07f57 | ||
|
|
74b81a5363 | ||
|
|
9b75764717 | ||
|
|
c1468112b0 | ||
|
|
950b74789c | ||
|
|
7e4f12e41a | ||
|
|
d75c1d7c0c | ||
|
|
7eacbedf59 | ||
|
|
2e5947279f | ||
|
|
ef5ac7d626 | ||
|
|
658c37cc4d | ||
|
|
ffc8e4b23e | ||
|
|
3fb96fc792 | ||
|
|
71016ba5e0 | ||
|
|
cd1a6fdaf6 | ||
|
|
c2afeed448 | ||
|
|
37fd7bbeda | ||
|
|
71fbde0099 | ||
|
|
ca6cb60d78 | ||
|
|
df1c0ea66c | ||
|
|
46279efc2c | ||
|
|
aca2848406 | ||
|
|
eaec3cf607 | ||
|
|
ad25d73f26 | ||
|
|
481b9ac1e0 | ||
|
|
4cd3791feb | ||
|
|
7de8699437 | ||
|
|
4c162676b1 | ||
|
|
ca390bdfa6 | ||
|
|
22d064fd38 | ||
|
|
444c9bbfdf | ||
|
|
b289686d42 | ||
|
|
eeb878b340 | ||
|
|
7894d69cc9 | ||
|
|
b992d7db24 | ||
|
|
50b72f4d85 | ||
|
|
44639f66b0 | ||
|
|
ae740efced | ||
|
|
66c020d903 | ||
|
|
562a7d6fc8 | ||
|
|
090c17c2c0 | ||
|
|
70637d6143 | ||
|
|
f38e8705de | ||
|
|
ba06ff72a0 | ||
|
|
82312a1e0d | ||
|
|
1a8cf11a3e | ||
|
|
3deacbabc3 | ||
|
|
c28805add9 | ||
|
|
80fb320ae4 | ||
|
|
76c9c1fa53 | ||
|
|
f38d83dbe0 | ||
|
|
ee9411729d | ||
|
|
f6f7c6cecd | ||
|
|
a45fc0dd60 | ||
|
|
348f7810b9 | ||
|
|
45bec128a9 | ||
|
|
4da307315c | ||
|
|
c87aa415a9 | ||
|
|
b1786ec16a | ||
|
|
6ad35e979e | ||
|
|
9d996d5cb7 | ||
|
|
008e3e8783 | ||
|
|
8458906b0b | ||
|
|
6933aa309b | ||
|
|
067ea68d3b | ||
|
|
e4e8a0b721 | ||
|
|
dc392adc1d | ||
|
|
741efff1fa | ||
|
|
38b7311e66 | ||
|
|
e0ccf049a6 | ||
|
|
1e58b35db5 | ||
|
|
498bd18630 | ||
|
|
b530ef882a | ||
|
|
850d14064a | ||
|
|
273ada837b | ||
|
|
280b812e5b |
@@ -1,12 +0,0 @@
|
||||
# Clone the repo and rename this file to .env if you want to run the frontend react app locally for some quick contributions to the project.
|
||||
# When used as it is, this env config will connect to our hosted UAT backend
|
||||
# Note that any data in staging will get cleared from time to time and you may have to sign up again and again
|
||||
|
||||
# Set it to the URL form where the app home page will be accessed
|
||||
PUBLIC_URL=http://localhost:3000
|
||||
# Set it to true if you want to generate the Sourcemap for debugging
|
||||
GENERATE_SOURCEMAP=false
|
||||
# Set it to the URL from where APIs will be accessible, for local development it should be localhost:3000/api/app (use your local port number instead)
|
||||
REACT_APP_SERVERURL=https://staging-app.opensignlabs.com/api/app
|
||||
# A 12 character long random app identifier. The value of this should be same as APP_ID which is a variable used by backend API.
|
||||
REACT_APP_APPID=opensign
|
||||
+1
-1
@@ -40,7 +40,7 @@ DO_SECRET_ACCESS_KEY=
|
||||
# Digital ocean spaces region or AWS s3 region
|
||||
DO_REGION=us-west
|
||||
# local storage
|
||||
USE_LOCAL=TRUE
|
||||
USE_LOCAL=true
|
||||
|
||||
# Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
|
||||
MAILGUN_API_KEY=
|
||||
|
||||
@@ -2,7 +2,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'staging'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
|
||||
@@ -136,7 +136,7 @@ We would like to thank all our contributors and users for their support and feed
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/VikramNagwal"><img src="https://avatars.githubusercontent.com/u/123088024?v=4?s=100" width="100px;" alt="Vikram"/><br /><sub><b>Vikram</b></sub></a><br /><a href="#code-VikramNagwal" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ugoconsonni"><img src="https://avatars.githubusercontent.com/u/13661702?v=4?s=100" width="100px;" alt="ugoconsonni"/><br /><sub><b>ugoconsonni</b></sub></a><br /><a href="#code-ugoconsonni" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/daniel-mutwiri"><img src="https://avatars.githubusercontent.com/u/8936960?v=4?s=100" width="100px;" alt="Daniel Mutwiri"/><br /><sub><b>Daniel Mutwiri</b></sub></a><br /><a href="#code-daniel-mutwiri" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Zathiel"><img src="https://avatars.githubusercontent.com/u/26553418?v=4?s=100" width="100px;" alt="Zathiel"/><br /><sub><b>Zathiel</b></sub></a><br /><a href="#code-Zathiel" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Zathiel"><img src="https://avatars.githubusercontent.com/u/26553418?v=4?s=100" width="100px;" alt="Zathiel"/><br /><sub><b>Zathiel</b></sub></a><br /><a href="#code-Zathiel" title="Code">💻</a><a href="#security-Zathiel" title="Security">🛡️</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Generated
+4475
-3918
File diff suppressed because it is too large
Load Diff
+28
-20
@@ -4,21 +4,24 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@formkit/auto-animate": "^0.8.2",
|
||||
"@radix-ui/themes": "^2.0.3",
|
||||
"@lottiefiles/dotlottie-react": "^0.6.4",
|
||||
"@radix-ui/themes": "^3.0.5",
|
||||
"@react-pdf/renderer": "^3.4.4",
|
||||
"@reduxjs/toolkit": "^2.2.1",
|
||||
"axios": "^1.6.8",
|
||||
"@reduxjs/toolkit": "^2.2.5",
|
||||
"axios": "^1.7.2",
|
||||
"file-saver": "^2.0.5",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"moment": "^2.30.1",
|
||||
"parse": "^4.3.1",
|
||||
"nth-check": "^2.1.1",
|
||||
"parse": "^5.1.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-confetti": "^6.1.0",
|
||||
"react-cookie": "^7.1.4",
|
||||
"react-datepicker": "^6.4.0",
|
||||
"react-datepicker": "^6.9.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dnd-multi-backend": "^8.0.3",
|
||||
@@ -27,25 +30,25 @@
|
||||
"react-gtm-module": "^2.0.11",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-konva": "^18.2.10",
|
||||
"react-modal": "^3.16.1",
|
||||
"react-pdf": "^7.7.3",
|
||||
"react-pdf": "^9.0.0",
|
||||
"react-quill": "^2.0.0",
|
||||
"react-redux": "^9.1.0",
|
||||
"react-rnd": "^10.4.10",
|
||||
"react-redux": "^9.1.2",
|
||||
"react-rnd": "^10.4.11",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"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.3",
|
||||
"react-tooltip": "^5.26.4",
|
||||
"react-web-share": "^2.0.2",
|
||||
"reactour": "^1.19.3",
|
||||
"reactour": "^1.19.4",
|
||||
"redux": "^5.0.1",
|
||||
"redux-thunk": "^3.1.0",
|
||||
"regex-parser": "^2.3.0",
|
||||
"serve": "^14.2.1",
|
||||
"serve": "^14.2.3",
|
||||
"styled-components": "^4.4.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
"web-vitals": "^4.0.1",
|
||||
"ws": "^8.17.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "serve -s build",
|
||||
@@ -83,16 +86,21 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/runtime-corejs2": "^7.24.5",
|
||||
"@babel/runtime-corejs2": "^7.24.7",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"commitizen": "^4.3.0",
|
||||
"daisyui": "^4.12.2",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"lint-staged": "^15.2.2",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react": "^7.34.3",
|
||||
"lint-staged": "^15.2.7",
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "^2.8.8",
|
||||
"pretty-quick": "^3.3.1",
|
||||
"tailwindcss": "^3.4.1"
|
||||
"prettier": "^3.3.2",
|
||||
"pretty-quick": "^4.0.0",
|
||||
"tailwindcss": "^3.4.4"
|
||||
},
|
||||
"overrides": {
|
||||
"nth-check": "$nth-check",
|
||||
"ws":"$ws"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,53 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<html lang="en" data-theme="opensigncss">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<!-- <link rel="icon" type="image/png"
|
||||
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC"
|
||||
sizes="40x40" /> -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="The fastest way to sign PDFs & request signatures from others" />
|
||||
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> -->
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"
|
||||
integrity="sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn+CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA=="
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
<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" />
|
||||
<title>OpenSign™</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -16,6 +16,8 @@ import PlaceHolderSign from "./pages/PlaceHolderSign";
|
||||
import PdfRequestFiles from "./pages/PdfRequestFiles";
|
||||
import LazyPage from "./primitives/LazyPage";
|
||||
import { isEnableSubscription } from "./constant/const";
|
||||
import SSOVerify from "./pages/SSOVerify";
|
||||
import Loader from "./primitives/Loader";
|
||||
const DebugPdf = lazy(() => import("./pages/DebugPdf"));
|
||||
const ForgetPassword = lazy(() => import("./pages/ForgetPassword"));
|
||||
const GuestLogin = lazy(() => import("./pages/GuestLogin"));
|
||||
@@ -28,25 +30,12 @@ const Opensigndrive = lazy(() => import("./pages/Opensigndrive"));
|
||||
const ManageSign = lazy(() => import("./pages/Managesign"));
|
||||
const GenerateToken = lazy(() => import("./pages/GenerateToken"));
|
||||
const Webhook = lazy(() => import("./pages/Webhook"));
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
|
||||
|
||||
const Loader = () => {
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
|
||||
const AppLoader = () => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="flex justify-center items-center h-[100vh]">
|
||||
<Loader />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -75,9 +64,9 @@ function App() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-[#eef1f5]">
|
||||
<div className="bg-base-200">
|
||||
{isloading ? (
|
||||
<Loader />
|
||||
<AppLoader />
|
||||
) : (
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
@@ -181,6 +170,7 @@ function App() {
|
||||
element={<PdfRequestFiles />}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="/sso" element={<SSOVerify />} />
|
||||
<Route path="*" element={<PageNotFound />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 61 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 234 KiB |
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Parse from "parse";
|
||||
import axios from "axios";
|
||||
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
const AddSigner = (props) => {
|
||||
const [name, setName] = useState("");
|
||||
@@ -23,7 +23,7 @@ const AddSigner = (props) => {
|
||||
);
|
||||
if (savedUserDetails && addYourself) {
|
||||
setName(savedUserDetails.name);
|
||||
setPhone(savedUserDetails.phone);
|
||||
setPhone(savedUserDetails?.phone || "");
|
||||
setEmail(savedUserDetails.email);
|
||||
}
|
||||
}, [addYourself]);
|
||||
@@ -50,145 +50,161 @@ const AddSigner = (props) => {
|
||||
e.stopPropagation();
|
||||
setIsLoader(true);
|
||||
if (localStorage.getItem("TenantId")) {
|
||||
try {
|
||||
const contactQuery = new Parse.Object("contracts_Contactbook");
|
||||
contactQuery.set("Name", name);
|
||||
contactQuery.set("Phone", phone);
|
||||
contactQuery.set("Email", email);
|
||||
contactQuery.set("UserRole", "contracts_Guest");
|
||||
|
||||
contactQuery.set("TenantId", {
|
||||
__type: "Pointer",
|
||||
className: "partners_Tenant",
|
||||
objectId: localStorage.getItem("TenantId")
|
||||
});
|
||||
|
||||
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("phone", phone);
|
||||
_user.set("password", 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_Guest",
|
||||
userId: user.id
|
||||
};
|
||||
await axios.post(roleurl, body, { headers: headers });
|
||||
const currentUser = Parse.User.current();
|
||||
contactQuery.set(
|
||||
"CreatedBy",
|
||||
Parse.User.createWithoutData(currentUser.id)
|
||||
);
|
||||
|
||||
contactQuery.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);
|
||||
|
||||
const res = await contactQuery.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) {
|
||||
props.handleUserData(parseData);
|
||||
const user = Parse.User.current();
|
||||
const query = new Parse.Query("contracts_Contactbook");
|
||||
query.equalTo("CreatedBy", user);
|
||||
query.notEqualTo("IsDeleted", true);
|
||||
query.equalTo("Email", email);
|
||||
const res = await query.first();
|
||||
// console.log(res);
|
||||
if (!res) {
|
||||
const contactQuery = new Parse.Object("contracts_Contactbook");
|
||||
contactQuery.set("Name", name);
|
||||
if (phone) {
|
||||
contactQuery.set("Phone", phone);
|
||||
}
|
||||
contactQuery.set("Email", email);
|
||||
contactQuery.set("UserRole", "contracts_Guest");
|
||||
|
||||
contactQuery.set("TenantId", {
|
||||
__type: "Pointer",
|
||||
className: "partners_Tenant",
|
||||
objectId: localStorage.getItem("TenantId")
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
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",
|
||||
Parse.User.createWithoutData(currentUser.id)
|
||||
);
|
||||
|
||||
contactQuery.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);
|
||||
|
||||
const res = await contactQuery.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) {
|
||||
props.handleUserData(parseData);
|
||||
}
|
||||
|
||||
setIsLoader(false);
|
||||
// Reset the form fields
|
||||
setAddYourself(false);
|
||||
setName("");
|
||||
setPhone("");
|
||||
setEmail("");
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err ", err);
|
||||
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",
|
||||
Parse.User.createWithoutData(currentUser.id)
|
||||
);
|
||||
|
||||
contactQuery.set("UserId", {
|
||||
__type: "Pointer",
|
||||
className: "_User",
|
||||
objectId: userRes.id
|
||||
});
|
||||
const acl = new Parse.ACL();
|
||||
acl.setPublicReadAccess(true);
|
||||
acl.setPublicWriteAccess(true);
|
||||
acl.setReadAccess(currentUser.id, true);
|
||||
acl.setWriteAccess(currentUser.id, true);
|
||||
|
||||
contactQuery.setACL(acl);
|
||||
const res = await contactQuery.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) {
|
||||
props.handleUserData(parseData);
|
||||
}
|
||||
setIsLoader(false);
|
||||
// Reset the form fields
|
||||
setAddYourself(false);
|
||||
setName("");
|
||||
setPhone("");
|
||||
setEmail("");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
alert("Contact already exist!");
|
||||
setIsLoader(false);
|
||||
// Reset the form fields
|
||||
setAddYourself(false);
|
||||
setName("");
|
||||
setPhone("");
|
||||
setEmail("");
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err ", err);
|
||||
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",
|
||||
Parse.User.createWithoutData(currentUser.id)
|
||||
);
|
||||
|
||||
contactQuery.set("UserId", {
|
||||
__type: "Pointer",
|
||||
className: "_User",
|
||||
objectId: userRes.id
|
||||
});
|
||||
const acl = new Parse.ACL();
|
||||
acl.setPublicReadAccess(true);
|
||||
acl.setPublicWriteAccess(true);
|
||||
acl.setReadAccess(currentUser.id, true);
|
||||
acl.setWriteAccess(currentUser.id, true);
|
||||
|
||||
contactQuery.setACL(acl);
|
||||
const res = await contactQuery.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) {
|
||||
props.handleUserData(parseData);
|
||||
}
|
||||
setIsLoader(false);
|
||||
// Reset the form fields
|
||||
setAddYourself(false);
|
||||
setName("");
|
||||
setPhone("");
|
||||
setEmail("");
|
||||
}
|
||||
console.log("err in fetch contact", err);
|
||||
setIsLoader(false);
|
||||
alert("something went wrong, please try again later");
|
||||
}
|
||||
} catch (err) {
|
||||
// console.log("err", err);
|
||||
} else {
|
||||
setIsLoader(false);
|
||||
alert("something went wrong!");
|
||||
}
|
||||
}else{
|
||||
alert('something went wrong, please try again later')
|
||||
alert("something went wrong, please try again later");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -211,38 +227,29 @@ const AddSigner = (props) => {
|
||||
<div className="h-full p-[20px]">
|
||||
{isLoader && (
|
||||
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30">
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full mx-auto p-2">
|
||||
<div className="w-full mx-auto p-2 text-base-content">
|
||||
{isUserExist && (
|
||||
<div className="mb-3">
|
||||
<div className="mb-3 flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="addYourself"
|
||||
checked={addYourself}
|
||||
onChange={handleAddYourselfChange}
|
||||
className="form-checkbox"
|
||||
className="op-checkbox op-checkbox-sm"
|
||||
/>
|
||||
<label htmlFor="addYourself" className="ml-2 text-gray-700">
|
||||
<label htmlFor="addYourself" className="ml-2 mb-0">
|
||||
Add Yourself
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
<label htmlFor="name" className="block text-xs font-semibold">
|
||||
Name
|
||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
||||
<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
@@ -251,59 +258,45 @@ const AddSigner = (props) => {
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
required
|
||||
disabled={addYourself}
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
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"
|
||||
>
|
||||
<label htmlFor="email" className="block text-xs font-semibold">
|
||||
Email
|
||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
||||
<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
onChange={(e) => setEmail(e.target.value?.toLowerCase())}
|
||||
required
|
||||
disabled={addYourself}
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
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"
|
||||
>
|
||||
<label htmlFor="phone" className="block text-xs font-semibold">
|
||||
Phone
|
||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="phone"
|
||||
value={phone}
|
||||
onChange={(e) => setPhone(e.target.value)}
|
||||
required
|
||||
disabled={addYourself}
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 flex justify-start">
|
||||
<button
|
||||
type="submit"
|
||||
style={{ backgroundColor: modalSubmitBtnColor }}
|
||||
className="mr-2 px-[20px] py-1.5 text-white rounded shadow-md text-center focus:outline-none "
|
||||
>
|
||||
<div className="mt-4 flex gap-x-2 justify-start">
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Submit
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleReset()}
|
||||
style={{ backgroundColor: modalCancelBtnColor }}
|
||||
className="px-4 py-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none"
|
||||
className="op-btn op-btn-secondary"
|
||||
>
|
||||
Reset
|
||||
</button>
|
||||
|
||||
@@ -3,6 +3,7 @@ import Parse from "parse";
|
||||
import axios from "axios";
|
||||
import Title from "./Title";
|
||||
import Alert from "../primitives/Alert";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
const AddUser = (props) => {
|
||||
const [name, setName] = useState("");
|
||||
@@ -62,8 +63,10 @@ const AddUser = (props) => {
|
||||
_user.set("name", name);
|
||||
_user.set("username", email);
|
||||
_user.set("email", email);
|
||||
_user.set("phone", phone);
|
||||
_user.set("password", phone);
|
||||
_user.set("password", email);
|
||||
if (phone) {
|
||||
_user.set("phone", phone);
|
||||
}
|
||||
|
||||
const user = await _user.save();
|
||||
if (user) {
|
||||
@@ -193,13 +196,7 @@ const AddUser = (props) => {
|
||||
{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
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full mx-auto">
|
||||
@@ -211,7 +208,7 @@ const AddUser = (props) => {
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Name
|
||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
||||
<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
@@ -219,7 +216,7 @@ const AddUser = (props) => {
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
required
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
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">
|
||||
@@ -228,7 +225,7 @@ const AddUser = (props) => {
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Email
|
||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
||||
<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
@@ -236,7 +233,7 @@ const AddUser = (props) => {
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
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">
|
||||
@@ -245,7 +242,7 @@ const AddUser = (props) => {
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Phone
|
||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
||||
<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
@@ -253,7 +250,7 @@ const AddUser = (props) => {
|
||||
value={phone}
|
||||
onChange={(e) => setPhone(e.target.value)}
|
||||
required
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import axios from "axios";
|
||||
import SuggestionInput from "./shared/fields/SuggestionInput";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
const BulkSendUi = (props) => {
|
||||
const [forms, setForms] = useState([]);
|
||||
const [formId, setFormId] = useState(2);
|
||||
const formRef = useRef(null);
|
||||
const [scrollOnNextUpdate, setScrollOnNextUpdate] = useState(false);
|
||||
const [isSubmit, setIsSubmit] = useState(false);
|
||||
const [allowedForm, setAllowedForm] = useState(0);
|
||||
const [isSignatureExist, setIsSignatureExist] = useState();
|
||||
const allowedSigners = 50;
|
||||
useEffect(() => {
|
||||
signatureExist();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
//function to check atleast one signature field exist
|
||||
const signatureExist = () => {
|
||||
const getPlaceholder = props.item?.Placeholders;
|
||||
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
|
||||
placeholderObj?.placeHolder?.some((holder) =>
|
||||
holder?.pos?.some((posItem) => posItem?.type === "signature")
|
||||
)
|
||||
);
|
||||
setIsSignatureExist(checkIsSignatureExistt);
|
||||
};
|
||||
useEffect(() => {
|
||||
if (scrollOnNextUpdate && formRef.current) {
|
||||
formRef.current.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "end",
|
||||
inline: "nearest"
|
||||
});
|
||||
setScrollOnNextUpdate(false);
|
||||
}
|
||||
}, [forms, scrollOnNextUpdate]);
|
||||
|
||||
useEffect(() => {
|
||||
(() => {
|
||||
if (props?.Placeholders?.length > 0) {
|
||||
let users = [];
|
||||
props?.Placeholders?.forEach((element) => {
|
||||
if (!element.signerObjId) {
|
||||
users = [
|
||||
...users,
|
||||
{
|
||||
fieldId: element.Id,
|
||||
email: "",
|
||||
label: element.Role,
|
||||
signer: {}
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
setForms((prevForms) => [...prevForms, { Id: 1, fields: users }]);
|
||||
const totalForms = Math.floor(allowedSigners / users?.length);
|
||||
setAllowedForm(totalForms);
|
||||
}
|
||||
})();
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
const handleInputChange = (index, signer, fieldIndex) => {
|
||||
const newForms = [...forms];
|
||||
newForms[index].fields[fieldIndex].email = signer?.Email
|
||||
? signer?.Email
|
||||
: signer || "";
|
||||
newForms[index].fields[fieldIndex].signer = signer?.objectId ? signer : "";
|
||||
setForms(newForms);
|
||||
};
|
||||
|
||||
const handleAddForm = (e) => {
|
||||
e.preventDefault();
|
||||
// Check if the quick send limit has been reached
|
||||
if (forms?.length < allowedForm) {
|
||||
if (props?.Placeholders.length > 0) {
|
||||
let newForm = [];
|
||||
props?.Placeholders?.forEach((element) => {
|
||||
if (!element.signerObjId) {
|
||||
newForm = [
|
||||
...newForm,
|
||||
{
|
||||
fieldId: element.Id,
|
||||
email: "",
|
||||
label: element.Role,
|
||||
signer: {}
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
setForms([...forms, { Id: formId, fields: newForm }]);
|
||||
}
|
||||
setFormId(formId + 1);
|
||||
setScrollOnNextUpdate(true);
|
||||
} else {
|
||||
// If the limit has been reached, throw an error with the appropriate message
|
||||
alert("Quick send reached limit.");
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveForm = (index) => {
|
||||
const updatedForms = forms.filter((_, i) => i !== index);
|
||||
setForms(updatedForms);
|
||||
};
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsSubmit(true);
|
||||
|
||||
// Create a copy of Placeholders array from props.item
|
||||
let Placeholders = [...props.item.Placeholders];
|
||||
// Initialize an empty array to store updated documents
|
||||
let Documents = [];
|
||||
// Loop through each form
|
||||
forms.forEach((form) => {
|
||||
//checking if user enter email which already exist as a signer then add user in a signers array
|
||||
let existSigner = [];
|
||||
form.fields.map((data) => {
|
||||
if (data.signer) {
|
||||
existSigner.push(data.signer);
|
||||
}
|
||||
});
|
||||
// Map through the copied Placeholders array to update email values
|
||||
const updatedPlaceholders = Placeholders.map((placeholder) => {
|
||||
// Find the field in the current form that matches the placeholder Id
|
||||
const field = form.fields.find(
|
||||
(element) => parseInt(element.fieldId) === placeholder.Id
|
||||
);
|
||||
// If a matching field is found, update the email value in the placeholder
|
||||
const signer = field?.signer?.objectId ? field.signer : "";
|
||||
if (field) {
|
||||
if (signer) {
|
||||
return {
|
||||
...placeholder,
|
||||
signerObjId: field?.signer?.objectId || "",
|
||||
signerPtr: signer
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
...placeholder,
|
||||
email: field.email,
|
||||
signerObjId: field?.signer?.objectId || "",
|
||||
signerPtr: signer
|
||||
};
|
||||
}
|
||||
}
|
||||
// If no matching field is found, keep the placeholder as is
|
||||
return placeholder;
|
||||
});
|
||||
|
||||
// Push a new document object with updated Placeholders into the Documents array
|
||||
if (existSigner?.length > 0) {
|
||||
Documents.push({
|
||||
...props.item,
|
||||
Placeholders: updatedPlaceholders,
|
||||
Signers: props.item.Signers
|
||||
? [...props.item.Signers, ...existSigner]
|
||||
: [...existSigner]
|
||||
});
|
||||
} else {
|
||||
Documents.push({
|
||||
...props.item,
|
||||
Placeholders: updatedPlaceholders
|
||||
});
|
||||
}
|
||||
});
|
||||
//console.log("Documents ", Documents);
|
||||
await batchQuery(Documents);
|
||||
};
|
||||
|
||||
const batchQuery = async (Documents) => {
|
||||
const serverUrl = localStorage.getItem("baseUrl");
|
||||
const functionsUrl = `${serverUrl}functions/batchdocuments`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
};
|
||||
const params = {
|
||||
Documents: JSON.stringify(Documents)
|
||||
};
|
||||
try {
|
||||
const res = await axios.post(functionsUrl, params, { headers: headers });
|
||||
// console.log("res ", res);
|
||||
if (res.data && res.data.result) {
|
||||
props.handleClose("success", Documents?.length);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err ", err);
|
||||
props.handleClose("error", 0);
|
||||
} finally {
|
||||
setIsSubmit(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{isSubmit && (
|
||||
<div className="absolute z-[999] h-full w-full flex justify-center items-center bg-black bg-opacity-30">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
{props.Placeholders?.length > 0 ? (
|
||||
isSignatureExist ? (
|
||||
<>
|
||||
{props.Placeholders?.some((x) => !x.signerObjId) ? (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="min-h-max max-h-[250px] overflow-y-auto">
|
||||
{forms?.map((form, index) => (
|
||||
<div
|
||||
key={form.Id}
|
||||
className="p-3 op-card border-[1px] border-gray-400 mt-3 mx-4 mb-4 bg-base-200 text-base-content grid grid-cols-1 md:grid-cols-2 gap-2 relative"
|
||||
>
|
||||
{form?.fields?.map((field, fieldIndex) => (
|
||||
<div className="flex flex-col" key={field.fieldId}>
|
||||
<label>{field.label}</label>
|
||||
<SuggestionInput
|
||||
required
|
||||
type="email"
|
||||
value={field.value}
|
||||
index={fieldIndex}
|
||||
onChange={(signer) =>
|
||||
handleInputChange(index, signer, fieldIndex)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
{forms?.length > 1 && (
|
||||
<button
|
||||
onClick={() => handleRemoveForm(index)}
|
||||
className="absolute right-3 top-1 text-[red] border-[1px] border-[red] rounded-lg w-[1.7rem] h-[1.7rem]"
|
||||
>
|
||||
<i className="fa-light fa-trash"></i>
|
||||
</button>
|
||||
)}
|
||||
<div ref={formRef}></div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex flex-col mx-4 mb-4 gap-3">
|
||||
<button
|
||||
onClick={handleAddForm}
|
||||
className="op-btn op-btn-primary focus:outline-none"
|
||||
>
|
||||
<i className="fa-light fa-plus"></i> <span>Add new</span>
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="op-btn op-btn-secondary focus:outline-none"
|
||||
>
|
||||
<i className="fa-light fa-paper-plane"></i>{" "}
|
||||
<span>Send</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
|
||||
All roles in this document are currently linked to contacts. To
|
||||
'quick send' copies of this template to multiple
|
||||
signers, please ensure that at least one role is not linked to
|
||||
any contact.
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
|
||||
Please ensure there's at least one signature widget added for
|
||||
all recipients.
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
|
||||
Please add at least one role to this template in order to 'quick
|
||||
send' copies of it to multiple signers.
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BulkSendUi;
|
||||
@@ -45,19 +45,23 @@ const Footer = () => {
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className="bg-[#222c3c] text-[#98a6ba] text-center text-[13px] py-3">
|
||||
All Rights Reserved © {new Date().getFullYear()}
|
||||
<span onClick={openUrl} className="hover:underline cursor-pointer">
|
||||
{appName} ( version: {version ? version : `${Package.version} `})
|
||||
</span>
|
||||
</div>
|
||||
<footer className="op-footer op-footer-center py-3 bg-base-300 text-base-content text-center text-[13px]">
|
||||
<aside>
|
||||
<p>
|
||||
All Rights Reserved © {new Date().getFullYear()}
|
||||
<span onClick={openUrl} className="hover:underline cursor-pointer">
|
||||
{appName} ( version: {version ? version : `${Package.version} `})
|
||||
</span>
|
||||
</p>
|
||||
</aside>
|
||||
</footer>
|
||||
<button
|
||||
className={`${
|
||||
showButton ? "block" : "hidden"
|
||||
} fixed bottom-4 right-4 px-3 p-2 text-xl bg-blue-500 text-white rounded focus:outline-none`}
|
||||
} fixed bottom-4 right-4 px-3 p-2 text-xl op-bg-secondary text-white rounded focus:outline-none`}
|
||||
onClick={scrollToTop}
|
||||
>
|
||||
<i className="fa-solid fa-angle-up"></i>
|
||||
<i className="fa-light fa-angle-up"></i>
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -67,12 +67,12 @@ const FullScreenButton = () => {
|
||||
<div className="flex items-center">
|
||||
<button
|
||||
onClick={toggleFullScreen}
|
||||
className="text-black p-2 text-sm focus:outline-none"
|
||||
className="text-base-content p-2 text-sm focus:outline-none"
|
||||
>
|
||||
{isFullScreen ? (
|
||||
<i className="fa-solid fa-compress"></i>
|
||||
<i className="fa-light fa-compress"></i>
|
||||
) : (
|
||||
<i className="fa fa-maximize"></i>
|
||||
<i className="fa-light fa-maximize"></i>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -44,7 +44,13 @@ const Header = ({ showSidebar }) => {
|
||||
|
||||
const closeDropdown = () => {
|
||||
setIsOpen(false);
|
||||
Parse.User.logOut();
|
||||
if (Parse?.User?.current()) {
|
||||
try {
|
||||
Parse.User.logOut();
|
||||
} catch (err) {
|
||||
console.log("Err", err);
|
||||
}
|
||||
}
|
||||
let appdata = localStorage.getItem("userSettings");
|
||||
let applogo = localStorage.getItem("appLogo");
|
||||
let appName = localStorage.getItem("appName");
|
||||
@@ -87,14 +93,16 @@ const Header = ({ showSidebar }) => {
|
||||
}, [isOpen]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-row justify-between items-center gap-x-3 md:gap-x-4 bg-white md:px-4 px-2 shadow h-[50px] md:w-full ">
|
||||
<button
|
||||
className="cursor-pointer focus:outline-none"
|
||||
onClick={showSidebar}
|
||||
>
|
||||
<i className={`fa-solid fa-bars text-xl `}></i>
|
||||
</button>
|
||||
<div className="flex-1">
|
||||
<div className="op-navbar bg-base-100 shadow">
|
||||
<div className="flex-none">
|
||||
<button
|
||||
className="op-btn op-btn-square op-btn-ghost focus:outline-none hover:bg-transparent op-btn-sm no-animation"
|
||||
onClick={showSidebar}
|
||||
>
|
||||
<i className="fa-light fa-bars text-xl text-base-content"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex-1 ml-2">
|
||||
<div className="h-[25px] md:h-[40px] w-auto overflow-hidden">
|
||||
<img
|
||||
className="object-contain h-full w-auto"
|
||||
@@ -103,14 +111,11 @@ const Header = ({ showSidebar }) => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="profile-menu"
|
||||
className="flex justify-between items-center gap-x-3"
|
||||
>
|
||||
<div id="profile-menu" className="flex-none gap-2">
|
||||
{!isSubscribe && (
|
||||
<div>
|
||||
<button
|
||||
className="text-xs bg-[#002864] p-2 text-white rounded shadow"
|
||||
className="text-xs md:text-sm shadow op-btn op-btn-outline op-btn-sm md:op-btn-md op-btn-accent"
|
||||
onClick={() => navigate("/subscription")}
|
||||
>
|
||||
Upgrade Now
|
||||
@@ -118,7 +123,7 @@ const Header = ({ showSidebar }) => {
|
||||
</div>
|
||||
)}
|
||||
{isPro && (
|
||||
<div className="w-[35px] h-[35px] rounded-full ring-[1px] ring-offset-2 ring-[#002862] text-[#002862] overflow-hidden font-semibold flex items-center justify-center">
|
||||
<div className="w-[35px] h-[35px] bg-white rounded-full ring-[1px] ring-offset-2 ring-[#002862] text-[#002862] overflow-hidden font-semibold flex items-center justify-center">
|
||||
PRO
|
||||
</div>
|
||||
)}
|
||||
@@ -138,60 +143,70 @@ const Header = ({ showSidebar }) => {
|
||||
</div>
|
||||
)}
|
||||
{width >= 768 && (
|
||||
<div onClick={toggleDropdown} className="cursor-pointer text-sm">
|
||||
<div
|
||||
onClick={toggleDropdown}
|
||||
className="cursor-pointer text-base-content text-sm"
|
||||
>
|
||||
{username && username}
|
||||
</div>
|
||||
)}
|
||||
<div className="relative">
|
||||
<div className="cursor-pointer">
|
||||
<i onClick={toggleDropdown} className="fa-solid fa-angle-down"></i>
|
||||
</div>
|
||||
<div className="op-dropdown op-dropdown-end" id="profile-menu">
|
||||
<div
|
||||
className={`dropdown absolute text-sm text-gray-700 font-light right-0 mt-4 p-1 w-48 bg-white border rounded-lg shadow-lg z-10 ${
|
||||
isOpen ? "block" : "hidden"
|
||||
}`}
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
className="op-btn op-btn-ghost op-btn-xs w-[10px] h-[20px] hover:bg-transparent"
|
||||
>
|
||||
<ul>
|
||||
<li
|
||||
className="hover:bg-gray-100 rounded-t-lg py-1 px-2 cursor-pointer font-normal"
|
||||
onClick={() => openInNewTab("https://docs.opensignlabs.com")}
|
||||
>
|
||||
<i className="fa-solid fa-book"></i> Docs
|
||||
</li>
|
||||
<li
|
||||
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
navigate("/profile");
|
||||
}}
|
||||
>
|
||||
<i className="fa-regular fa-user"></i> Profile
|
||||
</li>
|
||||
<li
|
||||
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
navigate("/changepassword");
|
||||
}}
|
||||
>
|
||||
<i className="fa-solid fa-lock"></i> Change Password
|
||||
</li>
|
||||
<li
|
||||
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
|
||||
onClick={() => {
|
||||
window.open("https://console.opensignlabs.com/");
|
||||
}}
|
||||
>
|
||||
<i className="fa-regular fa-id-card"></i> Console
|
||||
</li>
|
||||
<li
|
||||
className="hover:bg-gray-100 rounded-b-lg py-1 px-2 cursor-pointer font-normal"
|
||||
onClick={closeDropdown}
|
||||
>
|
||||
<i className="fa-solid fa-arrow-right-from-bracket"></i> Log Out
|
||||
</li>
|
||||
</ul>
|
||||
<i
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
onClick={toggleDropdown}
|
||||
className="fa-light fa-angle-down text-base-content"
|
||||
></i>
|
||||
</div>
|
||||
<ul
|
||||
tabIndex={0}
|
||||
className="mt-3 z-[1] p-2 shadow op-menu op-menu-sm op-dropdown-content text-base-content bg-base-100 rounded-box w-52"
|
||||
>
|
||||
<li onClick={() => openInNewTab("https://docs.opensignlabs.com")}>
|
||||
<span>
|
||||
<i className="fa-light fa-book"></i> Docs
|
||||
</span>
|
||||
</li>
|
||||
<li
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
navigate("/profile");
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
<i className="fa-light fa-user"></i> Profile
|
||||
</span>
|
||||
</li>
|
||||
<li
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
navigate("/changepassword");
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
<i className="fa-light fa-lock"></i> Change Password
|
||||
</span>
|
||||
</li>
|
||||
<li
|
||||
onClick={() => {
|
||||
window.open("https://console.opensignlabs.com/");
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
<i className="fa-light fa-id-card"></i> Console
|
||||
</span>
|
||||
</li>
|
||||
<li onClick={closeDropdown}>
|
||||
<span>
|
||||
<i className="fa-light fa-arrow-right-from-bracket"></i> Log Out
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import Parse from "parse";
|
||||
import Loader from "../primitives/Loader";
|
||||
// import FacebookLogin from "react-facebook-login";
|
||||
|
||||
const LoginFacebook = ({
|
||||
@@ -49,7 +50,7 @@ const LoginFacebook = ({
|
||||
const extRes = await Parse.Cloud.run("getUserDetails", params);
|
||||
// console.log("extRes ", extRes);
|
||||
if (extRes) {
|
||||
const params = { ...details, Phone: extRes.get("Phone") };
|
||||
const params = { ...details, Phone: extRes?.get("Phone") || "" };
|
||||
const payload = await Parse.Cloud.run("facebooksign", params);
|
||||
// console.log("payload ", payload);
|
||||
if (payload && payload.sessiontoken) {
|
||||
@@ -59,7 +60,7 @@ const LoginFacebook = ({
|
||||
const LocalUserDetails = {
|
||||
name: details.Name,
|
||||
email: details.Email,
|
||||
phone: extRes.get("Phone"),
|
||||
phone: extRes?.get("Phone") || "",
|
||||
company: extRes.get("Company")
|
||||
};
|
||||
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
||||
@@ -75,7 +76,7 @@ const LoginFacebook = ({
|
||||
const handleSubmitbtn = async () => {
|
||||
if (userDetails.Phone && userDetails.Company) {
|
||||
setThirdpartyLoader(true);
|
||||
const params = { ...fBDetails, Phone: userDetails.Phone };
|
||||
const params = { ...fBDetails, Phone: userDetails?.Phone || "" };
|
||||
const payload = await Parse.Cloud.run("facebooksign", params);
|
||||
// console.log("payload ", payload);
|
||||
|
||||
@@ -85,7 +86,7 @@ const LoginFacebook = ({
|
||||
name: userDetails.Name,
|
||||
email: userDetails.Email,
|
||||
// "passsword":userDetails.Phone,
|
||||
phone: userDetails.Phone,
|
||||
phone: userDetails?.Phone || "",
|
||||
role: "contracts_User",
|
||||
company: userDetails.Company
|
||||
}
|
||||
@@ -96,7 +97,7 @@ const LoginFacebook = ({
|
||||
const LocalUserDetails = {
|
||||
name: userDetails.Name,
|
||||
email: userDetails.Email,
|
||||
phone: userDetails.Phone,
|
||||
phone: userDetails?.Phone || "",
|
||||
company: userDetails.Company
|
||||
};
|
||||
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
||||
@@ -112,29 +113,10 @@ const LoginFacebook = ({
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div style={{ position: "relative" }}>
|
||||
<div className="relative">
|
||||
{thirdpartyLoader && (
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
width: "100vw",
|
||||
height: "100vh",
|
||||
backgroundColor: "rgba(0,0,0,0.2)",
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 2
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
fontSize: "50px",
|
||||
color: "#3ac9d6",
|
||||
top: "50%",
|
||||
left: "45%"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="fixed flex justify-center items-center inset-0 bg-black bg-opacity-25 z-20 ">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
{/* <FacebookLogin
|
||||
@@ -146,11 +128,10 @@ const LoginFacebook = ({
|
||||
/> */}
|
||||
{isModal && (
|
||||
<div
|
||||
className="modal fade show"
|
||||
className="modal fade show block z-[1]"
|
||||
id="exampleModal"
|
||||
tabIndex="-1"
|
||||
role="dialog"
|
||||
style={{ display: "block", zIndex: 1 }}
|
||||
>
|
||||
<div className="modal-dialog" role="document">
|
||||
<div className="modal-content">
|
||||
@@ -163,13 +144,8 @@ const LoginFacebook = ({
|
||||
<div className="modal-body">
|
||||
<form>
|
||||
<div className="form-group">
|
||||
<label
|
||||
htmlFor="Phone"
|
||||
style={{ display: "flex" }}
|
||||
className="col-form-label"
|
||||
>
|
||||
Phone{" "}
|
||||
<span style={{ fontSize: 13, color: "red" }}>*</span>
|
||||
<label htmlFor="Phone" className="col-form-label">
|
||||
Phone <span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="tel"
|
||||
@@ -186,13 +162,8 @@ const LoginFacebook = ({
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label
|
||||
htmlFor="Company"
|
||||
style={{ display: "flex" }}
|
||||
className="col-form-label"
|
||||
>
|
||||
Company{" "}
|
||||
<span style={{ fontSize: 13, color: "red" }}>*</span>
|
||||
<label htmlFor="Company" className="col-form-label">
|
||||
Company <span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
@@ -212,16 +183,14 @@ const LoginFacebook = ({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleSubmitbtn()}
|
||||
className="btn btn-info"
|
||||
style={{ marginRight: 10 }}
|
||||
className="btn btn-info mr-[10px]"
|
||||
>
|
||||
Sign up
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary"
|
||||
className="btn btn-secondary w-[90px]"
|
||||
onClick={() => setIsModal(false)}
|
||||
style={{ width: 90 }}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
@@ -3,7 +3,7 @@ import Parse from "parse";
|
||||
import { jwtDecode } from "jwt-decode";
|
||||
import { useScript } from "../hook/useScript";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
/*
|
||||
* `GoogleSignInBtn`as it's name indicates it render google sign in button
|
||||
@@ -110,7 +110,7 @@ const GoogleSignInBtn = ({
|
||||
const extRes = await Parse.Cloud.run("getUserDetails", params);
|
||||
// console.log("extRes ", extRes);
|
||||
if (extRes) {
|
||||
const params = { ...details, Phone: extRes.get("Phone") };
|
||||
const params = { ...details, Phone: extRes?.get("Phone") || "" };
|
||||
const payload = await Parse.Cloud.run("googlesign", params);
|
||||
// console.log("payload ", payload);
|
||||
if (payload && payload.sessiontoken) {
|
||||
@@ -121,7 +121,7 @@ const GoogleSignInBtn = ({
|
||||
const LocalUserDetails = {
|
||||
name: details.Name,
|
||||
email: details.Gmail,
|
||||
phone: extRes.get("Phone"),
|
||||
phone: extRes?.get("Phone") || "",
|
||||
company: extRes.get("Company")
|
||||
};
|
||||
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
||||
@@ -139,7 +139,7 @@ const GoogleSignInBtn = ({
|
||||
setThirdpartyLoader(true);
|
||||
// e.preventDefault()
|
||||
// console.log("handelSubmit", userDetails);
|
||||
const params = { ...googleDetails, Phone: userDetails.Phone };
|
||||
const params = { ...googleDetails, Phone: userDetails?.Phone };
|
||||
const payload = await Parse.Cloud.run("googlesign", params);
|
||||
|
||||
// console.log("payload ", payload);
|
||||
@@ -149,7 +149,7 @@ const GoogleSignInBtn = ({
|
||||
name: userDetails.Name,
|
||||
email: userDetails.Email,
|
||||
// "passsword":userDetails.Phone,
|
||||
phone: userDetails.Phone,
|
||||
phone: userDetails?.Phone || "",
|
||||
role: "contracts_User",
|
||||
company: userDetails.Company,
|
||||
jobTitle: userDetails.Destination
|
||||
@@ -161,7 +161,7 @@ const GoogleSignInBtn = ({
|
||||
const LocalUserDetails = {
|
||||
name: userDetails.Name,
|
||||
email: userDetails.Email,
|
||||
phone: userDetails.Phone,
|
||||
phone: userDetails?.Phone || "",
|
||||
company: userDetails.Company
|
||||
// jobTitle: userDetails.JobTitle
|
||||
};
|
||||
@@ -207,45 +207,22 @@ const GoogleSignInBtn = ({
|
||||
localStorage.setItem("parseAppId", appid);
|
||||
};
|
||||
return (
|
||||
<div style={{ position: "relative" }}>
|
||||
<div className="relative">
|
||||
{thirdpartyLoader && (
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
width: "100vw",
|
||||
height: "100vh",
|
||||
backgroundColor: "rgba(0,0,0,0.2)",
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 2
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
fontSize: "50px",
|
||||
color: "#3ac9d6",
|
||||
top: "50%",
|
||||
left: "45%"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="fixed flex justify-center items-center inset-0 bg-black bg-opacity-25 z-20 ">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
<div ref={googleBtn} className="text-sm"></div>
|
||||
<ModalUi showClose={false} isOpen={isModal} title="Sign up form">
|
||||
<form className="px-4 py-3">
|
||||
<form className="px-4 py-3 text-base-content">
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="Phone"
|
||||
style={{ display: "flex" }}
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Phone <span style={{ fontSize: 13, color: "red" }}>*</span>
|
||||
<label htmlFor="Phone" className="block text-xs font-semibold">
|
||||
Phone <span className="text-[13px] text-[red]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="tel"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
id="Phone"
|
||||
value={userDetails.Phone}
|
||||
onChange={(e) =>
|
||||
@@ -258,16 +235,12 @@ const GoogleSignInBtn = ({
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="Company"
|
||||
style={{ display: "flex" }}
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Company <span style={{ fontSize: 13, color: "red" }}>*</span>
|
||||
<label htmlFor="Company" className="block text-xs font-semibold">
|
||||
Company <span className="text-[13px] text-[red]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
id="Company"
|
||||
value={userDetails.Company}
|
||||
onChange={(e) =>
|
||||
@@ -280,16 +253,12 @@ const GoogleSignInBtn = ({
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="JobTitle"
|
||||
style={{ display: "flex" }}
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Job Title <span style={{ fontSize: 13, color: "red" }}>*</span>
|
||||
<label htmlFor="JobTitle" className="block text-xs font-semibold">
|
||||
Job Title <span className="text-[13px] text-[red]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
id="JobTitle"
|
||||
value={userDetails.Destination}
|
||||
onChange={(e) =>
|
||||
@@ -301,20 +270,18 @@ const GoogleSignInBtn = ({
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex flex-row gap-2">
|
||||
<button
|
||||
type="button"
|
||||
className="px-3 py-1.5 text-white rounded shadow-md text-center focus:outline-none "
|
||||
className="op-btn op-btn-primary"
|
||||
onClick={() => handleSubmitbtn()}
|
||||
style={{ marginRight: 10, backgroundColor: modalSubmitBtnColor }}
|
||||
>
|
||||
Sign up
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="p-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none"
|
||||
className="op-btn op-btn-ghost"
|
||||
onClick={handleCloseModal}
|
||||
style={{ width: 90, backgroundColor: modalCancelBtnColor }}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
@@ -1,39 +1,19 @@
|
||||
import React from "react";
|
||||
import { Document, Page } from "react-pdf";
|
||||
import { Stage, Layer, Rect } from "react-konva";
|
||||
import { Stage, Layer, Rect, Text } from "react-konva";
|
||||
const RenderDebugPdf = (props) => {
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
position: "sticky",
|
||||
top: 0,
|
||||
padding: 10,
|
||||
zIndex: 1,
|
||||
backgroundColor: "white",
|
||||
border: "1px solid grey",
|
||||
margin: "5px 0"
|
||||
}}
|
||||
>
|
||||
<div className="sticky top-0 p-[10px] z-10 bg-white border-[1px] border-[gray] my-[5px]">
|
||||
{`Co-ordinates: X - ${props.hoverCoordinates.x}, Y - ${props.hoverCoordinates.y}`}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
position: "relative",
|
||||
border: "1px solid grey",
|
||||
overflow: "auto",
|
||||
cursor: "crosshair"
|
||||
}}
|
||||
className="relative flex-1 cursor-crosshair border-[1px] border-[gray] overflow-auto"
|
||||
onMouseMove={props.handleMouseMoveDiv}
|
||||
>
|
||||
<Document
|
||||
onLoadError={() => {
|
||||
const load = {
|
||||
status: false,
|
||||
type: "failed"
|
||||
};
|
||||
props.setPdfLoadFail(load);
|
||||
props.setPdfLoadFail(false);
|
||||
}}
|
||||
loading={"Loading Document.."}
|
||||
onLoadSuccess={props.pageDetails}
|
||||
@@ -57,22 +37,36 @@ const RenderDebugPdf = (props) => {
|
||||
onMouseUp={props.handleMouseUp}
|
||||
width={props.pdfDimension.width}
|
||||
height={props.pdfDimension.height}
|
||||
style={{ position: "absolute", top: 0, left: 0 }}
|
||||
className="absolute top-0 right-0"
|
||||
>
|
||||
<Layer>
|
||||
{props.annotations
|
||||
.filter((value) => value.page === props.pageNumber)
|
||||
.map((value) => {
|
||||
const textX = value.x + value.width / 3;
|
||||
const textY = value.y + value.height / 2.5;
|
||||
return (
|
||||
<Rect
|
||||
key={value.key}
|
||||
x={value.x}
|
||||
y={value.y}
|
||||
width={value.width}
|
||||
height={value.height}
|
||||
fill="transparent"
|
||||
stroke="black"
|
||||
/>
|
||||
<React.Fragment key={value.key}>
|
||||
<Rect
|
||||
x={value.x}
|
||||
y={value.y}
|
||||
width={value.width}
|
||||
height={value.height}
|
||||
fill="#cbe9ed"
|
||||
stroke="black"
|
||||
/>
|
||||
<Text
|
||||
x={textX}
|
||||
y={textY}
|
||||
text={
|
||||
value?.key > 0 ? "box " + value.key.toString() : "box"
|
||||
}
|
||||
fontSize={16}
|
||||
fill="black"
|
||||
align="center"
|
||||
verticalAlign="middle"
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</Layer>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import "../../styles/loader.css";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { openInNewTab } from "../../constant/Utils";
|
||||
|
||||
@@ -26,19 +25,17 @@ const DashboardButton = (props) => {
|
||||
props.Data && props.Data.Redirect_type
|
||||
? "cursor-pointer"
|
||||
: "cursor-default"
|
||||
} w-full px-3 py-2 flex text-white rounded-md shadow overflow-hidden`}
|
||||
} w-full shadow-md px-3 py-2 op-card bg-base-100`}
|
||||
>
|
||||
<div className="flex items-center justify-start gap-5">
|
||||
<span className="rounded-full bg-black bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
|
||||
<div className="flex flex-row items-center">
|
||||
<span className="rounded-full bg-base-content bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
|
||||
<i
|
||||
className={`${
|
||||
props.Icon ? props.Icon : "fa fa-solid fa-info"
|
||||
props.Icon ? props.Icon : "fa-light fa-info"
|
||||
} text-[25px] lg:text-[30px]`}
|
||||
></i>
|
||||
</span>
|
||||
<div className="">
|
||||
<div className="text-base lg:text-lg text-black"> {props.Label}</div>
|
||||
</div>
|
||||
<div className=" text-lg ml-3 text-base-content">{props.Label}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useState, useEffect } from "react";
|
||||
import axios from "axios";
|
||||
import Parse from "parse";
|
||||
import getReplacedHashQuery from "../../constant/getReplacedHashQuery";
|
||||
import "../../styles/loader.css";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Tooltip from "../../primitives/Tooltip";
|
||||
|
||||
@@ -262,21 +261,14 @@ const DashboardCard = (props) => {
|
||||
}
|
||||
}
|
||||
body = str;
|
||||
await axios
|
||||
.post(url, body, { headers: headers })
|
||||
.then((response) => {
|
||||
try {
|
||||
if (response.data.result.length > 0) {
|
||||
setresponse(response.data.result[0][props.FilterData.key]);
|
||||
setLoading(false);
|
||||
} else {
|
||||
setresponse("0");
|
||||
setLoading(false);
|
||||
}
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
const response = await axios.post(url, body, { headers: headers });
|
||||
if (response.data.result.length > 0) {
|
||||
setresponse(response.data.result[0][props.FilterData.key]);
|
||||
setLoading(false);
|
||||
} else {
|
||||
setresponse("0");
|
||||
setLoading(false);
|
||||
}
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -336,25 +328,29 @@ const DashboardCard = (props) => {
|
||||
props.Data && props.Data.Redirect_type
|
||||
? "cursor-pointer"
|
||||
: "cursor-default"
|
||||
} w-full h-[140px] px-3 pt-4 pb-10 text-white rounded-md shadow overflow-hidden relative`}
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-start gap-5">
|
||||
<span className="rounded-full bg-black bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
|
||||
<div className="flex items-center justify-start gap-5 text-white">
|
||||
<span className="rounded-full bg-base-300 bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
|
||||
<i
|
||||
className={`${
|
||||
props.Icon ? props.Icon : "fa fa-solid fa-info"
|
||||
props.Icon ? props.Icon : "fa-light fa-info"
|
||||
} text-[25px] lg:text-[30px]`}
|
||||
></i>
|
||||
</span>
|
||||
<div className="">
|
||||
<div className="font-medium">
|
||||
<div className="text-base lg:text-lg"> {props.Label}</div>
|
||||
<div className="text-2xl font-light">
|
||||
{loading ? <div className="loader-01"></div> : setFormat(response)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-xs absolute top-2 right-1">
|
||||
<Tooltip id={props.Label} iconColor={"white"} message={props?.Data?.tourMessage} />
|
||||
<div className="text-xs absolute top-3 right-2">
|
||||
<Tooltip
|
||||
id={props.Label}
|
||||
iconColor={"white"}
|
||||
message={props?.Data?.tourMessage}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import Parse from "parse";
|
||||
import ReportTable from "../../primitives/GetReportDisplay";
|
||||
import reportJson from "../../json/ReportJson";
|
||||
import axios from "axios";
|
||||
import Loader from "../../primitives/Loader";
|
||||
function DashboardReport(props) {
|
||||
// console.log("props ", props)
|
||||
const [List, setList] = useState([]);
|
||||
@@ -121,21 +122,8 @@ function DashboardReport(props) {
|
||||
return (
|
||||
<>
|
||||
{isLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="h-[250px] flex justify-center items-center">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
|
||||
@@ -7,62 +7,37 @@ const buttonList = [
|
||||
label: "Sign yourself",
|
||||
redirectId: "sHAnZphf69",
|
||||
redirectType: "Form",
|
||||
icon: "fas fa-pen-nib"
|
||||
icon: "fa-light fa-pen-nib"
|
||||
},
|
||||
{
|
||||
label: "Request signature",
|
||||
redirectId: "8mZzFxbG1z",
|
||||
redirectType: "Form",
|
||||
icon: "fa-solid fa-paper-plane"
|
||||
icon: "fa-light fa-paper-plane"
|
||||
}
|
||||
];
|
||||
const GetDashboard = (props) => {
|
||||
const Button = ({ label, redirectId, redirectType, icon }) => (
|
||||
<div className={"bg-white rounded-md shadow w-full"}>
|
||||
<Suspense
|
||||
fallback={
|
||||
<div style={{ height: "300px" }}>
|
||||
<div
|
||||
style={{
|
||||
marginLeft: "45%",
|
||||
marginTop: "150px",
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<DashboardButton
|
||||
Icon={icon}
|
||||
Label={label}
|
||||
Data={{ Redirect_type: redirectType, Redirect_id: redirectId }}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
<DashboardButton
|
||||
Icon={icon}
|
||||
Label={label}
|
||||
Data={{ Redirect_type: redirectType, Redirect_id: redirectId }}
|
||||
/>
|
||||
);
|
||||
const renderSwitchWithTour = (col) => {
|
||||
switch (col.widget.type) {
|
||||
case "Card":
|
||||
return (
|
||||
<div
|
||||
className={"bg-[#2ed8b6] rounded-md shadow mb-3 md:mb-0"}
|
||||
className={`${
|
||||
col?.widget?.bgColor ? col.widget.bgColor : "bg-[#2ed8b6]"
|
||||
} op-card w-full h-[140px] px-3 pt-4 mb-3 shadow-md"`}
|
||||
data-tut={col.widget.data.tourSection}
|
||||
style={{ background: col.widget.bgColor }}
|
||||
>
|
||||
<Suspense
|
||||
fallback={
|
||||
<div style={{ height: "300px" }}>
|
||||
<div
|
||||
style={{
|
||||
marginLeft: "45%",
|
||||
marginTop: "150px",
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="h-[150px] w-full flex justify-center items-center">
|
||||
loading...
|
||||
</div>
|
||||
}
|
||||
>
|
||||
@@ -72,7 +47,6 @@ const GetDashboard = (props) => {
|
||||
Format={col.widget.format && col.widget.format}
|
||||
Data={col.widget.data}
|
||||
FilterData={col.widget.filter}
|
||||
DefaultQuery={props.DefaultQuery}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
@@ -89,7 +63,7 @@ const GetDashboard = (props) => {
|
||||
);
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
return <></>;
|
||||
}
|
||||
};
|
||||
const renderSwitch = (col) => {
|
||||
@@ -97,8 +71,9 @@ const GetDashboard = (props) => {
|
||||
case "Card":
|
||||
return (
|
||||
<div
|
||||
className={"bg-[#2ed8b6] rounded-md shadow mb-3 md:mb-0"}
|
||||
style={{ background: col.widget.bgColor }}
|
||||
className={`${
|
||||
col?.widget?.bgColor ? col.widget.bgColor : "bg-[#2ed8b6]"
|
||||
} op-card w-full h-[140px] px-3 pt-4 mb-3 shadow-md"`}
|
||||
>
|
||||
<Suspense fallback={<div>please wait</div>}>
|
||||
<DashboardCard
|
||||
@@ -107,7 +82,6 @@ const GetDashboard = (props) => {
|
||||
Format={col.widget.format && col.widget.format}
|
||||
Data={col.widget.data}
|
||||
FilterData={col.widget.filter}
|
||||
DefaultQuery={props.DefaultQuery}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
@@ -122,7 +96,7 @@ const GetDashboard = (props) => {
|
||||
);
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
return <></>;
|
||||
}
|
||||
};
|
||||
return (
|
||||
@@ -130,7 +104,7 @@ const GetDashboard = (props) => {
|
||||
<div className="mb-3">
|
||||
<div
|
||||
data-tut={"tourbutton"}
|
||||
className="flex flex-col md:flex-row gap-6 md:gap-8"
|
||||
className="flex flex-col md:flex-row gap-4"
|
||||
>
|
||||
{buttonList.map((btn) => (
|
||||
<Button
|
||||
@@ -143,21 +117,19 @@ const GetDashboard = (props) => {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{props.dashboard.map((val, key) => (
|
||||
<div key={"a" + key} className="row">
|
||||
{val.columns.map((col, i) =>
|
||||
col.widget.data && col.widget.data.tourSection ? (
|
||||
<div key={i} className={props.classnameArray[key][i]}>
|
||||
{renderSwitchWithTour(col)}
|
||||
</div>
|
||||
) : (
|
||||
<div key={i} className={props.classnameArray[key][i]}>
|
||||
{renderSwitch(col)}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<div className="grid grid-cols-12 w-full gap-x-4">
|
||||
{props?.dashboard?.columns?.map((col, i) =>
|
||||
col.widget.data && col.widget.data.tourSection ? (
|
||||
<div key={i} className={col?.colsize}>
|
||||
{renderSwitchWithTour(col)}
|
||||
</div>
|
||||
) : (
|
||||
<div key={i} className={col?.colsize}>
|
||||
{renderSwitch(col)}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import folder from "../../assets/images/folder.png";
|
||||
import "../../styles/opensigndrive.css";
|
||||
import pdfLogo from "../../assets/images/pdf3.png";
|
||||
import axios from "axios";
|
||||
import * as ContextMenu from "@radix-ui/react-context-menu";
|
||||
import { saveAs } from "file-saver";
|
||||
@@ -9,7 +7,6 @@ import { useNavigate } from "react-router-dom";
|
||||
import Table from "react-bootstrap/Table";
|
||||
import * as HoverCard from "@radix-ui/react-hover-card";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
import { themeColor } from "../../constant/const";
|
||||
import FolderModal from "../shared/fields/FolderModal";
|
||||
|
||||
function DriveBody(props) {
|
||||
@@ -20,10 +17,10 @@ function DriveBody(props) {
|
||||
const [selectDoc, setSelectDoc] = useState();
|
||||
const [isDeleteDoc, setIsDeleteDoc] = useState(false);
|
||||
const contextMenu = [
|
||||
{ type: "Download", icon: "fa-solid fa-arrow-down" },
|
||||
{ type: "Rename", icon: "fa-solid fa-font" },
|
||||
{ type: "Move", icon: "fa-solid fa-file-export" },
|
||||
{ type: "Delete", icon: "fa-solid fa-trash" }
|
||||
{ type: "Download", icon: "fa-light fa-arrow-down" },
|
||||
{ type: "Rename", icon: "fa-light fa-font" },
|
||||
{ type: "Move", icon: "fa-light fa-file-export" },
|
||||
{ type: "Delete", icon: "fa-light fa-trash" }
|
||||
];
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -313,32 +310,26 @@ function DriveBody(props) {
|
||||
|
||||
const signersName = () => {
|
||||
const getSignersName = signerExist.map((data) => data.Name);
|
||||
const signerName = getSignersName.join(",");
|
||||
const signerName = getSignersName.join(", ");
|
||||
|
||||
return (
|
||||
<span
|
||||
className="statusSpan"
|
||||
style={{ width: "90%", wordWrap: "break-word" }}
|
||||
>
|
||||
{signerName}{" "}
|
||||
<span className="text-[12px] font-medium w-[90%] break-words">
|
||||
{signerName}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
return listType === "table" ? (
|
||||
data.Type === "Folder" ? (
|
||||
<tr onClick={() => handleOnclikFolder(data)}>
|
||||
<td
|
||||
style={{ cursor: "pointer", display: "flex", alignItems: "center" }}
|
||||
>
|
||||
<i
|
||||
className="fa fa-folder"
|
||||
aria-hidden="true"
|
||||
style={{ color: "#f0ad26", marginRight: "8px", fontSize: "26px" }}
|
||||
></i>
|
||||
|
||||
<span style={{ fontSize: "12px", fontWeight: "500" }}>
|
||||
{data.Name}
|
||||
</span>
|
||||
<td className="cursor-pointer flex items-center gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
className="w-[26px] h-[26px] fill-current op-text-secondary"
|
||||
>
|
||||
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
|
||||
</svg>
|
||||
<span className="text-[12px] font-medium">{data.Name}</span>
|
||||
</td>
|
||||
<td>_</td>
|
||||
<td>Folder</td>
|
||||
@@ -347,17 +338,15 @@ function DriveBody(props) {
|
||||
</tr>
|
||||
) : (
|
||||
<tr onClick={() => checkPdfStatus(data)}>
|
||||
<td
|
||||
style={{ cursor: "pointer", display: "flex", alignItems: "center" }}
|
||||
>
|
||||
<i
|
||||
className="fa fa-file-pdf"
|
||||
style={{ color: "#ed4d0e", marginRight: "8px", fontSize: "26px" }}
|
||||
></i>
|
||||
|
||||
<span style={{ fontSize: "12px", fontWeight: "500" }}>
|
||||
{data.Name}
|
||||
</span>
|
||||
<td className="cursor-pointer flex items-center gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 384 512"
|
||||
className="w-[26px] h-[26px] fill-current op-text-primary"
|
||||
>
|
||||
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
|
||||
</svg>
|
||||
<span className="text-[12px] font-medium">{data.Name}</span>
|
||||
</td>
|
||||
<td>{createddate}</td>
|
||||
<td>Pdf</td>
|
||||
@@ -368,32 +357,29 @@ function DriveBody(props) {
|
||||
e.stopPropagation();
|
||||
handleMenuItemClick("Download", data);
|
||||
}}
|
||||
className="fa fa-download"
|
||||
className="fa-light fa-download mr-[8px] op-text-primary"
|
||||
aria-hidden="true"
|
||||
style={{ color: "#ed280e", marginRight: "8px" }}
|
||||
></i>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
) : listType === "list" && data.Type === "Folder" ? (
|
||||
<div key={ind} className="folderBox">
|
||||
<div key={ind} className="relative w-[100px] h-[100px] mx-2 my-3">
|
||||
<ContextMenu.Root>
|
||||
<ContextMenu.Trigger className="ContextMenuTrigger">
|
||||
<ContextMenu.Trigger className="flex flex-col justify-center items-center">
|
||||
{/* folder */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
cursor: "pointer"
|
||||
}}
|
||||
data-tut={props.dataTutSeventh}
|
||||
onClick={() => handleOnclikFolder(data)}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
<img
|
||||
alt="no img"
|
||||
onClick={() => handleOnclikFolder(data)}
|
||||
src={folder}
|
||||
width={100}
|
||||
height={103}
|
||||
/>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
className="w-[100px] h-[100px] fill-current op-text-secondary"
|
||||
>
|
||||
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
|
||||
</svg>
|
||||
{rename === data.objectId ? (
|
||||
<input
|
||||
onFocus={() => {
|
||||
@@ -411,15 +397,10 @@ function DriveBody(props) {
|
||||
defaultValue={renameValue}
|
||||
// value={renameValue}
|
||||
onChange={(e) => setRenameValue(e.target.value)}
|
||||
style={{
|
||||
width: "100px",
|
||||
border: "1.5px solid black",
|
||||
borderRadius: "2px",
|
||||
fontSize: "10px"
|
||||
}}
|
||||
className="w-[100px] border-[1.5px] border-black rounded-sm text-[10px]"
|
||||
/>
|
||||
) : (
|
||||
<span className="foldName">{data.Name}</span>
|
||||
<span className="fileName">{data.Name}</span>
|
||||
)}
|
||||
</div>
|
||||
</ContextMenu.Trigger>
|
||||
@@ -434,8 +415,8 @@ function DriveBody(props) {
|
||||
onClick={() => handleMenuItemClick("Rename", data)}
|
||||
className="ContextMenuItem"
|
||||
>
|
||||
<i className="fa-solid fa-font"></i>
|
||||
<span style={{ marginLeft: "8px" }}>Rename</span>
|
||||
<i className="fa-light fa-font mr-[8px]"></i>
|
||||
<span>Rename</span>
|
||||
</ContextMenu.Item>
|
||||
</ContextMenu.Content>
|
||||
</ContextMenu.Portal>
|
||||
@@ -446,63 +427,65 @@ function DriveBody(props) {
|
||||
<HoverCard.Trigger asChild>
|
||||
<div>
|
||||
<ContextMenu.Root>
|
||||
<div className="icon-container">
|
||||
<ContextMenu.Trigger className="ContextMenuTrigger">
|
||||
<img
|
||||
alt="PDF"
|
||||
className="pdf-icon"
|
||||
src={pdfLogo}
|
||||
onClick={() => checkPdfStatus(data)}
|
||||
<div className="relative w-[100px] h-[100px] mx-2 my-3">
|
||||
<ContextMenu.Trigger className="flex flex-col justify-center items-center">
|
||||
{/* pdf */}
|
||||
<div
|
||||
data-tut={props.dataTutSixth}
|
||||
/>
|
||||
{rename === data.objectId ? (
|
||||
<input
|
||||
autoFocus={true}
|
||||
type="text"
|
||||
onFocus={() => {
|
||||
inputRef.current.setSelectionRange(0, 0);
|
||||
const input = inputRef.current;
|
||||
if (input) {
|
||||
input.select();
|
||||
}
|
||||
}}
|
||||
onBlur={() => handledRenameDoc(data)}
|
||||
onKeyDown={(e) => handleEnterPress(e, data)}
|
||||
ref={inputRef}
|
||||
defaultValue={renameValue}
|
||||
// value={renameValue}
|
||||
onChange={(e) => setRenameValue(e.target.value)}
|
||||
style={{
|
||||
width: "100px",
|
||||
border: "1.5px solid black",
|
||||
borderRadius: "2px",
|
||||
fontSize: "10px"
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span className="fileName">{data.Name}</span>
|
||||
)}
|
||||
onClick={() => checkPdfStatus(data)}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 384 512"
|
||||
className="w-[100px] h-[100px] fill-current op-text-primary"
|
||||
>
|
||||
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
|
||||
</svg>
|
||||
{rename === data.objectId ? (
|
||||
<input
|
||||
autoFocus={true}
|
||||
type="text"
|
||||
onFocus={() => {
|
||||
inputRef.current.setSelectionRange(0, 0);
|
||||
const input = inputRef.current;
|
||||
if (input) {
|
||||
input.select();
|
||||
}
|
||||
}}
|
||||
onBlur={() => handledRenameDoc(data)}
|
||||
onKeyDown={(e) => handleEnterPress(e, data)}
|
||||
ref={inputRef}
|
||||
defaultValue={renameValue}
|
||||
// value={renameValue}
|
||||
onChange={(e) => setRenameValue(e.target.value)}
|
||||
className="w-[100px] border-[1.5px] border-black rounded-sm text-[10px]"
|
||||
/>
|
||||
) : (
|
||||
<span className="fileName">{data.Name}</span>
|
||||
)}
|
||||
</div>
|
||||
</ContextMenu.Trigger>
|
||||
{status === "Completed" ? (
|
||||
<div className="status-badge completed">
|
||||
<i className="fas fa-check-circle"></i>
|
||||
<i className="fa-light fa-check-circle"></i>
|
||||
</div>
|
||||
) : status === "Declined" ? (
|
||||
<div className="status-badge declined">
|
||||
<i className="fa fa-thumbs-down"></i>
|
||||
<i className="fa-light fa-thumbs-down"></i>
|
||||
</div>
|
||||
) : status === "Expired" ? (
|
||||
<div className="status-badge expired">
|
||||
<i className="fa fa-hourglass-end"></i>
|
||||
<i className="fa-light fa-hourglass-end"></i>
|
||||
</div>
|
||||
) : status === "Draft" ? (
|
||||
<div className="status-badge draft">
|
||||
<i className="fa fa-file"></i>
|
||||
<i className="fa-light fa-file"></i>
|
||||
</div>
|
||||
) : (
|
||||
status === "In Progress" && (
|
||||
<div className="status-badge in-progress">
|
||||
<i className="fa fa-paper-plane"></i>
|
||||
<i className="fa-light fa-paper-plane"></i>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
@@ -522,7 +505,7 @@ function DriveBody(props) {
|
||||
className="ContextMenuItem"
|
||||
>
|
||||
<i className={menu.icon}></i>
|
||||
<span style={{ marginLeft: "8px" }}>{menu.type}</span>
|
||||
<span className="ml-[8px]">{menu.type}</span>
|
||||
</ContextMenu.Item>
|
||||
);
|
||||
})}
|
||||
@@ -533,22 +516,18 @@ function DriveBody(props) {
|
||||
</HoverCard.Trigger>
|
||||
<HoverCard.Portal>
|
||||
<HoverCard.Content className="HoverCardContent" sideOffset={5}>
|
||||
<strong style={{ fontSize: "13px" }}>Title: </strong>
|
||||
<span className="statusSpan" style={{ marginBottom: "0px" }}>
|
||||
{" "}
|
||||
{data.Name}
|
||||
</span>
|
||||
<strong className="text-[13px]">Title: </strong>
|
||||
<span className="text-[12px] font-medium mb-0"> {data.Name}</span>
|
||||
<br />
|
||||
<strong style={{ fontSize: "13px" }}>Status: </strong>
|
||||
<span className="statusSpan"> {status}</span>
|
||||
<strong className="text-[13px]">Status: </strong>
|
||||
<span className="text-[12px] font-medium"> {status}</span>
|
||||
<br />
|
||||
<strong style={{ fontSize: "13px" }}>Created Date: </strong>
|
||||
<span className="statusSpan">{createddate}</span>
|
||||
<strong className="text-[13px]">Created Date: </strong>
|
||||
<span className="text-[12px] font-medium">{createddate}</span>
|
||||
<br />
|
||||
{signerExist && (
|
||||
<>
|
||||
<strong style={{ fontSize: "13px" }}>Signers: </strong>
|
||||
{/* <span className="statusSpan">kjefjjnejkfnkbjs bbfjkdsbjbfjkbjk kscbjkbjkb</span> */}
|
||||
<strong className="text-[13px]">Signers: </strong>
|
||||
{signersName()}
|
||||
</>
|
||||
)}
|
||||
@@ -587,13 +566,9 @@ function DriveBody(props) {
|
||||
</Table>
|
||||
</div>
|
||||
) : (
|
||||
<div className="pdfContainer">
|
||||
<div className="flex flex-row flex-wrap items-center mt-1 pb-[20px] mx-[5px]">
|
||||
{props.pdfData.map((data, ind) => {
|
||||
return (
|
||||
<div className="box" key={ind}>
|
||||
{handleFolderData(data, ind, "list")}
|
||||
</div>
|
||||
);
|
||||
return <div key={ind}>{handleFolderData(data, ind, "list")}</div>;
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
@@ -609,44 +584,23 @@ function DriveBody(props) {
|
||||
)}
|
||||
<ModalUi
|
||||
isOpen={isDeleteDoc}
|
||||
headerColor={themeColor}
|
||||
title={"Delete Document"}
|
||||
handleClose={() => {
|
||||
setIsDeleteDoc(false);
|
||||
}}
|
||||
handleClose={() => setIsDeleteDoc(false)}
|
||||
>
|
||||
<div style={{ height: "100%", padding: 20 }}>
|
||||
<div className="h-full p-[20px] text-base-content">
|
||||
<p>Are you sure you want to delete this document?</p>
|
||||
|
||||
<div
|
||||
style={{
|
||||
height: "1px",
|
||||
backgroundColor: "#9f9f9f",
|
||||
width: "100%",
|
||||
marginTop: "15px",
|
||||
marginBottom: "15px"
|
||||
}}
|
||||
></div>
|
||||
|
||||
<div className="h-[1px] w-full bg-[#9f9f9f] my-[15px]"></div>
|
||||
<button
|
||||
onClick={() => {
|
||||
handleDeleteDocument(selectDoc);
|
||||
}}
|
||||
style={{
|
||||
background: themeColor,
|
||||
color: "white"
|
||||
}}
|
||||
onClick={() => handleDeleteDocument(selectDoc)}
|
||||
type="button"
|
||||
className="finishBtn"
|
||||
className="op-btn op-btn-primary mr-2"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsDeleteDoc(false);
|
||||
}}
|
||||
onClick={() => setIsDeleteDoc(false)}
|
||||
type="button"
|
||||
className="finishBtn cancelBtn"
|
||||
className="op-btn op-btn-neutral"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
|
||||
@@ -8,11 +8,8 @@ const AddRoleModal = (props) => {
|
||||
isOpen={props.isModalRole}
|
||||
handleClose={props.handleCloseRoleModal}
|
||||
>
|
||||
<div className="addusercontainer">
|
||||
<form
|
||||
style={{ display: "flex", flexDirection: "column" }}
|
||||
onSubmit={props.handleAddRole}
|
||||
>
|
||||
<div className="h-full py-[10px] px-[20px]">
|
||||
<form className="flex flex-col" onSubmit={props.handleAddRole}>
|
||||
<input
|
||||
value={props.roleName}
|
||||
onChange={(e) => props.setRoleName(e.target.value)}
|
||||
@@ -21,39 +18,20 @@ const AddRoleModal = (props) => {
|
||||
? "User " + (props.signersdata.length + 1)
|
||||
: "User 1"
|
||||
}
|
||||
className="addUserInput"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs mt-1"
|
||||
/>
|
||||
<p
|
||||
style={{
|
||||
color: "grey",
|
||||
fontSize: 11,
|
||||
margin: "10px 0 10px 5px"
|
||||
}}
|
||||
>
|
||||
<p className="text-[gray] text-[11px] mt-[5px] mb-[10px] ml-[10px]">
|
||||
e.g: Customer, Hr, Director, Manager, Student, etc...
|
||||
</p>
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
height: "1px",
|
||||
backgroundColor: "#9f9f9f",
|
||||
width: "100%",
|
||||
marginBottom: "15px"
|
||||
}}
|
||||
></div>
|
||||
<button
|
||||
type="submit"
|
||||
style={{
|
||||
background: "#00a2b7"
|
||||
}}
|
||||
className="finishBtn"
|
||||
>
|
||||
<div className="h-[1px] w-full bg-[#9f9f9f] mb-[10px]"></div>
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Add
|
||||
</button>
|
||||
<button
|
||||
onClick={props.handleCloseRoleModal}
|
||||
type="button"
|
||||
className="finishBtn cancelBtn"
|
||||
className="op-btn op-btn-ghost ml-2"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
|
||||
@@ -3,13 +3,9 @@ import React from "react";
|
||||
function BorderResize({ right, top }) {
|
||||
return (
|
||||
<div
|
||||
className="borderResize"
|
||||
style={{
|
||||
right: right ? right + "px" : "-1px",
|
||||
bottom: top ? top + "px" : "-1px",
|
||||
borderRight: "3px solid #188ae2",
|
||||
borderBottom: "3px solid #188ae2"
|
||||
}}
|
||||
className={`${right ? `-right-[12px]` : "-right-[1px]"} ${
|
||||
top ? `-bottom-[11px]` : "-bottom-[1px]"
|
||||
} absolute inline-block w-[14px] h-[14px] hover:cursor-sw-resize border-r-[3px] border-b-[3px] border-[#188ae2]`}
|
||||
></div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import { themeColor } from "../../constant/const";
|
||||
function DefaultSignature({ defaultSignImg, xyPostion, setDefaultSignAlert }) {
|
||||
const confirmToaddDefaultSign = () => {
|
||||
if (xyPostion.length > 0) {
|
||||
@@ -17,55 +16,26 @@ function DefaultSignature({ defaultSignImg, xyPostion, setDefaultSignAlert }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
background: themeColor,
|
||||
color: "white",
|
||||
padding: "5px",
|
||||
fontFamily: "sans-serif",
|
||||
marginTop: "5px"
|
||||
}}
|
||||
>
|
||||
<div data-tut="reactourThird">
|
||||
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
|
||||
Signature
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
marginTop: "10px",
|
||||
fontWeight: "600"
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<p>Your Signature</p>
|
||||
<div className="defaultSignBox">
|
||||
<img
|
||||
alt="default img"
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "contain"
|
||||
}}
|
||||
src={defaultSignImg}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
style={{
|
||||
background: themeColor,
|
||||
color: "white",
|
||||
marginTop: "20px",
|
||||
cursor: "pointer",
|
||||
marginBottom: "10px"
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn finishnHover"
|
||||
onClick={() => confirmToaddDefaultSign()}
|
||||
>
|
||||
Auto Sign All
|
||||
</button>
|
||||
</>
|
||||
<div className="flex flex-col items-center mt-[10px] font-semibold">
|
||||
<p className="text-base-content">Your Signature</p>
|
||||
<div className="op-card shadow-md h-[111px] w-[90%] p-2">
|
||||
<img
|
||||
alt="signature"
|
||||
className="w-full h-full object-contain"
|
||||
src={defaultSignImg}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-primary op-btn-sm mt-[10px]"
|
||||
onClick={() => confirmToaddDefaultSign()}
|
||||
>
|
||||
Auto Sign All
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Loader from "../../primitives/LoaderWithMsg";
|
||||
import LoaderWithMsg from "../../primitives/LoaderWithMsg";
|
||||
import { contractDocument } from "../../constant/Utils";
|
||||
import HandleError from "../../primitives/HandleError";
|
||||
function DraftDocument() {
|
||||
@@ -86,7 +86,7 @@ function DraftDocument() {
|
||||
return (
|
||||
<div>
|
||||
{isLoading.isLoader ? (
|
||||
<Loader isLoading={isLoading} />
|
||||
<LoaderWithMsg isLoading={isLoading} />
|
||||
) : (
|
||||
<HandleError handleError={isLoading.message} />
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { isEnableSubscription, themeColor } from "../../constant/const";
|
||||
import { isEnableSubscription } from "../../constant/const";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
import { radioButtonWidget } from "../../constant/Utils";
|
||||
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
||||
@@ -147,7 +147,7 @@ function DropdownWidgetOption(props) {
|
||||
|
||||
return (
|
||||
<ModalUi isOpen={props.showDropdown} title={props.title} showClose={false}>
|
||||
<div className="h-full p-[15px]">
|
||||
<div className="h-full p-[15px] text-base-content">
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
@@ -155,38 +155,25 @@ function DropdownWidgetOption(props) {
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<label style={{ fontSize: "13px", fontWeight: "600" }}>
|
||||
Name<span style={{ color: "red", fontSize: 13 }}> *</span>
|
||||
<label className="text-[13px] font-semibold">
|
||||
Name<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
required
|
||||
defaultValue={dropdownName}
|
||||
value={dropdownName}
|
||||
onChange={(e) => setDropdownName(e.target.value)}
|
||||
className="drodown-input"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
|
||||
<label
|
||||
style={{ fontSize: "13px", fontWeight: "600", marginTop: "5px" }}
|
||||
>
|
||||
<label className="text-[13px] font-semibold mt-[5px]">
|
||||
Options
|
||||
</label>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
{dropdownOptionList.map((option, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
marginBottom: "5px",
|
||||
alignItems: "center"
|
||||
}}
|
||||
className="flex flex-row mb-[5px] items-center"
|
||||
>
|
||||
{props.type === "checkbox" && !props.isSignYourself && (
|
||||
<input
|
||||
@@ -206,51 +193,34 @@ function DropdownWidgetOption(props) {
|
||||
setDefaultCheckbox(removeOption);
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
width: "23px",
|
||||
height: "19px",
|
||||
marginRight: "5px"
|
||||
}}
|
||||
className="op-checkbox focus:outline-none hover:border-base-content mr-[5px]"
|
||||
/>
|
||||
)}
|
||||
<input
|
||||
required
|
||||
className="drodown-input"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
type="text"
|
||||
value={option}
|
||||
onChange={(e) => handleInputChange(index, e.target.value)}
|
||||
/>
|
||||
|
||||
<i
|
||||
className="fa-solid fa-rectangle-xmark"
|
||||
className="fa-light fa-rectangle-xmark text-[25px] ml-[10px] text-accent cursor-pointer"
|
||||
onClick={() => handleDeleteInput(index)}
|
||||
style={{
|
||||
color: "red",
|
||||
fontSize: "25px",
|
||||
marginLeft: "10px"
|
||||
}}
|
||||
></i>
|
||||
</div>
|
||||
))}
|
||||
<i
|
||||
onClick={handleAddInput}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
color: themeColor,
|
||||
fontSize: "25px",
|
||||
marginLeft: "10px"
|
||||
}}
|
||||
className="fa-solid fa-square-plus"
|
||||
className="fa-light fa-square-plus text-[25px] ml-[10px] op-text-primary cursor-pointer"
|
||||
></i>
|
||||
<div>
|
||||
{props.type === "checkbox" && !props.isSignYourself && (
|
||||
<>
|
||||
<label
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
fontWeight: "600",
|
||||
color: !props.isSubscribe && "gray"
|
||||
}}
|
||||
className={`${
|
||||
!props.isSubscribe ? "text-[gray]" : ""
|
||||
} text-[13px] font-semibold`}
|
||||
>
|
||||
Minimun check
|
||||
</label>
|
||||
@@ -263,18 +233,16 @@ function DropdownWidgetOption(props) {
|
||||
const count = handleSetMinMax(e);
|
||||
setMinCount(count);
|
||||
}}
|
||||
className={
|
||||
className={`${
|
||||
props.isSubscribe || !isEnableSubscription
|
||||
? "drodown-input"
|
||||
: "disabled drodown-input"
|
||||
}
|
||||
? ""
|
||||
: "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
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
fontWeight: "600",
|
||||
color: !props.isSubscribe && "gray"
|
||||
}}
|
||||
className={`${
|
||||
!props.isSubscribe ? "text-[gray]" : ""
|
||||
} text-[13px] font-semibold`}
|
||||
>
|
||||
Maximum check
|
||||
</label>
|
||||
@@ -286,11 +254,11 @@ function DropdownWidgetOption(props) {
|
||||
const count = handleSetMinMax(e);
|
||||
setMaxCount(count);
|
||||
}}
|
||||
className={
|
||||
className={`${
|
||||
props.isSubscribe || !isEnableSubscription
|
||||
? "drodown-input"
|
||||
: "disabled drodown-input"
|
||||
}
|
||||
? ""
|
||||
: "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`}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
@@ -298,32 +266,22 @@ function DropdownWidgetOption(props) {
|
||||
</div>
|
||||
{["dropdown", radioButtonWidget].includes(props.type) && (
|
||||
<>
|
||||
<label
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
fontWeight: "600",
|
||||
marginTop: "5px"
|
||||
}}
|
||||
>
|
||||
<label className="text-[13px] font-semibold mt-[5px]">
|
||||
Default value
|
||||
</label>
|
||||
<select
|
||||
onChange={(e) => setDefaultValue(e.target.value)}
|
||||
className="drodown-input"
|
||||
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
name="defaultvalue"
|
||||
value={defaultValue}
|
||||
placeholder="select default value"
|
||||
>
|
||||
<option value="" disabled hidden style={{ fontSize: "13px" }}>
|
||||
<option value="" disabled hidden className="text-[13px]">
|
||||
Select...
|
||||
</option>
|
||||
{dropdownOptionList.map((data, ind) => {
|
||||
return (
|
||||
<option
|
||||
style={{ fontSize: "13px" }}
|
||||
key={ind}
|
||||
value={data}
|
||||
>
|
||||
<option className="text-[13px]" key={ind} value={data}>
|
||||
{data}
|
||||
</option>
|
||||
);
|
||||
@@ -333,35 +291,21 @@ function DropdownWidgetOption(props) {
|
||||
)}
|
||||
{props.type !== "checkbox" && props.type !== radioButtonWidget && (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
gap: 10,
|
||||
marginTop: "0.5rem"
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row gap-[10px] mt-[0.5rem]">
|
||||
{statusArr.map((data, ind) => {
|
||||
return (
|
||||
<div
|
||||
key={ind}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
gap: 5,
|
||||
alignItems: "center"
|
||||
}}
|
||||
className="flex flex-row gap-[5px] items-center"
|
||||
>
|
||||
<input
|
||||
style={{ accentColor: "red" }}
|
||||
className="op-radio op-radio-xs my-1"
|
||||
type="radio"
|
||||
name="status"
|
||||
onChange={() => setStatus(data.toLowerCase())}
|
||||
checked={status.toLowerCase() === data.toLowerCase()}
|
||||
/>
|
||||
<div style={{ fontSize: "13px", fontWeight: "500" }}>
|
||||
{data}
|
||||
</div>
|
||||
<div className="text-[13px] font-500">{data}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -369,33 +313,31 @@ function DropdownWidgetOption(props) {
|
||||
</>
|
||||
)}
|
||||
{["checkbox", radioButtonWidget].includes(props.type) && (
|
||||
<div className="flex flex-row gap-5 mt-2 items-center text-center">
|
||||
<div className="flex flex-row gap-5 my-2 items-center text-center">
|
||||
{!props.isSignYourself && (
|
||||
<div>
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
id="isreadonly"
|
||||
type="checkbox"
|
||||
checked={isReadOnly}
|
||||
onChange={(e) => {
|
||||
setIsReadOnly(e.target.checked);
|
||||
}}
|
||||
className="op-checkbox op-checkbox-sm"
|
||||
onChange={(e) => setIsReadOnly(e.target.checked)}
|
||||
/>
|
||||
<label className="ml-1" htmlFor="isreadonly">
|
||||
<label className="ml-1 mb-0" htmlFor="isreadonly">
|
||||
Is read only
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
id="ishidelabel"
|
||||
type="checkbox"
|
||||
checked={isHideLabel}
|
||||
onChange={(e) => {
|
||||
setIsHideLabel(e.target.checked);
|
||||
}}
|
||||
className="op-checkbox op-checkbox-sm"
|
||||
onChange={(e) => setIsHideLabel(e.target.checked)}
|
||||
/>
|
||||
|
||||
<label className="ml-1" htmlFor="ishidelabel">
|
||||
<label className="ml-1 mb-0" htmlFor="ishidelabel">
|
||||
Hide labels
|
||||
</label>
|
||||
</div>
|
||||
@@ -421,19 +363,15 @@ function DropdownWidgetOption(props) {
|
||||
|
||||
<button
|
||||
disabled={dropdownOptionList.length === 0 && true}
|
||||
style={{
|
||||
background: themeColor,
|
||||
color: "white"
|
||||
}}
|
||||
type="submit"
|
||||
className={"finishBtn"}
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
{props.currWidgetsDetails?.options?.values?.length > 0 && (
|
||||
<button
|
||||
type="submit"
|
||||
className="finishBtn cancelBtn"
|
||||
className="op-btn op-btn-ghost ml-1"
|
||||
onClick={() => {
|
||||
props.handleClose && props.handleClose();
|
||||
resetState();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import React, { useState } from "react";
|
||||
import "../../styles/AddUser.css";
|
||||
import { getFileName } from "../../constant/Utils";
|
||||
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";
|
||||
|
||||
const EditTemplate = ({ template, onSuccess }) => {
|
||||
@@ -9,9 +11,21 @@ const EditTemplate = ({ template, onSuccess }) => {
|
||||
Name: template?.Name || "",
|
||||
Note: template?.Note || "",
|
||||
Description: template?.Description || "",
|
||||
SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false"
|
||||
SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false",
|
||||
AutomaticReminders: template?.AutomaticReminders || false,
|
||||
RemindOnceInEvery: template?.RemindOnceInEvery || 5
|
||||
});
|
||||
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
useEffect(() => {
|
||||
fetchSubscription();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
const fetchSubscription = async () => {
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
}
|
||||
};
|
||||
const handleStrInput = (e) => {
|
||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||
};
|
||||
@@ -25,34 +39,40 @@ const EditTemplate = ({ template, onSuccess }) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const isChecked = formData.SendinOrder === "true" ? true : false;
|
||||
const data = { ...formData, SendinOrder: isChecked };
|
||||
const AutoReminder = formData?.AutomaticReminders || false;
|
||||
|
||||
let reminderDate = {};
|
||||
if (AutoReminder) {
|
||||
const RemindOnceInEvery = parseInt(formData?.RemindOnceInEvery);
|
||||
const ReminderDate = new Date(template?.createdAt);
|
||||
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
||||
reminderDate = { NextReminderDate: ReminderDate };
|
||||
}
|
||||
const data = { ...formData, SendinOrder: isChecked, ...reminderDate };
|
||||
onSuccess(data);
|
||||
};
|
||||
|
||||
const handleAutoReminder = () => {
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
AutomaticReminders: !formData.AutomaticReminders
|
||||
}));
|
||||
};
|
||||
return (
|
||||
<div className="addusercontainer">
|
||||
<div className="form-wrapper">
|
||||
<div className="max-h-[300px] md:max-h-[400px] overflow-y-scroll p-[10px]">
|
||||
<div className="text-base-content">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div>
|
||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
||||
<div className="mb-[0.35rem]">
|
||||
<label htmlFor="name" className="text-[13px]">
|
||||
File
|
||||
</label>
|
||||
<div
|
||||
style={{
|
||||
padding: "0.5rem 0.75rem",
|
||||
border: "1px solid #d1d5db",
|
||||
borderRadius: "0.375rem",
|
||||
fontSize: "0.75rem",
|
||||
fontWeight: "700"
|
||||
}}
|
||||
>
|
||||
<div className="op-input op-input-bordered op-input-sm focus:outline-none py-2 font-semibold w-full text-xs">
|
||||
{getFileName(template.URL)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
||||
<div className="mb-[0.35rem]">
|
||||
<label htmlFor="name" className="text-[13px]">
|
||||
Name
|
||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
||||
<span className="text-[13px] text-[red]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
@@ -60,11 +80,11 @@ const EditTemplate = ({ template, onSuccess }) => {
|
||||
value={formData.Name}
|
||||
onChange={(e) => handleStrInput(e)}
|
||||
required
|
||||
className="addUserInput"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label htmlFor="Note" style={{ fontSize: 13 }}>
|
||||
<div className="mb-[0.35rem]">
|
||||
<label htmlFor="Note" className="text-[13px]">
|
||||
Note
|
||||
</label>
|
||||
<input
|
||||
@@ -73,11 +93,11 @@ const EditTemplate = ({ template, onSuccess }) => {
|
||||
id="Note"
|
||||
value={formData.Note}
|
||||
onChange={(e) => handleStrInput(e)}
|
||||
className="addUserInput"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label htmlFor="Description" style={{ fontSize: 13 }}>
|
||||
<div className="mb-[0.35rem]">
|
||||
<label htmlFor="Description" className="text-[13px]">
|
||||
Description
|
||||
</label>
|
||||
<input
|
||||
@@ -86,51 +106,85 @@ const EditTemplate = ({ template, onSuccess }) => {
|
||||
id="Description"
|
||||
value={formData.Description}
|
||||
onChange={(e) => handleStrInput(e)}
|
||||
className="addUserInput"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label style={{ fontSize: 13 }}>Send In Order</label>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
marginLeft: 8,
|
||||
marginBottom: 5
|
||||
}}
|
||||
>
|
||||
<div className="mb-[0.35rem]">
|
||||
<label className="text-[13px]">Send In Order</label>
|
||||
<div className="flex items-center gap-[8px] ml-[8px] mb-[5px]">
|
||||
<input
|
||||
type="radio"
|
||||
value={"true"}
|
||||
className="op-radio op-radio-xs"
|
||||
name="SendinOrder"
|
||||
checked={formData.SendinOrder === "true"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div style={{ fontSize: 12 }}>Yes</div>
|
||||
<div className="text-[12px]">Yes</div>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
marginLeft: 8,
|
||||
marginBottom: 5
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center gap-[8px] ml-[8px] mb-[5px]">
|
||||
<input
|
||||
type="radio"
|
||||
value={"false"}
|
||||
name="SendinOrder"
|
||||
className="op-radio op-radio-xs"
|
||||
checked={formData.SendinOrder === "false"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div style={{ fontSize: 12 }}>No</div>
|
||||
<div className="text-[12px]">No</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* <SelectFolder onSuccess={handleFolder} folderCls={"contracts_Template"} /> */}
|
||||
<div className="buttoncontainer">
|
||||
<button type="submit" className="submitbutton">
|
||||
<div className="text-xs mt-2">
|
||||
{!isEnableSubscription && (
|
||||
<PremiumAlertHeader
|
||||
message={
|
||||
"Auto reminder is free in beta, this feature will incur a fee later."
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<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>
|
||||
{isSubscribe && formData?.AutomaticReminders === true && (
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
Remind once in every (Days)
|
||||
<span className="text-red-500 text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
value={formData.RemindOnceInEvery}
|
||||
name="RemindOnceInEvery"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
onChange={handleStrInput}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-[1rem] flex justify-start">
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,52 +1,42 @@
|
||||
import React from "react";
|
||||
import Tooltip from "../../primitives/Tooltip";
|
||||
|
||||
import ReactQuill from "react-quill";
|
||||
import "react-quill/dist/quill.snow.css";
|
||||
import EditorToolbar, { module1, formats } from "./EditorToolbar";
|
||||
|
||||
export function EmailBody(props) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className={`flex justify-center py-1 p-2`}>
|
||||
<div className=" flex flex-col">
|
||||
<form>
|
||||
<div className="text-lg font-normal text-black">
|
||||
<div className=" m-2 md:m-10 p-3 md:p-10 shadow-md hover:shadow-lg border-[1px] border-indigo-800 rounded-md">
|
||||
<label className="text-sm ml-2">
|
||||
Subject <Tooltip message={"email subject"} />
|
||||
</label>
|
||||
<input
|
||||
required
|
||||
value={props.requestSubject}
|
||||
onChange={(e) => props.setRequestSubject(e.target.value)}
|
||||
placeholder='${senderName} has requested you to sign "${documentName}"'
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
/>
|
||||
<label className="text-sm ml-2 mt-3">
|
||||
Body <Tooltip message={"email body"} />
|
||||
</label>
|
||||
|
||||
<div className="px-3 py-2 w-full focus:outline-none text-xs">
|
||||
<EditorToolbar containerId="toolbar1" />
|
||||
<ReactQuill
|
||||
theme="snow"
|
||||
value={props.requestBody}
|
||||
// value={typedText}
|
||||
placeholder="add body of email "
|
||||
// readOnly={loading}
|
||||
// onChangeSelection={handleTextSelection} // Listen for text selection
|
||||
ref={props.editorRef}
|
||||
modules={module1}
|
||||
formats={formats}
|
||||
onChange={props.handleOnchangeRequest}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<form className="flex flex-col text-base-content text-lg font-normal">
|
||||
<div className="m-2 md:m-10 p-3 md:p-10 shadow-md hover:shadow-lg border-[1px] border-indigo-800 rounded-md">
|
||||
<label className="text-sm ml-2">
|
||||
Subject <Tooltip message={"email subject"} />
|
||||
</label>
|
||||
<input
|
||||
required
|
||||
value={props.requestSubject}
|
||||
onChange={(e) => props.setRequestSubject(e.target.value)}
|
||||
placeholder='${senderName} has requested you to sign "${documentName}"'
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
<label className="text-sm ml-2 mt-3">
|
||||
Body <Tooltip message={"email body"} />
|
||||
</label>
|
||||
<div className="px-3 py-2 w-full focus:outline-none text-xs">
|
||||
<EditorToolbar containerId="toolbar1" />
|
||||
<ReactQuill
|
||||
theme="snow"
|
||||
value={props.requestBody}
|
||||
// value={typedText}
|
||||
placeholder="add body of email "
|
||||
// readOnly={loading}
|
||||
// onChangeSelection={handleTextSelection} // Listen for text selection
|
||||
ref={props.editorRef}
|
||||
modules={module1}
|
||||
formats={formats}
|
||||
onChange={props.handleOnchangeRequest}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import React, { useState } from "react";
|
||||
import { saveAs } from "file-saver";
|
||||
import celebration from "../../assets/images/newCeleb.gif";
|
||||
import axios from "axios";
|
||||
import { getBase64FromUrl } from "../../constant/Utils";
|
||||
import { themeColor } from "../../constant/const";
|
||||
import printModule from "print-js";
|
||||
import loader from "../../assets/images/loader2.gif";
|
||||
import Loader from "../../primitives/Loader";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
|
||||
function EmailComponent({
|
||||
isEmail,
|
||||
pdfUrl,
|
||||
isCeleb,
|
||||
setIsEmail,
|
||||
setSuccessEmail,
|
||||
pdfName,
|
||||
@@ -166,266 +165,141 @@ function EmailComponent({
|
||||
<div>
|
||||
{/* isEmail */}
|
||||
{isEmail && (
|
||||
<div className="modaloverlay">
|
||||
<div className="modalcontainer">
|
||||
{isLoading && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
zIndex: "20",
|
||||
backgroundColor: "#e6f2f2",
|
||||
opacity: 0.8
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="no img"
|
||||
src={loader}
|
||||
style={{ width: "70px", height: "70px" }}
|
||||
/>
|
||||
<span style={{ fontSize: "12px", fontWeight: "bold" }}>
|
||||
This might take some time
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div style={{ background: "#32a3ac" }} className="modalheader">
|
||||
<span style={{ color: "white" }}>Successfully signed!</span>
|
||||
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<div></div>
|
||||
{!isAndroid && (
|
||||
<button
|
||||
onClick={handleToPrint}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
className="btn btn-primary btn-sm"
|
||||
>
|
||||
<i
|
||||
className="fa fa-print"
|
||||
style={{
|
||||
fontSize: "15px",
|
||||
marginRight: "3px",
|
||||
color: "white"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Print
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
className="btn btn-danger btn-sm"
|
||||
onClick={() => handleDownloadPdf()}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
marginLeft: "10px"
|
||||
}}
|
||||
>
|
||||
<i
|
||||
className="fa fa-download"
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "15px",
|
||||
marginRight: "3px"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Download
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ height: "100%", padding: 20 }}>
|
||||
{isCeleb && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
marginLeft: "50px"
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="print img"
|
||||
width={300}
|
||||
height={250}
|
||||
// style={styles.gifCeleb}
|
||||
src={celebration}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<p
|
||||
style={{
|
||||
fontFamily: "system-ui",
|
||||
verticalAlign: "baseline",
|
||||
fontWeight: "500",
|
||||
color: "#403f3e",
|
||||
fontSize: "15px",
|
||||
marginBottom: "5px"
|
||||
}}
|
||||
>
|
||||
Recipients added here will get a copy of the signed document.
|
||||
</p>
|
||||
{emailList.length > 0 ? (
|
||||
<>
|
||||
<div className="addEmail">
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
>
|
||||
{emailList.map((data, ind) => {
|
||||
return (
|
||||
<div
|
||||
className="emailChip"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
key={ind}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "13px"
|
||||
}}
|
||||
>
|
||||
{data}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: 13,
|
||||
fontWeight: 600,
|
||||
marginLeft: 7,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
onClick={() => removeChip(ind)}
|
||||
>
|
||||
<i className="fa-solid fa-xmark"></i>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{emailList.length <= 9 && (
|
||||
<input
|
||||
type="text"
|
||||
value={emailValue}
|
||||
className="addEmailInput"
|
||||
onChange={handleEmailValue}
|
||||
onKeyDown={handleEnterPress}
|
||||
onBlur={() => {
|
||||
if (emailValue) {
|
||||
handleEnterPress("add");
|
||||
}
|
||||
}}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
value={emailValue}
|
||||
className="emailInput"
|
||||
onChange={handleEmailValue}
|
||||
onKeyDown={handleEnterPress}
|
||||
placeholder="Add the email addresses"
|
||||
onBlur={() => {
|
||||
if (emailValue) {
|
||||
handleEnterPress("add");
|
||||
}
|
||||
}}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<span
|
||||
style={{
|
||||
cursor: emailValue && "pointer"
|
||||
}}
|
||||
onClick={() => {
|
||||
if (emailValue) {
|
||||
handleEnterPress("add");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<i
|
||||
style={{
|
||||
backgroundColor: themeColor,
|
||||
padding: "5px 7px",
|
||||
marginTop: "10px",
|
||||
color: "white",
|
||||
borderRadius: "2px"
|
||||
}}
|
||||
className="fa fa-plus"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<ModalUi isOpen showHeader={false}>
|
||||
{isLoading && (
|
||||
<div className="absolute w-full h-full flex flex-col justify-center items-center z-[20] bg-[#e6f2f2]/70">
|
||||
<Loader />
|
||||
<span className="text-[12px] text-base-content">
|
||||
This might take some time
|
||||
</span>
|
||||
|
||||
<div
|
||||
style={{
|
||||
background: "#e3e2e1",
|
||||
marginTop: "10px",
|
||||
padding: "5px",
|
||||
borderRadius: "3px"
|
||||
}}
|
||||
>
|
||||
<span style={{ fontWeight: "700" }}>Note:</span>
|
||||
<span style={{ fontSize: "15px" }}>
|
||||
{" "}
|
||||
You can only send to ten recipients at a time.
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
height: "1px",
|
||||
backgroundColor: "#9f9f9f",
|
||||
width: "100%",
|
||||
marginTop: "15px",
|
||||
marginBottom: "15px"
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex justify-between items-center py-[10px] px-[20px] border-b-[1px] border-base-content">
|
||||
<span className="text-base-content font-semibold">
|
||||
Successfully signed!
|
||||
</span>
|
||||
<div className="flex flex-row">
|
||||
<div></div>
|
||||
{!isAndroid && (
|
||||
<button
|
||||
onClick={handleToPrint}
|
||||
className="op-btn op-btn-neutral op-btn-sm text-[15px]"
|
||||
>
|
||||
<i className="fa-light fa-print" aria-hidden="true"></i>
|
||||
Print
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
disabled={emailList.length === 0 && true}
|
||||
style={{
|
||||
background: themeColor,
|
||||
color: "white"
|
||||
}}
|
||||
type="button"
|
||||
className={emailList.length === 0 ? "defaultBtn" : "finishBtn"}
|
||||
onClick={() => sendEmail()}
|
||||
className="op-btn op-btn-primary op-btn-sm text-[15px] ml-2"
|
||||
onClick={() => handleDownloadPdf()}
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="finishBtn cancelBtn"
|
||||
onClick={() => {
|
||||
setIsEmail(false);
|
||||
setEmailValue("");
|
||||
setEmailList([]);
|
||||
}}
|
||||
>
|
||||
Close
|
||||
<i className="fa-light fa-download" aria-hidden="true"></i>
|
||||
Download
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-full p-[20px]">
|
||||
<p className="font-medium text-[15px] mb-[5px] text-base-content align-baseline">
|
||||
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}
|
||||
>
|
||||
<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
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
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");
|
||||
}
|
||||
}}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
className={`${
|
||||
emailValue ? "cursor-pointer" : "cursor-default"
|
||||
} op-btn op-btn-primary op-btn-sm m-2 shadow-md`}
|
||||
onClick={() => {
|
||||
if (emailValue) {
|
||||
handleEnterPress("add");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<i className="fa-light fa-plus" aria-hidden="true"></i>
|
||||
</button>
|
||||
|
||||
<div className="bg-[#e3e2e1] mt-[10px] p-[5px] rounded">
|
||||
<span className="font-bold">Note: </span>
|
||||
<span className="text-[15px]">
|
||||
You can only send to ten recipients at a time.
|
||||
</span>
|
||||
</div>
|
||||
<hr className="w-full my-[15px] bg-base-content" />
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-secondary"
|
||||
onClick={() => emailList.length > 0 && sendEmail()}
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-ghost ml-2"
|
||||
onClick={() => {
|
||||
setIsEmail(false);
|
||||
setEmailValue("");
|
||||
setEmailList([]);
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</ModalUi>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import React, { useState } from "react";
|
||||
import PrevNext from "./PrevNext";
|
||||
import printModule from "print-js";
|
||||
import { getBase64FromUrl } from "../../constant/Utils";
|
||||
import { saveAs } from "file-saver";
|
||||
import {
|
||||
handleDownloadCertificate,
|
||||
handleDownloadPdf,
|
||||
handleToPrint
|
||||
} from "../../constant/Utils";
|
||||
import "../../styles/signature.css";
|
||||
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { themeColor } from "../../constant/const";
|
||||
import axios from "axios";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
import { appInfo } from "../../constant/appinfo";
|
||||
import Loader from "../../primitives/Loader";
|
||||
|
||||
function Header({
|
||||
isPdfRequestFiles,
|
||||
@@ -29,7 +29,6 @@ function Header({
|
||||
isShowHeader,
|
||||
decline,
|
||||
currentSigner,
|
||||
dataTut4,
|
||||
alreadySign,
|
||||
isSignYourself,
|
||||
setIsEmail,
|
||||
@@ -40,16 +39,9 @@ function Header({
|
||||
signerPos && signerPos?.filter((data) => data.Role !== "prefill");
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const navigate = useNavigate();
|
||||
const [isCertificate, setIsCertificate] = useState(false);
|
||||
const [isDownloading, setIsDownloading] = useState("");
|
||||
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
||||
//for go to previous page
|
||||
function previousPage() {
|
||||
changePage(-1);
|
||||
}
|
||||
//for go to next page
|
||||
function nextPage() {
|
||||
changePage(1);
|
||||
}
|
||||
|
||||
//function for show decline alert
|
||||
const handleDeclinePdfAlert = async () => {
|
||||
const currentDecline = {
|
||||
@@ -59,125 +51,8 @@ function Header({
|
||||
setIsDecline(currentDecline);
|
||||
};
|
||||
|
||||
//function for print digital sign pdf
|
||||
const handleToPrint = async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
try {
|
||||
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
|
||||
const axiosRes = await axios.post(
|
||||
`${appInfo.baseUrl}/functions/getsignedurl`,
|
||||
{ url: pdfUrl },
|
||||
{
|
||||
headers: {
|
||||
"content-type": "Application/json",
|
||||
"X-Parse-Application-Id": appInfo.appId,
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
);
|
||||
const url = axiosRes.data.result;
|
||||
const pdf = await getBase64FromUrl(url);
|
||||
const isAndroidDevice = navigator.userAgent.match(/Android/i);
|
||||
const isAppleDevice =
|
||||
(/iPad|iPhone|iPod/.test(navigator.platform) ||
|
||||
(navigator.platform === "MacIntel" &&
|
||||
navigator.maxTouchPoints > 1)) &&
|
||||
!window.MSStream;
|
||||
if (isAndroidDevice || isAppleDevice) {
|
||||
const byteArray = Uint8Array.from(
|
||||
atob(pdf)
|
||||
.split("")
|
||||
.map((char) => char.charCodeAt(0))
|
||||
);
|
||||
const blob = new Blob([byteArray], { type: "application/pdf" });
|
||||
const blobUrl = URL.createObjectURL(blob);
|
||||
window.open(blobUrl, "_blank");
|
||||
} else {
|
||||
printModule({ printable: pdf, type: "pdf", base64: true });
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err in getsignedurl", err);
|
||||
alert("something went wrong, please try again later.");
|
||||
}
|
||||
};
|
||||
|
||||
//handle download signed pdf
|
||||
const handleDownloadPdf = async () => {
|
||||
const pdfName = pdfDetails[0] && pdfDetails[0].Name;
|
||||
try {
|
||||
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
|
||||
const axiosRes = await axios.post(
|
||||
`${appInfo.baseUrl}/functions/getsignedurl`,
|
||||
{ url: pdfUrl },
|
||||
{
|
||||
headers: {
|
||||
"content-type": "Application/json",
|
||||
"X-Parse-Application-Id": appInfo.appId,
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
);
|
||||
const url = axiosRes.data.result;
|
||||
saveAs(url, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
|
||||
} catch (err) {
|
||||
console.log("err in getsignedurl", err);
|
||||
alert("something went wrong, please try again later.");
|
||||
}
|
||||
};
|
||||
|
||||
const sanitizeFileName = (pdfName) => {
|
||||
// Replace spaces with underscore
|
||||
return pdfName.replace(/ /g, "_");
|
||||
};
|
||||
|
||||
//handle download signed pdf
|
||||
const handleDownloadCertificate = async () => {
|
||||
if (pdfDetails?.length > 0 && pdfDetails[0]?.CertificateUrl) {
|
||||
try {
|
||||
await fetch(pdfDetails[0] && pdfDetails[0]?.CertificateUrl);
|
||||
const certificateUrl = pdfDetails[0] && pdfDetails[0]?.CertificateUrl;
|
||||
saveAs(certificateUrl, `Certificate_signed_by_OpenSign™.pdf`);
|
||||
} catch (err) {
|
||||
console.log("err in download in certificate", err);
|
||||
}
|
||||
} else {
|
||||
setIsCertificate(true);
|
||||
try {
|
||||
const data = {
|
||||
docId: pdfDetails[0]?.objectId
|
||||
};
|
||||
const docDetails = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}functions/getDocument`,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
);
|
||||
if (docDetails.data && docDetails.data.result) {
|
||||
const doc = docDetails.data.result;
|
||||
if (doc?.CertificateUrl) {
|
||||
await fetch(doc?.CertificateUrl);
|
||||
const certificateUrl = doc?.CertificateUrl;
|
||||
saveAs(certificateUrl, `Certificate_signed_by_OpenSign™.pdf`);
|
||||
setIsCertificate(false);
|
||||
} else {
|
||||
setIsCertificate(true);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err in download in certificate", err);
|
||||
alert("something went wrong, please try again later.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: "5px 0px 5px 0px" }} className="mobileHead">
|
||||
<div className="flex py-[5px]">
|
||||
{isMobile && isShowHeader ? (
|
||||
<div
|
||||
id="navbar"
|
||||
@@ -188,57 +63,26 @@ function Header({
|
||||
: window.innerWidth - 30 + "px"
|
||||
}}
|
||||
>
|
||||
<div className="preBtn2">
|
||||
<div className="flex justify-between items-center py-[5px] px-[10px] ">
|
||||
<div onClick={() => navigate(-1)}>
|
||||
<i
|
||||
className="fa fa-arrow-left"
|
||||
className="fa-light fa-arrow-left text-base-content"
|
||||
aria-hidden="true"
|
||||
style={{ color: themeColor, cursor: "pointer" }}
|
||||
></i>
|
||||
</div>
|
||||
<div>
|
||||
<i
|
||||
onClick={() => {
|
||||
if (pageNumber > 1) {
|
||||
previousPage();
|
||||
}
|
||||
}}
|
||||
className="fa fa-backward"
|
||||
style={{ color: "gray", cursor: "pointer" }}
|
||||
></i>
|
||||
<span
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
fontWeight: "600",
|
||||
marginLeft: "10px",
|
||||
marginRight: "10px"
|
||||
}}
|
||||
>
|
||||
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
|
||||
</span>
|
||||
<i
|
||||
onClick={() => {
|
||||
if (pageNumber < allPages) {
|
||||
nextPage();
|
||||
}
|
||||
}}
|
||||
className="fa fa-forward"
|
||||
style={{ color: "gray", cursor: "pointer" }}
|
||||
></i>
|
||||
</div>
|
||||
<PrevNext
|
||||
pageNumber={pageNumber}
|
||||
allPages={allPages}
|
||||
changePage={changePage}
|
||||
/>
|
||||
{pdfUrl && alreadySign ? (
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<div
|
||||
style={{
|
||||
color: themeColor,
|
||||
border: "none",
|
||||
fontWeight: "650",
|
||||
fontSize: "16px",
|
||||
padding: "0px 3px 0px 5px"
|
||||
}}
|
||||
>
|
||||
<i className="fa fa-ellipsis-v" aria-hidden="true"></i>
|
||||
<div className="op-link op-link-primary no-underline text-[16px] font-semibold pr-[3px] pl-[5px]">
|
||||
<i
|
||||
className="fa-light fa-ellipsis-v"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</div>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Portal>
|
||||
@@ -248,18 +92,14 @@ function Header({
|
||||
>
|
||||
<DropdownMenu.Item
|
||||
className="DropdownMenuItem"
|
||||
onClick={() => handleDownloadPdf()}
|
||||
onClick={() =>
|
||||
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
|
||||
}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row"
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row">
|
||||
<i
|
||||
className="fa fa-arrow-down"
|
||||
className="fa-light fa-arrow-down mr-[3px]"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "2px" }}
|
||||
></i>
|
||||
Download
|
||||
</div>
|
||||
@@ -267,17 +107,16 @@ function Header({
|
||||
{isCompleted && (
|
||||
<DropdownMenu.Item
|
||||
className="DropdownMenuItem"
|
||||
onClick={() => handleDownloadCertificate()}
|
||||
onClick={() =>
|
||||
handleDownloadCertificate(
|
||||
pdfDetails,
|
||||
setIsDownloading
|
||||
)
|
||||
}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
border: "none",
|
||||
backgroundColor: "#fff"
|
||||
}}
|
||||
>
|
||||
<div className="border-none bg-[#fff]">
|
||||
<i
|
||||
className="fa-solid fa-award"
|
||||
style={{ marginRight: "2px" }}
|
||||
className="fa-light fa-award mr-[3px]"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Certificate
|
||||
@@ -289,15 +128,9 @@ function Header({
|
||||
className="DropdownMenuItem"
|
||||
onClick={() => setIsEmail(true)}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row"
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row">
|
||||
<i
|
||||
className="fa fa-envelope"
|
||||
style={{ marginRight: "2px" }}
|
||||
className="fa-light fa-envelope mr-[3px]"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Mail
|
||||
@@ -306,18 +139,14 @@ function Header({
|
||||
)}
|
||||
<DropdownMenu.Item
|
||||
className="DropdownMenuItem"
|
||||
onClick={handleToPrint}
|
||||
onClick={(e) =>
|
||||
handleToPrint(e, pdfUrl, setIsDownloading)
|
||||
}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row"
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row">
|
||||
<i
|
||||
className="fa fa-print"
|
||||
className="fa-light fa-print mr-[3px]"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "2px" }}
|
||||
></i>
|
||||
Print
|
||||
</div>
|
||||
@@ -326,24 +155,16 @@ function Header({
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu.Root>
|
||||
) : (
|
||||
<div style={{ display: "flex", justifyContent: "space-around" }}>
|
||||
<div className="flex justify-around items-center">
|
||||
{/* current signer is checking user send request and check status of pdf sign than if current
|
||||
user exist than show finish button else no
|
||||
*/}
|
||||
{currentSigner && (
|
||||
<>
|
||||
<div className="flex items-center" data-tut="reactourFifth">
|
||||
{decline && (
|
||||
<div
|
||||
onClick={() => {
|
||||
handleDeclinePdfAlert();
|
||||
}}
|
||||
style={{
|
||||
color: "red",
|
||||
border: "none",
|
||||
fontWeight: "650",
|
||||
fontSize: "16px",
|
||||
marginRight: "10px"
|
||||
}}
|
||||
onClick={() => handleDeclinePdfAlert()}
|
||||
className="text-[red] border-none font-[650] text-[14px] mr-2"
|
||||
>
|
||||
Decline
|
||||
</div>
|
||||
@@ -355,13 +176,10 @@ function Header({
|
||||
alertSendEmail();
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
color: isMailSend ? "gray" : themeColor,
|
||||
border: "none",
|
||||
fontWeight: "650",
|
||||
fontSize: "16px"
|
||||
}}
|
||||
data-tut={dataTut4}
|
||||
className={`${
|
||||
isMailSend ? "" : "op-link-primary"
|
||||
} op-link no-underline font-[650] text-[14px]`}
|
||||
data-tut="headerArea"
|
||||
>
|
||||
{completeBtnTitle ? completeBtnTitle : "Send"}
|
||||
</div>
|
||||
@@ -375,24 +193,52 @@ function Header({
|
||||
embedWidgetsData();
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
color: themeColor,
|
||||
border: "none",
|
||||
fontWeight: "650",
|
||||
fontSize: "16px"
|
||||
}}
|
||||
className="border-none font-[650] text-[14px] op-link op-link-primary no-underline"
|
||||
>
|
||||
Finish
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<div className="font-[650] text-[18px] px-2 ml-[4px] text-base-content no-underline">
|
||||
<i
|
||||
className="fa-light fa-ellipsis-v"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</div>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content
|
||||
className="bg-white shadow-md rounded px-2 py-1"
|
||||
sideOffset={5}
|
||||
>
|
||||
<DropdownMenu.Item
|
||||
className="flex flex-row justify-center items-center text-[13px] focus:outline-none cursor-pointer"
|
||||
onClick={() =>
|
||||
handleDownloadPdf(
|
||||
pdfDetails,
|
||||
pdfUrl,
|
||||
setIsDownloading
|
||||
)
|
||||
}
|
||||
>
|
||||
<i
|
||||
className="fa-light fa-arrow-down mr-[3px]"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span className="font-[500]">Download</span>
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-wrap justify-between items-center mt-[5px]">
|
||||
<div className="flex flex-wrap justify-between items-center w-full gap-y-1 ml-1">
|
||||
<PrevNext
|
||||
pageNumber={pageNumber}
|
||||
allPages={allPages}
|
||||
@@ -406,12 +252,12 @@ function Header({
|
||||
signersdata.length !== filterPrefill.length && (
|
||||
<div>
|
||||
{filterPrefill.length === 0 ? (
|
||||
<span style={{ fontSize: "13px", color: "#f5405e" }}>
|
||||
<span className="text-[13px] text-[#f5405e]">
|
||||
Add {signersdata.length - filterPrefill.length}{" "}
|
||||
recipients signature
|
||||
</span>
|
||||
) : (
|
||||
<span style={{ fontSize: "13px", color: "#f5405e" }}>
|
||||
<span className="text-[13px] text-[#f5405e]">
|
||||
Add {signersdata.length - filterPrefill.length} more
|
||||
recipients signature
|
||||
</span>
|
||||
@@ -423,166 +269,192 @@ function Header({
|
||||
{setIsEditTemplate && (
|
||||
<button
|
||||
onClick={() => setIsEditTemplate(true)}
|
||||
className="outline-none border-none text-center mr-[5px]"
|
||||
className="outline-none border-none text-center mr-[3px]"
|
||||
>
|
||||
<i className="fa-solid fa-gear fa-lg"></i>
|
||||
<i className="fa-light fa-gear fa-lg"></i>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => navigate(-1)}
|
||||
type="button"
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-black font-[500] text-sm mr-[5px] bg-white"
|
||||
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
<button
|
||||
disabled={isMailSend && true}
|
||||
data-tut="reactourFour"
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] font-[500] text-sm mr-[5px]"
|
||||
style={{
|
||||
background: isMailSend ? "rgb(203, 203, 203)" : "#188ae2",
|
||||
color: isMailSend ? "rgb(77, 75, 75)" : "white"
|
||||
}}
|
||||
onClick={() => {
|
||||
alertSendEmail();
|
||||
}}
|
||||
data-tut="headerArea"
|
||||
className="op-btn op-btn-primary op-btn-sm mr-[3px]"
|
||||
onClick={() => alertSendEmail()}
|
||||
>
|
||||
{completeBtnTitle
|
||||
? completeBtnTitle
|
||||
: isMailSend
|
||||
? "Sent"
|
||||
: "Send"}
|
||||
? "Sent"
|
||||
: "Send"}
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
) : isPdfRequestFiles ? (
|
||||
alreadySign ? (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<div className="flex flex-row">
|
||||
{isCompleted && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleDownloadCertificate()}
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#08bc66]"
|
||||
onClick={() =>
|
||||
handleDownloadCertificate(pdfDetails, setIsDownloading)
|
||||
}
|
||||
className="op-btn op-btn-secondary op-btn-sm mr-[3px] shadow"
|
||||
>
|
||||
<i
|
||||
className="fa-solid fa-award py-[3px]"
|
||||
className="fa-light fa-award py-[3px]"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span className="hidden lg:block ml-1">Certificate</span>
|
||||
<span className="hidden lg:block">Certificate</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={handleToPrint}
|
||||
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
|
||||
type="button"
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#188ae2]"
|
||||
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
|
||||
>
|
||||
<i className="fa fa-print py-[3px]" aria-hidden="true"></i>
|
||||
<span className="hidden lg:block ml-1">Print</span>
|
||||
<i
|
||||
className="fa-light fa-print py-[3px]"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span className="hidden lg:block">Print</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#f14343]"
|
||||
onClick={() => handleDownloadPdf()}
|
||||
className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow"
|
||||
onClick={() =>
|
||||
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
|
||||
}
|
||||
>
|
||||
<i className="fa fa-download py-[3px]" aria-hidden="true"></i>
|
||||
<span className="hidden lg:block ml-1">Download</span>
|
||||
<i
|
||||
className="fa-light fa-download py-[3px]"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span className="hidden lg:block">Download</span>
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex">
|
||||
<div className="flex" data-tut="reactourFifth">
|
||||
<button
|
||||
onClick={() => navigate(-1)}
|
||||
type="button"
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-black font-[500] text-sm mr-[5px] bg-white"
|
||||
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
{currentSigner && (
|
||||
<>
|
||||
<button
|
||||
style={{ background: "#de4337" }}
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-white font-[500] text-[13px] mr-[5px] bg-[#f14343]"
|
||||
onClick={() => {
|
||||
handleDeclinePdfAlert();
|
||||
}}
|
||||
className="op-btn op-btn-secondary op-btn-sm mr-[3px] shadow"
|
||||
onClick={() => handleDeclinePdfAlert()}
|
||||
>
|
||||
Decline
|
||||
</button>
|
||||
<button
|
||||
style={{
|
||||
background: "#188ae2"
|
||||
}}
|
||||
type="button"
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-white font-[500] text-[13px] mr-[5px] bg-[#188ae2]"
|
||||
onClick={() => {
|
||||
embedWidgetsData();
|
||||
}}
|
||||
className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow"
|
||||
onClick={() => embedWidgetsData()}
|
||||
>
|
||||
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>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
) : isCompleted ? (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<div className="flex flex-row">
|
||||
{isCompleted && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleDownloadCertificate()}
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#08bc66]"
|
||||
onClick={() =>
|
||||
handleDownloadCertificate(pdfDetails, setIsDownloading)
|
||||
}
|
||||
className="op-btn op-btn-secondary op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
|
||||
>
|
||||
<i
|
||||
className="fa-solid fa-award py-[3px]"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<i className="fa-light fa-award" aria-hidden="true"></i>
|
||||
<span className="hidden lg:block ml-1">Certificate</span>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={handleToPrint}
|
||||
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
|
||||
type="button"
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#188ae2]"
|
||||
className="op-btn op-btn-neutral op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
|
||||
>
|
||||
<i className="fa fa-print py-[3px]" aria-hidden="true"></i>
|
||||
<i className="fa-light fa-print" aria-hidden="true"></i>
|
||||
<span className="hidden lg:block ml-1">Print</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#f14343]"
|
||||
onClick={() => handleDownloadPdf()}
|
||||
className="op-btn op-btn-primary op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
|
||||
onClick={() =>
|
||||
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
|
||||
}
|
||||
>
|
||||
<i className="fa fa-download py-[3px]" aria-hidden="true"></i>
|
||||
<i className="fa-light fa-download" aria-hidden="true"></i>
|
||||
<span className="hidden lg:block ml-1">Download</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#3ba7e5]"
|
||||
className="op-btn op-btn-info op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
|
||||
onClick={() => setIsEmail(true)}
|
||||
>
|
||||
<i className="fa fa-envelope py-[3px]" aria-hidden="true"></i>
|
||||
<i className="fa-light fa-envelope" aria-hidden="true"></i>
|
||||
<span className="hidden lg:block ml-1">Mail</span>
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex">
|
||||
<button
|
||||
onClick={() => {
|
||||
navigate(-1);
|
||||
}}
|
||||
onClick={() => navigate(-1)}
|
||||
type="button"
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-black font-[500] text-sm mr-[5px] bg-white"
|
||||
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
<button
|
||||
style={{
|
||||
background: "#188ae2"
|
||||
}}
|
||||
type="button"
|
||||
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-white font-[500] text-[13px] mr-[5px] bg-[#188ae2]"
|
||||
className="op-btn op-btn-primary op-btn-sm mr-[3px]"
|
||||
onClick={() => {
|
||||
if (!pdfUrl) {
|
||||
embedWidgetsData();
|
||||
@@ -595,18 +467,26 @@ function Header({
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{isDownloading === "pdf" && (
|
||||
<div className="fixed z-[200] inset-0 flex justify-center items-center bg-black bg-opacity-30">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
<ModalUi
|
||||
isOpen={isCertificate}
|
||||
title={"Generating certificate"}
|
||||
handleClose={() => setIsCertificate(false)}
|
||||
isOpen={isDownloading === "certificate"}
|
||||
title={
|
||||
isDownloading === "certificate"
|
||||
? "Generating certificate"
|
||||
: "PDF Download"
|
||||
}
|
||||
handleClose={() => setIsDownloading("")}
|
||||
>
|
||||
<div className="p-3 md:p-5 text-[13px] md:text-base text-center">
|
||||
<div className="p-3 md:p-5 text-[13px] md:text-base text-center text-base-content">
|
||||
{isDownloading === "certificate"}{" "}
|
||||
<p>
|
||||
Your completion certificate is being generated. Please wait
|
||||
momentarily.
|
||||
</p>
|
||||
<p>
|
||||
If the download doesn't start shortly, click the button again.
|
||||
momentarily. If the download doesn't start shortly, click the
|
||||
button again.
|
||||
</p>
|
||||
</div>
|
||||
</ModalUi>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import React from "react";
|
||||
|
||||
function PdfZoom(props) {
|
||||
const onClickZoomIn = () => {
|
||||
props.setScale(props.scale + 0.1 * props.scale);
|
||||
props.setZoomPercent(props.zoomPercent + 10);
|
||||
};
|
||||
const onClickZoomOut = () => {
|
||||
if (props.zoomPercent > 0) {
|
||||
if (props.zoomPercent === 10) {
|
||||
props.setScale(1);
|
||||
} else {
|
||||
props.setScale(props.scale - 0.1 * props.scale);
|
||||
}
|
||||
props.setZoomPercent(props.zoomPercent - 10);
|
||||
}
|
||||
};
|
||||
const handleReset = () => {
|
||||
props.setScale(1);
|
||||
props.setZoomPercent(0);
|
||||
};
|
||||
return (
|
||||
// md:mt-[41px] xl:mt-[63px]mt=[]
|
||||
<span className="hidden md:flex flex-col gap-1 text-center md:w-[5%] mt-[50px] 2xl:mt-[63px]">
|
||||
<span
|
||||
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
|
||||
onClick={onClickZoomIn}
|
||||
title="Zoom in"
|
||||
>
|
||||
<i className="fa-light fa-magnifying-glass-plus text-gray-500 2xl:text-[30px]"></i>
|
||||
</span>
|
||||
<span
|
||||
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
|
||||
onClick={handleReset}
|
||||
title="Reset"
|
||||
>
|
||||
<i className="fa-light fa-magnifying-glass-arrows-rotate text-gray-500 2xl:text-[30px]"></i>
|
||||
</span>
|
||||
<span
|
||||
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px]"
|
||||
onClick={onClickZoomOut}
|
||||
style={{
|
||||
cursor: props.zoomPercent > 0 ? "pointer" : "default"
|
||||
}}
|
||||
title="Zoom out"
|
||||
>
|
||||
<i className="fa-light fa-magnifying-glass-minus text-gray-500 2xl:text-[30px]"></i>
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export default PdfZoom;
|
||||
@@ -5,7 +5,7 @@ import { Rnd } from "react-rnd";
|
||||
import {
|
||||
defaultWidthHeight,
|
||||
handleCopyNextToWidget,
|
||||
isMobile,
|
||||
isTabAndMobile,
|
||||
onChangeInput,
|
||||
radioButtonWidget,
|
||||
textInputWidget,
|
||||
@@ -88,8 +88,10 @@ const getDefaultdate = (selectedDate, format = "dd-MM-yyyy") => {
|
||||
const getDefaultFormat = (dateFormat) => dateFormat || "MM/dd/yyyy";
|
||||
|
||||
function Placeholder(props) {
|
||||
const [placeholderBorder, setPlaceholderBorder] = useState({ w: 0, h: 0 });
|
||||
const [isDraggingEnabled, setDraggingEnabled] = useState(true);
|
||||
const [isShowDateFormat, setIsShowDateFormat] = useState(false);
|
||||
const [containerScale, setContainerScale] = useState();
|
||||
const [selectDate, setSelectDate] = useState({
|
||||
date:
|
||||
props.pos.type === "date"
|
||||
@@ -119,6 +121,14 @@ function Placeholder(props) {
|
||||
width: null,
|
||||
height: null
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const getPdfPageWidth = props.pdfOriginalWH.find(
|
||||
(data) => data.pageNumber === props.pageNumber
|
||||
);
|
||||
setContainerScale(props.containerWH.width / getPdfPageWidth.width);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [props.containerWH.width, props.pdfOriginalWH]);
|
||||
const dateFormatArr = [
|
||||
"L",
|
||||
"DD-MM-YYYY",
|
||||
@@ -293,12 +303,27 @@ function Placeholder(props) {
|
||||
props?.setShowDropdown(true);
|
||||
} else if (props.pos.type === "checkbox") {
|
||||
props?.setIsCheckbox(true);
|
||||
} else if (
|
||||
[
|
||||
textInputWidget,
|
||||
textWidget,
|
||||
"name",
|
||||
"company",
|
||||
"job title",
|
||||
"email"
|
||||
].includes(props.pos.type)
|
||||
) {
|
||||
props.handleTextSettingModal(true);
|
||||
} else {
|
||||
props?.handleNameModal(true);
|
||||
props?.handleNameModal && props?.handleNameModal(true);
|
||||
}
|
||||
|
||||
if (props.isPlaceholder && props.type !== textWidget) {
|
||||
props.setUniqueId(props.data.Id);
|
||||
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) {
|
||||
props.setTempSignerId(props.uniqueId);
|
||||
props.setUniqueId(props?.data?.Id);
|
||||
}
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setWidgetType(props.pos.type);
|
||||
@@ -375,7 +400,15 @@ function Placeholder(props) {
|
||||
<>
|
||||
{(props.isPlaceholder || props.isSignYourself) && (
|
||||
<>
|
||||
{props.pos.type === "checkbox" && props.isSignYourself ? (
|
||||
{[
|
||||
"checkbox",
|
||||
textInputWidget,
|
||||
textWidget,
|
||||
"name",
|
||||
"company",
|
||||
"job title",
|
||||
"email"
|
||||
].includes(props.pos.type) && props.isSignYourself ? (
|
||||
<i
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
@@ -385,7 +418,7 @@ function Placeholder(props) {
|
||||
e.stopPropagation();
|
||||
handleOnClickSettingIcon();
|
||||
}}
|
||||
className="fa-solid fa-gear settingIcon"
|
||||
className="fa-light fa-gear icon"
|
||||
style={{
|
||||
color: "#188ae2",
|
||||
right: "29px",
|
||||
@@ -395,9 +428,7 @@ function Placeholder(props) {
|
||||
) : (
|
||||
((!props?.pos?.type && props.pos.isStamp) ||
|
||||
(props?.pos?.type &&
|
||||
!["date", textWidget, "signature"].includes(
|
||||
props.pos.type
|
||||
) &&
|
||||
!["date", "signature"].includes(props.pos.type) &&
|
||||
!props.isSignYourself)) && (
|
||||
<i
|
||||
onClick={(e) => {
|
||||
@@ -408,8 +439,12 @@ function Placeholder(props) {
|
||||
e.stopPropagation();
|
||||
handleOnClickSettingIcon();
|
||||
}}
|
||||
className="fa-solid fa-gear settingIcon"
|
||||
style={{ color: "#188ae2", right: "47px", top: "-19px" }}
|
||||
className="fa-light fa-gear icon"
|
||||
style={{
|
||||
color: "#188ae2",
|
||||
right: props?.pos?.type === textWidget ? "32px" : "47px",
|
||||
top: "-19px"
|
||||
}}
|
||||
></i>
|
||||
)
|
||||
)}
|
||||
@@ -417,7 +452,7 @@ function Placeholder(props) {
|
||||
{props.pos.type !== textWidget && !props.isSignYourself && (
|
||||
<i
|
||||
data-tut="assignSigner"
|
||||
className="fa-regular fa-user signUserIcon"
|
||||
className="fa-light fa-user icon"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
props.handleLinkUser(props.data.Id);
|
||||
@@ -441,11 +476,7 @@ function Placeholder(props) {
|
||||
top: "-19px",
|
||||
right: props.isPlaceholder ? "60px" : "44px"
|
||||
}}
|
||||
className={
|
||||
isShowDateFormat
|
||||
? "dropdown signUserIcon show"
|
||||
: "dropdown signUserIcon"
|
||||
}
|
||||
className={`${isShowDateFormat ? "show" : ""} dropdown icon`}
|
||||
onClick={(e) => {
|
||||
setIsShowDateFormat(!isShowDateFormat);
|
||||
e.stopPropagation();
|
||||
@@ -464,7 +495,7 @@ function Placeholder(props) {
|
||||
}}
|
||||
>
|
||||
<i
|
||||
className="fa-solid fa-gear settingIcon"
|
||||
className="fa-light fa-gear icon"
|
||||
style={{
|
||||
color: "#188ae2",
|
||||
fontSize: "14px"
|
||||
@@ -492,8 +523,7 @@ function Placeholder(props) {
|
||||
setSelectDate(data);
|
||||
handleSaveDate(data);
|
||||
}}
|
||||
className="dropdown-item itemColor"
|
||||
style={{ fontSize: "12px" }}
|
||||
className="dropdown-item text-[13px]"
|
||||
>
|
||||
{data?.date ? data?.date : "nodata"}
|
||||
</span>
|
||||
@@ -503,13 +533,13 @@ function Placeholder(props) {
|
||||
</div>
|
||||
)}
|
||||
<i
|
||||
className="fa-regular fa-copy signCopy"
|
||||
className="fa-light fa-copy icon"
|
||||
onClick={(e) => handleCopyPlaceholder(e)}
|
||||
onTouchEnd={(e) => handleCopyPlaceholder(e)}
|
||||
style={{ color: "#188ae2", right: "12px", top: "-18px" }}
|
||||
></i>
|
||||
<i
|
||||
className="fa-regular fa-circle-xmark signCloseBtn"
|
||||
className="fa-light fa-circle-xmark icon"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -535,6 +565,61 @@ function Placeholder(props) {
|
||||
)
|
||||
);
|
||||
};
|
||||
const xPos = (pos, signYourself) => {
|
||||
const getPdfPageWidth = props.pdfOriginalWH.find(
|
||||
(data) => data.pageNumber === props.pageNumber
|
||||
);
|
||||
const containerScale = props.containerWH.width / getPdfPageWidth?.width;
|
||||
const resizePos = pos.xPosition;
|
||||
if (signYourself) {
|
||||
return resizePos * containerScale * props.scale;
|
||||
} else {
|
||||
//checking both condition mobile and desktop view
|
||||
if (pos.isMobile && pos.scale) {
|
||||
if (props.scale > 1) {
|
||||
return resizePos * pos.scale * containerScale * props.scale;
|
||||
} else {
|
||||
return resizePos * pos.scale * containerScale;
|
||||
}
|
||||
} else {
|
||||
// if (pos.scale === containerScale) {
|
||||
// return resizePos * pos.scale * props.scale;
|
||||
// } else {
|
||||
return resizePos * containerScale * props.scale;
|
||||
// }
|
||||
}
|
||||
}
|
||||
};
|
||||
const yPos = (pos, signYourself) => {
|
||||
const getPdfPageWidth = props.pdfOriginalWH.find(
|
||||
(data) => data.pageNumber === props.pageNumber
|
||||
);
|
||||
const containerScale = props.containerWH.width / getPdfPageWidth.width;
|
||||
const resizePos = pos.yPosition;
|
||||
|
||||
if (signYourself) {
|
||||
return resizePos * containerScale * props.scale;
|
||||
} else {
|
||||
//checking both condition mobile and desktop view
|
||||
if (pos.isMobile && pos.scale) {
|
||||
if (props.scale > 1) {
|
||||
return resizePos * pos.scale * containerScale * props.scale;
|
||||
} else {
|
||||
return resizePos * pos.scale * containerScale;
|
||||
}
|
||||
}
|
||||
// else if (pos.scale === containerScale) {
|
||||
// if (props.scale > 1) {
|
||||
// return resizePos * pos.scale * props.scale;
|
||||
// } else {
|
||||
// return resizePos * pos.scale;
|
||||
// }
|
||||
// }
|
||||
else {
|
||||
return resizePos * containerScale * props.scale;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Rnd
|
||||
@@ -620,8 +705,20 @@ function Placeholder(props) {
|
||||
setDraggingEnabled(true);
|
||||
props.setIsResize && props.setIsResize(true);
|
||||
}}
|
||||
onResizeStop={() => {
|
||||
onResizeStop={(e, direction, ref) => {
|
||||
props.setIsResize && props.setIsResize(false);
|
||||
props.handleSignYourselfImageResize &&
|
||||
props.handleSignYourselfImageResize(
|
||||
ref,
|
||||
props.pos.key,
|
||||
props.xyPostion,
|
||||
props.setXyPostion,
|
||||
props.index,
|
||||
containerScale,
|
||||
props.scale,
|
||||
props.data && props.data.Id,
|
||||
props.isResize
|
||||
);
|
||||
}}
|
||||
disableDragging={
|
||||
props.isNeedSign
|
||||
@@ -634,21 +731,15 @@ function Placeholder(props) {
|
||||
props.handleStop &&
|
||||
props.handleStop(event, dragElement, props.data?.Id, props.pos?.key)
|
||||
}
|
||||
default={{
|
||||
x: props.xPos(props.pos, props.isSignYourself),
|
||||
y: props.yPos(props.pos, props.isSignYourself)
|
||||
position={{
|
||||
x: xPos(props.pos, props.isSignYourself),
|
||||
y: yPos(props.pos, props.isSignYourself)
|
||||
}}
|
||||
onResize={(e, direction, ref) => {
|
||||
props.handleSignYourselfImageResize &&
|
||||
props.handleSignYourselfImageResize(
|
||||
ref,
|
||||
props.pos.key,
|
||||
props.xyPostion,
|
||||
props.setXyPostion,
|
||||
props.index,
|
||||
props.data && props.data.Id,
|
||||
false
|
||||
);
|
||||
setPlaceholderBorder({
|
||||
w: ref.offsetWidth / (props.scale * containerScale),
|
||||
h: ref.offsetHeight / (props.scale * containerScale)
|
||||
});
|
||||
}}
|
||||
onClick={() => handleOnClickPlaceholder()}
|
||||
>
|
||||
@@ -677,20 +768,23 @@ function Placeholder(props) {
|
||||
pos={props.pos}
|
||||
isPlaceholder={props.isPlaceholder}
|
||||
getCheckboxRenderWidth={getCheckboxRenderWidth}
|
||||
scale={props.scale}
|
||||
containerScale={containerScale}
|
||||
placeholderBorder={placeholderBorder}
|
||||
/>
|
||||
)}
|
||||
{isMobile ? (
|
||||
{isTabAndMobile ? (
|
||||
<div
|
||||
// className="sm:inline-block md:inline-block lg:hidden "
|
||||
className="flex items-stretch"
|
||||
style={{
|
||||
left: props.xPos(props.pos, props.isSignYourself),
|
||||
top: props.yPos(props.pos, props.isSignYourself),
|
||||
left: xPos(props.pos, props.isSignYourself),
|
||||
top: yPos(props.pos, props.isSignYourself),
|
||||
width:
|
||||
props.pos.type === radioButtonWidget ||
|
||||
props.pos.type === "checkbox"
|
||||
? "auto"
|
||||
: props.posWidth(props.pos, props.isSignYourself),
|
||||
// "auto", //props.posWidth(props.pos, props.isSignYourself),
|
||||
// height: props.posHeight(props.pos, props.isSignYourself),
|
||||
height:
|
||||
props.pos.type === radioButtonWidget ||
|
||||
props.pos.type === "checkbox"
|
||||
@@ -699,6 +793,7 @@ function Placeholder(props) {
|
||||
zIndex: "10"
|
||||
}}
|
||||
onTouchEnd={() => handleOnClickPlaceholder()}
|
||||
onClick={() => handleOnClickPlaceholder()}
|
||||
>
|
||||
{props.pos.key === props.selectWidgetId && <PlaceholderIcon />}
|
||||
|
||||
@@ -723,6 +818,7 @@ function Placeholder(props) {
|
||||
setStartDate={setStartDate}
|
||||
startDate={startDate}
|
||||
handleSaveDate={handleSaveDate}
|
||||
xPos={props.xPos}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
@@ -749,6 +845,7 @@ function Placeholder(props) {
|
||||
setStartDate={setStartDate}
|
||||
startDate={startDate}
|
||||
handleSaveDate={handleSaveDate}
|
||||
xPos={props.xPos}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -11,23 +11,34 @@ function PlaceholderBorder(props) {
|
||||
const getResizeBorderExtraWidth = resizeBorderExtraWidth();
|
||||
const defaultWidth = defaultWidthHeight(props.pos.type).width;
|
||||
const defaultHeight = defaultWidthHeight(props.pos.type).height;
|
||||
const width = () => {
|
||||
const getWidth =
|
||||
props.placeholderBorder.w || props.pos.Width || defaultWidth;
|
||||
return (
|
||||
getWidth * props.scale * props.containerScale + getResizeBorderExtraWidth
|
||||
);
|
||||
};
|
||||
const height = () => {
|
||||
const getHeight =
|
||||
props.placeholderBorder.h || props.pos.Height || defaultHeight;
|
||||
|
||||
return (
|
||||
getHeight * props.scale * props.containerScale + getResizeBorderExtraWidth
|
||||
);
|
||||
};
|
||||
|
||||
const handleMinWidth = () => {
|
||||
if (props.pos.type === "checkbox" || props.pos.type === radioButtonWidget) {
|
||||
return props.getCheckboxRenderWidth.width + getResizeBorderExtraWidth;
|
||||
} else {
|
||||
return props.pos.Width
|
||||
? props.pos.Width + getResizeBorderExtraWidth
|
||||
: defaultWidth + getResizeBorderExtraWidth;
|
||||
return width();
|
||||
}
|
||||
};
|
||||
const handleMinHeight = () => {
|
||||
if (props.pos.type === "checkbox" || props.pos.type === radioButtonWidget) {
|
||||
return props.getCheckboxRenderWidth.height + getResizeBorderExtraWidth;
|
||||
} else {
|
||||
return props.pos.Height
|
||||
? props.pos.Height + getResizeBorderExtraWidth
|
||||
: defaultHeight + getResizeBorderExtraWidth;
|
||||
return height();
|
||||
}
|
||||
};
|
||||
return (
|
||||
@@ -36,7 +47,7 @@ function PlaceholderBorder(props) {
|
||||
onTouchEnd={() =>
|
||||
props.pos.type === textWidget && props?.setDraggingEnabled(true)
|
||||
}
|
||||
className="borderResize"
|
||||
className="absolute inline-block w-[14px] h-[14px] hover:cursor-sw-resize"
|
||||
style={{
|
||||
borderColor: themeColor,
|
||||
borderStyle: "dashed",
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import React, { useState } from "react";
|
||||
import { themeColor } from "../../constant/const";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
import { randomId, textWidget } from "../../constant/Utils";
|
||||
|
||||
function PlaceholderCopy(props) {
|
||||
const copyType = ["All pages", "All pages but last", "All pages but first"];
|
||||
const [selectCopyType, setSelectCopyType] = useState("");
|
||||
|
||||
//function for get copy placeholder position
|
||||
const getCopyPlaceholderPosition = (
|
||||
type,
|
||||
@@ -195,13 +193,13 @@ function PlaceholderCopy(props) {
|
||||
props.setIsPageCopy(false);
|
||||
}}
|
||||
>
|
||||
<div style={{ height: "100%", padding: 20 }}>
|
||||
<div className="h-full p-[20px] text-base-content">
|
||||
{copyType.map((data, key) => {
|
||||
return (
|
||||
<div key={key} style={{ display: "flex", flexDirection: "column" }}>
|
||||
<label key={key} style={{ fontSize: "16px", fontWeight: "500" }}>
|
||||
<div key={key} className="flex flex-col">
|
||||
<label className="text-[16px] font-medium">
|
||||
<input
|
||||
style={{ accentColor: "red", marginRight: "10px" }}
|
||||
className="mr-[8px] op-radio op-radio-xs"
|
||||
type="radio"
|
||||
value={data}
|
||||
onChange={() => setSelectCopyType(data)}
|
||||
@@ -214,33 +212,22 @@ function PlaceholderCopy(props) {
|
||||
);
|
||||
})}
|
||||
|
||||
<div
|
||||
style={{
|
||||
height: "1px",
|
||||
backgroundColor: "#9f9f9f",
|
||||
width: "100%",
|
||||
marginTop: "15px",
|
||||
marginBottom: "15px"
|
||||
}}
|
||||
></div>
|
||||
<div className="flex bg-[#9f9f9f] w-full my-[15px]"></div>
|
||||
<button
|
||||
onClick={() => {
|
||||
handleApplyCopy();
|
||||
handleUniqueId();
|
||||
}}
|
||||
style={{ background: themeColor }}
|
||||
type="button"
|
||||
disabled={!selectCopyType}
|
||||
className="finishBtn"
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
Apply
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="finishBtn cancelBtn"
|
||||
onClick={() => {
|
||||
handleUniqueId();
|
||||
}}
|
||||
className="op-btn op-btn-ghost"
|
||||
onClick={() => handleUniqueId()}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useEffect, useState, forwardRef, useRef } from "react";
|
||||
import {
|
||||
getMonth,
|
||||
getYear,
|
||||
isMobile,
|
||||
onChangeHeightOfTextArea,
|
||||
onChangeInput,
|
||||
radioButtonWidget,
|
||||
@@ -14,7 +13,10 @@ import DatePicker from "react-datepicker";
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import "../../styles/signature.css";
|
||||
import RegexParser from "regex-parser";
|
||||
|
||||
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";
|
||||
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";
|
||||
function PlaceholderType(props) {
|
||||
const type = props?.pos?.type;
|
||||
const [selectOption, setSelectOption] = useState("");
|
||||
@@ -137,13 +139,13 @@ function PlaceholderType(props) {
|
||||
|
||||
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
|
||||
<div
|
||||
className="inputPlaceholder"
|
||||
style={{ overflow: "hidden", fontSize: calculateFontSize() }}
|
||||
className={`${selectWidgetCls} overflow-hidden`}
|
||||
style={{ fontSize: calculateFontSize() }}
|
||||
onClick={onClick}
|
||||
ref={ref}
|
||||
>
|
||||
{value}
|
||||
<i className="fa-regular fa-calendar" style={{ marginLeft: "5px" }}></i>
|
||||
<i className="fa-light fa-calendar ml-[5px]"></i>
|
||||
</div>
|
||||
));
|
||||
ExampleCustomInput.displayName = "ExampleCustomInput";
|
||||
@@ -304,17 +306,13 @@ function PlaceholderType(props) {
|
||||
case "signature":
|
||||
return props.pos.SignUrl ? (
|
||||
<img
|
||||
alt="signimg"
|
||||
alt="signature"
|
||||
draggable="false"
|
||||
src={props.pos.SignUrl}
|
||||
style={{
|
||||
width: "99%",
|
||||
height: "100%",
|
||||
objectFit: "contain"
|
||||
}}
|
||||
className="w-full h-full "
|
||||
/>
|
||||
) : (
|
||||
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
|
||||
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
|
||||
{props?.handleUserName &&
|
||||
props?.handleUserName(
|
||||
props?.data?.Id,
|
||||
@@ -326,17 +324,13 @@ function PlaceholderType(props) {
|
||||
case "stamp":
|
||||
return props.pos.SignUrl ? (
|
||||
<img
|
||||
alt="signimg"
|
||||
alt="stamp"
|
||||
draggable="false"
|
||||
src={props.pos.SignUrl}
|
||||
style={{
|
||||
width: "99%",
|
||||
height: "100%",
|
||||
objectFit: "contain"
|
||||
}}
|
||||
className="w-full h-full"
|
||||
/>
|
||||
) : (
|
||||
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
|
||||
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
|
||||
{props?.handleUserName &&
|
||||
props?.handleUserName(
|
||||
props?.data?.Id,
|
||||
@@ -352,12 +346,9 @@ function PlaceholderType(props) {
|
||||
return (
|
||||
<div key={ind} className="flex items-center text-center gap-0.5">
|
||||
<input
|
||||
style={{
|
||||
// width: props.pos.Width,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
marginTop: ind === 0 ? 0 : "5px"
|
||||
}}
|
||||
className={`${
|
||||
ind === 0 ? "mt-0" : "mt-[5px]"
|
||||
} flex justify-center op-checkbox op-checkbox-xs rounded-[0.350rem]`}
|
||||
onBlur={handleInputBlur}
|
||||
disabled={
|
||||
props.isNeedSign &&
|
||||
@@ -420,19 +411,20 @@ function PlaceholderType(props) {
|
||||
false
|
||||
);
|
||||
}}
|
||||
className={
|
||||
isMobile
|
||||
? "labelTextArea labelWidthMobile"
|
||||
: "labelTextArea labelWidthDesktop"
|
||||
}
|
||||
style={{ whiteSpace: "pre-wrap" }}
|
||||
className={textWidgetCls}
|
||||
style={{
|
||||
fontSize: props.pos.options?.fontSize
|
||||
? props.pos.options?.fontSize + "px"
|
||||
: "12px",
|
||||
color: props.pos.options?.fontColor || "black"
|
||||
}}
|
||||
cols="50"
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
color: "black",
|
||||
fontSize: calculateFontSize()
|
||||
fontSize: "12px"
|
||||
}}
|
||||
>
|
||||
<span>{type}</span>
|
||||
@@ -441,9 +433,8 @@ function PlaceholderType(props) {
|
||||
case "dropdown":
|
||||
return props.data?.signerObjId === props.signerObjId ? (
|
||||
<select
|
||||
className="inputPlaceholder"
|
||||
className={`${selectWidgetCls} text-[12px]`}
|
||||
id="myDropdown"
|
||||
style={{ fontSize: "12px" }}
|
||||
value={selectOption}
|
||||
onChange={(e) => {
|
||||
setSelectOption(e.target.value);
|
||||
@@ -463,7 +454,7 @@ function PlaceholderType(props) {
|
||||
{props?.pos?.options?.name}
|
||||
</option>
|
||||
|
||||
{props.pos?.options?.values.map((data, ind) => {
|
||||
{props.pos?.options?.values?.map((data, ind) => {
|
||||
return (
|
||||
<option key={ind} value={data}>
|
||||
{data}
|
||||
@@ -473,7 +464,7 @@ function PlaceholderType(props) {
|
||||
</select>
|
||||
) : (
|
||||
<div
|
||||
className="inputPlaceholder"
|
||||
className={selectWidgetCls}
|
||||
style={{ fontSize: calculateFontSize() }}
|
||||
>
|
||||
{props.pos?.options?.name ? props.pos.options.name : type}
|
||||
@@ -482,17 +473,13 @@ function PlaceholderType(props) {
|
||||
case "initials":
|
||||
return props.pos.SignUrl ? (
|
||||
<img
|
||||
alt="signimg"
|
||||
alt="initials"
|
||||
draggable="false"
|
||||
src={props.pos.SignUrl}
|
||||
style={{
|
||||
width: "99%",
|
||||
height: "100%",
|
||||
objectFit: "contain"
|
||||
}}
|
||||
className="w-full h-full"
|
||||
/>
|
||||
) : (
|
||||
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
|
||||
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
|
||||
{props?.handleUserName &&
|
||||
props?.handleUserName(
|
||||
props?.data?.Id,
|
||||
@@ -523,19 +510,20 @@ function PlaceholderType(props) {
|
||||
isDefault
|
||||
);
|
||||
}}
|
||||
className={
|
||||
isMobile
|
||||
? "labelTextArea labelWidthMobile"
|
||||
: "labelTextArea labelWidthDesktop"
|
||||
}
|
||||
style={{ whiteSpace: "pre-wrap" }}
|
||||
className={textWidgetCls}
|
||||
style={{
|
||||
fontSize: props.pos.options?.fontSize
|
||||
? props.pos.options?.fontSize + "px"
|
||||
: "12px",
|
||||
color: props.pos.options?.fontColor || "black"
|
||||
}}
|
||||
cols="50"
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
color: "black",
|
||||
fontSize: calculateFontSize()
|
||||
fontSize: "12px"
|
||||
}}
|
||||
>
|
||||
<span>{type}</span>
|
||||
@@ -562,19 +550,20 @@ function PlaceholderType(props) {
|
||||
false
|
||||
);
|
||||
}}
|
||||
className={
|
||||
isMobile
|
||||
? "labelTextArea labelWidthMobile"
|
||||
: "labelTextArea labelWidthDesktop"
|
||||
}
|
||||
style={{ whiteSpace: "pre-wrap" }}
|
||||
className={textWidgetCls}
|
||||
style={{
|
||||
fontSize: props.pos.options?.fontSize
|
||||
? props.pos.options?.fontSize + "px"
|
||||
: "12px",
|
||||
color: props.pos.options?.fontColor || "black"
|
||||
}}
|
||||
cols="50"
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
color: "black",
|
||||
fontSize: calculateFontSize()
|
||||
fontSize: "12px"
|
||||
}}
|
||||
>
|
||||
<span>{type}</span>
|
||||
@@ -601,19 +590,20 @@ function PlaceholderType(props) {
|
||||
false
|
||||
);
|
||||
}}
|
||||
className={
|
||||
isMobile
|
||||
? "labelTextArea labelWidthMobile"
|
||||
: "labelTextArea labelWidthDesktop"
|
||||
}
|
||||
style={{ whiteSpace: "pre-wrap" }}
|
||||
className={textWidgetCls}
|
||||
style={{
|
||||
fontSize: props.pos.options?.fontSize
|
||||
? props.pos.options?.fontSize + "px"
|
||||
: "12px",
|
||||
color: props.pos.options?.fontColor || "black"
|
||||
}}
|
||||
cols="50"
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
color: "black",
|
||||
fontSize: calculateFontSize()
|
||||
fontSize: "12px"
|
||||
}}
|
||||
>
|
||||
<span>{type}</span>
|
||||
@@ -658,8 +648,7 @@ function PlaceholderType(props) {
|
||||
}
|
||||
onBlur={handleInputBlur}
|
||||
closeOnScroll={true}
|
||||
className="inputPlaceholder"
|
||||
style={{ outlineColor: "#007bff" }}
|
||||
className={`${selectWidgetCls} outline-[#007bff]`}
|
||||
selected={
|
||||
props?.startDate
|
||||
? props?.startDate
|
||||
@@ -682,17 +671,13 @@ function PlaceholderType(props) {
|
||||
case "image":
|
||||
return props.pos.SignUrl ? (
|
||||
<img
|
||||
alt="signimg"
|
||||
alt="image"
|
||||
draggable="false"
|
||||
src={props.pos.SignUrl}
|
||||
style={{
|
||||
width: "99%",
|
||||
height: "100%",
|
||||
objectFit: "contain"
|
||||
}}
|
||||
className="w-full h-full"
|
||||
/>
|
||||
) : (
|
||||
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
|
||||
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
|
||||
{props?.handleUserName &&
|
||||
props?.handleUserName(
|
||||
props?.data?.Id,
|
||||
@@ -723,19 +708,20 @@ function PlaceholderType(props) {
|
||||
false
|
||||
);
|
||||
}}
|
||||
className={
|
||||
isMobile
|
||||
? "labelTextArea labelWidthMobile"
|
||||
: "labelTextArea labelWidthDesktop"
|
||||
}
|
||||
style={{ whiteSpace: "pre-wrap" }}
|
||||
className={textWidgetCls}
|
||||
style={{
|
||||
fontSize: props.pos.options?.fontSize
|
||||
? props.pos.options?.fontSize + "px"
|
||||
: "12px",
|
||||
color: props.pos.options?.fontColor || "black"
|
||||
}}
|
||||
cols="50"
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
color: "black",
|
||||
fontSize: calculateFontSize()
|
||||
fontSize: "12px"
|
||||
}}
|
||||
>
|
||||
<span>{type}</span>
|
||||
@@ -748,12 +734,9 @@ function PlaceholderType(props) {
|
||||
return (
|
||||
<div key={ind} className="flex items-center text-center gap-0.5">
|
||||
<input
|
||||
style={{
|
||||
width: props.pos.Width,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
marginTop: ind === 0 ? 0 : "5px"
|
||||
}}
|
||||
className={`${
|
||||
ind === 0 ? "mt-0" : "mt-[5px]"
|
||||
} ${"w-[15px] h-[15px]"} flex justify-center op-radio`}
|
||||
type="radio"
|
||||
disabled={
|
||||
props.isNeedSign &&
|
||||
@@ -795,37 +778,28 @@ function PlaceholderType(props) {
|
||||
false
|
||||
);
|
||||
}}
|
||||
className={
|
||||
isMobile
|
||||
? "labelTextArea labelWidthMobile"
|
||||
: "labelTextArea labelWidthDesktop"
|
||||
}
|
||||
style={{ whiteSpace: "pre-wrap", overflow: "hidden" }}
|
||||
className={textWidgetCls}
|
||||
style={{
|
||||
fontSize: props.pos.options?.fontSize
|
||||
? props.pos.options?.fontSize + "px"
|
||||
: "12px",
|
||||
color: props.pos.options?.fontColor || "black"
|
||||
}}
|
||||
cols="50"
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return props.pos.SignUrl ? (
|
||||
<div style={{ pointerEvents: "none" }}>
|
||||
<div className="pointer-events-none">
|
||||
<img
|
||||
alt="signimg"
|
||||
alt="image"
|
||||
draggable="false"
|
||||
src={props.pos.SignUrl}
|
||||
style={{
|
||||
width: "99%",
|
||||
height: "100%",
|
||||
objectFit: "contain"
|
||||
}}
|
||||
className="w-full h-full"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
fontSize: "10px",
|
||||
color: "black",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
|
||||
{props.pos.isStamp ? <div>stamp</div> : <div>signature</div>}
|
||||
{props?.handleUserName &&
|
||||
props?.handleUserName(props?.data?.Id, props?.data?.Role)}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import { themeColor } from "../../constant/const";
|
||||
|
||||
function PrevNext({ pageNumber, allPages, changePage }) {
|
||||
//for go to previous page
|
||||
@@ -12,40 +11,30 @@ function PrevNext({ pageNumber, allPages, changePage }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="preBtn1">
|
||||
<button
|
||||
className="py-[3px] px-[10px] text-xs bg-[#d3edeb] font-[600] mr-[5px]"
|
||||
disabled={pageNumber <= 1}
|
||||
onClick={previousPage}
|
||||
>
|
||||
<span className="block lg:hidden">
|
||||
<i
|
||||
className="fa fa-backward"
|
||||
aria-hidden="true"
|
||||
style={{ color: themeColor, cursor: "pointer" }}
|
||||
></i>
|
||||
</span>
|
||||
<span className="lg:block hidden">Prev</span>
|
||||
</button>
|
||||
<span className="text-xs font-[500]">
|
||||
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
|
||||
<div className="flex items-center">
|
||||
<button
|
||||
className="op-btn op-btn-neutral op-btn-xs md:op-btn-sm font-semibold text-xs"
|
||||
disabled={pageNumber <= 1}
|
||||
onClick={previousPage}
|
||||
>
|
||||
<span className="block lg:hidden">
|
||||
<i className="fa-light fa-backward" aria-hidden="true"></i>
|
||||
</span>
|
||||
<button
|
||||
className="py-[3px] px-[10px] text-xs bg-[#d3edeb] font-[600] ml-[5px]"
|
||||
disabled={pageNumber >= allPages}
|
||||
onClick={nextPage}
|
||||
>
|
||||
<span className="block lg:hidden">
|
||||
<i
|
||||
className="fa fa-forward"
|
||||
aria-hidden="true"
|
||||
style={{ color: themeColor, cursor: "pointer" }}
|
||||
></i>
|
||||
</span>
|
||||
<span className="lg:block hidden">Next</span>
|
||||
</button>
|
||||
</div>
|
||||
<span className="lg:block hidden 2xl:text-[30px]">Prev</span>
|
||||
</button>
|
||||
<span className="text-xs text-base-content font-medium mx-2 2xl:text-[30px]">
|
||||
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
|
||||
</span>
|
||||
<button
|
||||
className="op-btn op-btn-neutral op-btn-xs md:op-btn-sm font-semibold text-xs"
|
||||
disabled={pageNumber >= allPages}
|
||||
onClick={nextPage}
|
||||
>
|
||||
<span className="block lg:hidden">
|
||||
<i className="fa-light fa-forward" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span className="lg:block hidden 2xl:text-[30px]">Next</span>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,37 +7,14 @@ import {
|
||||
isMobile,
|
||||
nameColor
|
||||
} from "../../constant/Utils";
|
||||
|
||||
const cursor =
|
||||
"cursor-[url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAASElEQVR4nGNgwAMkJSUbpKSkOvCpIaT5PxSTbogUQjMYMwxeIIXmVFIxA8UGDDyQGg0DnIDi6JKUlCxHMqCeZAOghjSAMD5FAKfeaURdUFxCAAAAAElFTkSuQmCC'),_pointer]";
|
||||
const RecipientList = (props) => {
|
||||
const [animationParent] = useAutoAnimate();
|
||||
const [isHover, setIsHover] = useState();
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
//function for onhover signer name change background color
|
||||
const inputRef = useRef(null);
|
||||
const onHoverStyle = (ind, blockColor) => {
|
||||
const style = {
|
||||
background: blockColor ? blockColor : color[ind % color.length],
|
||||
padding: "10px",
|
||||
marginTop: "2px",
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
borderBottom: "1px solid #e3e1e1",
|
||||
alignItems: "center"
|
||||
};
|
||||
return style;
|
||||
};
|
||||
//function for onhover signer name remove background color
|
||||
const nonHoverStyle = () => {
|
||||
const style = {
|
||||
padding: "10px",
|
||||
marginTop: "2px",
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
borderBottom: "1px solid #e3e1e1",
|
||||
alignItems: "center"
|
||||
};
|
||||
return style;
|
||||
};
|
||||
const isWidgetExist = (Id) => {
|
||||
return props.signerPos.some((x) => x.Id === Id);
|
||||
};
|
||||
@@ -94,7 +71,6 @@ const RecipientList = (props) => {
|
||||
props.setRoleName(remainingItems[index]?.Role);
|
||||
props.setBlockColor(remainingItems[index]?.blockColor);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{props.signersdata.length > 0 &&
|
||||
@@ -113,21 +89,24 @@ const RecipientList = (props) => {
|
||||
onDrop={(e) =>
|
||||
props.sendInOrder && !isMobile && handleChangeSequence(e, ind)
|
||||
}
|
||||
data-tut="reactourFirst"
|
||||
data-tut="recipientArea"
|
||||
onMouseEnter={() => setIsHover(ind)}
|
||||
onMouseLeave={() => setIsHover(null)}
|
||||
className={
|
||||
className={`${
|
||||
props.sendInOrder
|
||||
? props.isMailSend
|
||||
? "disabled"
|
||||
: "dragCursor"
|
||||
: props.isMailSend && "disabled"
|
||||
}
|
||||
style={
|
||||
(!isMobile && isHover === ind) || props.isSelectListId === ind
|
||||
? onHoverStyle(ind, obj?.blockColor)
|
||||
: nonHoverStyle(ind)
|
||||
}
|
||||
? "pointer-events-none bg-opacity-80"
|
||||
: `text-[12px] font-bold ${cursor}`
|
||||
: props.isMailSend && "pointer-events-none bg-opacity-80"
|
||||
} 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
|
||||
? obj?.blockColor
|
||||
? obj?.blockColor
|
||||
: color[ind % color.length]
|
||||
: "transparent"
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
props.setSignerObjId(obj?.objectId || "");
|
||||
@@ -141,40 +120,18 @@ const RecipientList = (props) => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row items-center w-full">
|
||||
<div
|
||||
className="flex w-[30px] h-[30px] rounded-full items-center justify-center mr-2"
|
||||
style={{
|
||||
background: obj?.blockColor
|
||||
? darkenColor(obj?.blockColor, 0.4)
|
||||
: nameColor[ind % nameColor.length],
|
||||
width: 30,
|
||||
height: 30,
|
||||
display: "flex",
|
||||
borderRadius: 30 / 2,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginRight: "12px"
|
||||
: nameColor[ind % nameColor.length]
|
||||
}}
|
||||
>
|
||||
<span
|
||||
className={props.sendInOrder && "dragCursor"}
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
textAlign: "center",
|
||||
fontWeight: "bold",
|
||||
color: "white",
|
||||
textTransform: "uppercase"
|
||||
}}
|
||||
>
|
||||
<span className="text-white uppercase font-bold text-center text-[12px]">
|
||||
{isWidgetExist(obj.Id) ? (
|
||||
<i className="fa-solid fa-check"></i>
|
||||
<i className="fa-light fa-check"></i>
|
||||
) : (
|
||||
<>
|
||||
{obj.Name
|
||||
@@ -185,67 +142,74 @@ const RecipientList = (props) => {
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: obj.Name ? "column" : "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
className={`${
|
||||
obj.Name ? "flex-col" : "flex-row"
|
||||
} flex items-center`}
|
||||
>
|
||||
{obj.Name ? (
|
||||
<span className={"userName"}>{obj.Name}</span>
|
||||
<span
|
||||
className={`${
|
||||
(!isMobile && isHover === ind) ||
|
||||
props.isSelectListId === ind
|
||||
? "text-[#424242]"
|
||||
: "text-base-content"
|
||||
} text-[12px] font-bold w-[100px] whitespace-nowrap overflow-hidden text-ellipsis`}
|
||||
>
|
||||
{obj.Name}
|
||||
</span>
|
||||
) : (
|
||||
<>
|
||||
<span
|
||||
className="userName"
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => {
|
||||
setIsEdit({ [obj.Id]: true });
|
||||
props.setRoleName(obj.Role);
|
||||
}}
|
||||
>
|
||||
{isEdit?.[obj.Id] && props.handleRoleChange ? (
|
||||
<input
|
||||
ref={inputRef}
|
||||
style={{
|
||||
backgroundColor: "transparent",
|
||||
width: "inherit",
|
||||
padding: "3px"
|
||||
}}
|
||||
value={obj.Role}
|
||||
onChange={(e) => props.handleRoleChange(e, obj.Id)}
|
||||
onBlur={() => {
|
||||
setIsEdit({});
|
||||
props.handleOnBlur(obj.Role, obj.Id);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
inputRef.current.blur();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span style={{ padding: "3px" }}>{obj.Role}</span>
|
||||
)}
|
||||
</span>
|
||||
</>
|
||||
<span
|
||||
className={`${
|
||||
(!isMobile && isHover === ind) ||
|
||||
props.isSelectListId === ind
|
||||
? "text-[#424242]"
|
||||
: "text-base-content"
|
||||
} text-[12px] font-bold w-[100px] whitespace-nowrap overflow-hidden text-ellipsis cursor-pointer`}
|
||||
onClick={() => {
|
||||
setIsEdit({ [obj.Id]: true });
|
||||
props.setRoleName(obj.Role);
|
||||
}}
|
||||
>
|
||||
{isEdit?.[obj.Id] && props.handleRoleChange ? (
|
||||
<input
|
||||
ref={inputRef}
|
||||
className="bg-transparent p-[3px]"
|
||||
value={obj.Role}
|
||||
onChange={(e) => props.handleRoleChange(e, obj.Id)}
|
||||
onBlur={() => {
|
||||
setIsEdit({});
|
||||
props.handleOnBlur(obj.Role, obj.Id);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
inputRef.current.blur();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span className="text-[13px] 2xl:text-[25px]">
|
||||
{obj.Role}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
{obj.Name && (
|
||||
<span className={"useEmail"}>
|
||||
<span
|
||||
className={` ${
|
||||
(!isMobile && isHover === ind) ||
|
||||
props.isSelectListId === ind
|
||||
? "text-[#424242]"
|
||||
: "text-base-content"
|
||||
} text-[10px] font-medium w-[100px] whitespace-nowrap overflow-hidden text-ellipsis`}
|
||||
>
|
||||
{obj?.Role || obj?.Email}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{isMobile && props.sendInOrder && (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 5
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row items-center gap-[5px] mr-2">
|
||||
<div
|
||||
onClick={(e) => {
|
||||
if (ind !== 0) {
|
||||
@@ -253,7 +217,7 @@ const RecipientList = (props) => {
|
||||
handleChangeSequence(e, ind, "up");
|
||||
}
|
||||
}}
|
||||
style={{ color: ind === 0 ? "gray" : "black" }}
|
||||
className={ind === 0 ? "text-[gray]" : "text-black"}
|
||||
>
|
||||
▲
|
||||
</div>
|
||||
@@ -264,10 +228,11 @@ const RecipientList = (props) => {
|
||||
handleChangeSequence(e, ind, null, "down");
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
color:
|
||||
ind === props.signersdata.length - 1 ? "gray" : "black"
|
||||
}}
|
||||
className={
|
||||
ind === props.signersdata.length - 1
|
||||
? "text-[gray]"
|
||||
: "text-black"
|
||||
}
|
||||
>
|
||||
▼
|
||||
</div>
|
||||
@@ -279,9 +244,14 @@ const RecipientList = (props) => {
|
||||
e.stopPropagation();
|
||||
props.handleDeleteUser(obj.Id);
|
||||
}}
|
||||
style={{ cursor: "pointer", marginLeft: "5px" }}
|
||||
className={`${
|
||||
(!isMobile && isHover === ind) ||
|
||||
props.isSelectListId === ind
|
||||
? "text-[#424242]"
|
||||
: "text-base-content"
|
||||
} cursor-pointer`}
|
||||
>
|
||||
<i className="fa-regular fa-trash-can"></i>
|
||||
<i className="fa-light fa-trash-can 2xl:text-[30px]"></i>
|
||||
</div>
|
||||
)}
|
||||
<hr />
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import RSC from "react-scrollbars-custom";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Document, Page } from "react-pdf";
|
||||
import { themeColor } from "../../constant/const";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
function RenderAllPdfPage({
|
||||
signPdfUrl,
|
||||
@@ -34,115 +33,79 @@ function RenderAllPdfPage({
|
||||
}
|
||||
}
|
||||
}
|
||||
const pageContainer = useRef();
|
||||
const isHeader = useSelector((state) => state.showHeader);
|
||||
const [pageWidth, setPageWidth] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const updateSize = () => {
|
||||
if (pageContainer.current) {
|
||||
setPageWidth(pageContainer.current.offsetWidth);
|
||||
}
|
||||
};
|
||||
|
||||
// Use setTimeout to wait for the transition to complete
|
||||
const timer = setTimeout(updateSize, 100); // match the transition duration
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [isHeader, pageContainer]);
|
||||
//'function `addSignatureBookmark` is used to display the page where the user's signature is located.
|
||||
const addSignatureBookmark = (index) => {
|
||||
const ispageNumber = signPageNumber.includes(index + 1);
|
||||
return (
|
||||
ispageNumber && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
zIndex: 2,
|
||||
top: -12,
|
||||
right: -7,
|
||||
transform: "translate(50% -50%)"
|
||||
}}
|
||||
>
|
||||
<div className="absolute z-20 top-[1px] -right-[13px] -translate-x-1/2 -translate-y-1/2">
|
||||
<i
|
||||
style={{ color: bookmarkColor || "red" }}
|
||||
className="fa-solid fa-bookmark"
|
||||
className="fa-light fa-bookmark"
|
||||
></i>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
};
|
||||
return (
|
||||
<div className="showPages">
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
|
||||
backgroundColor: "white",
|
||||
height: "100%"
|
||||
}}
|
||||
>
|
||||
<div style={{ width: "140px" }}>
|
||||
<div
|
||||
style={{
|
||||
background: themeColor
|
||||
// color:"white"
|
||||
}}
|
||||
className="signedStyle"
|
||||
>
|
||||
Pages
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<RSC
|
||||
id="RSC-Example"
|
||||
style={{
|
||||
width: "135px",
|
||||
height: window.innerHeight - 130 + "px"
|
||||
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">
|
||||
Pages
|
||||
</div>
|
||||
<div
|
||||
className={`flex h-[90%] flex-col items-center m-2
|
||||
autoSignScroll hide-scrollbar max-h-[100vh] `}
|
||||
>
|
||||
<Document
|
||||
loading={"Loading Document.."}
|
||||
onLoadSuccess={onDocumentLoad}
|
||||
file={signPdfUrl}
|
||||
>
|
||||
{Array.from(new Array(allPages), (el, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`${
|
||||
pageNumber - 1 === index ? "border-[red]" : "border-[#878787]"
|
||||
} border-2 m-[10px] flex justify-center items-center relative`}
|
||||
onClick={() => {
|
||||
setPageNumber(index + 1);
|
||||
if (setSignBtnPosition) {
|
||||
setSignBtnPosition([]);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Document
|
||||
loading={"Loading Document.."}
|
||||
onLoadSuccess={onDocumentLoad}
|
||||
file={signPdfUrl}
|
||||
>
|
||||
{Array.from(new Array(allPages), (el, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
width: "100px",
|
||||
border:
|
||||
pageNumber - 1 === index
|
||||
? "2px solid red"
|
||||
: "2px solid #878787",
|
||||
// padding: "5px",
|
||||
margin: "10px",
|
||||
{signerPos && addSignatureBookmark(index)}
|
||||
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
|
||||
position: "relative"
|
||||
}}
|
||||
onClick={() => {
|
||||
setPageNumber(index + 1);
|
||||
if (setSignBtnPosition) {
|
||||
setSignBtnPosition([]);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{signerPos && addSignatureBookmark(index)}
|
||||
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
zIndex: 1,
|
||||
overflow: "hidden"
|
||||
}}
|
||||
>
|
||||
<Page
|
||||
key={`page_${index + 1}`}
|
||||
pageNumber={index + 1}
|
||||
width={100}
|
||||
height={100}
|
||||
scale={1}
|
||||
renderAnnotationLayer={false}
|
||||
renderTextLayer={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</Document>
|
||||
</RSC>
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
<div className="relative z-[1] overflow-hidden">
|
||||
<Page
|
||||
key={`page_${index + 1}`}
|
||||
pageNumber={index + 1}
|
||||
width={pageWidth - 60}
|
||||
scale={1}
|
||||
renderAnnotationLayer={false}
|
||||
renderTextLayer={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</Document>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -11,8 +11,6 @@ import Alert from "../../primitives/Alert";
|
||||
|
||||
function RenderPdf({
|
||||
pageNumber,
|
||||
pdfOriginalWidth,
|
||||
pdfNewWidth,
|
||||
drop,
|
||||
signerPos,
|
||||
successEmail,
|
||||
@@ -26,15 +24,13 @@ function RenderPdf({
|
||||
pdfDetails,
|
||||
xyPostion,
|
||||
pdfUrl,
|
||||
numPages,
|
||||
pageDetails,
|
||||
pdfRequest,
|
||||
setCurrentSigner,
|
||||
signerObjectId,
|
||||
signedSigners,
|
||||
setPdfLoadFail,
|
||||
pdfLoad,
|
||||
setPdfLoad,
|
||||
placeholder,
|
||||
pdfLoadFail,
|
||||
setSignerPos,
|
||||
setXyPostion,
|
||||
index,
|
||||
@@ -57,183 +53,105 @@ function RenderPdf({
|
||||
unSignedWidgetId,
|
||||
setIsCheckbox,
|
||||
handleNameModal,
|
||||
handleTextSettingModal,
|
||||
setTempSignerId,
|
||||
uniqueId
|
||||
uniqueId,
|
||||
pdfOriginalWH,
|
||||
scale
|
||||
}) {
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const newWidth = containerWH.width;
|
||||
const scale = isMobile ? pdfOriginalWidth / newWidth : 1;
|
||||
//check isGuestSigner is present in local if yes than handle login flow header in mobile view
|
||||
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
||||
|
||||
// handle signature block width and height according to screen
|
||||
const posWidth = (pos, signYourself) => {
|
||||
const getPdfPageWidth = pdfOriginalWH.find(
|
||||
(data) => data.pageNumber === pageNumber
|
||||
);
|
||||
const containerScale = containerWH.width / getPdfPageWidth.width || 1;
|
||||
const defaultWidth = defaultWidthHeight(pos.type).width;
|
||||
const posWidth = pos.Width ? pos.Width : defaultWidth;
|
||||
let width;
|
||||
if (signYourself) {
|
||||
width = posWidth;
|
||||
return width;
|
||||
return posWidth * scale * containerScale;
|
||||
} else {
|
||||
if (isMobile) {
|
||||
if (!pos.isMobile) {
|
||||
if (pos.IsResize) {
|
||||
width = posWidth ? posWidth : defaultWidth;
|
||||
return width;
|
||||
if (pos.isMobile && pos.scale) {
|
||||
if (pos.IsResize) {
|
||||
if (scale > 1) {
|
||||
return posWidth * pos.scale * containerScale * scale;
|
||||
} else {
|
||||
width = (posWidth || defaultWidth) / scale;
|
||||
|
||||
return width;
|
||||
return posWidth * containerScale;
|
||||
}
|
||||
} else {
|
||||
width = posWidth;
|
||||
return width;
|
||||
if (scale > 1) {
|
||||
return posWidth * pos.scale * containerScale * scale;
|
||||
} else {
|
||||
return posWidth * pos.scale * containerScale;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (pos.isMobile) {
|
||||
if (pos.IsResize) {
|
||||
width = posWidth ? posWidth : defaultWidth;
|
||||
return width;
|
||||
} else {
|
||||
width = (posWidth || defaultWidth) * pos.scale;
|
||||
return width;
|
||||
}
|
||||
} else {
|
||||
width = posWidth ? posWidth : defaultWidth;
|
||||
return width;
|
||||
}
|
||||
return posWidth * scale * containerScale;
|
||||
}
|
||||
}
|
||||
};
|
||||
const posHeight = (pos, signYourself) => {
|
||||
let height;
|
||||
const posHeight = pos.Height;
|
||||
const defaultHeight = defaultWidthHeight(pos.type).height;
|
||||
|
||||
if (signYourself) {
|
||||
height = posHeight ? posHeight : defaultHeight;
|
||||
|
||||
return height;
|
||||
} else {
|
||||
if (isMobile) {
|
||||
if (!pos.isMobile) {
|
||||
if (pos.IsResize) {
|
||||
height = posHeight ? posHeight : defaultHeight;
|
||||
return height;
|
||||
} else {
|
||||
height = (posHeight || defaultHeight) / scale;
|
||||
|
||||
return height;
|
||||
}
|
||||
} else {
|
||||
height = posHeight ? posHeight : defaultHeight;
|
||||
return height;
|
||||
}
|
||||
} else {
|
||||
if (pos.isMobile) {
|
||||
if (pos.IsResize) {
|
||||
height = posHeight ? posHeight : defaultHeight;
|
||||
return height;
|
||||
} else {
|
||||
height = (posHeight || defaultHeight) * pos.scale;
|
||||
return height;
|
||||
}
|
||||
} else {
|
||||
height = posHeight ? posHeight : defaultHeight;
|
||||
return height;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const xPos = (pos, signYourself) => {
|
||||
const resizePos = pos.xPosition;
|
||||
if (signYourself) {
|
||||
return resizePos;
|
||||
} else {
|
||||
//checking both condition mobile and desktop view
|
||||
if (isMobile) {
|
||||
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
|
||||
if (!pos.isMobile) {
|
||||
return resizePos / scale;
|
||||
}
|
||||
//pos.isMobile true -- placeholder save from mobile view(small device) handle position in mobile view(small screen) view divided by scale
|
||||
else {
|
||||
return resizePos * (pos.scale / scale);
|
||||
}
|
||||
} else {
|
||||
//else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale
|
||||
|
||||
if (pos.isMobile) {
|
||||
return pos.scale && resizePos * pos.scale;
|
||||
}
|
||||
//else placeholder save from desktop(bigscreen) and show in desktop(bigscreen)
|
||||
else {
|
||||
return resizePos;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const yPos = (pos, signYourself) => {
|
||||
const resizePos = pos.yPosition;
|
||||
if (signYourself) {
|
||||
return resizePos;
|
||||
} else {
|
||||
//checking both condition mobile and desktop view
|
||||
if (isMobile) {
|
||||
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
|
||||
if (!pos.isMobile) {
|
||||
return resizePos / scale;
|
||||
}
|
||||
//pos.isMobile true -- placeholder save from mobile view(small device) handle position in mobile view(small screen) view divided by scale
|
||||
else {
|
||||
return resizePos * (pos.scale / scale);
|
||||
}
|
||||
} else {
|
||||
//else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale
|
||||
|
||||
if (pos.isMobile) {
|
||||
return pos.scale && resizePos * pos.scale;
|
||||
}
|
||||
//else placeholder save from desktop(bigscreen) and show in desktop(bigscreen)
|
||||
else {
|
||||
return resizePos;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
//function for render placeholder block over pdf document
|
||||
const checkSignedSignes = (data) => {
|
||||
const checkSign = signedSigners.filter(
|
||||
(sign) => sign.objectId === data.signerObjId
|
||||
const getPdfPageWidth = pdfOriginalWH.find(
|
||||
(data) => data.pageNumber === pageNumber
|
||||
);
|
||||
if (data.signerObjId === signerObjectId) {
|
||||
setCurrentSigner(true);
|
||||
}
|
||||
const handleAllUserName = (Id, Role, type) => {
|
||||
return pdfDetails[0].Signers.map((signerData, key) => {
|
||||
return (
|
||||
signerData.objectId === data.signerObjId && (
|
||||
<React.Fragment key={key}>
|
||||
{signerData?.Name && (
|
||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
||||
{signerData.Name}
|
||||
</div>
|
||||
)}
|
||||
{type && (
|
||||
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
||||
)}
|
||||
{Role && (
|
||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
||||
{`(${Role})`}
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
)
|
||||
);
|
||||
});
|
||||
};
|
||||
const containerScale = containerWH.width / getPdfPageWidth?.width || 1;
|
||||
|
||||
const posHeight = pos.Height || defaultWidthHeight(pos.type).height;
|
||||
if (signYourself) {
|
||||
return posHeight * scale * containerScale;
|
||||
} else {
|
||||
if (pos.isMobile && pos.scale) {
|
||||
if (pos.IsResize) {
|
||||
if (scale > 1) {
|
||||
return posHeight * pos.scale * containerScale * scale;
|
||||
} else {
|
||||
return posHeight * containerScale;
|
||||
}
|
||||
} else {
|
||||
if (scale > 1) {
|
||||
return posHeight * pos.scale * containerScale * scale;
|
||||
} else {
|
||||
return posHeight * pos.scale * containerScale;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return posHeight * scale * containerScale;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//function for render placeholder block over pdf document
|
||||
const checkSignedSigners = (data) => {
|
||||
let checkSign = [];
|
||||
//condition to handle quick send flow and using normal request sign flow
|
||||
checkSign = signedSigners
|
||||
? signedSigners?.filter(
|
||||
(sign) =>
|
||||
sign?.Id === data?.Id || sign?.objectId === data?.signerObjId
|
||||
)
|
||||
: [];
|
||||
const handleAllUserName = (Id, Role, type) => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="text-black text-[8px] font-bold">
|
||||
{
|
||||
pdfDetails[0].Signers?.find(
|
||||
(signer) => signer.objectId === data.signerObjId
|
||||
)?.Name
|
||||
}
|
||||
</div>
|
||||
{type && <div className="text-[11px] font-bold">{type}</div>}
|
||||
{Role && (
|
||||
<div className="text-black text-[8px] font-medium">
|
||||
{`(${Role})`}
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
return (
|
||||
checkSign.length === 0 &&
|
||||
data.placeHolder.map((placeData, key) => {
|
||||
@@ -260,8 +178,6 @@ function RenderPdf({
|
||||
isShowDropdown={true}
|
||||
isNeedSign={true}
|
||||
isSignYourself={false}
|
||||
xPos={xPos}
|
||||
yPos={yPos}
|
||||
posWidth={posWidth}
|
||||
posHeight={posHeight}
|
||||
handleUserName={handleAllUserName}
|
||||
@@ -273,6 +189,11 @@ function RenderPdf({
|
||||
setSelectWidgetId={setSelectWidgetId}
|
||||
selectWidgetId={selectWidgetId}
|
||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||
uniqueId={uniqueId}
|
||||
scale={scale}
|
||||
containerWH={containerWH}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pageNumber={pageNumber}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)
|
||||
@@ -283,6 +204,7 @@ function RenderPdf({
|
||||
})
|
||||
);
|
||||
};
|
||||
//function for render placeholder block over pdf document
|
||||
|
||||
const handleUserName = (Id, Role, type) => {
|
||||
if (Id) {
|
||||
@@ -290,14 +212,12 @@ function RenderPdf({
|
||||
if (checkSign?.Name) {
|
||||
return (
|
||||
<>
|
||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
||||
<div className="text-black text-[8px] font-medium">
|
||||
{checkSign?.Name}
|
||||
</div>
|
||||
{type && (
|
||||
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
||||
)}
|
||||
{type && <div className="text-[11px] font-bold">{type}</div>}
|
||||
{Role && (
|
||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
||||
<div className="text-black text-[8px] font-medium">
|
||||
{`(${Role})`}
|
||||
</div>
|
||||
)}
|
||||
@@ -306,47 +226,39 @@ function RenderPdf({
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
{type && (
|
||||
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
||||
)}
|
||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
||||
{Role}
|
||||
</div>
|
||||
{type && <div className="text-[11px] font-bold">{type}</div>}
|
||||
<div className="text-black text-[8px] font-medium">{Role}</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
{type && (
|
||||
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
||||
)}
|
||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
||||
{Role}
|
||||
</div>
|
||||
{type && <div className="text-[11px] font-bold">{type}</div>}
|
||||
<div className="text-black text-[8px] font-medium">{Role}</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{successEmail && <Alert type={"success"}>Email sent successfully!</Alert>}
|
||||
{isMobile && scale ? (
|
||||
{isMobile ? (
|
||||
<div
|
||||
style={{
|
||||
border: "0.1px solid #ebe8e8",
|
||||
marginTop: isGuestSigner && "30px"
|
||||
}}
|
||||
data-tut="reactourForth"
|
||||
className={`${
|
||||
isGuestSigner ? "30px" : ""
|
||||
} border-[0.1px] border-[#ebe8e8]`}
|
||||
ref={drop}
|
||||
id="container"
|
||||
>
|
||||
{pdfLoadFail.status &&
|
||||
{containerWH?.width &&
|
||||
pdfOriginalWH.length > 0 &&
|
||||
(pdfRequest
|
||||
? signerPos.map((data, key) => {
|
||||
return (
|
||||
<React.Fragment key={key}>
|
||||
{checkSignedSignes(data)}
|
||||
{checkSignedSigners(data)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
@@ -385,8 +297,6 @@ function RenderPdf({
|
||||
handleLinkUser={handleLinkUser}
|
||||
handleUserName={handleUserName}
|
||||
isSignYourself={false}
|
||||
xPos={xPos}
|
||||
yPos={yPos}
|
||||
posWidth={posWidth}
|
||||
posHeight={posHeight}
|
||||
isDragging={isDragging}
|
||||
@@ -402,6 +312,13 @@ function RenderPdf({
|
||||
handleNameModal={handleNameModal}
|
||||
setTempSignerId={setTempSignerId}
|
||||
uniqueId={uniqueId}
|
||||
handleTextSettingModal={
|
||||
handleTextSettingModal
|
||||
}
|
||||
scale={scale}
|
||||
containerWH={containerWH}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pageNumber={pageNumber}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
@@ -433,13 +350,10 @@ function RenderPdf({
|
||||
index={index}
|
||||
xyPostion={xyPostion}
|
||||
setXyPostion={setXyPostion}
|
||||
pdfOriginalWidth={pdfOriginalWidth}
|
||||
containerWH={containerWH}
|
||||
setIsSignPad={setIsSignPad}
|
||||
isShowBorder={true}
|
||||
isSignYourself={true}
|
||||
xPos={xPos}
|
||||
yPos={yPos}
|
||||
posWidth={posWidth}
|
||||
posHeight={posHeight}
|
||||
pdfDetails={pdfDetails[0]}
|
||||
@@ -452,6 +366,12 @@ function RenderPdf({
|
||||
setIsCheckbox={setIsCheckbox}
|
||||
setValidateAlert={setValidateAlert}
|
||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||
handleTextSettingModal={
|
||||
handleTextSettingModal
|
||||
}
|
||||
scale={scale}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pageNumber={pageNumber}
|
||||
/>
|
||||
)
|
||||
);
|
||||
@@ -461,16 +381,10 @@ function RenderPdf({
|
||||
}))}
|
||||
|
||||
{/* this component for render pdf document is in middle of the component */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center justify-center">
|
||||
<Document
|
||||
onLoadError={() => {
|
||||
setPdfLoadFail(true);
|
||||
setPdfLoad(false);
|
||||
}}
|
||||
loading={"Loading Document.."}
|
||||
onLoadSuccess={pageDetails}
|
||||
@@ -488,19 +402,16 @@ function RenderPdf({
|
||||
: pdfDetails[0].URL
|
||||
}
|
||||
>
|
||||
{Array.from(new Array(numPages), (el, index) => (
|
||||
<Page
|
||||
key={index}
|
||||
pageNumber={pageNumber}
|
||||
width={containerWH.width}
|
||||
height={containerWH.height}
|
||||
renderAnnotationLayer={false}
|
||||
renderTextLayer={false}
|
||||
onGetAnnotationsError={(error) => {
|
||||
console.log("annotation error", error);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<Page
|
||||
key={index}
|
||||
pageNumber={pageNumber}
|
||||
width={containerWH.width}
|
||||
renderAnnotationLayer={false}
|
||||
renderTextLayer={false}
|
||||
onGetAnnotationsError={(error) => {
|
||||
console.log("annotation error", error);
|
||||
}}
|
||||
/>
|
||||
</Document>
|
||||
</div>
|
||||
</div>
|
||||
@@ -509,31 +420,31 @@ function RenderPdf({
|
||||
style={{
|
||||
position: "relative",
|
||||
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
|
||||
width:
|
||||
pdfOriginalWidth > pdfNewWidth ? pdfNewWidth : pdfOriginalWidth,
|
||||
height: window.innerHeight - 110 + "px"
|
||||
height: window.innerHeight + "px",
|
||||
zIndex: 0
|
||||
}}
|
||||
noScrollY={false}
|
||||
noScrollX={pdfNewWidth < pdfOriginalWidth ? false : true}
|
||||
noScrollX={scale === 1 ? true : false}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
border: "0.1px solid #ebe8e8",
|
||||
width: pdfOriginalWidth
|
||||
width: containerWH.width * scale
|
||||
}}
|
||||
ref={drop}
|
||||
id="container"
|
||||
>
|
||||
{pdfLoadFail.status &&
|
||||
(pdfRequest
|
||||
? signerPos.map((data, key) => {
|
||||
{pdfLoad &&
|
||||
containerWH?.width &&
|
||||
pdfOriginalWH.length > 0 &&
|
||||
(pdfRequest //pdf request sign flow
|
||||
? signerPos?.map((data, key) => {
|
||||
return (
|
||||
<React.Fragment key={key}>
|
||||
{checkSignedSignes(data)}
|
||||
{checkSignedSigners(data)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
: placeholder
|
||||
: placeholder //placeholder and template flow
|
||||
? signerPos.map((data, ind) => {
|
||||
return (
|
||||
<React.Fragment key={ind}>
|
||||
@@ -568,8 +479,6 @@ function RenderPdf({
|
||||
handleLinkUser={handleLinkUser}
|
||||
handleUserName={handleUserName}
|
||||
isSignYourself={false}
|
||||
xPos={xPos}
|
||||
yPos={yPos}
|
||||
posWidth={posWidth}
|
||||
posHeight={posHeight}
|
||||
isDragging={isDragging}
|
||||
@@ -585,6 +494,13 @@ function RenderPdf({
|
||||
handleNameModal={handleNameModal}
|
||||
setTempSignerId={setTempSignerId}
|
||||
uniqueId={uniqueId}
|
||||
handleTextSettingModal={
|
||||
handleTextSettingModal
|
||||
}
|
||||
scale={scale}
|
||||
containerWH={containerWH}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pageNumber={pageNumber}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
@@ -596,53 +512,55 @@ function RenderPdf({
|
||||
);
|
||||
})
|
||||
: xyPostion.map((data, ind) => {
|
||||
// signyourself flow
|
||||
return (
|
||||
<React.Fragment key={ind}>
|
||||
{data.pageNumber === pageNumber &&
|
||||
data.pos.map((pos) => {
|
||||
return (
|
||||
pos && (
|
||||
<React.Fragment key={pos.key}>
|
||||
<Placeholder
|
||||
pos={pos}
|
||||
setIsPageCopy={setIsPageCopy}
|
||||
setSignKey={setSignKey}
|
||||
handleDeleteSign={handleDeleteSign}
|
||||
setIsStamp={setIsStamp}
|
||||
handleTabDrag={handleTabDrag}
|
||||
handleStop={(event, dragElement) =>
|
||||
handleStop(event, dragElement, pos.type)
|
||||
}
|
||||
handleSignYourselfImageResize={
|
||||
handleSignYourselfImageResize
|
||||
}
|
||||
index={index}
|
||||
xyPostion={xyPostion}
|
||||
setXyPostion={setXyPostion}
|
||||
pdfOriginalWidth={pdfOriginalWidth}
|
||||
containerWH={containerWH}
|
||||
setIsSignPad={setIsSignPad}
|
||||
isShowBorder={true}
|
||||
isSignYourself={true}
|
||||
xPos={xPos}
|
||||
yPos={yPos}
|
||||
posWidth={posWidth}
|
||||
posHeight={posHeight}
|
||||
pdfDetails={pdfDetails[0]}
|
||||
isDragging={isDragging}
|
||||
setIsInitial={setIsInitial}
|
||||
setWidgetType={setWidgetType}
|
||||
setSelectWidgetId={setSelectWidgetId}
|
||||
selectWidgetId={selectWidgetId}
|
||||
handleUserName={handleUserName}
|
||||
setIsCheckbox={setIsCheckbox}
|
||||
setValidateAlert={setValidateAlert}
|
||||
setCurrWidgetsDetails={
|
||||
setCurrWidgetsDetails
|
||||
}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)
|
||||
<React.Fragment key={pos.key}>
|
||||
<Placeholder
|
||||
pos={pos}
|
||||
setIsPageCopy={setIsPageCopy}
|
||||
setSignKey={setSignKey}
|
||||
handleDeleteSign={handleDeleteSign}
|
||||
setIsStamp={setIsStamp}
|
||||
handleTabDrag={handleTabDrag}
|
||||
handleStop={(event, dragElement) =>
|
||||
handleStop(event, dragElement, pos.type)
|
||||
}
|
||||
handleSignYourselfImageResize={
|
||||
handleSignYourselfImageResize
|
||||
}
|
||||
index={index}
|
||||
xyPostion={xyPostion}
|
||||
setXyPostion={setXyPostion}
|
||||
setIsSignPad={setIsSignPad}
|
||||
isShowBorder={true}
|
||||
isSignYourself={true}
|
||||
posWidth={posWidth}
|
||||
posHeight={posHeight}
|
||||
pdfDetails={pdfDetails[0]}
|
||||
isDragging={isDragging}
|
||||
setIsInitial={setIsInitial}
|
||||
setWidgetType={setWidgetType}
|
||||
setSelectWidgetId={setSelectWidgetId}
|
||||
selectWidgetId={selectWidgetId}
|
||||
handleUserName={handleUserName}
|
||||
setIsCheckbox={setIsCheckbox}
|
||||
setValidateAlert={setValidateAlert}
|
||||
setCurrWidgetsDetails={
|
||||
setCurrWidgetsDetails
|
||||
}
|
||||
handleTextSettingModal={
|
||||
handleTextSettingModal
|
||||
}
|
||||
scale={scale}
|
||||
containerWH={containerWH}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pageNumber={pageNumber}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</React.Fragment>
|
||||
@@ -652,11 +570,7 @@ function RenderPdf({
|
||||
{/* this component for render pdf document is in middle of the component */}
|
||||
<Document
|
||||
onLoadError={() => {
|
||||
const load = {
|
||||
status: false,
|
||||
type: "failed"
|
||||
};
|
||||
setPdfLoadFail(load);
|
||||
pdfLoad(false);
|
||||
}}
|
||||
loading={"Loading Document.."}
|
||||
onLoadSuccess={pageDetails}
|
||||
@@ -674,17 +588,18 @@ function RenderPdf({
|
||||
: pdfDetails[0].URL
|
||||
}
|
||||
>
|
||||
{Array.from(new Array(numPages), (el, index) => (
|
||||
<Page
|
||||
key={index}
|
||||
pageNumber={pageNumber}
|
||||
renderAnnotationLayer={false}
|
||||
renderTextLayer={false}
|
||||
onGetAnnotationsError={(error) => {
|
||||
console.log("annotation error", error);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<Page
|
||||
key={index}
|
||||
width={containerWH.width}
|
||||
scale={scale || 1}
|
||||
className={"-z-[1]"} // when user zoom-in in tablet widgets move backward that's why pass -z-[1]
|
||||
pageNumber={pageNumber}
|
||||
renderAnnotationLayer={false}
|
||||
renderTextLayer={false}
|
||||
onGetAnnotationsError={(error) => {
|
||||
console.log("annotation error", error);
|
||||
}}
|
||||
/>
|
||||
</Document>
|
||||
</div>
|
||||
</RSC>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useRef, useState, useEffect } from "react";
|
||||
import SignatureCanvas from "react-signature-canvas";
|
||||
import { themeColor } from "../../constant/const";
|
||||
|
||||
function SignPad({
|
||||
isSignPad,
|
||||
@@ -62,7 +61,6 @@ function SignPad({
|
||||
} else if (isStamp) {
|
||||
setImage("");
|
||||
}
|
||||
|
||||
setIsSignImg("");
|
||||
} else if (isTab === "uploadImage") {
|
||||
setImage("");
|
||||
@@ -70,29 +68,23 @@ function SignPad({
|
||||
// setIsInitial(false);
|
||||
};
|
||||
//function for set signature url
|
||||
const handleSignatureChange = () => {
|
||||
setSignature(canvasRef.current.toDataURL());
|
||||
setIsSignImg(canvasRef.current.toDataURL());
|
||||
const handleSignatureChange = (data) => {
|
||||
setSignature(data);
|
||||
setIsSignImg(data);
|
||||
};
|
||||
|
||||
//save button component
|
||||
const SaveBtn = () => {
|
||||
return (
|
||||
<div style={{ marginTop: "2px" }}>
|
||||
<div>
|
||||
{(isTab === "draw" || isTab === "uploadImage") && (
|
||||
<button
|
||||
style={{
|
||||
color: "black",
|
||||
border: "1px solid #ccc"
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn saveBtn"
|
||||
className="op-btn op-btn-ghost mr-1 mt-[2px]"
|
||||
onClick={() => handleClear()}
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
setCurrWidgetsDetails({});
|
||||
@@ -109,6 +101,8 @@ function SignPad({
|
||||
setIsSignImg("");
|
||||
onSaveSign(null, false, textWidth, textHeight);
|
||||
} else {
|
||||
setIsSignImg("");
|
||||
canvasRef.current.clear();
|
||||
onSaveSign(signatureType);
|
||||
}
|
||||
}
|
||||
@@ -127,18 +121,21 @@ function SignPad({
|
||||
setSignValue("");
|
||||
setIsStamp(false);
|
||||
}}
|
||||
style={{
|
||||
background: themeColor,
|
||||
color: "white"
|
||||
}}
|
||||
disabled={
|
||||
isSignImg || image || isDefaultSign || textWidth ? false : true
|
||||
}
|
||||
type="button"
|
||||
className={
|
||||
className={`${
|
||||
isSignImg || image || isDefaultSign || textWidth
|
||||
? "finishBtn saveBtn"
|
||||
: "disabledFinish saveBtn"
|
||||
? ""
|
||||
: "pointer-events-none"
|
||||
} op-btn op-btn-primary shadow-lg`}
|
||||
disabled={
|
||||
(isTab === "draw" && isSignImg) ||
|
||||
(isTab === "image" && image) ||
|
||||
(isTab === "mysignature" && isDefaultSign) ||
|
||||
(isTab === "type" && textWidth)
|
||||
? false
|
||||
: image
|
||||
? false
|
||||
: true
|
||||
}
|
||||
>
|
||||
Save
|
||||
@@ -206,7 +203,6 @@ function SignPad({
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isTab]);
|
||||
|
||||
//function for convert input text value in image
|
||||
const convertToImg = async (fontStyle, text, color) => {
|
||||
//get text content to convert in image
|
||||
@@ -214,8 +210,8 @@ function SignPad({
|
||||
const fontfamily = fontStyle
|
||||
? fontStyle
|
||||
: fontSelect
|
||||
? fontSelect
|
||||
: "Fasthand";
|
||||
? fontSelect
|
||||
: "Fasthand";
|
||||
|
||||
//creating span for getting text content width
|
||||
const span = document.createElement("span");
|
||||
@@ -256,7 +252,7 @@ function SignPad({
|
||||
|
||||
const PenColorComponent = (props) => {
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<div className="flex flex-row items-start">
|
||||
{allColor.map((data, key) => {
|
||||
return (
|
||||
<i
|
||||
@@ -267,10 +263,10 @@ function SignPad({
|
||||
key === 0 && penColor === "blue"
|
||||
? "2px solid blue"
|
||||
: key === 1 && penColor === "red"
|
||||
? "2px solid red"
|
||||
: key === 2 && penColor === "black"
|
||||
? "2px solid black"
|
||||
: "2px solid white"
|
||||
? "2px solid red"
|
||||
: key === 2 && penColor === "black"
|
||||
? "2px solid black"
|
||||
: "2px solid white"
|
||||
}}
|
||||
onClick={() => {
|
||||
props?.convertToImg &&
|
||||
@@ -284,7 +280,7 @@ function SignPad({
|
||||
}
|
||||
}}
|
||||
key={key}
|
||||
className="fa solid fa-pen-nib"
|
||||
className="fa-light fa-pen-nib"
|
||||
width={20}
|
||||
height={20}
|
||||
></i>
|
||||
@@ -296,33 +292,14 @@ function SignPad({
|
||||
return (
|
||||
<div>
|
||||
{isSignPad && (
|
||||
<div className="modaloverlay">
|
||||
<div className="modalcontainer">
|
||||
<div
|
||||
className="modalheader"
|
||||
style={{ padding: "0 13px", marginTop: "5px" }}
|
||||
>
|
||||
<div className="modaltitle">
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
background: "white",
|
||||
marginTop: "3px"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-around",
|
||||
alignItems: "end",
|
||||
gap: 10
|
||||
}}
|
||||
>
|
||||
<div className="op-modal op-modal-open">
|
||||
<div className="op-modal-box px-[13px] pt-2 pb-0">
|
||||
<div className="flex justify-between text-base-content items-center">
|
||||
<div className="text-[1.2rem]">
|
||||
<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 style={{ color: themeColor }} className="signTab">
|
||||
<span className="op-link-primary op-link">
|
||||
{widgetType === "image"
|
||||
? "Upload image"
|
||||
: "Upload stamp image"}
|
||||
@@ -336,24 +313,18 @@ function SignPad({
|
||||
setIsImageSelect(false);
|
||||
setIsTab("draw");
|
||||
setImage();
|
||||
if (isSignImg) {
|
||||
setSignature(isSignImg);
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
color: isTab === "draw" ? themeColor : "#515252",
|
||||
marginLeft: "2px"
|
||||
}}
|
||||
className="signTab"
|
||||
className={`${
|
||||
isTab === "draw"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
Draw
|
||||
</span>
|
||||
|
||||
<div
|
||||
style={{
|
||||
border:
|
||||
isTab === "draw"
|
||||
? "1.5px solid #108783"
|
||||
: "1.5px solid #ffffff"
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
@@ -363,22 +334,14 @@ function SignPad({
|
||||
setIsTab("uploadImage");
|
||||
setSignatureType("");
|
||||
}}
|
||||
style={{
|
||||
color:
|
||||
isTab === "uploadImage" ? themeColor : "#515252"
|
||||
}}
|
||||
className="signTab"
|
||||
className={`${
|
||||
isTab === "uploadImage"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
Upload Image
|
||||
</span>
|
||||
<div
|
||||
style={{
|
||||
border:
|
||||
isTab === "uploadImage"
|
||||
? "1.5px solid #108783"
|
||||
: "1.5px solid #ffffff"
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
@@ -389,23 +352,14 @@ function SignPad({
|
||||
setSignatureType("");
|
||||
setImage();
|
||||
}}
|
||||
style={{
|
||||
color: isTab === "type" ? themeColor : "#515252",
|
||||
marginLeft: "2px"
|
||||
}}
|
||||
className="signTab"
|
||||
className={`${
|
||||
isTab === "type"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
Type
|
||||
</span>
|
||||
|
||||
<div
|
||||
style={{
|
||||
border:
|
||||
isTab === "type"
|
||||
? "1.5px solid #108783"
|
||||
: "1.5px solid #ffffff"
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
{!isInitial && defaultSign ? (
|
||||
<div>
|
||||
@@ -417,24 +371,14 @@ function SignPad({
|
||||
setSignatureType("");
|
||||
setImage();
|
||||
}}
|
||||
style={{
|
||||
color:
|
||||
isTab === "mysignature"
|
||||
? themeColor
|
||||
: "#515252"
|
||||
}}
|
||||
className="signTab"
|
||||
className={`${
|
||||
isTab === "mysignature"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
My Signature
|
||||
</span>
|
||||
<div
|
||||
style={{
|
||||
border:
|
||||
isTab === "mysignature"
|
||||
? "1.5px solid #108783"
|
||||
: "1.5px solid #ffffff"
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
) : (
|
||||
isInitial &&
|
||||
@@ -448,24 +392,14 @@ function SignPad({
|
||||
setSignatureType("");
|
||||
setImage();
|
||||
}}
|
||||
style={{
|
||||
color:
|
||||
isTab === "mysignature"
|
||||
? themeColor
|
||||
: "#515252"
|
||||
}}
|
||||
className="signTab"
|
||||
className={`${
|
||||
isTab === "mysignature"
|
||||
? "op-link-primary"
|
||||
: "no-underline"
|
||||
} op-link underline-offset-8 ml-[2px]`}
|
||||
>
|
||||
My Initials
|
||||
</span>
|
||||
<div
|
||||
style={{
|
||||
border:
|
||||
isTab === "mysignature"
|
||||
? "1.5px solid #108783"
|
||||
: "1.5px solid #ffffff"
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
@@ -475,8 +409,7 @@ function SignPad({
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="closebtn"
|
||||
style={{ color: "black" }}
|
||||
className="text-[1.5rem] cursor-pointer"
|
||||
onClick={() => {
|
||||
setPenColor("blue");
|
||||
setIsSignPad(false);
|
||||
@@ -493,10 +426,10 @@ function SignPad({
|
||||
×
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ height: "100%", padding: 20 }}>
|
||||
<div className="p-[20px] h-full">
|
||||
{isDefaultSign ? (
|
||||
<>
|
||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
||||
<div className="flex justify-center">
|
||||
<div
|
||||
style={{
|
||||
border: "1.3px solid #007bff",
|
||||
@@ -514,24 +447,19 @@ function SignPad({
|
||||
>
|
||||
<img
|
||||
alt="stamp img"
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
background: "rgb(255, 255, 255)",
|
||||
objectFit: "contain"
|
||||
}}
|
||||
className="w-full h-full object-contain bg-white"
|
||||
draggable="false"
|
||||
src={isInitial ? myInitial : defaultSign}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: "flex", justifyContent: "flex-end" }}>
|
||||
<div className="flex justify-end">
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</>
|
||||
) : isImageSelect || isStamp ? (
|
||||
!image ? (
|
||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
||||
<div className="flex justify-center">
|
||||
<div
|
||||
style={{
|
||||
border: "1.3px solid #007bff",
|
||||
@@ -556,13 +484,13 @@ function SignPad({
|
||||
ref={imageRef}
|
||||
hidden
|
||||
/>
|
||||
<i className="fas fa-cloud-upload-alt uploadImgLogo"></i>
|
||||
<div className="uploadImg">Upload</div>
|
||||
<i className="fa-light fa-cloud-upload-alt uploadImgLogo"></i>
|
||||
<div className="text-[10px]">Upload</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
||||
<div className="flex justify-center">
|
||||
<div
|
||||
style={{
|
||||
border: "1.3px solid #007bff",
|
||||
@@ -581,39 +509,26 @@ function SignPad({
|
||||
ref={imageRef}
|
||||
src={image.src}
|
||||
draggable="false"
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
height: "100%",
|
||||
width: "100%"
|
||||
}}
|
||||
className=" object-contain h-full w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={{ display: "flex", justifyContent: "flex-end" }}
|
||||
>
|
||||
<div className="flex justify-end">
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
) : isTab === "type" ? (
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<span className="signatureText">
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="mr-[5px] text-[12px]">
|
||||
{isInitial ? "Initials" : "Signature"}:
|
||||
</span>
|
||||
|
||||
<input
|
||||
maxLength={isInitial ? 3 : 30}
|
||||
style={{ fontFamily: fontSelect, color: penColor }}
|
||||
type="text"
|
||||
className="signatureInput"
|
||||
className="ml-1 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-[20px]"
|
||||
placeholder="Your signature"
|
||||
value={signValue}
|
||||
onChange={(e) => {
|
||||
@@ -622,8 +537,7 @@ function SignPad({
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="fontOptionContainer">
|
||||
<div className="border-[1px] border-[#d6d3d3] mt-[10px] ml-[5px]">
|
||||
{fontOptions.map((font, ind) => {
|
||||
return (
|
||||
<div
|
||||
@@ -653,21 +567,14 @@ function SignPad({
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginTop: "10px"
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row justify-between mt-[10px]">
|
||||
<PenColorComponent convertToImg={convertToImg} />
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
||||
<div className="flex justify-center">
|
||||
<SignatureCanvas
|
||||
ref={canvasRef}
|
||||
penColor={penColor}
|
||||
@@ -682,19 +589,12 @@ function SignPad({
|
||||
}}
|
||||
backgroundColor="rgb(255, 255, 255)"
|
||||
onEnd={() =>
|
||||
handleSignatureChange(canvasRef.current.toDataURL())
|
||||
handleSignatureChange(canvasRef.current?.toDataURL())
|
||||
}
|
||||
dotSize={1}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginTop: "10px"
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row justify-between mt-[10px]">
|
||||
<PenColorComponent />
|
||||
<SaveBtn />
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import { themeColor } from "../../constant/const";
|
||||
import "../../styles/signature.css";
|
||||
function Signedby({ pdfDetails }) {
|
||||
const getFirstLetter = (name) => {
|
||||
@@ -8,52 +7,24 @@ function Signedby({ pdfDetails }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="signerComponent">
|
||||
<div
|
||||
style={{
|
||||
background: themeColor,
|
||||
color: "white"
|
||||
}}
|
||||
className="signedStyle"
|
||||
>
|
||||
<div className="hidden md:block w-full h-full bg-base-100">
|
||||
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
|
||||
Signed By
|
||||
</div>
|
||||
<div style={{ marginTop: "2px", background: "white" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
padding: "10px",
|
||||
background: "#93a3db"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="signerStyle"
|
||||
style={{
|
||||
background: "#abd1d0",
|
||||
width: 20,
|
||||
height: 20,
|
||||
display: "flex",
|
||||
borderRadius: 30 / 2,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginRight: "20px",
|
||||
marginTop: "5px"
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: "8px",
|
||||
textAlign: "center",
|
||||
fontWeight: "bold"
|
||||
}}
|
||||
>
|
||||
<div className="mt-[2px] bg-base-100">
|
||||
<div className="bg-[#93a3db] rounded-xl mx-1 flex flex-row items-center py-[10px]">
|
||||
<div className="bg-[#576081] flex w-[30px] h-[30px] rounded-full justify-center items-center mx-1">
|
||||
<span className="text-[12px] text-center font-bold text-white uppercase">
|
||||
{getFirstLetter(pdfDetails.ExtUserPtr.Name)}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
<span className="userName">{pdfDetails.ExtUserPtr.Name}</span>
|
||||
<span className="useEmail">{pdfDetails.ExtUserPtr.Email}</span>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-[12px] font-bold text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
|
||||
{pdfDetails.ExtUserPtr.Name}
|
||||
</span>
|
||||
<span className="text-[10px] font-medium text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
|
||||
{pdfDetails.ExtUserPtr.Email}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import React from "react";
|
||||
import { darkenColor, getFirstLetter } from "../../constant/Utils";
|
||||
|
||||
function SignerListComponent(props) {
|
||||
const checkSignerBackColor = (obj) => {
|
||||
if (obj) {
|
||||
let data = "";
|
||||
if (obj?.Id) {
|
||||
data = props.signerPos.filter((data) => data.Id === obj.Id);
|
||||
} else {
|
||||
data = props.signerPos.filter(
|
||||
(data) => data.signerObjId === obj.objectId
|
||||
);
|
||||
}
|
||||
return data && data.length > 0 && data[0].blockColor;
|
||||
}
|
||||
};
|
||||
const checkUserNameColor = (obj) => {
|
||||
const getBackColor = checkSignerBackColor(obj);
|
||||
if (getBackColor) {
|
||||
const color = darkenColor(getBackColor, 0.4);
|
||||
return color;
|
||||
} else {
|
||||
return "#abd1d0";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="rounded-xl mx-1 flex flex-row items-center py-[10px] mt-1"
|
||||
style={{ background: checkSignerBackColor(props.obj) }}
|
||||
>
|
||||
<div
|
||||
style={{ background: checkUserNameColor(props.obj) }}
|
||||
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)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-[12px] font-bold text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
|
||||
{props.obj?.Name || props?.obj?.Role}
|
||||
</span>
|
||||
<span className="text-[10px] font-medium text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
|
||||
{props.obj?.Email || props.obj?.email}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SignerListComponent;
|
||||
@@ -1,39 +1,26 @@
|
||||
import React from "react";
|
||||
import { themeColor } from "../../constant/const";
|
||||
import RecipientList from "./RecipientList";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
|
||||
function SignerListPlace(props) {
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
background: themeColor,
|
||||
padding: "5px"
|
||||
}}
|
||||
>
|
||||
<span className="signedStyle">
|
||||
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
|
||||
<span className="relative">
|
||||
{props.title ? props.title : "Recipients"}
|
||||
<span className="absolute text-xs z-[30] mt-1 ml-0.5">
|
||||
{props?.title === "Roles" && (
|
||||
<>
|
||||
<a data-tooltip-id="my-tooltip">
|
||||
<sup>
|
||||
<i
|
||||
className="fa-solid fa-question rounded-full"
|
||||
style={{
|
||||
borderColor: "white",
|
||||
color: "white",
|
||||
fontSize: 11,
|
||||
borderWidth: 1.5,
|
||||
padding: "1px 3px"
|
||||
}}
|
||||
></i>
|
||||
<i className="fa-light fa-question rounded-full border-[1px] border-base-content text-[11px] py-[1px] px-[3px]"></i>
|
||||
</sup>
|
||||
</a>
|
||||
<Tooltip id="my-tooltip">
|
||||
<div className="max-w-[450px]">
|
||||
<p className="font-bold">What are template roles?</p>
|
||||
<Tooltip id="my-tooltip" className="z-[100]">
|
||||
<div className="max-w-[450px] 2xl:max-w-[500px] 2xl:text-[20px] p-[1px]">
|
||||
<p className="font-bold pb-[1px]">
|
||||
What are template roles?
|
||||
</p>
|
||||
<p>
|
||||
Begin by specifying each role needed for the completion of
|
||||
the document. Think about the parties involved in the
|
||||
@@ -68,36 +55,32 @@ function SignerListPlace(props) {
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="signerList">
|
||||
<div className="overflow-auto hide-scrollbar max-h-[180px]">
|
||||
<RecipientList {...props} />
|
||||
</div>
|
||||
{props.handleAddSigner ? (
|
||||
<div
|
||||
data-tut="reactourAddbtn"
|
||||
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
|
||||
onClick={() => props.handleAddSigner()}
|
||||
style={{
|
||||
opacity: props.isMailSend && "0.5",
|
||||
pointerEvents: props.isMailSend && "none"
|
||||
}}
|
||||
>
|
||||
<i className="fa-solid fa-plus"></i>
|
||||
<span style={{ marginLeft: 2 }}>Add role</span>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
data-tut="reactourAddbtn"
|
||||
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
|
||||
onClick={() => props.setIsAddSigner(true)}
|
||||
style={{
|
||||
opacity: props.isMailSend && "0.5",
|
||||
pointerEvents: props.isMailSend && "none"
|
||||
}}
|
||||
>
|
||||
<i className="fa-solid fa-plus"></i>
|
||||
<span style={{ marginLeft: 2 }}>Add recipients</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="mx-1">
|
||||
{props.handleAddSigner ? (
|
||||
<div
|
||||
role="button"
|
||||
data-tut="reactourAddbtn"
|
||||
disabled={props?.isMailSend ? true : false}
|
||||
className="op-btn op-btn-accent op-btn-outline w-full mt-[14px]"
|
||||
onClick={() => props.handleAddSigner()}
|
||||
>
|
||||
<i className="fa-light fa-plus"></i> Add role
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
role="button"
|
||||
data-tut="addRecipient"
|
||||
className="op-btn op-btn-accent op-btn-outline w-full mt-[14px]"
|
||||
disabled={props?.isMailSend ? true : false}
|
||||
onClick={() => props.setIsAddSigner(true)}
|
||||
>
|
||||
<i className="fa-light fa-plus"></i> Add recipients
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import React from "react";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
import { fontColorArr, fontsizeArr } from "../../constant/Utils";
|
||||
|
||||
function TextFontSetting(props) {
|
||||
return (
|
||||
<ModalUi
|
||||
headerColor={"#dc3545"}
|
||||
isOpen={props.isTextSetting}
|
||||
reduceWidth={"max-w-[350px]"}
|
||||
title={"Text field"}
|
||||
handleClose={() => {
|
||||
props.setIsTextSetting(false);
|
||||
}}
|
||||
>
|
||||
<div className="h-full p-[20px]">
|
||||
<div className="flex items-center">
|
||||
<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.currWidgetsDetails?.options?.fontSize
|
||||
}
|
||||
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.currWidgetsDetails?.options?.fontColor
|
||||
}
|
||||
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.currWidgetsDetails?.options?.fontColor
|
||||
}}
|
||||
className="w-5 h-[19px] ml-1"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="h-[1px] bg-[#9f9f9f] w-full mt-[15px] mb-2"></div>
|
||||
<button
|
||||
onClick={() => props.handleSaveFontSize()}
|
||||
type="button"
|
||||
className="op-btn op-btn-primary mt-2"
|
||||
>
|
||||
save
|
||||
</button>
|
||||
</div>
|
||||
</ModalUi>
|
||||
);
|
||||
}
|
||||
|
||||
export default TextFontSetting;
|
||||
@@ -1,16 +1,13 @@
|
||||
import React from "react";
|
||||
import { rejectBtn, submitBtn, themeColor } from "../../constant/const";
|
||||
import Loader from "../../primitives/Loader";
|
||||
|
||||
function VerifyEmail(props) {
|
||||
return (
|
||||
<div className="bg-black bg-opacity-[75%] absolute z-[999] flex flex-col items-center justify-center w-full h-full rounded">
|
||||
<div className="bg-white rounded outline-none md:w-[40%] w-[80%]">
|
||||
<div
|
||||
style={{ backgroundColor: themeColor }}
|
||||
className=" text-white p-[10px] rounded-t"
|
||||
>
|
||||
<dialog className="op-modal op-modal-open absolute z-[1999]">
|
||||
<div className="md:w-[40%] w-[80%] op-modal-box p-0 overflow-y-auto hide-scrollbar text-sm">
|
||||
<h3 className="font-bold text-lg pt-[15px] px-[20px] text-base-content">
|
||||
OTP verification
|
||||
</div>
|
||||
</h3>
|
||||
{props.isVerifyModal ? (
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
@@ -18,25 +15,24 @@ function VerifyEmail(props) {
|
||||
props.handleVerifyEmail(e);
|
||||
}}
|
||||
>
|
||||
<div className="px-6 py-3">
|
||||
<div className="px-6 py-3 text-base-content">
|
||||
<label className="mb-2">Enter OTP</label>
|
||||
<input
|
||||
required
|
||||
type="tel"
|
||||
pattern="[0-9]{4}"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
||||
placeholder="Enter OTP received over email"
|
||||
value={props.otp}
|
||||
onChange={(e) => props.setOtp(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<hr />
|
||||
<div className="px-6 my-3">
|
||||
<button type="submit" className={submitBtn}>
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Verify
|
||||
</button>
|
||||
<button
|
||||
className={`${rejectBtn} ml-2`}
|
||||
className="op-btn op-btn-secondary ml-2"
|
||||
onClick={(e) => props.handleResend(e)}
|
||||
>
|
||||
Resend
|
||||
@@ -44,29 +40,15 @@ function VerifyEmail(props) {
|
||||
</div>
|
||||
</form>
|
||||
) : props.otpLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "150px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="h-[150px] flex items-center justify-center">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<div className="px-6 py-3">
|
||||
<p className="mb-2">Please verify your email !</p>
|
||||
<hr />
|
||||
<div className="px-6 py-3 text-base-content">
|
||||
<p className="mb-2 text-sm">Please verify your email !</p>
|
||||
<div className="px-0 mt-3">
|
||||
<button
|
||||
className={submitBtn}
|
||||
className="op-btn op-btn-primary"
|
||||
type="submit"
|
||||
onClick={() => {
|
||||
props.handleVerifyBtn();
|
||||
@@ -78,7 +60,7 @@ function VerifyEmail(props) {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
textWidget,
|
||||
widgets
|
||||
} from "../../constant/Utils";
|
||||
import { themeColor } from "../../constant/const";
|
||||
function WidgetComponent({
|
||||
dragSignature,
|
||||
signRef,
|
||||
@@ -251,122 +250,87 @@ function WidgetComponent({
|
||||
{isMobile ? (
|
||||
!isMailSend && (
|
||||
<div
|
||||
data-tut={dataTut}
|
||||
id="navbar"
|
||||
className="stickyfooter"
|
||||
className="fixed z-[99] bottom-0 right-0"
|
||||
style={{ width: window.innerWidth + "px" }}
|
||||
>
|
||||
{isSigners && (
|
||||
<div
|
||||
data-tut={dataTut}
|
||||
style={{
|
||||
background: blockColor
|
||||
? blockColor
|
||||
: isSelectListId
|
||||
? color[isSelectListId % color.length]
|
||||
: color[0],
|
||||
padding: "10px 20px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
onClick={() => handleModal()}
|
||||
>
|
||||
<span
|
||||
<div className="mx-1">
|
||||
{isSigners && (
|
||||
<div
|
||||
data-tut="recipientArea"
|
||||
className="py-[10px] flex justify-center items-center op-card"
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
fontWeight: "700",
|
||||
textAlign: "center"
|
||||
background: blockColor
|
||||
? blockColor
|
||||
: isSelectListId
|
||||
? color[isSelectListId % color.length]
|
||||
: color[0]
|
||||
}}
|
||||
onClick={() => handleModal()}
|
||||
>
|
||||
{title ? title : "Recipient"}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
fontWeight: "700",
|
||||
display: "flex",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
{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}
|
||||
</>
|
||||
)}
|
||||
<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>
|
||||
)}
|
||||
<div style={{ marginLeft: 6, fontSize: 16 }}>
|
||||
<i className="fa-solid fa-angle-down"></i>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{handleAddSigner ? (
|
||||
<div
|
||||
data-tut="reactourAddbtn"
|
||||
style={{
|
||||
margin: "5px 0 5px 0",
|
||||
backgroundColor: themeColor,
|
||||
color: "white"
|
||||
}}
|
||||
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
|
||||
onClick={() => handleAddSigner()}
|
||||
>
|
||||
<i className="fa-solid fa-plus"></i>
|
||||
<span style={{ marginLeft: 2 }}>Add role</span>
|
||||
</div>
|
||||
) : (
|
||||
setIsAddSigner && (
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="mx-1">
|
||||
{handleAddSigner ? (
|
||||
<div
|
||||
data-tut="reactourAddbtn"
|
||||
style={{
|
||||
margin: "5px 0 5px 0",
|
||||
backgroundColor: themeColor,
|
||||
color: "white"
|
||||
}}
|
||||
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
|
||||
onClick={() => setIsAddSigner(true)}
|
||||
className="op-btn op-btn-accent w-full my-[2px]"
|
||||
onClick={() => handleAddSigner()}
|
||||
>
|
||||
<i className="fa-solid fa-plus"></i>
|
||||
<span style={{ marginLeft: 2 }}>Add recipients</span>
|
||||
<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>
|
||||
<div
|
||||
data-tut="addWidgets"
|
||||
ref={scrollContainerRef}
|
||||
style={{
|
||||
background: "white",
|
||||
borderTop: `2px solid ${themeColor}`
|
||||
}}
|
||||
className="bg-base-100 border-[2px] border-t-primary"
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
overflowX: "scroll",
|
||||
whiteSpace: "nowrap",
|
||||
padding: "10px 5px 10px 1px"
|
||||
}}
|
||||
>
|
||||
<div className="flex whitespace-nowrap overflow-x-scroll pt-[10px] pb-[5px] pr-[5px]">
|
||||
<WidgetList
|
||||
updateWidgets={updateWidgets}
|
||||
handleDivClick={handleDivClick}
|
||||
@@ -383,20 +347,18 @@ function WidgetComponent({
|
||||
) : (
|
||||
<div
|
||||
data-tut={dataTut}
|
||||
className={
|
||||
isMailSend ? "disabled signerComponent " : "signerComponent"
|
||||
}
|
||||
className={`${
|
||||
isMailSend ? "bg-opacity-50 pointer-events-none" : ""
|
||||
} hidden md:block h-full bg-base-100`}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
background: themeColor,
|
||||
padding: "5px"
|
||||
}}
|
||||
>
|
||||
<span className="signedStyle">Fields</span>
|
||||
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
|
||||
<span>Fields</span>
|
||||
</div>
|
||||
|
||||
<div className="signLayoutContainer1">
|
||||
<div
|
||||
className="p-[15px] flex flex-col pt-4 2xl:m-5"
|
||||
data-tut="addWidgets"
|
||||
>
|
||||
<WidgetList
|
||||
updateWidgets={updateWidgets}
|
||||
handleDivClick={handleDivClick}
|
||||
@@ -413,7 +375,7 @@ function WidgetComponent({
|
||||
handleClose={handleModal}
|
||||
>
|
||||
{signersdata.length > 0 ? (
|
||||
<div style={{ maxHeight: "600px", overflow: "auto" }}>
|
||||
<div className="max-h-[600px] overflow-auto pb-1">
|
||||
<RecipientList
|
||||
signerPos={signerPos}
|
||||
signersdata={signersdata}
|
||||
@@ -433,14 +395,7 @@ function WidgetComponent({
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
padding: 20,
|
||||
fontSize: 15,
|
||||
fontWeight: "500",
|
||||
textAlign: "center"
|
||||
}}
|
||||
>
|
||||
<div className=" p-[20px] text-[15px] font-medium text-center">
|
||||
Please add a {title ? title : "recipients"}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -4,9 +4,9 @@ import { getWidgetType } from "../../constant/Utils";
|
||||
function WidgetList(props) {
|
||||
return props.updateWidgets.map((item, ind) => {
|
||||
return (
|
||||
<div key={ind} style={{ marginBottom: "5px" }}>
|
||||
<div className="2xl:p-3 mb-[5px]" key={ind}>
|
||||
<div
|
||||
className="widgets"
|
||||
className="select-none mx-[2px] md:mx-0 cursor-all-scroll"
|
||||
onClick={() => {
|
||||
props.addPositionOfSignature &&
|
||||
props.addPositionOfSignature("onclick", item);
|
||||
@@ -22,11 +22,10 @@ function WidgetList(props) {
|
||||
}
|
||||
}}
|
||||
onMouseMove={props?.handleDivClick}
|
||||
onMouseDown={() => {
|
||||
props?.handleMouseLeave();
|
||||
}}
|
||||
onMouseDown={() => props?.handleMouseLeave()}
|
||||
onTouchStart={props?.handleDivClick}
|
||||
>
|
||||
{item.ref && getWidgetType(item, props?.marginLeft)}
|
||||
{item.ref && getWidgetType(item)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -6,6 +6,7 @@ import { textInputWidget } from "../../constant/Utils";
|
||||
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
||||
import Upgrade from "../../primitives/Upgrade";
|
||||
import { isEnableSubscription } from "../../constant/const";
|
||||
import Tooltip from "../../primitives/Tooltip";
|
||||
|
||||
const WidgetNameModal = (props) => {
|
||||
const [formdata, setFormdata] = useState({
|
||||
@@ -121,15 +122,15 @@ const WidgetNameModal = (props) => {
|
||||
props.widgetName === textInputWidget
|
||||
? "pt-0"
|
||||
: ""
|
||||
} p-[20px]`}
|
||||
} p-[20px] text-base-content`}
|
||||
>
|
||||
<div className="form-section">
|
||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
||||
<div className="mb-[0.75rem] text-[13px]">
|
||||
<label htmlFor="name">
|
||||
Name
|
||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
||||
<span className="text-[red]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
className="addUserInput"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
name="name"
|
||||
value={formdata.name}
|
||||
onChange={(e) => handleChange(e)}
|
||||
@@ -139,39 +140,41 @@ const WidgetNameModal = (props) => {
|
||||
{(props.defaultdata?.type === textInputWidget ||
|
||||
props.widgetName === textInputWidget) && (
|
||||
<>
|
||||
<div className="form-section">
|
||||
<label
|
||||
htmlFor="textvalidate"
|
||||
className={
|
||||
!props.isSubscribe && isEnableSubscription && "disabled"
|
||||
}
|
||||
style={{ fontSize: 13 }}
|
||||
>
|
||||
Validation
|
||||
</label>
|
||||
{!props.isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
<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 && "disabled"
|
||||
}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
gap: 10,
|
||||
marginBottom: "0.5rem"
|
||||
}}
|
||||
className={`${
|
||||
!props.isSubscribe && isEnableSubscription
|
||||
? "bg-opacity-50 pointer-events-none"
|
||||
: ""
|
||||
} flex flex-row gap-[10px] mb-[0.5rem]`}
|
||||
>
|
||||
<div style={{ width: "100%", position: "relative" }}>
|
||||
<div className="w-full relative group">
|
||||
<input
|
||||
className="relative z-20 w-[87%] md:w-[92%] p-2.5 border-[1px] border-[#d1d5db] rounded-l-md outline-none text-xs"
|
||||
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 expression"
|
||||
placeholder="Enter custom regular expression"
|
||||
value={formdata.textvalidate}
|
||||
onChange={(e) => handleChange(e)}
|
||||
// onBlur={() => handleBlurRegex()}
|
||||
/>
|
||||
<select
|
||||
className="validationlist addUserInput"
|
||||
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)}
|
||||
@@ -179,17 +182,13 @@ const WidgetNameModal = (props) => {
|
||||
>
|
||||
<option
|
||||
disabled={formdata?.textvalidate}
|
||||
style={{ fontSize: "13px" }}
|
||||
className="text-[13px]"
|
||||
>
|
||||
Select...
|
||||
</option>
|
||||
{inputOpt.map((data, ind) => {
|
||||
return (
|
||||
<option
|
||||
style={{ fontSize: "13px" }}
|
||||
key={ind}
|
||||
value={data}
|
||||
>
|
||||
<option className="text-[13px]" key={ind} value={data}>
|
||||
{data}
|
||||
</option>
|
||||
);
|
||||
@@ -199,12 +198,12 @@ const WidgetNameModal = (props) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-section">
|
||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
||||
<div className="mb-[0.75rem]">
|
||||
<label htmlFor="name" className="text-[13px]">
|
||||
Default value
|
||||
</label>
|
||||
<input
|
||||
className="addUserInput"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
name="defaultValue"
|
||||
value={formdata.defaultValue}
|
||||
onChange={(e) => handledefaultChange(e)}
|
||||
@@ -222,37 +221,22 @@ const WidgetNameModal = (props) => {
|
||||
style={{ fontSize: 12 }}
|
||||
>
|
||||
<i
|
||||
className="fas fa-exclamation-circle"
|
||||
style={{ color: "#fab005", fontSize: 15 }}
|
||||
></i>{" "}
|
||||
className="fa-light fa-exclamation-circle text-[15px]"
|
||||
style={{ color: "#fab005" }}
|
||||
></i>
|
||||
invalid default value
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className="form-section">
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
gap: 10,
|
||||
marginBottom: "0.5rem"
|
||||
}}
|
||||
>
|
||||
<div className="mb-[0.75rem]">
|
||||
<div className="flex flex-row gap-[10px] mb-[0.5rem]">
|
||||
{statusArr.map((data, ind) => {
|
||||
return (
|
||||
<div
|
||||
key={ind}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
gap: 5,
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<div key={ind} className="flex flex-row gap-[5px] items-center">
|
||||
<input
|
||||
style={{ accentColor: "red", marginRight: "10px" }}
|
||||
className="mr-[2px] op-radio op-radio-xs"
|
||||
type="radio"
|
||||
name="status"
|
||||
onChange={() =>
|
||||
@@ -262,9 +246,7 @@ const WidgetNameModal = (props) => {
|
||||
formdata.status.toLowerCase() === data.toLowerCase()
|
||||
}
|
||||
/>
|
||||
<div style={{ fontSize: "13px", fontWeight: "500" }}>
|
||||
{data}
|
||||
</div>
|
||||
<div className="text-[13px] font-medium">{data}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -272,35 +254,20 @@ const WidgetNameModal = (props) => {
|
||||
</div>
|
||||
{(props.defaultdata?.type === textInputWidget ||
|
||||
props?.widgetName === textInputWidget) && (
|
||||
<div className="form-section">
|
||||
<label htmlFor="hint" style={{ fontSize: 13 }}>
|
||||
<div className="mb-[0.75rem]">
|
||||
<label htmlFor="hint" className="text-[13px]">
|
||||
Hint
|
||||
</label>
|
||||
<input
|
||||
className="addUserInput"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
name="hint"
|
||||
value={formdata.hint}
|
||||
onChange={(e) => handleChange(e)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
height: 1,
|
||||
backgroundColor: "#b7b3b3",
|
||||
width: "100%",
|
||||
marginBottom: "16px"
|
||||
}}
|
||||
></div>
|
||||
<button
|
||||
style={{
|
||||
color: "white",
|
||||
padding: "5px 20px",
|
||||
backgroundColor: "#32a3ac"
|
||||
}}
|
||||
type="submit"
|
||||
className="finishBtn"
|
||||
>
|
||||
<div className="h-[1px] w-full mb-[16px] bg-[#b7b3b3]"></div>
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Save
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Parse from "parse";
|
||||
import Alert from "../../../primitives/Alert";
|
||||
import Loader from "../../../primitives/Loader";
|
||||
|
||||
const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
||||
const folderPtr = {
|
||||
@@ -25,9 +26,13 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
||||
if (parentFolderId) {
|
||||
FolderQuery.equalTo("Folder", folderPtr);
|
||||
FolderQuery.equalTo("Type", "Folder");
|
||||
FolderQuery.notEqualTo("IsArchive", true);
|
||||
FolderQuery.equalTo("CreatedBy", Parse.User.current());
|
||||
} else {
|
||||
FolderQuery.doesNotExist("Folder");
|
||||
FolderQuery.equalTo("Type", "Folder");
|
||||
FolderQuery.notEqualTo("IsArchive", true);
|
||||
FolderQuery.equalTo("CreatedBy", Parse.User.current());
|
||||
}
|
||||
|
||||
const res = await FolderQuery.find();
|
||||
@@ -49,6 +54,7 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
||||
const exsitQuery = new Parse.Query(folderCls);
|
||||
exsitQuery.equalTo("Name", name);
|
||||
exsitQuery.equalTo("Type", "Folder");
|
||||
exsitQuery.notEqualTo("IsArchive", true);
|
||||
if (parentFolderId) {
|
||||
exsitQuery.equalTo("Folder", folderPtr);
|
||||
}
|
||||
@@ -110,20 +116,17 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
||||
{isAlert && <Alert type={alert.type}>{alert.message}</Alert>}
|
||||
<div id="createFolder" className="relative">
|
||||
{isLoader && (
|
||||
<div className="absolute h-full w-full flex justify-center items-center ">
|
||||
<div
|
||||
style={{ fontSize: "45px", color: "#3dd3e0" }}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="absolute h-full w-full flex justify-center items-center">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
<h1 className="text-base font-semibold">Create Folder</h1>
|
||||
<h1 className="text-base font-semibold mt-[0.4rem]">Create Folder</h1>
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
Name<span className="text-red-500 text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
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
|
||||
@@ -134,7 +137,7 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
||||
<select
|
||||
value={selectedParent}
|
||||
onChange={handleOptions}
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
>
|
||||
<option>select</option>
|
||||
{folderList.length > 0 &&
|
||||
@@ -149,9 +152,9 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
||||
<button
|
||||
onClick={handleCreateFolder}
|
||||
disabled={isLoader}
|
||||
className="flex items-center rounded p-2 bg-[#32a3ac] text-white mt-3"
|
||||
className="op-btn op-btn-primary op-btn-sm mt-3"
|
||||
>
|
||||
<i className="fa-solid fa-plus mr-1"></i>
|
||||
<i className="fa-light fa-plus"></i>
|
||||
<span>Create</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -24,10 +24,14 @@ const FolderModal = (props) => {
|
||||
const FolderQuery = new Parse.Query(props.folderCls);
|
||||
if (folderPtr) {
|
||||
FolderQuery.equalTo("Folder", folderPtr);
|
||||
FolderQuery.equalTo("Type", "Folder");
|
||||
FolderQuery.descending("Type");
|
||||
FolderQuery.notEqualTo("IsArchive", true);
|
||||
FolderQuery.equalTo("CreatedBy", Parse.User.current());
|
||||
} else {
|
||||
FolderQuery.doesNotExist("Folder");
|
||||
FolderQuery.equalTo("Type", "Folder");
|
||||
FolderQuery.descending("Type");
|
||||
FolderQuery.notEqualTo("IsArchive", true);
|
||||
FolderQuery.equalTo("CreatedBy", Parse.User.current());
|
||||
}
|
||||
|
||||
const res = await FolderQuery.find();
|
||||
@@ -141,14 +145,14 @@ const FolderModal = (props) => {
|
||||
handleCreate();
|
||||
};
|
||||
return (
|
||||
<div className="text-xs mt-2 ">
|
||||
<div className="text-xs mt-2">
|
||||
<ModalUi
|
||||
title={"Select Folder"}
|
||||
isOpen={props.isOpenModal}
|
||||
handleClose={handleCancel}
|
||||
>
|
||||
<div className="w-full min-w-[300px] md:min-w-[500px] max-w-[500px] px-3">
|
||||
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
|
||||
<div className="pt-1 text-[#ac4848] text-[14px] font-[500]">
|
||||
<span
|
||||
className="cursor-pointer"
|
||||
title="OpenSign™ Drive"
|
||||
@@ -169,27 +173,50 @@ const FolderModal = (props) => {
|
||||
{" / "}
|
||||
</React.Fragment>
|
||||
))}
|
||||
<hr />
|
||||
<hr className="bg-[#8a8a8a] mt-[0.750rem]" />
|
||||
</div>
|
||||
<div className="mt-2 mb-3">
|
||||
<div className="max-h-[210px] overflow-auto">
|
||||
{!isAdd &&
|
||||
folderList.length > 0 &&
|
||||
folderList.map((folder) => (
|
||||
<div
|
||||
key={folder.Name}
|
||||
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer "
|
||||
onClick={() => handleSelect(folder)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<i
|
||||
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span className="font-semibold">{folder.Name}</span>
|
||||
{!isAdd && folderList.length > 0
|
||||
? folderList.map((folder) => (
|
||||
<div
|
||||
key={folder.objectId}
|
||||
className={`${
|
||||
folder.Type === "Folder"
|
||||
? "cursor-pointer"
|
||||
: "cursor-default"
|
||||
} border-b-[1px] border-[#8a8a8a] py-2 mb-0.5"`}
|
||||
onClick={() =>
|
||||
folder.Type === "Folder" && handleSelect(folder)
|
||||
}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
{folder.Type === "Folder" ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
className="w-[1.4rem] h-[1.4rem] fill-current op-text-secondary"
|
||||
>
|
||||
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 384 512"
|
||||
className="w-[1.4rem] h-[1.4rem] fill-current op-text-primary"
|
||||
>
|
||||
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
|
||||
</svg>
|
||||
)}
|
||||
<span className="font-semibold">{folder.Name}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
))
|
||||
: !isLoader && (
|
||||
<div className="text-base-content text-center my-2">
|
||||
No data found
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{isAdd && (
|
||||
<CreateFolder
|
||||
@@ -199,8 +226,8 @@ const FolderModal = (props) => {
|
||||
/>
|
||||
)}
|
||||
{isLoader && (
|
||||
<div className="flex justify-center">
|
||||
<i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i>
|
||||
<div className="flex justify-center my-4">
|
||||
<i className="fa-light fa-spinner fa-spin-pulse text-[30px]"></i>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -208,22 +235,28 @@ const FolderModal = (props) => {
|
||||
<hr />
|
||||
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
|
||||
<div
|
||||
className="text-[30px] cursor-pointer text-[#32a3ac]"
|
||||
className="op-btn op-btn-seconday op-btn-sm"
|
||||
title="Save Here"
|
||||
onClick={handleCreate}
|
||||
>
|
||||
{isAdd ? (
|
||||
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
|
||||
<>
|
||||
<i className="fa-light fa-arrow-left" aria-hidden="true"></i>
|
||||
<span className="text-xs">Back</span>
|
||||
</>
|
||||
) : (
|
||||
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
|
||||
<>
|
||||
<i className="fa-light fa-square-plus" aria-hidden="true"></i>
|
||||
<span className="">Add folder</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="text-[30px] cursor-pointer"
|
||||
className="op-btn op-btn-primary op-btn-sm"
|
||||
title="Save Here"
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
<i className="fas fa-save" aria-hidden="true"></i>
|
||||
<i className="fa-light fa-save" aria-hidden="true"></i>Save here
|
||||
</div>
|
||||
</div>
|
||||
</ModalUi>
|
||||
|
||||
@@ -44,10 +44,14 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
||||
const FolderQuery = new Parse.Query(folderCls);
|
||||
if (folderPtr) {
|
||||
FolderQuery.equalTo("Folder", folderPtr);
|
||||
FolderQuery.equalTo("Type", "Folder");
|
||||
FolderQuery.notEqualTo("IsArchive", true);
|
||||
FolderQuery.descending("Type");
|
||||
FolderQuery.equalTo("CreatedBy", Parse.User.current());
|
||||
} else {
|
||||
FolderQuery.doesNotExist("Folder");
|
||||
FolderQuery.equalTo("Type", "Folder");
|
||||
FolderQuery.notEqualTo("IsArchive", true);
|
||||
FolderQuery.descending("Type");
|
||||
FolderQuery.equalTo("CreatedBy", Parse.User.current());
|
||||
}
|
||||
|
||||
const res = await FolderQuery.find();
|
||||
@@ -172,14 +176,16 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
||||
<div className="relative max-w-sm">
|
||||
<div
|
||||
onClick={() => SetIsOpen(true)}
|
||||
className=" cursor-pointer rounded px-[20px] py-[20px] bg-white border border-gray-200 shadow flex max-w-sm gap-8 items-center"
|
||||
className="cursor-pointer rounded px-[20px] py-[20px] bg-base-100 border-[1px] border-base-200 shadow flex max-w-sm gap-8 items-center"
|
||||
>
|
||||
<div>
|
||||
<i
|
||||
className="far fa-folder-open text-[40px] text-[#33bbff]"
|
||||
style={{ fontSize: "40px" }}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
className="w-[40px] h-[40px] fill-current op-text-secondary"
|
||||
>
|
||||
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="font-semibold ">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -188,12 +194,9 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
||||
? selectFolder.Name
|
||||
: "OpenSign™ Drive"}
|
||||
</p>
|
||||
<div
|
||||
className="text-black text-sm"
|
||||
// onClick={() => SetIsOpen(true)}
|
||||
>
|
||||
<div className="text-black text-sm">
|
||||
<i
|
||||
className="fa fa-pencil cursor-pointer"
|
||||
className="fa-light fa-pencil cursor-pointer"
|
||||
title="Select Folder"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
@@ -218,7 +221,7 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
||||
handleClose={handleCancel}
|
||||
>
|
||||
<div className="w-full min-w-[300px] md:min-w-[500px] max-w-[500px] px-3">
|
||||
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
|
||||
<div className="pt-1 text-[#ac4848] text-[14px] font-[500]">
|
||||
<span
|
||||
className="cursor-pointer"
|
||||
title="OpenSign™ Drive"
|
||||
@@ -239,27 +242,50 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
||||
{" / "}
|
||||
</React.Fragment>
|
||||
))}
|
||||
<hr />
|
||||
<hr className="bg-[#8a8a8a] mt-[0.750rem]" />
|
||||
</div>
|
||||
<div className="mt-2 mb-3">
|
||||
<div className="mb-2">
|
||||
<div className="max-h-[210px] overflow-auto">
|
||||
{!isAdd &&
|
||||
folderList.length > 0 &&
|
||||
folderList.map((folder) => (
|
||||
<div
|
||||
key={folder.Name}
|
||||
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer "
|
||||
onClick={() => handleSelect(folder)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<i
|
||||
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span className="font-semibold">{folder.Name}</span>
|
||||
{!isAdd && folderList.length > 0
|
||||
? folderList.map((folder) => (
|
||||
<div
|
||||
key={folder.objectId}
|
||||
className={`${
|
||||
folder.Type === "Folder"
|
||||
? "cursor-pointer"
|
||||
: "cursor-default"
|
||||
} border-b-[1px] border-[#8a8a8a] py-2 mb-0.5"`}
|
||||
onClick={() =>
|
||||
folder.Type === "Folder" && handleSelect(folder)
|
||||
}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
{folder.Type === "Folder" ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
className="w-[1.4rem] h-[1.4rem] fill-current op-text-secondary"
|
||||
>
|
||||
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 384 512"
|
||||
className="w-[1.4rem] h-[1.4rem] fill-current op-text-primary"
|
||||
>
|
||||
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
|
||||
</svg>
|
||||
)}
|
||||
<span className="font-semibold">{folder.Name}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
))
|
||||
: !isLoader && (
|
||||
<div className="text-base-content text-center my-2">
|
||||
No data found
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{isAdd && (
|
||||
<CreateFolder
|
||||
@@ -269,8 +295,8 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
||||
/>
|
||||
)}
|
||||
{isLoader && (
|
||||
<div className="flex justify-center">
|
||||
<i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i>
|
||||
<div className="flex justify-center my-4">
|
||||
<i className="fa-light fa-spinner fa-spin-pulse text-[30px]"></i>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -278,22 +304,28 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
||||
<hr />
|
||||
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
|
||||
<div
|
||||
className="text-[30px] cursor-pointer text-[#32a3ac]"
|
||||
className="op-btn op-btn-seconday op-btn-sm"
|
||||
title="Save Here"
|
||||
onClick={handleCreate}
|
||||
>
|
||||
{isAdd ? (
|
||||
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
|
||||
<>
|
||||
<i className="fa-light fa-arrow-left" aria-hidden="true"></i>
|
||||
<span className="text-xs">Back</span>
|
||||
</>
|
||||
) : (
|
||||
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
|
||||
<>
|
||||
<i className="fa-light fa-square-plus" aria-hidden="true"></i>
|
||||
<span className="">Add folder</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="text-[30px] cursor-pointer"
|
||||
className="op-btn op-btn-primary op-btn-sm"
|
||||
title="Save Here"
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
<i className="fas fa-save" aria-hidden="true"></i>
|
||||
<i className="fa-light fa-save" aria-hidden="true"></i>Save here
|
||||
</div>
|
||||
</div>
|
||||
</ModalUi>
|
||||
|
||||
@@ -1,18 +1,7 @@
|
||||
import React, { useState } from "react";
|
||||
import Parse from "parse";
|
||||
import "../../../styles/AddUser.css";
|
||||
import AsyncSelect from "react-select/async";
|
||||
|
||||
const customStyles = {
|
||||
control: (provided) => ({
|
||||
...provided,
|
||||
fontSize: "13px" // Font size for the control
|
||||
}),
|
||||
option: (provided) => ({
|
||||
...provided,
|
||||
fontSize: "13px" // Font size for the options
|
||||
})
|
||||
};
|
||||
const SelectSigners = (props) => {
|
||||
const [userList, setUserList] = useState([]);
|
||||
const [selected, setSelected] = useState();
|
||||
@@ -79,32 +68,44 @@ const SelectSigners = (props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="addusercontainer">
|
||||
<div className="form-wrapper">
|
||||
<div className="form-section" style={{ marginBottom: 0 }}>
|
||||
<label style={{ fontSize: 14, fontWeight: "700" }}>Choose User</label>
|
||||
<div className="h-full px-[20px] py-[10px] text-base-content">
|
||||
<div className="w-full mx-auto p-[8px]">
|
||||
<div className="mb-0">
|
||||
<label className="text-[14px] font-bold">Choose from contacts</label>
|
||||
<AsyncSelect
|
||||
cacheOptions
|
||||
defaultOptions
|
||||
value={selected}
|
||||
loadingMessage={() => "Loading..."}
|
||||
noOptionsMessage={() => "User not Found"}
|
||||
noOptionsMessage={() => "Contact not found"}
|
||||
loadOptions={loadOptions}
|
||||
onChange={handleOptions}
|
||||
styles={customStyles}
|
||||
unstyled
|
||||
classNames={{
|
||||
control: () =>
|
||||
"op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full h-full text-[11px]",
|
||||
valueContainer: () =>
|
||||
"flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]",
|
||||
multiValue: () => "op-badge op-badge-primary h-full text-[11px]",
|
||||
multiValueLabel: () => "mb-[2px]",
|
||||
menu: () =>
|
||||
"mt-1 shadow-md rounded-lg bg-base-200 text-base-content",
|
||||
menuList: () => "shadow-md rounded-lg overflow-hidden",
|
||||
option: () =>
|
||||
"bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2",
|
||||
noOptionsMessage: () => "p-2 bg-base-200 rounded-lg m-1 p-2"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{isError ? (
|
||||
<p style={{ color: "red", fontSize: "12px", margin: "5px" }}>
|
||||
Please select signer
|
||||
</p>
|
||||
) : (
|
||||
<p style={{ color: "transparent", fontSize: "12px", margin: "5px" }}>
|
||||
.
|
||||
</p>
|
||||
)}
|
||||
<p
|
||||
className={`${
|
||||
isError ? "text-[red]" : "text-transparent"
|
||||
} text-[11px] ml-[6px] my-[2px]`}
|
||||
>
|
||||
Please select signer
|
||||
</p>
|
||||
<div>
|
||||
<button className="submitbutton" onClick={() => handleAdd()}>
|
||||
<button className="op-btn op-btn-primary" onClick={() => handleAdd()}>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,15 +1,30 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Select from "react-select";
|
||||
import AddSigner from "../../AddSigner";
|
||||
import Modal from "react-modal";
|
||||
import Parse from "parse";
|
||||
import Tooltip from "../../../primitives/Tooltip";
|
||||
import { createPortal } from "react-dom";
|
||||
function arrayMove(array, from, to) {
|
||||
array = array.slice();
|
||||
array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]);
|
||||
return array;
|
||||
}
|
||||
|
||||
const AddSignerModal = ({ isOpen, children }) => {
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createPortal(
|
||||
<div className="op-modal op-modal-open">
|
||||
<div className="op-modal-box p-0 min-w-[90%] md:min-w-[500px] max-h-90 overflow-y-auto hide-scrollbar text-sm">
|
||||
{children}
|
||||
</div>
|
||||
</div>,
|
||||
document.body
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* react-sortable-hoc is depcreated not usable from react 18.x.x
|
||||
* need to replace it with @dnd-kit
|
||||
@@ -17,7 +32,6 @@ function arrayMove(array, from, to) {
|
||||
*/
|
||||
|
||||
const SignersInput = (props) => {
|
||||
Modal.setAppElement("body");
|
||||
const [state, setState] = useState(undefined);
|
||||
// const [editFormData, setEditFormData] = useState([]);
|
||||
const [selected, setSelected] = useState([]);
|
||||
@@ -108,15 +122,17 @@ const SignersInput = (props) => {
|
||||
<label className="block relative">
|
||||
Signers
|
||||
{props.required && <span className="text-red-500 text-[13px]">*</span>}
|
||||
<span className="absolute ml-1 text-xs z-50">
|
||||
<span className="absolute ml-1 text-xs z-30">
|
||||
<Tooltip
|
||||
id={"signer-tooltip"}
|
||||
message={"Begin typing a contact's name to see suggested signers from your saved contacts or add new ones. Arrange the signing order by adding signers in the desired sequence. Use the '+' button to include signers and the 'x' to remove them. Each signer will receive an email prompt to sign the document in the order listed."}
|
||||
message={
|
||||
"Begin typing a contact's name to see suggested signers from your saved contacts or add new ones. Arrange the signing order by adding signers in the desired sequence. Use the '+' button to include signers and the 'x' to remove them. Each signer will receive an email prompt to sign the document in the order listed."
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
</label>
|
||||
<div style={{ display: "flex", gap: 5 }}>
|
||||
<div style={{ flexWrap: "wrap", width: "100%" }}>
|
||||
<div className="flex gap-x-[5px]">
|
||||
<div className="w-full">
|
||||
<Select
|
||||
onSortEnd={onSortEnd}
|
||||
distance={4}
|
||||
@@ -126,6 +142,22 @@ const SignersInput = (props) => {
|
||||
onChange={onChange}
|
||||
closeMenuOnSelect={false}
|
||||
required={props.required}
|
||||
noOptionsMessage={() => "Contact not found"}
|
||||
unstyled
|
||||
classNames={{
|
||||
control: () =>
|
||||
"op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full h-full text-[11px]",
|
||||
valueContainer: () =>
|
||||
"flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]",
|
||||
multiValue: () => "op-badge op-badge-primary h-full text-[11px]",
|
||||
multiValueLabel: () => "mb-[2px]",
|
||||
menu: () =>
|
||||
"mt-1 shadow-md rounded-lg bg-base-200 text-base-content",
|
||||
menuList: () => "shadow-md rounded-lg overflow-hidden",
|
||||
option: () =>
|
||||
"bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2",
|
||||
noOptionsMessage: () => "p-2 bg-base-200 rounded-lg m-1 p-2"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
@@ -133,66 +165,29 @@ const SignersInput = (props) => {
|
||||
setIsModel(true);
|
||||
openModal();
|
||||
}}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
borderRadius: 4,
|
||||
border: "1px solid #ccc",
|
||||
minHeight: 38,
|
||||
minWidth: 48,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
className="cursor-pointer op-input op-input-bordered focus:outline-none hover:border-base-content max-h-[38px] min-w-[48px] flex justify-center items-center"
|
||||
>
|
||||
<i className="fas fa-plus"></i>
|
||||
<i className="fa-light fa-plus"></i>
|
||||
</div>
|
||||
<Modal
|
||||
isOpen={modalIsOpen}
|
||||
onRequestClose={handleModalCloseClick}
|
||||
shouldCloseOnOverlayClick={false}
|
||||
id="modal1"
|
||||
contentLabel="Modal"
|
||||
style={{
|
||||
content: {
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
right: "auto",
|
||||
bottom: "auto",
|
||||
transform: "translate(-50%, -50%)",
|
||||
border: "1px transparent",
|
||||
padding: 0
|
||||
},
|
||||
overlay: {
|
||||
width: "100%",
|
||||
backgroundColor: "rgba(0, 0, 0, 0.75)",
|
||||
zIndex: 50
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="min-w-full md:min-w-[500px]">
|
||||
<div
|
||||
className="flex justify-between rounded-t items-center py-[10px] px-[20px] text-white"
|
||||
style={{ background: "#32a3ac" }}
|
||||
>
|
||||
<div className="text-[1.2rem] font-normal">Add Signer</div>
|
||||
<button
|
||||
onClick={handleModalCloseClick}
|
||||
className="text-[1.5rem] cursor-pointer focus:outline-none"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{isModal && (
|
||||
<AddSigner
|
||||
valueKey={"objectId"}
|
||||
displayKey={"Name"}
|
||||
details={handleNewDetails}
|
||||
closePopup={handleModalCloseClick}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
<AddSignerModal isOpen={modalIsOpen}>
|
||||
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||
Add Signer
|
||||
</h3>
|
||||
<button
|
||||
onClick={handleModalCloseClick}
|
||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
{isModal && (
|
||||
<AddSigner
|
||||
valueKey={"objectId"}
|
||||
displayKey={"Name"}
|
||||
details={handleNewDetails}
|
||||
closePopup={handleModalCloseClick}
|
||||
/>
|
||||
)}
|
||||
</AddSignerModal>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { findContact } from "../../../constant/Utils";
|
||||
const SuggestionInput = (props) => {
|
||||
const [inputValue, setInputValue] = useState(props?.value || "");
|
||||
const [suggestions, setSuggestions] = useState([]);
|
||||
const [showSuggestions, setShowSuggestions] = useState(false);
|
||||
const ref = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener("mousedown", Clickout);
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", Clickout);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const Clickout = (event) => {
|
||||
if (ref.current && !ref.current.contains(event.target)) {
|
||||
setShowSuggestions(false);
|
||||
}
|
||||
};
|
||||
// create debounce to avoid unnecessay api calls
|
||||
useEffect(() => {
|
||||
let timer;
|
||||
if (inputValue) {
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
(async () => {
|
||||
const res = await findContact(inputValue);
|
||||
if (res?.length > 0) {
|
||||
setSuggestions(res);
|
||||
setShowSuggestions(true);
|
||||
} else {
|
||||
setSuggestions(res);
|
||||
setShowSuggestions(false);
|
||||
}
|
||||
})();
|
||||
}, 1000);
|
||||
}
|
||||
return () => clearTimeout(timer);
|
||||
}, [inputValue]);
|
||||
|
||||
const handleInputChange = async (e) => {
|
||||
const value = e.target.value;
|
||||
setInputValue(value?.toLowerCase());
|
||||
if (props.onChange) {
|
||||
props.onChange(value);
|
||||
}
|
||||
|
||||
if (value.trim() === "") {
|
||||
setSuggestions([]);
|
||||
setShowSuggestions(false);
|
||||
return;
|
||||
}
|
||||
};
|
||||
const handleSuggestionClick = (suggestion) => {
|
||||
setInputValue(suggestion.Email);
|
||||
setSuggestions([]);
|
||||
setShowSuggestions(false);
|
||||
if (props.onChange) {
|
||||
props.onChange(suggestion);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="flex flex-col items-center relative text-base-content">
|
||||
<input
|
||||
type={props?.type || "text"}
|
||||
value={inputValue}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Enter Email..."
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs lowercase"
|
||||
required={props.required}
|
||||
/>
|
||||
{showSuggestions && (
|
||||
<ul
|
||||
ref={ref}
|
||||
className="absolute z-50 left-0 top-[2.55rem] w-full max-h-[100px] overflow-auto bg-base-200 border border-gray-300 rounded shadow-md"
|
||||
>
|
||||
{suggestions.map((suggestion, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className="py-2 px-2 w-full text-sm cursor-pointer hover:bg-base-300"
|
||||
onClick={() => handleSuggestionClick(suggestion)}
|
||||
>
|
||||
{suggestion.Email}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default SuggestionInput;
|
||||
@@ -3,14 +3,18 @@ import { NavLink } from "react-router-dom";
|
||||
|
||||
const Menu = ({ item, isOpen, closeSidebar }) => {
|
||||
return (
|
||||
<li key={item.title} role="none">
|
||||
<li key={item.title} role="none" className="my-0.5">
|
||||
<NavLink
|
||||
to={
|
||||
item.pageType
|
||||
? `/${item.pageType}/${item.objectId}`
|
||||
: `/${item.objectId}`
|
||||
}
|
||||
className="mx-auto flex items-center hover:bg-[#eef1f5] p-3 lg:p-4 cursor-pointer focus:text-[#0056b3] focus:bg-[#eef1f5]"
|
||||
className={({ isActive }) =>
|
||||
`${
|
||||
isActive ? " bg-base-300 text-base-content" : ""
|
||||
} flex items-center text-left p-3 lg:p-4 text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none`
|
||||
}
|
||||
onClick={closeSidebar}
|
||||
tabIndex={isOpen ? 0 : -1}
|
||||
role="menuitem"
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
import Menu from "./Menu";
|
||||
import Submenu from "./SubMenu";
|
||||
import SocialMedia from "./SocialMedia";
|
||||
|
||||
import Parse from "parse";
|
||||
import dp from "../../assets/images/dp.png";
|
||||
import sidebarList from "../../json/menuJson";
|
||||
|
||||
const Sidebar = ({ isOpen, closeSidebar }) => {
|
||||
const [menuList, setmenuList] = useState([]);
|
||||
const [submenuOpen, setSubmenuOpen] = useState(false);
|
||||
let username = localStorage.getItem("username");
|
||||
const image = localStorage.getItem("profileImg") || dp;
|
||||
const tenantname = localStorage.getItem("TenantName");
|
||||
const tenantname = localStorage.getItem("Extand_Class")
|
||||
? JSON.parse(localStorage.getItem("Extand_Class"))?.[0]?.Company
|
||||
: "";
|
||||
|
||||
useEffect(() => {
|
||||
if (localStorage.getItem("accesstoken")) {
|
||||
@@ -21,22 +22,49 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
|
||||
|
||||
const menuItem = async () => {
|
||||
try {
|
||||
var sideMenu = Parse.Object.extend("w_menu");
|
||||
var query = new Parse.Query(sideMenu);
|
||||
query.equalTo("objectId", localStorage.getItem("defaultmenuid"));
|
||||
const results = await query.first();
|
||||
const resultjson = results.toJSON();
|
||||
let result = resultjson;
|
||||
setmenuList(result.menuItems);
|
||||
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 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);
|
||||
return newItem;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
setmenuList(newSidebarList);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Problem", e);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleSubmenu = (title) => {
|
||||
setSubmenuOpen({ [title]: !submenuOpen[title] });
|
||||
};
|
||||
|
||||
const handleMenuItem = () => {
|
||||
closeSidebar();
|
||||
setSubmenuOpen({});
|
||||
};
|
||||
return (
|
||||
<aside
|
||||
className={`bg-white text-[#444] h-screen w-full md:w-[300px] overflow-y-auto transform transition-transform z-40 md:translate-x-0
|
||||
${isOpen ? "translate-x-0 block" : "-translate-x-full hidden"}`}
|
||||
className={`absolute lg:relative bg-base-100 h-screen overflow-y-auto transition-all z-[999] 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">
|
||||
@@ -47,13 +75,20 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-[14px] font-bold">{username}</p>
|
||||
<p className={`text-[12px] ${tenantname ? "mt-2" : ""}`}>
|
||||
<p className="text-[14px] font-bold text-base-content">{username}</p>
|
||||
<p
|
||||
className={`text-[12px] text-base-content ${
|
||||
tenantname ? "mt-2" : ""
|
||||
}`}
|
||||
>
|
||||
{tenantname}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<nav aria-label="OpenSign Sidebar Navigation">
|
||||
<nav
|
||||
className="op-menu op-menu-sm"
|
||||
aria-label="OpenSign Sidebar Navigation"
|
||||
>
|
||||
<ul
|
||||
className="text-sm"
|
||||
role="menubar"
|
||||
@@ -65,19 +100,21 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
|
||||
key={item.title}
|
||||
item={item}
|
||||
isOpen={isOpen}
|
||||
closeSidebar={closeSidebar}
|
||||
closeSidebar={handleMenuItem}
|
||||
/>
|
||||
) : (
|
||||
<Submenu
|
||||
key={item.title}
|
||||
item={item}
|
||||
closeSidebar={closeSidebar}
|
||||
toggleSubmenu={toggleSubmenu}
|
||||
submenuOpen={submenuOpen}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
</nav>
|
||||
<footer className="mt-4 flex justify-center items-center text-[25px] text-black gap-3">
|
||||
<footer className="mt-4 flex justify-center items-center text-[25px] text-base-content gap-3">
|
||||
<SocialMedia />
|
||||
</footer>
|
||||
</aside>
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
import { NavLink } from "react-router-dom";
|
||||
|
||||
const Submenu = ({ item, closeSidebar }) => {
|
||||
const [submenuOpen, setSubmenuOpen] = useState(false);
|
||||
const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
|
||||
const { title, icon, children } = item;
|
||||
|
||||
const toggleSubmenu = () => {
|
||||
setSubmenuOpen(!submenuOpen);
|
||||
};
|
||||
|
||||
return (
|
||||
<li role="none">
|
||||
<li role="none" className="my-0.5">
|
||||
<button
|
||||
onClick={toggleSubmenu}
|
||||
className="w-full flex items-center text-left text-[#444] p-3 lg:p-4 hover:bg-[#eef1f5] focus:outline-none focus:text-[#0056b3] focus:bg-[#eef1f5]"
|
||||
onClick={() => toggleSubmenu(item.title)}
|
||||
className="flex items-center text-left p-3 lg:p-4 text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none "
|
||||
aria-expanded={submenuOpen}
|
||||
aria-haspopup="true"
|
||||
aria-controls={`submenu-${title}`}
|
||||
@@ -23,23 +17,29 @@ const Submenu = ({ item, closeSidebar }) => {
|
||||
<span className="ml-3 lg:ml-4">{title}</span>
|
||||
<i
|
||||
className={`${
|
||||
submenuOpen ? "fa-solid fa-angle-down" : "fa-solid fa-angle-right"
|
||||
submenuOpen[item.title]
|
||||
? "fa-light fa-angle-down"
|
||||
: "fa-light fa-angle-right"
|
||||
}`}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</div>
|
||||
</button>
|
||||
{submenuOpen && (
|
||||
{submenuOpen[item.title] && (
|
||||
<ul id={`submenu-${title}`} role="menu" aria-label={`${title} submenu`}>
|
||||
{children.map((childItem) => (
|
||||
<li key={childItem.title} role="none">
|
||||
<li key={childItem.title} role="none" className="my-0.5">
|
||||
<NavLink
|
||||
to={
|
||||
childItem.pageType
|
||||
? `/${childItem.pageType}/${childItem.objectId}`
|
||||
: `/${childItem.objectId}`
|
||||
}
|
||||
className="block pl-6 md:pl-8 py-2 text-sm text-gray-700 hover:bg-blue-500 hover:text-white focus:text-[#0056b3] focus:bg-[#eef1f5] cursor-pointer"
|
||||
className={({ isActive }) =>
|
||||
`${
|
||||
isActive ? "bg-base-300 text-base-content" : ""
|
||||
} flex items-center text-left pl-6 md:pl-8 py-2 text-sm cursor-pointer text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none`
|
||||
}
|
||||
onClick={closeSidebar}
|
||||
role="menuitem"
|
||||
tabIndex={submenuOpen ? 0 : -1}
|
||||
|
||||
+496
-343
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,6 @@
|
||||
export const contactCls = "contracts_Contactbook";
|
||||
export const templateCls = "contracts_Template";
|
||||
export const documentCls = "contracts_Document";
|
||||
export const rejectBtn =
|
||||
"bg-[#ffffff] rounded-sm shadow-md text-[12px] font-semibold uppercase text-black py-1.5 px-4 focus:outline-none text-center border-[1px] border-[#b4b4b4]";
|
||||
export const submitBtn =
|
||||
"bg-[#32a3ac] rounded-sm shadow-md text-[12px] font-semibold uppercase text-white py-1.5 px-4 focus:outline-none text-center";
|
||||
export const modalSubmitBtnColor = "#17a2b8";
|
||||
export const modalCancelBtnColor = "white";
|
||||
export const themeColor = "#47a3ad";
|
||||
export const iconColor = "#686968";
|
||||
export const isEnableSubscription = process.env.REACT_APP_ENABLE_SUBSCRIPTION;
|
||||
|
||||
@@ -2,17 +2,72 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body{
|
||||
background-color: white;
|
||||
body {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/* Custom CSS to hide scrollbar */
|
||||
.hide-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hide-scrollbar {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.hide-scrollbar {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
|
||||
/* below css class replace bootstrap background color with daisy */
|
||||
.op-bg-primary {
|
||||
@apply bg-primary;
|
||||
}
|
||||
.op-bg-secondary {
|
||||
@apply bg-secondary;
|
||||
}
|
||||
.op-bg-info {
|
||||
@apply bg-info;
|
||||
}
|
||||
.op-bg-success{
|
||||
@apply bg-success;
|
||||
}
|
||||
.op-bg-warning {
|
||||
@apply bg-warning;
|
||||
}
|
||||
|
||||
/* below css class replace bootstrap text color with daisy */
|
||||
.op-text-primary {
|
||||
@apply text-primary;
|
||||
}
|
||||
.op-text-secondary {
|
||||
@apply text-secondary;
|
||||
}
|
||||
.op-text-info {
|
||||
@apply text-info;
|
||||
}
|
||||
.op-text-success{
|
||||
@apply text-success;
|
||||
}
|
||||
.op-text-warning {
|
||||
@apply text-warning;
|
||||
}
|
||||
.op-border-primary{
|
||||
@apply border-primary
|
||||
}
|
||||
/* CSS for scrollbar customization */
|
||||
* {
|
||||
scrollbar-width: thin; /* For Firefox */
|
||||
scrollbar-color: gray; /* For Firefox */
|
||||
}
|
||||
|
||||
/* For webkit-based browsers like Chrome, Safari */
|
||||
*::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background-color: gray;
|
||||
border-radius: 10px;
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
import DragElement from "./components/pdf/DragElement";
|
||||
import TagManager from "react-gtm-module";
|
||||
import Parse from "parse";
|
||||
import './polyfills'
|
||||
const appId = process.env.REACT_APP_APPID
|
||||
? process.env.REACT_APP_APPID
|
||||
: "opensign";
|
||||
|
||||
@@ -3,7 +3,7 @@ export default function reportJson(id) {
|
||||
const head = ["Sr.No", "Title", "Note", "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"];
|
||||
switch (id) {
|
||||
// draft documents report
|
||||
case "ByHuevtCFY":
|
||||
@@ -14,18 +14,16 @@ export default function reportJson(id) {
|
||||
{
|
||||
btnId: "1231",
|
||||
hoverLabel: "Edit",
|
||||
btnColor: "#4bd396",
|
||||
textColor: "white",
|
||||
btnIcon: "fa-solid fa-pen",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-pen",
|
||||
redirectUrl: "draftDocument",
|
||||
action: "redirect"
|
||||
},
|
||||
{
|
||||
btnId: "2142",
|
||||
hoverLabel: "Delete",
|
||||
btnColor: "#ff4848",
|
||||
textColor: "white",
|
||||
btnIcon: "fa fa-trash",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-trash",
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
}
|
||||
@@ -43,9 +41,8 @@ export default function reportJson(id) {
|
||||
btnId: "4536",
|
||||
btnLabel: "sign",
|
||||
hoverLabel: "Sign",
|
||||
btnColor: "#3ac9d6",
|
||||
textColor: "white",
|
||||
btnIcon: "fa-solid fa-signature",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-signature",
|
||||
redirectUrl: "pdfRequestFiles",
|
||||
action: "redirect"
|
||||
}
|
||||
@@ -62,34 +59,40 @@ export default function reportJson(id) {
|
||||
{
|
||||
btnId: "8901",
|
||||
hoverLabel: "Share",
|
||||
btnColor: "#4bd396",
|
||||
textColor: "white",
|
||||
btnIcon: "fa-solid fa-share",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-share",
|
||||
redirectUrl: "",
|
||||
action: "share"
|
||||
},
|
||||
{
|
||||
btnId: "1588",
|
||||
hoverLabel: "View",
|
||||
btnColor: "#3ac9d6",
|
||||
textColor: "white",
|
||||
btnIcon: "fa fa-eye",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-eye",
|
||||
redirectUrl: "pdfRequestFiles",
|
||||
action: "redirect"
|
||||
},
|
||||
{
|
||||
btnId: "2234",
|
||||
hoverLabel: "option",
|
||||
btnColor: "transparent",
|
||||
btnColor: "",
|
||||
textColor: "black",
|
||||
btnIcon: "fa-solid fa-ellipsis-vertical fa-lg",
|
||||
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
|
||||
action: "option",
|
||||
subaction: [
|
||||
{
|
||||
btnId: "1630",
|
||||
btnLabel: "Resend",
|
||||
hoverLabel: "Resend",
|
||||
btnIcon: "fa-light fa-envelope",
|
||||
redirectUrl: "",
|
||||
action: "resend"
|
||||
},
|
||||
{
|
||||
btnId: "1688",
|
||||
btnLabel: "Revoke",
|
||||
hoverLabel: "Revoke",
|
||||
btnIcon: "fa-solid fa-file-circle-xmark",
|
||||
btnIcon: "fa-light fa-file-circle-xmark",
|
||||
redirectUrl: "",
|
||||
action: "revoke"
|
||||
},
|
||||
@@ -97,7 +100,7 @@ export default function reportJson(id) {
|
||||
btnId: "1488",
|
||||
btnLabel: "Delete",
|
||||
hoverLabel: "Delete",
|
||||
btnIcon: "fa fa-trash",
|
||||
btnIcon: "fa-light fa-trash",
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
}
|
||||
@@ -116,18 +119,16 @@ export default function reportJson(id) {
|
||||
{
|
||||
btnId: "1378",
|
||||
hoverLabel: "Edit",
|
||||
btnColor: "#4bd396",
|
||||
textColor: "white",
|
||||
btnIcon: "fa fa-eye",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-eye",
|
||||
redirectUrl: "draftDocument",
|
||||
action: "redirect"
|
||||
},
|
||||
{
|
||||
btnId: "1278",
|
||||
hoverLabel: "Delete",
|
||||
btnColor: "#ff4848",
|
||||
textColor: "white",
|
||||
btnIcon: "fa fa-trash",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-trash",
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
}
|
||||
@@ -144,18 +145,16 @@ export default function reportJson(id) {
|
||||
{
|
||||
btnId: "1458",
|
||||
hoverLabel: "View",
|
||||
btnColor: "#4bd396",
|
||||
textColor: "white",
|
||||
btnIcon: "fa fa-eye",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-eye",
|
||||
redirectUrl: "draftDocument",
|
||||
action: "redirect"
|
||||
},
|
||||
{
|
||||
btnId: "1358",
|
||||
hoverLabel: "Delete",
|
||||
btnColor: "#ff4848",
|
||||
textColor: "white",
|
||||
btnIcon: "fa fa-trash",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-trash",
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
}
|
||||
@@ -172,18 +171,16 @@ export default function reportJson(id) {
|
||||
{
|
||||
btnId: "1898",
|
||||
hoverLabel: "View",
|
||||
btnColor: "#4bd396",
|
||||
textColor: "white",
|
||||
btnIcon: "fa fa-eye",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-eye",
|
||||
redirectUrl: "draftDocument",
|
||||
action: "redirect"
|
||||
},
|
||||
{
|
||||
btnId: "1998",
|
||||
hoverLabel: "Delete",
|
||||
btnColor: "#ff4848",
|
||||
textColor: "white",
|
||||
btnIcon: "fa fa-trash",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-trash",
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
}
|
||||
@@ -200,34 +197,40 @@ export default function reportJson(id) {
|
||||
{
|
||||
btnId: "1999",
|
||||
hoverLabel: "Share",
|
||||
btnColor: "#4bd396",
|
||||
textColor: "white",
|
||||
btnIcon: "fa-solid fa-share",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-share",
|
||||
redirectUrl: "",
|
||||
action: "share"
|
||||
},
|
||||
{
|
||||
btnId: "1999",
|
||||
hoverLabel: "View",
|
||||
btnColor: "#3ac9d6",
|
||||
textColor: "white",
|
||||
btnIcon: "fa fa-eye",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-eye",
|
||||
redirectUrl: "pdfRequestFiles",
|
||||
action: "redirect"
|
||||
},
|
||||
{
|
||||
btnId: "2234",
|
||||
hoverLabel: "option",
|
||||
btnColor: "transparent",
|
||||
btnColor: "",
|
||||
textColor: "black",
|
||||
btnIcon: "fa-solid fa-ellipsis-vertical fa-lg",
|
||||
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
|
||||
action: "option",
|
||||
subaction: [
|
||||
{
|
||||
btnId: "1631",
|
||||
btnLabel: "Resend",
|
||||
hoverLabel: "Resend",
|
||||
btnIcon: "fa-light fa-envelope",
|
||||
redirectUrl: "",
|
||||
action: "resend"
|
||||
},
|
||||
{
|
||||
btnId: "6788",
|
||||
btnLabel: "Revoke",
|
||||
hoverLabel: "Revoke",
|
||||
btnIcon: "fa-solid fa-file-circle-xmark",
|
||||
btnIcon: "fa-light fa-file-circle-xmark",
|
||||
redirectUrl: "",
|
||||
action: "revoke"
|
||||
},
|
||||
@@ -235,7 +238,7 @@ export default function reportJson(id) {
|
||||
btnId: "2000",
|
||||
btnLabel: "Delete",
|
||||
hoverLabel: "Delete",
|
||||
btnIcon: "fa fa-trash",
|
||||
btnIcon: "fa-light fa-trash",
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
}
|
||||
@@ -253,9 +256,8 @@ export default function reportJson(id) {
|
||||
btnId: "2001",
|
||||
btnLabel: "sign",
|
||||
hoverLabel: "Sign",
|
||||
btnColor: "#3ac9d6",
|
||||
textColor: "white",
|
||||
btnIcon: "fa-solid fa-signature",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-signature",
|
||||
redirectUrl: "pdfRequestFiles",
|
||||
action: "redirect"
|
||||
}
|
||||
@@ -270,18 +272,16 @@ export default function reportJson(id) {
|
||||
{
|
||||
btnId: "2003",
|
||||
hoverLabel: "Edit",
|
||||
btnColor: "#4bd396",
|
||||
textColor: "white",
|
||||
btnIcon: "fa-solid fa-pen",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-pen",
|
||||
redirectUrl: "draftDocument",
|
||||
action: "redirect"
|
||||
},
|
||||
{
|
||||
btnId: "2004",
|
||||
hoverLabel: "Delete",
|
||||
btnColor: "#ff4848",
|
||||
textColor: "white",
|
||||
btnIcon: "fa fa-trash",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-trash",
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
}
|
||||
@@ -296,9 +296,8 @@ export default function reportJson(id) {
|
||||
{
|
||||
btnId: "2204",
|
||||
hoverLabel: "Delete",
|
||||
btnColor: "#f55a42",
|
||||
textColor: "white",
|
||||
btnIcon: "fa-solid fa-trash",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-trash",
|
||||
action: "delete"
|
||||
}
|
||||
],
|
||||
@@ -310,27 +309,38 @@ export default function reportJson(id) {
|
||||
case "6TeaPr321t":
|
||||
return {
|
||||
reportName: "Templates",
|
||||
heading: head,
|
||||
heading: templateReport,
|
||||
actions: [
|
||||
{
|
||||
btnId: "2234",
|
||||
btnLabel: "Use",
|
||||
hoverLabel: "Use",
|
||||
btnColor: "#4bd396",
|
||||
textColor: "white",
|
||||
btnIcon: "fa fa-plus",
|
||||
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: "transparent",
|
||||
btnColor: "",
|
||||
textColor: "black",
|
||||
btnIcon: "fa-solid fa-ellipsis-vertical fa-lg",
|
||||
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
|
||||
action: "option",
|
||||
selector: "reactourThird",
|
||||
message:
|
||||
@@ -340,7 +350,7 @@ export default function reportJson(id) {
|
||||
btnId: "2434",
|
||||
btnLabel: "Edit",
|
||||
hoverLabel: "Edit",
|
||||
btnIcon: "fa-solid fa-pen",
|
||||
btnIcon: "fa-light fa-pen",
|
||||
redirectUrl: "template",
|
||||
action: "redirect"
|
||||
},
|
||||
@@ -348,7 +358,7 @@ export default function reportJson(id) {
|
||||
btnId: "1834",
|
||||
btnLabel: "Delete",
|
||||
hoverLabel: "Delete",
|
||||
btnIcon: "fa fa-trash",
|
||||
btnIcon: "fa-light fa-trash",
|
||||
redirectUrl: "",
|
||||
action: "delete"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
const dashboardJson = [
|
||||
{
|
||||
id: "35KBoSgoAK",
|
||||
columns: [
|
||||
{
|
||||
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
|
||||
widget: {
|
||||
type: "Card",
|
||||
icon: "fa-light fa-signature",
|
||||
bgColor: "op-bg-primary",
|
||||
label: "Need your Signature",
|
||||
description: null,
|
||||
data: {
|
||||
id: "e04ee9dc-932d-6b80-0202-703fd154eb74",
|
||||
queryType: "",
|
||||
class: "contracts_Document",
|
||||
query:
|
||||
'where={"$and":[{"AuditTrail.UserPtr":{"$ne":{"__type":"Pointer","className": "contracts_Users","objectId":"#objectId#"}}},{"AuditTrail.Activity":{"$ne":"Signed"}}],"Signers":{"$in":[{"__type":"Pointer","className":"contracts_Users","objectId":"#objectId#"}]},"IsDeclined":{"$ne":true},"IsCompleted":{"$ne":true},"Type":{"$ne":"Folder"},"Placeholders":{"$ne":null},"ExpiryDate":{"#*gt":{"__type":"#Date#","iso":"#today#"}}}&count=1',
|
||||
key: "count",
|
||||
Redirect_type: "Report",
|
||||
Redirect_id: "4Hhwbp482K",
|
||||
tourSection: "tourcard1",
|
||||
tourMessage:
|
||||
"Clicking on this card will take you to the list of documents awaiting your review."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
|
||||
widget: {
|
||||
type: "Card",
|
||||
icon: "fa-light fa-sign-out-alt",
|
||||
bgColor: "op-bg-secondary",
|
||||
label: "Out for signatures",
|
||||
description: null,
|
||||
data: {
|
||||
id: "c1935cc0-28d4-3d73-b72a-8c1e3d18a17f",
|
||||
queryType: "",
|
||||
class: "contracts_Document",
|
||||
query:
|
||||
'where={"Type":{"#*ne":"Folder"},"Signers":{"#*exists":true,"#*ne":[]},"Placeholders":{"#*ne":null},"IsCompleted":{"#*ne":true},"IsDeclined":{"#*ne":true},"IsArchive":{"#*ne":true},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"#UserId.objectId#"},"ExpiryDate":{"#*gt":{"__type":"#Date#","iso":"#today#"}}}&count=1',
|
||||
key: "count",
|
||||
Redirect_type: "Report",
|
||||
Redirect_id: "1MwEuxLEkF",
|
||||
tourSection: "tourcard2",
|
||||
tourMessage:
|
||||
"Clicking on this card will take you to a list of documents awaiting signature."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
|
||||
widget: {
|
||||
type: "report",
|
||||
reportId: "5Go51Q7T8r",
|
||||
data: {
|
||||
tourSection: "tourreport1",
|
||||
tourMessage:
|
||||
"This is a list of documents that are waiting for your signature."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
|
||||
widget: {
|
||||
type: "report",
|
||||
reportId: "d9k3UfYHBc",
|
||||
data: {
|
||||
tourSection: "tourreport2",
|
||||
tourMessage:
|
||||
"This is a list of documents you've sent to other parties for signature."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
colsize: "col-span-12 md:col-span-12 lg:col-span-12",
|
||||
widget: {
|
||||
type: "report",
|
||||
reportId: "kC5mfynCi4",
|
||||
data: {
|
||||
tourSection: "tourreport3",
|
||||
tourMessage:
|
||||
"This are documents you have started but have not finalized for sending."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
export default dashboardJson;
|
||||
@@ -0,0 +1,161 @@
|
||||
const sidebarList = [
|
||||
{
|
||||
icon: "fa-light fa-tachometer-alt",
|
||||
title: "Dashboard",
|
||||
target: "",
|
||||
pageType: "dashboard",
|
||||
description: "",
|
||||
objectId: "35KBoSgoAK"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-pen-nib",
|
||||
title: "Sign yourself",
|
||||
target: "_self",
|
||||
pageType: "form",
|
||||
description: "",
|
||||
objectId: "sHAnZphf69"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-paper-plane",
|
||||
title: "Request signatures",
|
||||
target: "_self",
|
||||
pageType: "form",
|
||||
description: "",
|
||||
objectId: "8mZzFxbG1z"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-newspaper",
|
||||
title: "Templates",
|
||||
target: "_self",
|
||||
pageType: null,
|
||||
description: null,
|
||||
objectId: null,
|
||||
children: [
|
||||
{
|
||||
icon: "fa-light fa-file-signature",
|
||||
title: "Create template",
|
||||
target: "_self",
|
||||
pageType: "form",
|
||||
description: "",
|
||||
objectId: "template"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-file-contract",
|
||||
title: "Manage templates",
|
||||
target: "_self",
|
||||
pageType: "report",
|
||||
description: "",
|
||||
objectId: "6TeaPr321t"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-folder",
|
||||
title: "OpenSign™ Drive",
|
||||
target: "_self",
|
||||
pageType: "",
|
||||
description: "",
|
||||
objectId: "opensigndrive"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-address-card",
|
||||
title: "Reports",
|
||||
target: "_self",
|
||||
pageType: null,
|
||||
description: "",
|
||||
objectId: null,
|
||||
children: [
|
||||
{
|
||||
icon: "fa-light fa-signature",
|
||||
title: "Need your sign",
|
||||
target: "_self",
|
||||
pageType: "report",
|
||||
description: "",
|
||||
objectId: "4Hhwbp482K"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-tasks",
|
||||
title: "In Progress",
|
||||
target: "_self",
|
||||
pageType: "report",
|
||||
description: "",
|
||||
objectId: "1MwEuxLEkF"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-check-circle",
|
||||
title: "Completed",
|
||||
target: "_self",
|
||||
pageType: "report",
|
||||
description: "",
|
||||
objectId: "kQUoW4hUXz"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-edit",
|
||||
title: "Drafts",
|
||||
target: "_self",
|
||||
pageType: "report",
|
||||
description: "",
|
||||
objectId: "ByHuevtCFY"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-times-circle",
|
||||
title: "Declined",
|
||||
target: "_self",
|
||||
pageType: "report",
|
||||
description: "",
|
||||
objectId: "UPr2Fm5WY3"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-hourglass-end",
|
||||
title: "Expired",
|
||||
target: "_self",
|
||||
pageType: "report",
|
||||
description: "",
|
||||
objectId: "zNqBHXHsYH"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-address-book",
|
||||
title: "Contactbook",
|
||||
target: "_self",
|
||||
pageType: "report",
|
||||
description: "",
|
||||
objectId: "5KhaPr482K"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-cog",
|
||||
title: "Settings",
|
||||
target: "_self",
|
||||
pageType: null,
|
||||
description: "",
|
||||
objectId: null,
|
||||
children: [
|
||||
{
|
||||
icon: "fa-light fa-pen-fancy",
|
||||
title: "My Signature",
|
||||
target: "_self",
|
||||
pageType: "",
|
||||
description: "",
|
||||
objectId: "managesign"
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-key",
|
||||
title: "API Token",
|
||||
target: "_self",
|
||||
pageType: "generatetoken",
|
||||
description: "",
|
||||
objectId: ""
|
||||
},
|
||||
{
|
||||
icon: "fa-light fa-globe",
|
||||
title: "Webhook",
|
||||
target: "_self",
|
||||
pageType: "webhook",
|
||||
description: "",
|
||||
objectId: ""
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
export default sidebarList;
|
||||
@@ -52,7 +52,8 @@ const plans = [
|
||||
"API Access",
|
||||
"100 API signatures included",
|
||||
"DocumentId removal from signed docs",
|
||||
"Custom email templates"
|
||||
"Custom email templates",
|
||||
"Auto reminders"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -5,17 +5,20 @@ import Sidebar from "../components/sidebar/Sidebar";
|
||||
import { useWindowSize } from "../hook/useWindowSize";
|
||||
import Tour from "reactour";
|
||||
import axios from "axios";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import Parse from "parse";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import { useNavigate, useLocation, Outlet } from "react-router-dom";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { useCookies } from "react-cookie";
|
||||
import { fetchSubscription } from "../constant/Utils";
|
||||
import Loader from "../primitives/Loader";
|
||||
import { showHeader } from "../redux/reducers/showHeader";
|
||||
|
||||
const HomeLayout = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const dispatch = useDispatch();
|
||||
const { width } = useWindowSize();
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
const arr = useSelector((state) => state.TourSteps);
|
||||
@@ -97,6 +100,7 @@ const HomeLayout = () => {
|
||||
}
|
||||
const showSidebar = () => {
|
||||
setIsOpen((value) => !value);
|
||||
dispatch(showHeader(!isOpen));
|
||||
};
|
||||
useEffect(() => {
|
||||
if (width && width <= 768) {
|
||||
@@ -230,7 +234,7 @@ const HomeLayout = () => {
|
||||
}
|
||||
|
||||
const closeSidebar = () => {
|
||||
if (width <= 768) {
|
||||
if (width <= 1023) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
@@ -247,27 +251,14 @@ const HomeLayout = () => {
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<div className="sticky top-0 z-50">
|
||||
<div className="sticky top-0 z-[101]">
|
||||
{!isLoader && <Header showSidebar={showSidebar} />}
|
||||
</div>
|
||||
{isUserValid ? (
|
||||
<>
|
||||
{isLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="flex h-[100vh] justify-center items-center">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
@@ -277,7 +268,7 @@ const HomeLayout = () => {
|
||||
id="renderList"
|
||||
className="relative h-screen flex flex-col justify-between w-full overflow-y-auto"
|
||||
>
|
||||
<div className="bg-[#eef1f5] p-3">{<Outlet />}</div>
|
||||
<div className="bg-base-200 p-3">{<Outlet />}</div>
|
||||
<div className="z-30">
|
||||
<Footer />
|
||||
</div>
|
||||
@@ -298,13 +289,10 @@ const HomeLayout = () => {
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<ModalUi title={"Session Expired"} isOpen={true} showClose={false}>
|
||||
<ModalUi showHeader={false} isOpen={true} showClose={false}>
|
||||
<div className="flex flex-col justify-center items-center py-4 md:py-5 gap-5">
|
||||
<p className="text-xl font-normal">Your session has expired.</p>
|
||||
<button
|
||||
onClick={handleLoginBtn}
|
||||
className="text-base px-3 py-1.5 rounded shadow-md text-white bg-[#1ab6ce]"
|
||||
>
|
||||
<p className="text-xl font-medium">Your session has expired.</p>
|
||||
<button onClick={handleLoginBtn} className="op-btn op-btn-neutral">
|
||||
Login
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -49,13 +49,13 @@ function ChangePassword() {
|
||||
return <Navigate to="/" />;
|
||||
}
|
||||
return (
|
||||
<div className="w-full bg-white shadow rounded p-2">
|
||||
<Title title={"Change Password"} />
|
||||
<div className="w-full bg-base-100 text-base-content shadow rounded-box p-2">
|
||||
<Title title="Change Password" />
|
||||
<div className="text-xl font-bold border-b-[1px] border-gray-300">
|
||||
Change Password
|
||||
</div>
|
||||
<div className="m-2">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<form onSubmit={handleSubmit} className=" flex flex-col gap-y-2">
|
||||
<div>
|
||||
<label htmlFor="currentpassword" className="block text-xs ml-1">
|
||||
Current Password
|
||||
@@ -65,7 +65,7 @@ function ChangePassword() {
|
||||
name="currentpassword"
|
||||
value={currentpassword}
|
||||
onChange={(e) => setCurrentPassword(e.target.value)}
|
||||
className="px-3 py-2 mb-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-input op-input-bordered op-input-sm text-xs w-full"
|
||||
placeholder="Current Password"
|
||||
required
|
||||
/>
|
||||
@@ -79,7 +79,7 @@ function ChangePassword() {
|
||||
name="newpassword"
|
||||
value={newpassword}
|
||||
onChange={(e) => setnewpassword(e.target.value)}
|
||||
className="px-3 py-2 mb-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-input op-input-bordered op-input-sm text-xs w-full"
|
||||
placeholder="New Password"
|
||||
required
|
||||
/>
|
||||
@@ -91,7 +91,7 @@ function ChangePassword() {
|
||||
<input
|
||||
type="password"
|
||||
name="confirmpassword"
|
||||
className="px-3 py-2 mb-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-input op-input-bordered op-input-sm text-xs w-full"
|
||||
value={confirmpassword}
|
||||
onChange={(e) => setconfirmpassword(e.target.value)}
|
||||
placeholder="Confirm Password"
|
||||
@@ -100,7 +100,7 @@ function ChangePassword() {
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-[#188ae2] m-2 px-4 py-3 rounded-sm shadow-md text-white text-xs font-semibold uppercase"
|
||||
className="op-btn op-btn-primary shadow-md mt-2"
|
||||
>
|
||||
Change Password
|
||||
</button>
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Parse from "parse";
|
||||
import "../styles/loader.css";
|
||||
import GetDashboard from "../components/dashboard/GetDashboard";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import Title from "../components/Title";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { saveTourSteps } from "../redux/reducers/TourStepsReducer";
|
||||
import dashboardJson from "../json/dashboardJson";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
const Dashboard = () => {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const { id } = useParams();
|
||||
const [dashboard, setdashboard] = useState([]);
|
||||
const [classnameArray, setclassnameArray] = useState([]);
|
||||
const [loading, setloading] = useState(false);
|
||||
const [defaultQuery, setDefaultQuery] = useState("");
|
||||
const [dashboard, setdashboard] = useState({});
|
||||
const [loading, setloading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (localStorage.getItem("accesstoken")) {
|
||||
@@ -30,53 +28,10 @@ const Dashboard = () => {
|
||||
}, [id]);
|
||||
|
||||
const getDashboard = async (id) => {
|
||||
setloading(true);
|
||||
try {
|
||||
var forms = Parse.Object.extend("w_dashboard");
|
||||
var query = new Parse.Query(forms);
|
||||
query.equalTo("objectId", id);
|
||||
const results = await query.first();
|
||||
const resultjson = results.toJSON();
|
||||
let classArray = [];
|
||||
let DefaultQuery = "";
|
||||
resultjson.rows.forEach((x) => {
|
||||
let col_lg = "",
|
||||
col_md = "",
|
||||
col_xs = "",
|
||||
col_sm = "",
|
||||
col_ = "",
|
||||
obj = {};
|
||||
let subItem = [];
|
||||
let item = "";
|
||||
x.columns.forEach((y) => {
|
||||
if (y.widget.type === "customeHtml") {
|
||||
DefaultQuery = y.widget.data[0].default;
|
||||
}
|
||||
if (Number(y["collg"]) > 0) {
|
||||
col_lg = "col-lg-" + y["collg"];
|
||||
}
|
||||
if (Number(y["colmd"]) > 0) {
|
||||
col_md = "col-md-" + y["colmd"];
|
||||
}
|
||||
if (Number(y["colxs"]) > 0) {
|
||||
col_xs = "col-xs-" + y["colxs"];
|
||||
}
|
||||
if (Number(y["colsm"]) > 0) {
|
||||
col_sm = "col-sm-" + y["colsm"];
|
||||
}
|
||||
if (Number(y["col"]) > 0) {
|
||||
col_ = "col-" + y["col"];
|
||||
}
|
||||
item =
|
||||
col_lg + " " + col_md + " " + col_xs + " " + col_sm + " " + col_;
|
||||
subItem.push(item);
|
||||
});
|
||||
obj = subItem;
|
||||
classArray.push(obj);
|
||||
});
|
||||
setdashboard(resultjson.rows);
|
||||
// console.log("resultjson.rows ", resultjson.rows);
|
||||
const arr = resultjson.rows[0].columns
|
||||
const dashboard = dashboardJson.find((x) => x.id === id);
|
||||
setdashboard(dashboard);
|
||||
const dashboardTour = dashboard.columns
|
||||
.filter((col) => {
|
||||
if (col.widget.data && col.widget.data.tourSection) {
|
||||
return col;
|
||||
@@ -90,14 +45,7 @@ const Dashboard = () => {
|
||||
// style: { backgroundColor: "#abd4d2" },
|
||||
};
|
||||
});
|
||||
dispatch(saveTourSteps(arr));
|
||||
// console.log("arr ", arr);
|
||||
setclassnameArray(classArray);
|
||||
if (localStorage.getItem("DashboardDefaultFilter")) {
|
||||
setDefaultQuery(localStorage.getItem("DashboardDefaultFilter"));
|
||||
} else {
|
||||
setDefaultQuery(DefaultQuery);
|
||||
}
|
||||
dispatch(saveTourSteps(dashboardTour));
|
||||
setloading(false);
|
||||
} catch (e) {
|
||||
console.error("Problem", e);
|
||||
@@ -105,32 +53,16 @@ const Dashboard = () => {
|
||||
}
|
||||
};
|
||||
|
||||
let _dash = (
|
||||
<GetDashboard
|
||||
dashboard={dashboard}
|
||||
classnameArray={classnameArray}
|
||||
DefaultQuery={defaultQuery}
|
||||
/>
|
||||
);
|
||||
if (loading) {
|
||||
_dash = (
|
||||
<div style={{ height: "300px", backgroundColor: "white" }}>
|
||||
<div
|
||||
style={{
|
||||
marginLeft: "45%",
|
||||
marginTop: "150px",
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Title title="Dashboard" />
|
||||
{_dash}
|
||||
{loading ? (
|
||||
<div className="h-[300px] w-full bg-white flex justify-center items-center rounded-md">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<GetDashboard dashboard={dashboard} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage";
|
||||
import "../styles/signature.css";
|
||||
import "../styles/AddUser.css";
|
||||
import Title from "../components/Title";
|
||||
import RenderDebugPdf from "../components/RenderDebugPdf";
|
||||
import { pdfjs } from "react-pdf";
|
||||
@@ -58,7 +56,7 @@ const DebugPdf = () => {
|
||||
const fetchPdfMetadata = async () => {
|
||||
try {
|
||||
const pdfDataURL = URL.createObjectURL(pdf); // Convert File to data URL
|
||||
console.log("pdfDataURL ", pdfDataURL);
|
||||
// console.log("pdfDataURL ", pdfDataURL);
|
||||
const pdfInfo = await pdfjs.getDocument({ url: pdfDataURL }).promise;
|
||||
const pdfType = await inferPdfType(pdfInfo);
|
||||
setPdfDetails((prevDetails) => ({
|
||||
@@ -76,7 +74,7 @@ const DebugPdf = () => {
|
||||
|
||||
const inferPdfType = async (pdf) => {
|
||||
try {
|
||||
const firstPage = await pdf.getPage(1);
|
||||
const firstPage = await pdf.getPage(2);
|
||||
const scale = 1;
|
||||
const { width, height } = firstPage.getViewport({ scale });
|
||||
setPdfDimension({ width: width, height: height });
|
||||
@@ -217,14 +215,18 @@ const DebugPdf = () => {
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
{copied && <Alert type="success">Copied</Alert>}
|
||||
{copied && (
|
||||
<Alert type="success">
|
||||
<span className="ml-3">Copied</span>
|
||||
</Alert>
|
||||
)}
|
||||
<Title title={"Debug Pdf"} />
|
||||
{width < 800 ? (
|
||||
<HandleError handleError={"Debug PDF only availble for PC"} />
|
||||
) : (
|
||||
<>
|
||||
{!isModal && (
|
||||
<div className="signatureContainer">
|
||||
<div className="flex flex-row justify-between">
|
||||
{/* this component used to render all pdf pages in left side */}
|
||||
<RenderAllPdfPage
|
||||
signPdfUrl={pdf}
|
||||
@@ -253,126 +255,68 @@ const DebugPdf = () => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ backgroundColor: "white", width: 220 }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 18,
|
||||
fontWeight: 500,
|
||||
padding: "10px 12px",
|
||||
borderBottom: "1px solid grey"
|
||||
}}
|
||||
>
|
||||
<div className="w-[220px] bg-base-100">
|
||||
<div className="text-[18px] font-medium py-[10px] px-[12px] border-b-[1px] border-[gray]">
|
||||
PDF details
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
<div className="text-[14px] py-[5px] px-[12px]">
|
||||
Name: {pdfDetails?.name}
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
<div className="text-[14px] py-[5px] px-[12px]">
|
||||
Pdf type: {pdfDetails?.pdftype}
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
<div className="text-[14px] py-[5px] px-[12px]">
|
||||
Total Pages: {pdfDetails?.totalPages}
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
<div className="text-[14px] py-[5px] px-[12px]">
|
||||
Current Page: {pdfDetails?.currentPage}
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
<div className="text-[14px] py-[5px] px-[12px]">
|
||||
Base64 : {pdfDetails?.base64.slice(0, 10)}...
|
||||
<span
|
||||
style={{
|
||||
borderRadius: 4,
|
||||
padding: "3px 5px",
|
||||
border: "1px solid gray",
|
||||
fontSize: 12,
|
||||
margin: 2,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
className="op-btn op-btn-outline op-btn-primary op-btn-xs rounded-md w-[25px] h-[25px] text-[12px] m-[2px] "
|
||||
onClick={() => copytoclipboard(pdfDetails?.base64)}
|
||||
>
|
||||
<i className="fa-solid fa-copy"></i>
|
||||
<i className="fa-light fa-copy"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 18,
|
||||
fontWeight: 500,
|
||||
padding: "10px 12px",
|
||||
borderBottom: "1px solid grey"
|
||||
}}
|
||||
>
|
||||
<div className="text-[18px] font-medium py-[10px] px-[12px] border-b-[1px] border-[gray]">
|
||||
Last click
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
<div className="text-[14px] py-[5px] px-[12px]">
|
||||
x co-ordinate: {pdfDetails?.x}
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
<div className="text-[14px] py-[5px] px-[12px]">
|
||||
y co-ordinate: {pdfDetails?.y}
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
fontSize: 18,
|
||||
fontWeight: 500,
|
||||
padding: "10px 12px",
|
||||
borderBottom: "1px solid grey",
|
||||
borderTop: "1px solid grey"
|
||||
}}
|
||||
>
|
||||
<div className="text-[18px] font-medium py-[10px] px-[12px] border-y-[1px] border-[gray]">
|
||||
Annotation
|
||||
</div>
|
||||
<ul
|
||||
style={{
|
||||
listStyle: "none",
|
||||
padding: 10,
|
||||
height: 500,
|
||||
overflowY: "auto",
|
||||
scrollbarWidth: 5
|
||||
}}
|
||||
>
|
||||
<ul className=" list-none p-[10px] h-[500px] overflow-y-auto">
|
||||
{annotations.map((coord, index) => (
|
||||
<li key={index}>
|
||||
<span style={{ fontSize: 13, fontWeight: 500 }}>{`Box ${
|
||||
<span className="text-[13px] font-medium">{`Box ${
|
||||
index + 1
|
||||
}:`}</span>
|
||||
<code
|
||||
style={{
|
||||
fontSize: 12,
|
||||
color: "black",
|
||||
cursor: "pointer"
|
||||
}}
|
||||
>
|
||||
<code className="text-[12px] text-base-content select-none">
|
||||
{` ["page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]`}
|
||||
</code>
|
||||
<div>
|
||||
<span
|
||||
style={{
|
||||
borderRadius: 4,
|
||||
padding: "3px 5px",
|
||||
border: "1px solid gray",
|
||||
fontSize: 12,
|
||||
margin: 2,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
className="op-btn op-btn-outline op-btn-primary op-btn-xs rounded-md w-[23px] h-[20px] text-[12px] m-[2px] "
|
||||
onClick={() =>
|
||||
copytoclipboard(
|
||||
`"page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<i className="fa-solid fa-copy"></i>
|
||||
<i className="fa-light fa-copy"></i>
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
borderRadius: 4,
|
||||
padding: "3px 5px",
|
||||
border: "1px solid gray",
|
||||
fontSize: 12,
|
||||
margin: 2,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
className="op-btn op-btn-outline op-btn-error op-btn-xs rounded-md w-[23px] h-[20px] text-[12px] m-[2px] "
|
||||
onClick={() => handleDelete(coord.key)}
|
||||
>
|
||||
<i className="fa-solid fa-trash-can"></i>
|
||||
<i className="fa-light fa-trash-can"></i>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
@@ -382,38 +326,16 @@ const DebugPdf = () => {
|
||||
</div>
|
||||
)}
|
||||
<ModalUi title={"Select PDF"} isOpen={isModal}>
|
||||
<form onSubmit={handleSubmit} style={{ margin: "10px" }}>
|
||||
<form onSubmit={handleSubmit} className="m-[10px]">
|
||||
<input
|
||||
type="file"
|
||||
onChange={(e) => handleFileChange(e.target.files)}
|
||||
style={{
|
||||
width: "100%",
|
||||
border: "1px solid grey",
|
||||
borderRadius: "4px",
|
||||
padding: "5px",
|
||||
fontSize: 12
|
||||
}}
|
||||
className="op-file-input op-file-input-bordered op-file-input-sm focus:outline-none hover:border-base-content w-full h-[40px] text-xs"
|
||||
accept=".pdf"
|
||||
required
|
||||
/>
|
||||
<div
|
||||
style={{ borderTop: "1px solid grey", margin: "10px 0" }}
|
||||
></div>
|
||||
<button
|
||||
style={{
|
||||
background: "#32a3ac",
|
||||
borderRadius: "2px",
|
||||
boxShadow:
|
||||
"0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18)",
|
||||
border: "none",
|
||||
textTransform: "uppercase",
|
||||
fontSize: "13px",
|
||||
fontWeight: "600",
|
||||
padding: "0.375rem 0.75rem",
|
||||
textAlign: "center",
|
||||
color: "#ffffff",
|
||||
outline: "none"
|
||||
}}
|
||||
className="op-btn op-btn-primary w-full mt-3 mb-1"
|
||||
type="submit"
|
||||
>
|
||||
Submit
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Title from "../components/Title";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import login_img from "../assets/images/login_img.svg";
|
||||
import Parse from "parse";
|
||||
import Alert from "../primitives/Alert";
|
||||
import { appInfo } from "../constant/appinfo";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { getAppLogo } from "../constant/Utils";
|
||||
|
||||
function ForgotPassword() {
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const [state, setState] = useState({
|
||||
email: "",
|
||||
password: "",
|
||||
hideNav: ""
|
||||
});
|
||||
const [sentStatus, setSentStatus] = useState("");
|
||||
const [image, setImage] = useState();
|
||||
|
||||
const handleChange = (event) => {
|
||||
const { name, value } = event.target;
|
||||
setState({ ...state, [name]: value });
|
||||
@@ -51,15 +56,26 @@ function ForgotPassword() {
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchAppInfo());
|
||||
saveLogo();
|
||||
resize();
|
||||
window.addEventListener("resize", resize);
|
||||
return () => window.removeEventListener("resize", resize);
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
let image = appInfo.applogo;
|
||||
const saveLogo = async () => {
|
||||
if (isEnableSubscription) {
|
||||
const logo = await getAppLogo();
|
||||
if (logo) {
|
||||
setImage(logo);
|
||||
} else {
|
||||
setImage(appInfo?.applogo || undefined);
|
||||
}
|
||||
} else {
|
||||
setImage(appInfo?.applogo || undefined);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="bg-white">
|
||||
<div>
|
||||
<Title title="Forgot password page" />
|
||||
{sentStatus === "success" && (
|
||||
<Alert type="success">
|
||||
@@ -69,29 +85,31 @@ function ForgotPassword() {
|
||||
{sentStatus === "failed" && (
|
||||
<Alert type={"danger"}>Please setup email adapter </Alert>
|
||||
)}
|
||||
<div>
|
||||
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
||||
<div className="w-[250px] h-[66px] inline-block">
|
||||
{state.hideNav ? (
|
||||
<img src={image} width="100%" alt="" />
|
||||
) : (
|
||||
<img src={image} width="100%" alt="" />
|
||||
<div className="md:p-10 lg:p-16">
|
||||
<div className="md:p-4 lg:p-10 p-4 bg-base-100 text-base-content op-card">
|
||||
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
||||
{image && (
|
||||
<img
|
||||
src={image}
|
||||
className="object-contain h-full"
|
||||
alt="applogo"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-2">
|
||||
<div className="">
|
||||
<div>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<h2 className="text-[30px] mt-6">Welcome Back !</h2>
|
||||
<span className="text-[12px] text-[#878787]">
|
||||
Reset Your Password
|
||||
</span>
|
||||
<div className="shadow-md rounded my-4">
|
||||
<div className="w-full my-4 op-card bg-base-100 shadow-md outline outline-1 outline-slate-300/50">
|
||||
<div className="px-6 py-4">
|
||||
<label className="block text-xs">Email</label>
|
||||
<input
|
||||
type="text"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
type="email"
|
||||
name="email"
|
||||
className="op-input op-input-bordered op-input-sm w-full"
|
||||
value={state.email}
|
||||
onChange={handleChange}
|
||||
required
|
||||
@@ -99,19 +117,16 @@ function ForgotPassword() {
|
||||
<hr className="my-2 border-none" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between items-center px-4">
|
||||
<button
|
||||
type="submit"
|
||||
className="rounded-sm bg-[#3ac9d6] text-white px-4 py-3 text-xs font-semibold shadow uppercase"
|
||||
>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-center text-xs font-bold">
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Submit
|
||||
</button>
|
||||
<NavLink
|
||||
to="/"
|
||||
className="rounded-sm bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] px-4 py-3 text-xs font-semibold shadow uppercase"
|
||||
<button
|
||||
onClick={() => navigate("/", { replace: true })}
|
||||
className="op-btn op-btn-secondary"
|
||||
>
|
||||
Login
|
||||
</NavLink>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
+203
-138
@@ -11,12 +11,15 @@ import SignersInput from "../components/shared/fields/SignersInput";
|
||||
import Title from "../components/Title";
|
||||
import PageNotFound from "./PageNotFound";
|
||||
import { SaveFileSize } from "../constant/saveFileSize";
|
||||
import { getFileName, toDataUrl } from "../constant/Utils";
|
||||
import { checkIsSubscribed, getFileName, toDataUrl } from "../constant/Utils";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
import axios from "axios";
|
||||
import { isEnableSubscription, submitBtn } from "../constant/const";
|
||||
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
|
||||
function Form() {
|
||||
@@ -48,7 +51,9 @@ const Forms = (props) => {
|
||||
TimeToCompleteDays: 15,
|
||||
SendinOrder: "false",
|
||||
password: "",
|
||||
file: ""
|
||||
file: "",
|
||||
remindOnceInEvery: 5,
|
||||
autoreminder: false
|
||||
});
|
||||
const [fileupload, setFileUpload] = useState("");
|
||||
const [fileload, setfileload] = useState(false);
|
||||
@@ -60,6 +65,7 @@ const Forms = (props) => {
|
||||
const [isPassword, setIsPassword] = useState(false);
|
||||
const [isDecrypting, setIsDecrypting] = useState(false);
|
||||
const [isCorrectPass, setIsCorrectPass] = useState(true);
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
const handleStrInput = (e) => {
|
||||
setIsCorrectPass(true);
|
||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||
@@ -70,6 +76,17 @@ const Forms = (props) => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [props.title]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchSubscription();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
const fetchSubscription = async () => {
|
||||
if (isEnableSubscription) {
|
||||
const getIsSubscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
}
|
||||
};
|
||||
|
||||
function getFileAsArrayBuffer(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
@@ -383,6 +400,8 @@ const Forms = (props) => {
|
||||
if (props.title !== "Sign Yourself") {
|
||||
const isChecked = formData.SendinOrder === "false" ? false : true;
|
||||
object.set("SendinOrder", isChecked);
|
||||
object.set("AutomaticReminders", formData.autoreminder);
|
||||
object.set("RemindOnceInEvery", parseInt(formData.remindOnceInEvery));
|
||||
}
|
||||
object.set("URL", fileupload);
|
||||
object.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
|
||||
@@ -402,7 +421,6 @@ const Forms = (props) => {
|
||||
className: "contracts_Users",
|
||||
objectId: ExtCls[0].objectId
|
||||
});
|
||||
|
||||
const res = await object.save();
|
||||
if (res) {
|
||||
setSigners([]);
|
||||
@@ -427,7 +445,7 @@ const Forms = (props) => {
|
||||
setIsSubmit(false);
|
||||
}
|
||||
} else {
|
||||
alert("Please wait until the PDF has been uploading.");
|
||||
alert("Please wait while the document is being uploaded.");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -457,12 +475,19 @@ const Forms = (props) => {
|
||||
? "Note to myself"
|
||||
: "Please review and sign this document",
|
||||
TimeToCompleteDays: 15,
|
||||
SendinOrder: "true"
|
||||
SendinOrder: "true",
|
||||
password: "",
|
||||
file: "",
|
||||
remindOnceInEvery: 5,
|
||||
autoreminder: false
|
||||
});
|
||||
setFileUpload("");
|
||||
setpercentage(0);
|
||||
setTimeout(() => setIsReset(false), 50);
|
||||
};
|
||||
const handleCancel = () => {
|
||||
navigate("/dashboard/35KBoSgoAK");
|
||||
};
|
||||
const handlePasswordSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setIsPassword(false);
|
||||
@@ -536,8 +561,11 @@ const Forms = (props) => {
|
||||
inputFileRef.current.value = ""; // Set file input value to empty string
|
||||
}
|
||||
};
|
||||
const handleAutoReminder = () => {
|
||||
setFormData((prev) => ({ ...prev, autoreminder: !formData.autoreminder }));
|
||||
};
|
||||
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-[2px] p-3 bg-base-100 text-base-content">
|
||||
<Title title={props?.title} />
|
||||
{isAlert && (
|
||||
<Alert type={isErr ? "danger" : "success"}>
|
||||
@@ -547,16 +575,8 @@ const Forms = (props) => {
|
||||
</Alert>
|
||||
)}
|
||||
{isSubmit ? (
|
||||
<div style={{ height: "300px" }}>
|
||||
<div
|
||||
style={{
|
||||
marginLeft: "45%",
|
||||
marginTop: "150px",
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="h-[300px] flex justify-center items-center">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
@@ -567,29 +587,30 @@ const Forms = (props) => {
|
||||
>
|
||||
<form onSubmit={handlePasswordSubmit}>
|
||||
<div className="px-6 pt-3 pb-2">
|
||||
<label className="mb-2 text-xs">Password</label>
|
||||
<label className="mb-2 text-xs text-base-content">
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="password"
|
||||
value={formData.password}
|
||||
onChange={(e) => handleStrInput(e)}
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
||||
placeholder="Enter pdf password"
|
||||
required
|
||||
/>
|
||||
{!isCorrectPass ? (
|
||||
<p className="ml-2 text-[11px] text-red-600">
|
||||
Please provide correct password
|
||||
</p>
|
||||
) : (
|
||||
<p className="ml-2 text-[11px] text-transparent text-red-600">
|
||||
.
|
||||
</p>
|
||||
)}
|
||||
<p
|
||||
className={`${
|
||||
!isCorrectPass
|
||||
? "text-red-600"
|
||||
: "text-transparent pointer-events-none"
|
||||
} ml-2 text-[11px] `}
|
||||
>
|
||||
Please provide correct password
|
||||
</p>
|
||||
</div>
|
||||
<hr />
|
||||
<div className="px-6 my-3">
|
||||
<button type="submit" className={submitBtn}>
|
||||
<div className="px-6 mb-3">
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
@@ -605,12 +626,12 @@ const Forms = (props) => {
|
||||
style={{ width: `${percentage}%` }}
|
||||
></div>
|
||||
</div>
|
||||
<span className="text-black text-sm">{percentage}%</span>
|
||||
<span className="text-base-content text-sm">{percentage}%</span>
|
||||
</div>
|
||||
)}
|
||||
{isDecrypting && (
|
||||
<div className="flex items-center gap-x-2">
|
||||
<span className="text-black text-sm">
|
||||
<span className="text-base-content text-sm">
|
||||
Decrypting pdf please wait...
|
||||
</span>
|
||||
</div>
|
||||
@@ -624,15 +645,15 @@ const Forms = (props) => {
|
||||
</label>
|
||||
{fileupload.length > 0 ? (
|
||||
<div className="flex gap-2 justify-center items-center">
|
||||
<div className="flex justify-between items-center px-2 py-2 w-full font-bold rounded border-[1px] border-[#ccc] text-gray-500 bg-white text-[13px]">
|
||||
<div className="break-all">
|
||||
file selected : {getFileName(fileupload)}
|
||||
<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 ">
|
||||
file selected: {getFileName(fileupload)}
|
||||
</div>
|
||||
<div
|
||||
onClick={() => setFileUpload("")}
|
||||
className="cursor-pointer px-[10px] text-[20px] font-bold bg-white text-red-500"
|
||||
className="cursor-pointer px-[10px] text-[20px] font-bold text-red-500"
|
||||
>
|
||||
<i className="fa-solid fa-xmark"></i>
|
||||
<i className="fa-light fa-xmark"></i>
|
||||
</div>
|
||||
</div>
|
||||
{process.env.REACT_APP_DROPBOX_API_KEY && (
|
||||
@@ -643,10 +664,10 @@ const Forms = (props) => {
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex gap-2 justify-center items-center">
|
||||
<div className="flex gap-2 justify-center items-center ">
|
||||
<input
|
||||
type="file"
|
||||
className="bg-white px-2 py-1.5 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-file-input op-file-input-bordered op-file-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
onChange={(e) => handleFileInput(e)}
|
||||
ref={inputFileRef}
|
||||
accept={
|
||||
@@ -674,21 +695,23 @@ const Forms = (props) => {
|
||||
</label>
|
||||
<input
|
||||
name="Name"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={formData.Name}
|
||||
onChange={(e) => handleStrInput(e)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">Description</label>
|
||||
<input
|
||||
name="Description"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
value={formData.Description}
|
||||
onChange={(e) => handleStrInput(e)}
|
||||
/>
|
||||
</div>
|
||||
{props.title === "New Template" && (
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">Description</label>
|
||||
<input
|
||||
name="Description"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={formData.Description}
|
||||
onChange={(e) => handleStrInput(e)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{props.signers && (
|
||||
<SignersInput
|
||||
onChange={handleSigners}
|
||||
@@ -702,7 +725,7 @@ const Forms = (props) => {
|
||||
</label>
|
||||
<input
|
||||
name="Note"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={formData.Note}
|
||||
onChange={(e) => handleStrInput(e)}
|
||||
required
|
||||
@@ -724,7 +747,7 @@ const Forms = (props) => {
|
||||
<input
|
||||
type="number"
|
||||
name="TimeToCompleteDays"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={formData.TimeToCompleteDays}
|
||||
onChange={(e) => handleStrInput(e)}
|
||||
required
|
||||
@@ -732,105 +755,147 @@ const Forms = (props) => {
|
||||
</div>
|
||||
)}
|
||||
{props.title !== "Sign Yourself" && (
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
Send In Order
|
||||
<a data-tooltip-id="sendInOrder-tooltip" className="ml-1">
|
||||
<sup>
|
||||
<i
|
||||
className="fa-solid fa-question rounded-full"
|
||||
style={{
|
||||
borderColor: "#33bbff",
|
||||
color: "#33bbff",
|
||||
fontSize: 13,
|
||||
borderWidth: 1.5,
|
||||
padding: "1.5px 4px"
|
||||
}}
|
||||
></i>
|
||||
</sup>
|
||||
</a>
|
||||
<Tooltip id="sendInOrder-tooltip" className="z-50">
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">Send in Order</p>
|
||||
<p>
|
||||
Choose how you want the signing requests to be sent to
|
||||
the document signers:
|
||||
</p>
|
||||
<p className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">Yes:</span>
|
||||
<span>
|
||||
{" "}
|
||||
Selecting this option will send the signing
|
||||
request to the first signer initially. Once the
|
||||
first signer completes their part, the next signer
|
||||
in the sequence will receive the request. This
|
||||
process continues until all signers have signed
|
||||
the document. This method ensures that the
|
||||
document is signed in a specific order.
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="font-bold">No: </span>
|
||||
<span>
|
||||
Selecting this option will send the signing links
|
||||
to all signers simultaneously. Every signer can
|
||||
sign the document at their convenience, regardless
|
||||
of whether other signers have completed their
|
||||
signatures. This method is faster but does not
|
||||
enforce any signing order among the participants.
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
<>
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
Send In Order
|
||||
<a data-tooltip-id="sendInOrder-tooltip" className="ml-1">
|
||||
<sup>
|
||||
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
|
||||
</sup>
|
||||
</a>
|
||||
<Tooltip id="sendInOrder-tooltip" className="z-50">
|
||||
<div className="max-w-[200px] md:max-w-[450px]">
|
||||
<p className="font-bold">Send in Order</p>
|
||||
<p>
|
||||
Choose how you want the signing requests to be sent to
|
||||
the document signers:
|
||||
</p>
|
||||
<p className="p-[5px]">
|
||||
<ol className="list-disc">
|
||||
<li>
|
||||
<span className="font-bold">Yes:</span>
|
||||
<span>
|
||||
Selecting this option will send the signing
|
||||
request to the first signer initially. Once the
|
||||
first signer completes their part, the next
|
||||
signer in the sequence will receive the request.
|
||||
This process continues until all signers have
|
||||
signed the document. This method ensures that
|
||||
the document is signed in a specific order.
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="font-bold">No: </span>
|
||||
<span>
|
||||
Selecting this option will send the signing
|
||||
links to all signers simultaneously. Every
|
||||
signer can sign the document at their
|
||||
convenience, regardless of whether other signers
|
||||
have completed their signatures. This method is
|
||||
faster but does not enforce any signing order
|
||||
among the participants.
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Select the option that best suits the needs of your
|
||||
document processing.
|
||||
</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</label>
|
||||
|
||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||
<input
|
||||
type="radio"
|
||||
value={"true"}
|
||||
name="SendinOrder"
|
||||
checked={formData.SendinOrder === "true"}
|
||||
className=""
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">Yes</div>
|
||||
<p>
|
||||
Select the option that best suits the needs of your
|
||||
document processing.
|
||||
</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</label>
|
||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||
<input
|
||||
type="radio"
|
||||
value={"true"}
|
||||
className="op-radio op-radio-xs"
|
||||
name="SendinOrder"
|
||||
checked={formData.SendinOrder === "true"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">Yes</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||
<input
|
||||
type="radio"
|
||||
value={"false"}
|
||||
name="SendinOrder"
|
||||
className="op-radio op-radio-xs"
|
||||
checked={formData.SendinOrder === "false"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">No</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||
<input
|
||||
type="radio"
|
||||
value={"false"}
|
||||
name="SendinOrder"
|
||||
checked={formData.SendinOrder === "false"}
|
||||
onChange={handleStrInput}
|
||||
/>
|
||||
<div className="text-center">No</div>
|
||||
<div className="text-xs mt-2">
|
||||
{!isEnableSubscription && (
|
||||
<PremiumAlertHeader
|
||||
message={
|
||||
"Auto reminder is free in beta, this feature will incur a fee later."
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<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>
|
||||
</div>
|
||||
{formData?.autoreminder === true && (
|
||||
<div className="text-xs mt-2">
|
||||
<label className="block">
|
||||
Remind once in every (Days)
|
||||
<span className="text-red-500 text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
value={formData.remindOnceInEvery}
|
||||
name="remindOnceInEvery"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
onChange={handleStrInput}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<div className="flex items-center mt-3 gap-2">
|
||||
<button
|
||||
className={`${
|
||||
isSubmit && "cursor-progress"
|
||||
} bg-[#1ab6ce] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 focus:outline-none`}
|
||||
isSubmit ? "cursor-progress" : ""
|
||||
} op-btn op-btn-primary`}
|
||||
type="submit"
|
||||
disabled={isSubmit}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
<div
|
||||
className="cursor-pointer 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"
|
||||
onClick={() => handleReset()}
|
||||
className="op-btn op-btn-ghost"
|
||||
onClick={() => handleCancel()}
|
||||
>
|
||||
Reset
|
||||
Cancel
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,26 +1,31 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Title from "../components/Title";
|
||||
import axios from "axios";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Alert from "../primitives/Alert";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import { isEnableSubscription, rejectBtn, submitBtn } from "../constant/const";
|
||||
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";
|
||||
import Tour from "reactour";
|
||||
const tourSteps = [
|
||||
{
|
||||
selector: '[data-tut="apisubscribe"]',
|
||||
content: "Upgrade now to generate API token"
|
||||
}
|
||||
];
|
||||
|
||||
function GenerateToken() {
|
||||
const navigation = useNavigate();
|
||||
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
|
||||
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
|
||||
const [apiToken, SetApiToken] = useState("");
|
||||
const [isLoader, setIsLoader] = useState(true);
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [isGenerate, setIsGenerate] = useState(false);
|
||||
const [isErr, setIsErr] = useState(false);
|
||||
const [isModal, setIsModal] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
|
||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||
const [isTour, setIsTour] = useState(false);
|
||||
useEffect(() => {
|
||||
fetchToken();
|
||||
// eslint-disable-next-line
|
||||
@@ -32,7 +37,6 @@ function GenerateToken() {
|
||||
const getIsSubscribe = await checkIsSubscribed();
|
||||
setIsSubscribe(getIsSubscribe);
|
||||
}
|
||||
|
||||
const url = parseBaseUrl + "functions/getapitoken";
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
@@ -43,7 +47,6 @@ function GenerateToken() {
|
||||
if (res) {
|
||||
SetApiToken(res.data.result.result);
|
||||
}
|
||||
|
||||
setIsLoader(false);
|
||||
} catch (err) {
|
||||
SetApiToken();
|
||||
@@ -53,49 +56,43 @@ function GenerateToken() {
|
||||
};
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setIsLoader(true);
|
||||
setIsModal(false);
|
||||
try {
|
||||
const url = parseBaseUrl + "functions/generateapitoken";
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseAppId,
|
||||
sessiontoken: localStorage.getItem("accesstoken")
|
||||
};
|
||||
await axios.post(url, {}, { headers: headers }).then((res) => {
|
||||
if (!isSubscribe && isEnableSubscription) {
|
||||
setIsTour(true);
|
||||
} else {
|
||||
setIsLoader(true);
|
||||
setIsModal(false);
|
||||
try {
|
||||
const url = parseBaseUrl + "functions/generateapitoken";
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseAppId,
|
||||
sessiontoken: localStorage.getItem("accesstoken")
|
||||
};
|
||||
const res = await axios.post(url, {}, { headers: headers });
|
||||
if (res) {
|
||||
SetApiToken(res.data.result.token);
|
||||
// localStorage.setItem("apiToken", res.data.result.token);
|
||||
setIsGenerate(true);
|
||||
setTimeout(() => {
|
||||
setIsGenerate(false);
|
||||
}, 1500);
|
||||
setIsLoader(false);
|
||||
setIsAlert({ type: "success", msg: "Token generated successfully." });
|
||||
} else {
|
||||
console.error("Error while generating Token");
|
||||
setIsLoader(false);
|
||||
setIsErr(true);
|
||||
setTimeout(() => {
|
||||
setIsErr(false);
|
||||
}, 1500);
|
||||
setIsAlert({ type: "danger", msg: "Something went wrong." });
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
setIsLoader(false);
|
||||
setIsErr(true);
|
||||
setTimeout(() => {
|
||||
setIsErr(false);
|
||||
}, 1500);
|
||||
|
||||
console.log("err", error);
|
||||
} catch (error) {
|
||||
setIsAlert({ type: "danger", msg: "Something went wrong." });
|
||||
console.log("while generating Token", error);
|
||||
} finally {
|
||||
setIsLoader(false);
|
||||
setTimeout(() => {
|
||||
setIsAlert({ type: "success", msg: "" });
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const copytoclipboard = (text) => {
|
||||
copytoData(text);
|
||||
setCopied(true);
|
||||
setIsAlert({ type: "success", msg: "Copied" });
|
||||
setTimeout(() => {
|
||||
setCopied(false);
|
||||
setIsAlert({ type: "success", msg: "" });
|
||||
}, 1500); // Reset copied state after 1.5 seconds
|
||||
};
|
||||
const handleModal = () => setIsModal(!isModal);
|
||||
@@ -103,139 +100,124 @@ function GenerateToken() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Title title={"API Token"} />
|
||||
{isGenerate && (
|
||||
<Alert type="success">Token generated successfully!</Alert>
|
||||
{isAlert.msg && (
|
||||
<Alert type={isAlert.type}>
|
||||
<div className="ml-3">{isAlert.msg}</div>
|
||||
</Alert>
|
||||
)}
|
||||
{copied && <Alert type="success">Copied</Alert>}
|
||||
{isErr && <Alert type="danger">Something went wrong!</Alert>}
|
||||
{isLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="flex justify-center items-center h-screen">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<div className="bg-white flex flex-col justify-center shadow rounded">
|
||||
{!isEnableSubscription && <PremiumAlertHeader />}
|
||||
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||
OpenSign™ API{" "}
|
||||
<Tooltip
|
||||
url={
|
||||
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
||||
}
|
||||
isSubscribe={true}
|
||||
/>
|
||||
</h1>
|
||||
<ul
|
||||
className={
|
||||
isSubscribe || !isEnableSubscription
|
||||
? "w-full flex flex-col p-2 text-sm "
|
||||
: "w-full flex flex-col p-2 text-sm opacity-20 pointer-events-none select-none"
|
||||
}
|
||||
>
|
||||
<li
|
||||
className={`flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
|
||||
<>
|
||||
<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
|
||||
url={
|
||||
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
||||
}
|
||||
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"
|
||||
>
|
||||
<div className="w-[70%] flex-col md:flex-row flex items-center gap-5 ">
|
||||
<span className="">Api Token:</span>{" "}
|
||||
<span
|
||||
id="token"
|
||||
className=" md:text-end cursor-pointer"
|
||||
onClick={() => copytoclipboard(apiToken)}
|
||||
<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
|
||||
? ""
|
||||
: "bg-white/20 pointer-events-none select-none"
|
||||
} md:text-end py-2 md:py-0`}
|
||||
>
|
||||
<span
|
||||
className="cursor-pointer"
|
||||
onClick={() => copytoclipboard(apiToken)}
|
||||
>
|
||||
{apiToken ? apiToken : "_____"}
|
||||
</span>
|
||||
<button
|
||||
className="op-btn op-btn-accent op-btn-outline op-btn-sm ml-2 cursor-pointer"
|
||||
onClick={() => copytoclipboard(apiToken)}
|
||||
>
|
||||
<i className="fa-light fa-copy"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={apiToken ? handleModal : handleSubmit}
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
{apiToken ? apiToken : "_____"}
|
||||
</span>
|
||||
</div>
|
||||
{apiToken ? "Regenerate Token" : "Generate Token"}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="flex items-center justify-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={apiToken ? handleModal : handleSubmit}
|
||||
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base focus:outline-none"
|
||||
onClick={() =>
|
||||
openInNewTab(
|
||||
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
||||
)
|
||||
}
|
||||
className="op-btn op-btn-secondary mt-2 mb-3 px-8"
|
||||
>
|
||||
{apiToken ? "Regenerate Token" : "Generate Token"}
|
||||
View Docs
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div className="flex items-center justify-center ">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
openInNewTab(
|
||||
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
||||
)
|
||||
}
|
||||
className="rounded hover:bg-[#15b4e9] border-[1px] my-2 border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
|
||||
>
|
||||
View Docs
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{!isSubscribe && isEnableSubscription && (
|
||||
<>
|
||||
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||
Upgrade to PRO Plan
|
||||
</h1>
|
||||
<ul className={"w-full flex flex-col p-2 text-sm "}>
|
||||
<li
|
||||
className={`flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
|
||||
>
|
||||
<div className="w-[70%] flex-col md:flex-row flex items-center gap-3 ">
|
||||
<span className="">$29.99/month:</span>{" "}
|
||||
<span id="token" className=" md:text-end cursor-pointer">
|
||||
Sign 100 docs using API. Only 0.15/docs after that.
|
||||
</span>
|
||||
</div>
|
||||
{!isSubscribe && isEnableSubscription && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigation("/subscription")}
|
||||
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
|
||||
>
|
||||
Upgrade Now
|
||||
</button>
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
|
||||
<ModalUi
|
||||
isOpen={isModal}
|
||||
title={"Regenerate Token"}
|
||||
handleClose={handleModal}
|
||||
>
|
||||
<div className="m-[20px]">
|
||||
<div className="text-lg font-normal text-black">
|
||||
Are you sure you want to regenerate token it will expire old
|
||||
token?
|
||||
</div>
|
||||
<hr className="bg-[#ccc] mt-4 " />
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<button
|
||||
onClick={handleSubmit}
|
||||
className={submitBtn + "ml-[2px]"}
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button onClick={handleModal} className={rejectBtn}>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalUi>
|
||||
</div>
|
||||
<ModalUi
|
||||
isOpen={isModal}
|
||||
title={apiToken ? "Regenerate Token" : "Generate Token"}
|
||||
handleClose={handleModal}
|
||||
>
|
||||
<div className="m-[20px]">
|
||||
<div className="text-lg font-normal text-base-content">
|
||||
Are you sure you want to regenerate token it will expire old
|
||||
token?
|
||||
</div>
|
||||
<hr className="bg-[#ccc] mt-4" />
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<button
|
||||
onClick={handleSubmit}
|
||||
className="op-btn op-btn-primary ml-[2px]"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
onClick={handleModal}
|
||||
className="op-btn op-btn-secondary"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalUi>
|
||||
</div>
|
||||
{!isSubscribe && isEnableSubscription && (
|
||||
<div data-tut="apisubscribe">
|
||||
<SubscribeCard />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Tour
|
||||
onRequestClose={() => setIsTour(false)}
|
||||
steps={tourSteps}
|
||||
isOpen={isTour}
|
||||
closeWithMask={false}
|
||||
disableKeyboardNavigation={["esc"]}
|
||||
scrollOffset={-100}
|
||||
rounded={5}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import "../styles/loginPage.css";
|
||||
import loader from "../assets/images/loader2.gif";
|
||||
import axios from "axios";
|
||||
import { isEnableSubscription, themeColor } from "../constant/const";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { contractUsers, getAppLogo } from "../constant/Utils";
|
||||
import logo from "../assets/images/logo.png";
|
||||
import { appInfo } from "../constant/appinfo";
|
||||
import Parse from "parse";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
function GuestLogin() {
|
||||
const { id, userMail, contactBookId, base64url } = useParams();
|
||||
let navigate = useNavigate();
|
||||
const navigate = useNavigate();
|
||||
const [email, setEmail] = useState(userMail);
|
||||
const [OTP, setOTP] = useState("");
|
||||
const [EnterOTP, setEnterOtp] = useState(false);
|
||||
@@ -19,9 +19,10 @@ function GuestLogin() {
|
||||
const [appLogo, setAppLogo] = useState("");
|
||||
const [documentId, setDocumentId] = useState(id);
|
||||
const [contactId, setContactId] = useState(contactBookId);
|
||||
const [sendmail, setSendmail] = useState();
|
||||
const [contact, setContact] = useState({ name: "", phone: "", email: "" });
|
||||
useEffect(() => {
|
||||
handleServerUrl();
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
@@ -52,53 +53,51 @@ function GuestLogin() {
|
||||
//split url in array from '/'
|
||||
const checkSplit = decodebase64.split("/");
|
||||
setDocumentId(checkSplit[0]);
|
||||
setContact((prev) => ({ ...prev, email: checkSplit[1] }));
|
||||
setEmail(checkSplit[1]);
|
||||
setContactId(checkSplit[2]);
|
||||
const contactId = checkSplit?.[2];
|
||||
setSendmail(checkSplit[3]);
|
||||
if (!contactId) {
|
||||
const params = { email: checkSplit[1], docId: checkSplit[0] };
|
||||
try {
|
||||
const linkContactRes = await Parse.Cloud.run(
|
||||
"linkcontacttodoc",
|
||||
params
|
||||
);
|
||||
// console.log("linkContactRes ", linkContactRes);
|
||||
setContactId(linkContactRes?.contactId);
|
||||
} catch (err) {
|
||||
console.log("Err in link ext contact", err);
|
||||
}
|
||||
} else {
|
||||
setContactId(checkSplit[2]);
|
||||
}
|
||||
}
|
||||
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
const handleChange = (event) => {
|
||||
const { value } = event.target;
|
||||
setOTP(value);
|
||||
};
|
||||
|
||||
//send email OTP function
|
||||
const SendOtp = async (e) => {
|
||||
const serverUrl =
|
||||
localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl");
|
||||
const parseId =
|
||||
localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId");
|
||||
if (serverUrl && localStorage) {
|
||||
setLoading(true);
|
||||
e.preventDefault();
|
||||
setEmail(email);
|
||||
|
||||
try {
|
||||
let url = `${serverUrl}functions/SendOTPMailV1/`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseId
|
||||
};
|
||||
let body = {
|
||||
email: email.toString(),
|
||||
docId: documentId
|
||||
};
|
||||
let Otp = await axios.post(url, body, { headers: headers });
|
||||
|
||||
if (Otp) {
|
||||
setLoading(false);
|
||||
setEnterOtp(true);
|
||||
}
|
||||
} catch (error) {
|
||||
alert("something went wrong!");
|
||||
const SendOtp = async () => {
|
||||
setLoading(true);
|
||||
setEmail(email);
|
||||
try {
|
||||
const params = { email: email.toString(), docId: documentId };
|
||||
const Otp = await Parse.Cloud.run("SendOTPMailV1", params);
|
||||
if (Otp) {
|
||||
setLoading(false);
|
||||
setEnterOtp(true);
|
||||
}
|
||||
} else {
|
||||
} catch (error) {
|
||||
alert("something went wrong!");
|
||||
}
|
||||
};
|
||||
|
||||
const handleSendOTPBtn = async (e) => {
|
||||
e.preventDefault();
|
||||
await SendOtp();
|
||||
};
|
||||
|
||||
//verify OTP send on via email
|
||||
const VerifyOTP = async (e) => {
|
||||
e.preventDefault();
|
||||
@@ -134,7 +133,8 @@ function GuestLogin() {
|
||||
`Parse/${parseId}/currentUser`,
|
||||
JSON.stringify(_user)
|
||||
);
|
||||
if (contractUserDetails) {
|
||||
// console.log("contractUserDetails ", contractUserDetails);
|
||||
if (contractUserDetails && contractUserDetails.length > 0) {
|
||||
localStorage.setItem(
|
||||
"Extand_Class",
|
||||
JSON.stringify(contractUserDetails)
|
||||
@@ -146,7 +146,13 @@ function GuestLogin() {
|
||||
//save isGuestSigner true in local to handle login flow header in mobile view
|
||||
localStorage.setItem("isGuestSigner", true);
|
||||
setLoading(false);
|
||||
navigate(`/load/recipientSignPdf/${documentId}/${contactId}`);
|
||||
if (sendmail === "false") {
|
||||
navigate(
|
||||
`/load/recipientSignPdf/${documentId}/${contactId}?sendmail=${sendmail}`
|
||||
);
|
||||
} else {
|
||||
navigate(`/load/recipientSignPdf/${documentId}/${contactId}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("err ", error);
|
||||
@@ -155,156 +161,169 @@ function GuestLogin() {
|
||||
alert("Please Enter OTP!");
|
||||
}
|
||||
};
|
||||
|
||||
const handleUserData = async (e) => {
|
||||
e.preventDefault();
|
||||
const params = { ...contact, docId: documentId };
|
||||
try {
|
||||
setLoading(true);
|
||||
const linkContactRes = await Parse.Cloud.run("linkcontacttodoc", params);
|
||||
// console.log("linkContactRes ", linkContactRes);
|
||||
setContactId(linkContactRes.contactId);
|
||||
setEnterOtp(true);
|
||||
await SendOtp();
|
||||
} catch (err) {
|
||||
setLoading(false);
|
||||
alert("something went wron, please try agian later.");
|
||||
console.log("Err in link ext contact", err);
|
||||
}
|
||||
};
|
||||
const handleInputChange = (e) => {
|
||||
setContact((prev) => ({ ...prev, [e.target.name]: e.target.value }));
|
||||
};
|
||||
return (
|
||||
<div style={{ padding: "2rem", background: "white" }}>
|
||||
<div className="p-[2rem]">
|
||||
{isLoading ? (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100vh",
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="no img"
|
||||
src={loader}
|
||||
style={{ width: "80px", height: "80px" }}
|
||||
/>
|
||||
<span style={{ fontSize: "13px", color: "gray" }}>
|
||||
{isLoading.message}
|
||||
</span>
|
||||
<div className="flex flex-col justify-center items-center h-[100vh]">
|
||||
<Loader />
|
||||
<span className="text-[13px] text-[gray]">{isLoading.message}</span>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
margin: "10px",
|
||||
border: "0.5px solid #c5c7c9",
|
||||
padding: "30px",
|
||||
boxShadow: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"
|
||||
}}
|
||||
>
|
||||
<div className="main_head">
|
||||
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
||||
{appLogo && (
|
||||
<img
|
||||
src={appLogo}
|
||||
className="object-contain h-full"
|
||||
alt="logo"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="m-1 md:m-2 p-[30px] text-base-content bg-base-100 op-card shadow-md">
|
||||
<div className="md:w-[250px] md:h-[66px] inline-block overflow-hidden mt-2 mb-11">
|
||||
{appLogo && (
|
||||
<img src={appLogo} className="object-contain" alt="logo" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{!EnterOTP ? (
|
||||
<div className="row">
|
||||
<div className="col-sm-6 KLO">
|
||||
<span className="welcomeText">Welcome Back !</span>
|
||||
<br />
|
||||
<span className="KNLO">
|
||||
Verification code is sent to your email
|
||||
</span>
|
||||
<div className="card card-box" style={{ borderRadius: "0px" }}>
|
||||
<div className="card-body">
|
||||
{contactId ? (
|
||||
<>
|
||||
{!EnterOTP ? (
|
||||
<div className="w-full md:w-[50%] text-base-content">
|
||||
<h1 className="text-2xl md:text-[30px]">Welcome Back!</h1>
|
||||
<legend className="text-[12px] text-[#878787] mt-2 mb-1">
|
||||
Verification code is sent to your email
|
||||
</legend>
|
||||
<div className="p-[20px] outline outline-1 outline-slate-300/50 my-2 op-card shadow-md">
|
||||
<input
|
||||
type="email"
|
||||
name="mobile"
|
||||
value={email}
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full disabled:text-[#5c5c5c] text-xs"
|
||||
disabled
|
||||
className="loginInput"
|
||||
/>
|
||||
<br />
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<button
|
||||
className="op-btn op-btn-primary"
|
||||
onClick={(e) => handleSendOTPBtn(e)}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? "Loading..." : "Get verification code"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="btnContainer">
|
||||
{loading ? (
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
background: themeColor,
|
||||
color: "white"
|
||||
}}
|
||||
className="verifyBtn"
|
||||
disabled
|
||||
>
|
||||
<span
|
||||
className="spinner-border spinner-border-sm "
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
Loading...
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
className="verifyBtn"
|
||||
style={{
|
||||
background: themeColor,
|
||||
color: "white",
|
||||
marginLeft: "0px !important"
|
||||
}}
|
||||
onClick={(e) => SendOtp(e)}
|
||||
>
|
||||
Send OTP
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="row">
|
||||
<div className="col-sm-6 KLO">
|
||||
<span className="welcomeText">Welcome Back !</span>
|
||||
<br />
|
||||
<span className="KNLO">You will get a OTP via Email</span>
|
||||
<div className="card card-box">
|
||||
<div className="card-body">
|
||||
<label>Enter Verification Code</label>
|
||||
) : (
|
||||
<form
|
||||
className="w-full md:w-[50%] text-base-content"
|
||||
onSubmit={VerifyOTP}
|
||||
>
|
||||
<h1 className="text-2xl md:text-[30px]">Welcome Back!</h1>
|
||||
<legend className="text-[12px] text-[#878787] mt-2">
|
||||
You will get a verification code via Email
|
||||
</legend>
|
||||
<div className="p-[20px] pt-[15px] outline outline-1 outline-slate-300/50 op-card my-2 shadow-md">
|
||||
<p className="text-sm">Enter Verification Code</p>
|
||||
<input
|
||||
type="number"
|
||||
className="loginInput"
|
||||
className="mt-2 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
name="OTP"
|
||||
value={OTP}
|
||||
onChange={handleChange}
|
||||
onChange={(e) => setOTP(e.target.value)}
|
||||
/>
|
||||
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{loading ? (
|
||||
<div className="mt-2.5">
|
||||
<button
|
||||
style={{
|
||||
background: themeColor,
|
||||
color: "white"
|
||||
}}
|
||||
className="verifyBtn"
|
||||
type="button"
|
||||
disabled
|
||||
className="op-btn op-btn-primary"
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
>
|
||||
<span
|
||||
className="spinner-border spinner-border-sm "
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
Loading...
|
||||
{loading ? "Loading..." : "Verify"}
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => VerifyOTP(e)}
|
||||
style={{
|
||||
background: themeColor,
|
||||
color: "white"
|
||||
}}
|
||||
className="verifyBtn"
|
||||
>
|
||||
Verify
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div className="w-full md:w-[50%] text-base-content">
|
||||
<h1 className="text-2xl md:text-[30px]">Welcome</h1>
|
||||
<legend className="text-[12px] text-[#878787] mt-2">
|
||||
Provide your details
|
||||
</legend>
|
||||
<form
|
||||
className="p-[20px] pt-[15px] outline outline-1 outline-slate-300/50 my-2 op-card shadow-md"
|
||||
onSubmit={handleUserData}
|
||||
>
|
||||
<div className="mb-2">
|
||||
<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={contact.name}
|
||||
onChange={handleInputChange}
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
disabled={loading}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-2">
|
||||
<label
|
||||
htmlFor="email"
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Email
|
||||
<span className="text-[red] text-[13px]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
value={contact.email}
|
||||
onChange={handleInputChange}
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
required
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2.5">
|
||||
<label
|
||||
htmlFor="phone"
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Phone
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="phone"
|
||||
value={contact.phone}
|
||||
onChange={handleInputChange}
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2 flex justify-start">
|
||||
<button
|
||||
type="submit"
|
||||
className="op-btn op-btn-primary"
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? "Loading..." : "Next"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
+156
-194
@@ -1,6 +1,5 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Parse from "parse";
|
||||
import "../styles/loader.css";
|
||||
import { useDispatch } from "react-redux";
|
||||
import axios from "axios";
|
||||
import Title from "../components/Title";
|
||||
@@ -10,16 +9,13 @@ import { NavLink, useNavigate, useLocation } from "react-router-dom";
|
||||
import login_img from "../assets/images/login_img.svg";
|
||||
import { useWindowSize } from "../hook/useWindowSize";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import {
|
||||
isEnableSubscription,
|
||||
modalCancelBtnColor,
|
||||
modalSubmitBtnColor
|
||||
} from "../constant/const";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import Alert from "../primitives/Alert";
|
||||
import { appInfo } from "../constant/appinfo";
|
||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||
import { fetchSubscription, getAppLogo } from "../constant/Utils";
|
||||
import { fetchSubscription, getAppLogo, openInNewTab } from "../constant/Utils";
|
||||
import Loader from "../primitives/Loader";
|
||||
function Login() {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
@@ -45,6 +41,7 @@ function Login() {
|
||||
});
|
||||
const [isModal, setIsModal] = useState(false);
|
||||
const [image, setImage] = useState();
|
||||
const [isLoginSSO, setIsLoginSSO] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (localStorage.getItem("accesstoken")) {
|
||||
@@ -263,7 +260,7 @@ function Login() {
|
||||
const LocalUserDetails = {
|
||||
name: results[0].get("Name"),
|
||||
email: results[0].get("Email"),
|
||||
phone: results[0].get("Phone"),
|
||||
phone: results[0]?.get("Phone") || "",
|
||||
company: results[0].get("Company")
|
||||
};
|
||||
localStorage.setItem(
|
||||
@@ -317,7 +314,7 @@ function Login() {
|
||||
const LocalUserDetails = {
|
||||
name: _user.name,
|
||||
email: email,
|
||||
phone: _user.phone
|
||||
phone: _user?.phone || ""
|
||||
// company: results.get("Company"),
|
||||
};
|
||||
localStorage.setItem(
|
||||
@@ -868,7 +865,7 @@ function Login() {
|
||||
const LocalUserDetails = {
|
||||
name: results[0].get("Name"),
|
||||
email: results[0].get("Email"),
|
||||
phone: results[0].get("Phone"),
|
||||
phone: results[0]?.get("Phone") || "",
|
||||
company: results[0].get("Company")
|
||||
};
|
||||
localStorage.setItem(
|
||||
@@ -905,7 +902,7 @@ function Login() {
|
||||
const LocalUserDetails = {
|
||||
name: results[0].get("Name"),
|
||||
email: results[0].get("Email"),
|
||||
phone: results[0].get("Phone")
|
||||
phone: results[0]?.get("Phone") || ""
|
||||
// company: results.get("Company"),
|
||||
};
|
||||
localStorage.setItem(
|
||||
@@ -982,7 +979,7 @@ function Login() {
|
||||
userDetails: {
|
||||
name: userInformation.name,
|
||||
email: userInformation.email,
|
||||
phone: userInformation.phone,
|
||||
phone: userInformation?.phone || "",
|
||||
role: "contracts_User",
|
||||
company: userDetails.Company,
|
||||
jobTitle: userDetails.Destination
|
||||
@@ -994,7 +991,7 @@ function Login() {
|
||||
const LocalUserDetails = {
|
||||
name: userInformation.name,
|
||||
email: userInformation.email,
|
||||
phone: userInformation.phone,
|
||||
phone: userInformation?.phone || "",
|
||||
company: userDetails.Company,
|
||||
jobTitle: userDetails.JobTitle
|
||||
};
|
||||
@@ -1016,8 +1013,9 @@ function Login() {
|
||||
|
||||
const handleCloseModal = () => {
|
||||
setIsModal(false);
|
||||
Parse.User.logOut();
|
||||
|
||||
if (Parse?.User?.current()) {
|
||||
Parse.User.logOut();
|
||||
}
|
||||
let appdata = localStorage.getItem("userSettings");
|
||||
let applogo = localStorage.getItem("appLogo");
|
||||
let appName = localStorage.getItem("appName");
|
||||
@@ -1040,201 +1038,174 @@ function Login() {
|
||||
localStorage.setItem("baseUrl", baseUrl);
|
||||
localStorage.setItem("parseAppId", appid);
|
||||
};
|
||||
|
||||
// `handleSignInWithSSO` is trigger when user click sign in with sso and open sso authorize endpoint
|
||||
const handleSignInWithSSO = () => {
|
||||
if (isLoginSSO === false) {
|
||||
if (state?.email) {
|
||||
setIsLoginSSO(true);
|
||||
const encodedEmail = encodeURIComponent(state.email);
|
||||
const clientUrl = window.location.origin;
|
||||
const domain = state.email.split("@")?.pop();
|
||||
const ssoApiUrl =
|
||||
process.env.SSO_API_URL || "https://sso.opensignlabs.com/api";
|
||||
openInNewTab(
|
||||
`${ssoApiUrl}/oauth/authorize?response_type=code&provider=saml&tenant=${domain}&product=OpenSign&redirect_uri=${clientUrl}/sso&state=${encodedEmail}`,
|
||||
"_self"
|
||||
);
|
||||
} else {
|
||||
alert("Please provide email.");
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="bg-white">
|
||||
<div>
|
||||
<Title title={"Login Page"} />
|
||||
{state.loading && (
|
||||
<div
|
||||
aria-live="assertive"
|
||||
style={{
|
||||
position: "fixed",
|
||||
width: "100vw",
|
||||
height: "100vh",
|
||||
backgroundColor: "rgba(0,0,0,0.2)",
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 2
|
||||
}}
|
||||
className="fixed w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-50"
|
||||
>
|
||||
<div
|
||||
role="status"
|
||||
style={{
|
||||
position: "fixed",
|
||||
fontSize: "50px",
|
||||
color: "#3ac9d6",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)"
|
||||
}}
|
||||
className="loader-37"
|
||||
>
|
||||
<span className="sr-only">Loading...</span>
|
||||
</div>
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
{appInfo && appInfo.appId ? (
|
||||
<>
|
||||
<div aria-labelledby="loginHeading" role="region">
|
||||
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-4 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
||||
<div
|
||||
aria-labelledby="loginHeading"
|
||||
role="region"
|
||||
className="md:p-10 lg:p-16"
|
||||
>
|
||||
<div className="md:p-4 lg:p-10 p-4 bg-base-100 text-base-content op-card">
|
||||
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
||||
{image && (
|
||||
<img
|
||||
src={image}
|
||||
className="object-contain h-full"
|
||||
alt="The image displays the OpenSign logo with a stylized blue square with an open corner, accompanied by the tagline Seal the Deal, Openly."
|
||||
alt="applogo"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-2">
|
||||
<div>
|
||||
<div>
|
||||
<form onSubmit={handleSubmit} aria-label="Login Form">
|
||||
<h1 className="text-[30px] mt-6">Welcome Back!</h1>
|
||||
<fieldset>
|
||||
<legend className="text-[12px] text-[#878787]">
|
||||
Login to your account
|
||||
</legend>
|
||||
<div className="px-6 py-4 outline outline-1 outline-slate-300/50 my-2 rounded shadow-md">
|
||||
<label className="block text-xs" htmlFor="email">
|
||||
Username
|
||||
</label>
|
||||
<input
|
||||
id="email"
|
||||
type="text"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded text-xs"
|
||||
name="email"
|
||||
value={state.email}
|
||||
onChange={handleChange}
|
||||
required
|
||||
/>
|
||||
<hr className="my-2 border-none" />
|
||||
<label className="block text-xs" htmlFor="password">
|
||||
Password
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
id="password"
|
||||
type={state.passwordVisible ? "text" : "password"}
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded text-xs"
|
||||
name="password"
|
||||
value={state.password}
|
||||
onChange={handleChange}
|
||||
required
|
||||
/>
|
||||
<span
|
||||
className={`absolute top-[50%] right-[10px] -translate-y-[50%] cursor-pointer ${
|
||||
state.passwordVisible
|
||||
? "text-[#007bff]"
|
||||
: "text-black"
|
||||
}`}
|
||||
onClick={togglePasswordVisibility}
|
||||
>
|
||||
{state.passwordVisible ? (
|
||||
<i className="fa fa-eye-slash text-xs pb-1" /> // Close eye icon
|
||||
) : (
|
||||
<i className="fa fa-eye text-xs pb-1 " /> // Open eye icon
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div className="flex flex-row justify-between items-center ml-4 py-2">
|
||||
<div>
|
||||
<label
|
||||
className="form-check-label inline-block cursor-pointer"
|
||||
htmlFor="rememberpassword"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input mr-1"
|
||||
value=""
|
||||
id="rememberpassword"
|
||||
/>
|
||||
<span className="text-[13px]">
|
||||
Remember Password
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<form onSubmit={handleSubmit} aria-label="Login Form">
|
||||
<h1 className="text-[30px] mt-6">Welcome Back!</h1>
|
||||
<fieldset>
|
||||
<legend className="text-[12px] text-[#878787]">
|
||||
Login to your account
|
||||
</legend>
|
||||
<div className="w-full px-6 py-3 my-1 op-card bg-base-100 shadow-md outline outline-1 outline-slate-300/50">
|
||||
<label className="block text-xs" htmlFor="email">
|
||||
Email
|
||||
</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"
|
||||
name="email"
|
||||
autoComplete="username"
|
||||
value={state.email}
|
||||
onChange={handleChange}
|
||||
required
|
||||
/>
|
||||
<hr className="my-1 border-none" />
|
||||
{!isLoginSSO && (
|
||||
<>
|
||||
<label className="block text-xs" htmlFor="password">
|
||||
Password
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
id="password"
|
||||
type={
|
||||
state.passwordVisible ? "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={state.password}
|
||||
autoComplete="current-password"
|
||||
onChange={handleChange}
|
||||
required
|
||||
/>
|
||||
<span
|
||||
className="absolute cursor-pointer top-[50%] right-[10px] -translate-y-[50%] text-base-content"
|
||||
onClick={togglePasswordVisibility}
|
||||
>
|
||||
{state.passwordVisible ? (
|
||||
<i className="fa fa-eye-slash text-xs pb-1" /> // Close eye icon
|
||||
) : (
|
||||
<i className="fa fa-eye text-xs pb-1 " /> // Open eye icon
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className="relative mt-1">
|
||||
<NavLink
|
||||
to="/forgetpassword"
|
||||
className="text-[13px] underline focus:outline-none focus:ring-2 focus:ring-blue-600"
|
||||
className="text-[13px] op-link op-link-primary underline-offset-1 focus:outline-none ml-1"
|
||||
>
|
||||
Forgot Password ?
|
||||
Forgot Password?
|
||||
</NavLink>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col md:flex-row justify-between items-stretch gap-8 text-center text-xs font-bold mt-2">
|
||||
<button
|
||||
type="submit"
|
||||
className="rounded-sm bg-[#3ac9d6] text-white w-full py-3 shadow outline-none uppercase focus:ring-2 focus:ring-blue-600"
|
||||
disabled={state.loading}
|
||||
>
|
||||
{state.loading ? "Loading..." : "Login"}
|
||||
</button>
|
||||
<NavLink
|
||||
className="rounded-sm cursor-pointer bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] w-full py-3 shadow uppercase"
|
||||
to={
|
||||
</fieldset>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-center text-xs font-bold mt-2">
|
||||
<button
|
||||
type="submit"
|
||||
className="op-btn op-btn-primary"
|
||||
disabled={state.loading}
|
||||
>
|
||||
{state.loading ? "Loading..." : "Login"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-accent"
|
||||
disabled={state.loading}
|
||||
onClick={() =>
|
||||
navigate(
|
||||
location.search
|
||||
? "/signup" + location.search
|
||||
: "/signup"
|
||||
}
|
||||
style={width < 768 ? { textAlign: "center" } : {}}
|
||||
>
|
||||
Create Account
|
||||
</NavLink>
|
||||
</div>
|
||||
</form>
|
||||
<br />
|
||||
{(appInfo.fbAppId || appInfo.googleClietId) && (
|
||||
<div className="text-sm flex justify-center items-center">
|
||||
<hr className="border-[1px] border-gray-300 w-full" />
|
||||
<span className="px-2 text-gray-500 cursor-default">
|
||||
OR
|
||||
</span>
|
||||
<hr className="border-[1px] border-gray-300 w-full" />
|
||||
</div>
|
||||
)}
|
||||
<br />
|
||||
<div
|
||||
style={{
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
{/* {appInfo.fbAppId && appInfo.fbAppId !== "" ? (
|
||||
)
|
||||
}
|
||||
>
|
||||
Create Account
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{(appInfo.googleClietId || isEnableSubscription) && (
|
||||
<div className="op-divider my-4 text-sm">OR</div>
|
||||
)}
|
||||
<div className="flex flex-col justify-center items-center gap-y-3">
|
||||
{/* {appInfo?.fbAppId && (
|
||||
<LoginFacebook
|
||||
FBCred={appInfo.fbAppId}
|
||||
thirdpartyLoginfn={thirdpartyLoginfn}
|
||||
thirdpartyLoader={state.thirdpartyLoader}
|
||||
setThirdpartyLoader={setThirdpartyLoader}
|
||||
/>
|
||||
) : null} */}
|
||||
</div>
|
||||
<div style={{ margin: "10px 0" }}></div>
|
||||
<div
|
||||
style={{
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
{appInfo.googleClietId && appInfo.googleClietId !== "" ? (
|
||||
<GoogleSignInBtn
|
||||
GoogleCred={appInfo.googleClietId}
|
||||
thirdpartyLoginfn={thirdpartyLoginfn}
|
||||
thirdpartyLoader={state.thirdpartyLoader}
|
||||
setThirdpartyLoader={setThirdpartyLoader}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
)} */}
|
||||
{appInfo?.googleClietId && (
|
||||
<GoogleSignInBtn
|
||||
GoogleCred={appInfo.googleClietId}
|
||||
thirdpartyLoginfn={thirdpartyLoginfn}
|
||||
thirdpartyLoader={state.thirdpartyLoader}
|
||||
setThirdpartyLoader={setThirdpartyLoader}
|
||||
/>
|
||||
)}
|
||||
{isEnableSubscription && (
|
||||
<div
|
||||
className="cursor-pointer border-[1px] border-gray-300 rounded px-[40px] py-2 font-semibold text-sm hover:border-[#d2e3fc] hover:bg-[#ecf3feb7]"
|
||||
onClick={() => handleSignInWithSSO()}
|
||||
>
|
||||
Sign in with SSO
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{width >= 768 && (
|
||||
<div className="self-center">
|
||||
<div className="place-self-center">
|
||||
<div className="mx-auto md:w-[300px] lg:w-[400px] xl:w-[500px]">
|
||||
<img
|
||||
src={login_img}
|
||||
@@ -1249,18 +1220,18 @@ function Login() {
|
||||
<Alert type={state.alertType}>{state.alertMsg}</Alert>
|
||||
</div>
|
||||
<ModalUi isOpen={isModal} title="Additional Info" showClose={false}>
|
||||
<form className="px-4 py-3">
|
||||
<form className="px-4 py-3 text-base-content">
|
||||
<div className="mb-3">
|
||||
<label
|
||||
htmlFor="Company"
|
||||
style={{ display: "flex" }}
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Company <span style={{ fontSize: 13, color: "red" }}>*</span>
|
||||
Company <span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
id="Company"
|
||||
value={userDetails.Company}
|
||||
onChange={(e) =>
|
||||
@@ -1279,11 +1250,11 @@ function Login() {
|
||||
className="block text-xs text-gray-700 font-semibold"
|
||||
>
|
||||
Job Title
|
||||
<span style={{ fontSize: 13, color: "red" }}>*</span>
|
||||
<span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
id="JobTitle"
|
||||
value={userDetails.Destination}
|
||||
onChange={(e) =>
|
||||
@@ -1295,23 +1266,18 @@ function Login() {
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<div className="mt-4 gap-2 flex flex-row">
|
||||
<button
|
||||
type="button"
|
||||
className="px-3 py-1.5 text-white rounded shadow-md text-center focus:outline-none "
|
||||
className="op-btn op-btn-primary"
|
||||
onClick={(e) => handleSubmitbtn(e)}
|
||||
style={{
|
||||
marginRight: 10,
|
||||
backgroundColor: modalSubmitBtnColor
|
||||
}}
|
||||
>
|
||||
Login
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="py-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none"
|
||||
className="op-btn op-btn-ghost"
|
||||
onClick={handleCloseModal}
|
||||
style={{ width: 75, backgroundColor: modalCancelBtnColor }}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
@@ -1321,15 +1287,11 @@ function Login() {
|
||||
</>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
fontSize: "50px",
|
||||
color: "#3ac9d6",
|
||||
top: "50%",
|
||||
left: "45%"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
aria-live="assertive"
|
||||
className="fixed w-full h-full flex justify-center items-center z-50"
|
||||
>
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -6,6 +6,8 @@ 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");
|
||||
@@ -17,7 +19,7 @@ const ManageSign = () => {
|
||||
const [isvalue, setIsValue] = useState(false);
|
||||
const allColor = ["blue", "red", "black"];
|
||||
const [isLoader, setIsLoader] = useState(true);
|
||||
const [isSuccess, setIsSuccess] = useState(false);
|
||||
const [isAlert, setIsAlert] = useState({ type: "success", message: "" });
|
||||
const [Initials, setInitials] = useState("");
|
||||
const [isInitials, setIsInitials] = useState(false);
|
||||
const [id, setId] = useState("");
|
||||
@@ -185,12 +187,20 @@ const ManageSign = () => {
|
||||
updateSign.set("UserId", userId);
|
||||
const res = await updateSign.save();
|
||||
setIsLoader(false);
|
||||
setIsSuccess(true);
|
||||
setIsAlert({
|
||||
type: "success",
|
||||
message: "Signature saved successfully."
|
||||
});
|
||||
setTimeout(() => setIsAlert({}), 2000);
|
||||
return res;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
setIsLoader(false);
|
||||
alert(`${err.message}`);
|
||||
setIsAlert({
|
||||
type: "danger",
|
||||
message: `${err.message}`
|
||||
});
|
||||
setTimeout(() => setIsAlert({}), 2000);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
@@ -201,21 +211,24 @@ const ManageSign = () => {
|
||||
updateSign.set("UserId", userId);
|
||||
const res = await updateSign.save();
|
||||
setIsLoader(false);
|
||||
setIsSuccess(true);
|
||||
setIsAlert({
|
||||
type: "success",
|
||||
message: "Signature saved successfully."
|
||||
});
|
||||
setTimeout(() => setIsAlert({}), 2000);
|
||||
return res;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
setIsLoader(false);
|
||||
alert(`${err.message}`);
|
||||
setIsAlert({
|
||||
type: "success",
|
||||
message: `${err.message}`
|
||||
});
|
||||
setTimeout(() => setIsAlert({}), 2000);
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleSignatureBtn = () => {
|
||||
if (imageRef.current) {
|
||||
imageRef.current.value = "";
|
||||
}
|
||||
setImage("");
|
||||
};
|
||||
|
||||
const handleUploadBtn = () => {
|
||||
imageRef.current.click();
|
||||
};
|
||||
@@ -224,213 +237,130 @@ const ManageSign = () => {
|
||||
setIsValue(true);
|
||||
};
|
||||
return (
|
||||
<div className="relative h-full bg-white flex shadow rounded overflow-auto">
|
||||
<div className="relative h-full bg-base-100 text-base-content flex shadow-md rounded-box overflow-auto">
|
||||
{isLoader && (
|
||||
<div className="absolute bg-black bg-opacity-75 z-50 w-full h-full flex justify-center items-center">
|
||||
<div
|
||||
style={{ color: "#3dd3e0" }}
|
||||
className="loader-37 text-[45px]"
|
||||
></div>
|
||||
<div className="absolute bg-black bg-opacity-30 z-50 w-full h-full flex justify-center items-center">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
{isSuccess && (
|
||||
<div
|
||||
className="alert alert-success successBox"
|
||||
role="alert"
|
||||
onAnimationEnd={() => setIsSuccess(false)}
|
||||
>
|
||||
Signature saved successfully!
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className="mainDiv"
|
||||
style={{
|
||||
width: "100%",
|
||||
paddingRight: "10px"
|
||||
}}
|
||||
>
|
||||
<div style={{ margin: 20 }}>
|
||||
<div
|
||||
style={{
|
||||
fontWeight: "700",
|
||||
fontSize: 15,
|
||||
color: "#000",
|
||||
paddingBottom: 8
|
||||
}}
|
||||
>
|
||||
{isAlert?.message && <Alert type={isAlert.type}>{isAlert.message}</Alert>}
|
||||
<div className="relative w-full">
|
||||
<div className="ml-[5px] my-[20px] md:m-[20px]">
|
||||
<div className="text-[20px] font-semibold m-[10px] md:m-0 mb-2">
|
||||
My Signature
|
||||
</div>
|
||||
<div className="signBlock mt-4">
|
||||
<div>
|
||||
<div style={{ position: "relative" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
width: "50%",
|
||||
paddingLeft: 10
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-around",
|
||||
alignItems: "center",
|
||||
gap: 10,
|
||||
marginBottom: 10
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<span
|
||||
onClick={() => handleSignatureBtn()}
|
||||
className="signature"
|
||||
>
|
||||
Signature
|
||||
</span>
|
||||
</>
|
||||
|
||||
<span
|
||||
onClick={() => handleUploadBtn()}
|
||||
className="imgupload"
|
||||
>
|
||||
Upload Image
|
||||
</span>
|
||||
<input
|
||||
type="file"
|
||||
onChange={onImageChange}
|
||||
className="filetype"
|
||||
accept="image/*"
|
||||
ref={imageRef}
|
||||
hidden
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ position: "relative" }}>
|
||||
<div>
|
||||
{image ? (
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
border: "2px solid #888"
|
||||
}}
|
||||
className="signatureCanvas"
|
||||
>
|
||||
<img
|
||||
alt="preview image"
|
||||
src={image}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "contain"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<SignatureCanvas
|
||||
ref={canvasRef}
|
||||
penColor={penColor}
|
||||
canvasProps={{
|
||||
width: "456px",
|
||||
height: "180px",
|
||||
className: "signatureCanvas"
|
||||
}}
|
||||
backgroundColor="rgb(255, 255, 255)"
|
||||
onEnd={() =>
|
||||
handleSignatureChange(canvasRef.current.toDataURL())
|
||||
}
|
||||
dotSize={1}
|
||||
<div className="flex flex-col md:flex-row gap-0 md:gap-[12px]">
|
||||
<div className="relative">
|
||||
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
|
||||
Signature
|
||||
</span>
|
||||
<input
|
||||
type="file"
|
||||
onChange={onImageChange}
|
||||
className="filetype"
|
||||
accept="image/*"
|
||||
ref={imageRef}
|
||||
hidden
|
||||
/>
|
||||
<div className="relative">
|
||||
<div>
|
||||
{image ? (
|
||||
<div className="signatureCanvas relative border-[2px] border-[#888] rounded-box">
|
||||
<img
|
||||
alt="signature"
|
||||
src={image}
|
||||
className="w-full h-full object-contain"
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between"
|
||||
</div>
|
||||
) : (
|
||||
<SignatureCanvas
|
||||
ref={canvasRef}
|
||||
penColor={penColor}
|
||||
canvasProps={{
|
||||
width: "456px",
|
||||
height: "180px",
|
||||
className: "signatureCanvas rounded-box"
|
||||
}}
|
||||
className="penContainerDefault"
|
||||
>
|
||||
<div>
|
||||
{!image && (
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "row" }}
|
||||
>
|
||||
{allColor.map((data, key) => {
|
||||
return (
|
||||
<i
|
||||
style={{
|
||||
margin: "5px",
|
||||
color: data,
|
||||
borderBottom:
|
||||
key === 0 && penColor === "blue"
|
||||
? "2px solid blue"
|
||||
: key === 1 && penColor === "red"
|
||||
backgroundColor="rgb(255, 255, 255)"
|
||||
onEnd={() =>
|
||||
handleSignatureChange(canvasRef.current.toDataURL())
|
||||
}
|
||||
dotSize={1}
|
||||
/>
|
||||
)}
|
||||
<div className="penContainerDefault flex flex-row justify-between">
|
||||
<div>
|
||||
{!image && (
|
||||
<div className="flex flex-row">
|
||||
{allColor.map((data, key) => {
|
||||
return (
|
||||
<i
|
||||
style={{
|
||||
margin: "5px",
|
||||
color: data,
|
||||
borderBottom:
|
||||
key === 0 && penColor === "blue"
|
||||
? "2px solid blue"
|
||||
: key === 1 && penColor === "red"
|
||||
? "2px solid red"
|
||||
: key === 2 && penColor === "black"
|
||||
? "2px solid black"
|
||||
: "2px solid white"
|
||||
}}
|
||||
onClick={() => {
|
||||
if (key === 0) {
|
||||
setPenColor("blue");
|
||||
} else if (key === 1) {
|
||||
setPenColor("red");
|
||||
} else if (key === 2) {
|
||||
setPenColor("black");
|
||||
}
|
||||
}}
|
||||
key={key}
|
||||
className="fa solid fa-pen-nib"
|
||||
width={20}
|
||||
height={20}
|
||||
></i>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
type="button"
|
||||
className="clearbtn cursor-pointer"
|
||||
onClick={() => handleClear()}
|
||||
>
|
||||
Clear
|
||||
? "2px solid black"
|
||||
: "2px solid white"
|
||||
}}
|
||||
onClick={() => {
|
||||
if (key === 0) {
|
||||
setPenColor("blue");
|
||||
} else if (key === 1) {
|
||||
setPenColor("red");
|
||||
} else if (key === 2) {
|
||||
setPenColor("black");
|
||||
}
|
||||
}}
|
||||
key={key}
|
||||
className="fa-light fa-pen-nib"
|
||||
width={20}
|
||||
height={20}
|
||||
></i>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-row gap-2 text-sm md:text-base mr-1">
|
||||
<div
|
||||
type="button"
|
||||
className="op-link"
|
||||
onClick={() => handleUploadBtn()}
|
||||
>
|
||||
Upload image
|
||||
</div>
|
||||
<div
|
||||
type="button"
|
||||
className="op-link"
|
||||
onClick={() => handleClear()}
|
||||
>
|
||||
Clear
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{warning && (
|
||||
<div
|
||||
className="warning signWarning"
|
||||
style={{ fontSize: 12 }}
|
||||
>
|
||||
<i
|
||||
className="fas fa-exclamation-circle"
|
||||
style={{ color: "#fab005", fontSize: 15 }}
|
||||
></i>{" "}
|
||||
Please upload signature/Image
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{warning && (
|
||||
<span className="customwarning signWarning text-[12px] w-[220px] md:w-[300px]">
|
||||
<i className="fa-light fa-exclamation-circle text-[#fab005] text-[15px] mr-[4px]"></i>
|
||||
Please upload signature/Image
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ position: "relative" }}>
|
||||
<div style={{ margin: "6px 5px 18px" }}>
|
||||
<span className="signature">Initials</span>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
|
||||
Initials
|
||||
</span>
|
||||
<div>
|
||||
{isInitials ? (
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
border: "2px solid #888"
|
||||
}}
|
||||
className="intialSignature"
|
||||
>
|
||||
<div className="intialSignature relative border-[1px] border-[#888] rounded-box overflow-hidden">
|
||||
<img
|
||||
alt="preview image"
|
||||
alt="inititals"
|
||||
src={Initials}
|
||||
style={{
|
||||
width: "100%",
|
||||
@@ -444,7 +374,7 @@ const ManageSign = () => {
|
||||
ref={initailsRef}
|
||||
penColor={initialPen}
|
||||
canvasProps={{
|
||||
className: "intialSignature"
|
||||
className: "intialSignature rounded-box"
|
||||
}}
|
||||
backgroundColor="rgb(255, 255, 255)"
|
||||
onEnd={() =>
|
||||
@@ -453,17 +383,10 @@ const ManageSign = () => {
|
||||
dotSize={1}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between"
|
||||
}}
|
||||
className="penContainerInitial"
|
||||
>
|
||||
<div className="flex flex-row justify-between w-[183px]">
|
||||
<div>
|
||||
{!isInitials && (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<div className="flex flex-row">
|
||||
{allColor.map((data, key) => {
|
||||
return (
|
||||
<i
|
||||
@@ -474,10 +397,10 @@ const ManageSign = () => {
|
||||
key === 0 && initialPen === "blue"
|
||||
? "2px solid blue"
|
||||
: key === 1 && initialPen === "red"
|
||||
? "2px solid red"
|
||||
: key === 2 && initialPen === "black"
|
||||
? "2px solid black"
|
||||
: "2px solid white"
|
||||
? "2px solid red"
|
||||
: key === 2 && initialPen === "black"
|
||||
? "2px solid black"
|
||||
: "2px solid white"
|
||||
}}
|
||||
onClick={() => {
|
||||
if (key === 0) {
|
||||
@@ -489,7 +412,7 @@ const ManageSign = () => {
|
||||
}
|
||||
}}
|
||||
key={key}
|
||||
className="fa solid fa-pen-nib"
|
||||
className="fa-light fa-pen-nib"
|
||||
width={20}
|
||||
height={20}
|
||||
></i>
|
||||
@@ -501,7 +424,7 @@ const ManageSign = () => {
|
||||
<div>
|
||||
<div
|
||||
type="button"
|
||||
className="clearbtn cursor-pointer"
|
||||
className="op-link text-sm md:text-base mr-1"
|
||||
onClick={() => handleClearInitials()}
|
||||
>
|
||||
Clear
|
||||
@@ -509,20 +432,11 @@ const ManageSign = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* {!warning && (
|
||||
<div className="warning signWarning" style={{ fontSize: 12 }}>
|
||||
<i
|
||||
className="fas fa-exclamation-circle"
|
||||
style={{ color: "#fab005", fontSize: 15 }}
|
||||
></i>{" "}
|
||||
Please upload signature/Image
|
||||
</div>
|
||||
)} */}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ paddingTop: 10 }}>
|
||||
<div className="pt-3 ml-2 md:ml-0">
|
||||
<button
|
||||
className="customBtn successBtn"
|
||||
className="op-btn op-btn-primary"
|
||||
onClick={(e) => handleSubmit(e)}
|
||||
>
|
||||
save
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import "../styles/opensigndrive.css";
|
||||
import loader from "../assets/images/loader2.gif";
|
||||
import { themeColor, iconColor } from "../constant/const";
|
||||
import { iconColor } from "../constant/const";
|
||||
import { getDrive } from "../constant/Utils";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Title from "../components/Title";
|
||||
@@ -10,27 +9,15 @@ import ModalUi from "../primitives/ModalUi";
|
||||
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
||||
import Tour from "reactour";
|
||||
import axios from "axios";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
const DriveBody = React.lazy(
|
||||
() => import("../components/opensigndrive/DriveBody")
|
||||
);
|
||||
const Loader = () => {
|
||||
const AppLoader = () => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="h-[100vh] flex justify-center items-center">
|
||||
<Loader />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -279,7 +266,8 @@ function Opensigndrive() {
|
||||
setNewFolderName(value);
|
||||
};
|
||||
//function for create folder
|
||||
const handleAddFolder = async () => {
|
||||
const handleAddFolder = async (e) => {
|
||||
e.preventDefault();
|
||||
if (newFolderName) {
|
||||
setIsFolderLoader(true);
|
||||
const getParentObjId = folderName[folderName.length - 1];
|
||||
@@ -300,6 +288,7 @@ function Opensigndrive() {
|
||||
const exsitQuery = new Parse.Query(foldercls);
|
||||
exsitQuery.equalTo("Name", newFolderName);
|
||||
exsitQuery.equalTo("Type", "Folder");
|
||||
exsitQuery.notEqualTo("IsArchive", true);
|
||||
if (parentId) {
|
||||
exsitQuery.equalTo("Folder", folderPtr);
|
||||
}
|
||||
@@ -449,21 +438,10 @@ function Opensigndrive() {
|
||||
<React.Fragment key={id}>
|
||||
<span
|
||||
onClick={() => handleRoute(id, folderData)}
|
||||
style={{
|
||||
color: "#a64b4e",
|
||||
fontWeight: "400",
|
||||
cursor: "pointer"
|
||||
}}
|
||||
className="text-[#a64b4e] font-normal cursor-pointer"
|
||||
>
|
||||
{data.name}
|
||||
<span
|
||||
style={{
|
||||
color: "#a64b4e",
|
||||
fontWeight: "200",
|
||||
cursor: "pointer",
|
||||
margin: "0 4px"
|
||||
}}
|
||||
>
|
||||
<span className="text-[#a64b4e] font-extralight cursor-pointer mx-[4px]">
|
||||
>
|
||||
</span>
|
||||
</span>
|
||||
@@ -544,411 +522,295 @@ function Opensigndrive() {
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div style={{ backgroundColor: "white" }} className="folderComponent">
|
||||
<div className="bg-base-100 text-base-content rounded-box w-full shadow-md">
|
||||
<Title title={"OpenSign™ Drive"} drive={true} />
|
||||
|
||||
<div>
|
||||
<ModalUi
|
||||
headerColor={"#dc3545"}
|
||||
isOpen={isAlert.isShow}
|
||||
title={"Alert"}
|
||||
handleClose={() => {
|
||||
setIsAlert({
|
||||
isShow: false,
|
||||
alertMessage: ""
|
||||
});
|
||||
}}
|
||||
>
|
||||
<div style={{ height: "100%", padding: 20 }}>
|
||||
<p>{isAlert.alertMessage}</p>
|
||||
|
||||
<div
|
||||
style={{
|
||||
height: "1px",
|
||||
backgroundColor: "#9f9f9f",
|
||||
width: "100%",
|
||||
marginTop: "15px",
|
||||
marginBottom: "15px"
|
||||
}}
|
||||
></div>
|
||||
<button
|
||||
onClick={() =>
|
||||
setIsAlert({
|
||||
isShow: false,
|
||||
alertMessage: ""
|
||||
})
|
||||
}
|
||||
type="button"
|
||||
className="finishBtn cancelBtn"
|
||||
<ModalUi
|
||||
isOpen={isAlert.isShow}
|
||||
title={"Alert"}
|
||||
handleClose={() => {
|
||||
setIsAlert({
|
||||
isShow: false,
|
||||
alertMessage: ""
|
||||
});
|
||||
}}
|
||||
>
|
||||
<div className="h-full p-[20px] pb-[15px]">
|
||||
<p>{isAlert.alertMessage}</p>
|
||||
<div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div>
|
||||
<button
|
||||
onClick={() =>
|
||||
setIsAlert({
|
||||
isShow: false,
|
||||
alertMessage: ""
|
||||
})
|
||||
}
|
||||
type="button"
|
||||
className="op-btn op-btn-neutral op-btn-sm"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</ModalUi>
|
||||
<ModalUi
|
||||
isOpen={isFolder}
|
||||
title={"Add New Folder"}
|
||||
handleClose={oncloseFolder}
|
||||
>
|
||||
<div className="h-full p-[20px] pt-[10px] pb-[15px]">
|
||||
{folderLoader ? (
|
||||
<div className="h-[200px] flex justify-center items-center">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<form
|
||||
onSubmit={handleAddFolder}
|
||||
className="flex flex-col text-base-content"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</ModalUi>
|
||||
<ModalUi
|
||||
isOpen={isFolder}
|
||||
title={"Add New Folder"}
|
||||
handleClose={oncloseFolder}
|
||||
>
|
||||
<div style={{ height: "100%", padding: 20 }}>
|
||||
{folderLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "200px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="loader img"
|
||||
src={loader}
|
||||
style={{ width: "50px", height: "50px" }}
|
||||
/>
|
||||
<span style={{ fontSize: "13px", color: "gray" }}>
|
||||
Loading...
|
||||
</span>
|
||||
<label className="py-[8px] text-[15px] font-[400] mb-0">
|
||||
Name
|
||||
<span className="text-[red]">*</span>
|
||||
</label>
|
||||
<input
|
||||
required
|
||||
className="op-input op-input-bordered op-input-sm"
|
||||
type="text"
|
||||
value={newFolderName}
|
||||
onChange={(e) => handleFolderName(e)}
|
||||
/>
|
||||
<span className="text-[red] text-[12px] mt-[6px]">{error}</span>
|
||||
<div className="w-full h-[1px] bg-[#9f9f9f] my-[15px]"></div>
|
||||
<div className="flex flex-row">
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Add
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-ghost ml-1"
|
||||
onClick={oncloseFolder}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
handleAddFolder();
|
||||
}}
|
||||
style={{ display: "flex", flexDirection: "column" }}
|
||||
>
|
||||
<label
|
||||
style={{
|
||||
margin: "10px 0px 10px 0px",
|
||||
fontSize: "15px",
|
||||
fontWeight: "400"
|
||||
}}
|
||||
>
|
||||
Name
|
||||
<span style={{ color: "red" }}>*</span>
|
||||
</label>
|
||||
|
||||
<input
|
||||
required
|
||||
className="form-control inputStyle"
|
||||
type="text"
|
||||
value={newFolderName}
|
||||
onChange={(e) => handleFolderName(e)}
|
||||
// className="addFolderInput"
|
||||
/>
|
||||
<span
|
||||
style={{ color: "red", fontSize: "12px", marginTop: "6px" }}
|
||||
>
|
||||
{error}
|
||||
</span>
|
||||
<div
|
||||
style={{
|
||||
height: "1px",
|
||||
backgroundColor: "#9f9f9f",
|
||||
width: "100%",
|
||||
marginTop: "15px",
|
||||
marginBottom: "15px"
|
||||
}}
|
||||
></div>
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<button
|
||||
style={{ background: themeColor }}
|
||||
type="submit"
|
||||
className="finishBtn"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="finishBtn cancelBtn"
|
||||
onClick={oncloseFolder}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</ModalUi>
|
||||
{isLoading.isLoad ? (
|
||||
<div className="flex flex-col justify-center items-center h-[100vh] w-full">
|
||||
<Loader />
|
||||
<span className="text-[13px] text-base-content">
|
||||
{isLoading.message}
|
||||
</span>
|
||||
</div>
|
||||
) : handleError ? (
|
||||
<div className="flex justify-center items-center h-[100vh] w-full">
|
||||
<span className="text-[20px] text-base-content">{handleError}</span>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex flex-row justify-between items-center px-[25px] pt-[20px]">
|
||||
{tourData && (
|
||||
<Tour
|
||||
onRequestClose={closeTour}
|
||||
steps={tourData}
|
||||
isOpen={isTour}
|
||||
closeWithMask={false}
|
||||
scrollOffset={-100}
|
||||
rounded={5}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</ModalUi>
|
||||
|
||||
{isLoading.isLoad ? (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100vh",
|
||||
width: "100%",
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="loader img"
|
||||
src={loader}
|
||||
style={{ width: "80px", height: "80px" }}
|
||||
/>
|
||||
<span style={{ fontSize: "13px", color: "gray" }}>
|
||||
{isLoading.message}
|
||||
</span>
|
||||
</div>
|
||||
) : handleError ? (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100vh",
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: "20px", color: "gray" }}>
|
||||
{handleError}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="folderContainer">
|
||||
{tourData && (
|
||||
<Tour
|
||||
onRequestClose={closeTour}
|
||||
steps={tourData}
|
||||
isOpen={isTour}
|
||||
closeWithMask={false}
|
||||
scrollOffset={-100}
|
||||
rounded={5}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div
|
||||
data-tut="reactourFirst"
|
||||
onMouseEnter={(e) => handleMouseEnter(e)}
|
||||
ref={scrollRef}
|
||||
className="w-full whitespace-nowrap cursor-pointer select-none overflow-x-auto"
|
||||
>
|
||||
{handleFolderTab(folderName)}
|
||||
</div>
|
||||
<div className="flex flex-row items-center">
|
||||
<div
|
||||
data-tut="reactourFirst"
|
||||
onMouseEnter={(e) => handleMouseEnter(e)}
|
||||
ref={scrollRef}
|
||||
style={{
|
||||
width: "100%"
|
||||
}}
|
||||
className="folderPath"
|
||||
id="folder-menu"
|
||||
className={
|
||||
isNewFol ? "dropdown show dropDownStyle" : "dropdown"
|
||||
}
|
||||
onClick={() => setIsNewFol(!isNewFol)}
|
||||
>
|
||||
{handleFolderTab(folderName)}
|
||||
</div>
|
||||
<div className="dropMenuBD">
|
||||
<div
|
||||
id="folder-menu"
|
||||
className={
|
||||
isNewFol ? "dropdown show dropDownStyle" : "dropdown"
|
||||
}
|
||||
onClick={() => setIsNewFol(!isNewFol)}
|
||||
>
|
||||
<div className="sort" data-tut="reactourSecond">
|
||||
<i
|
||||
className="fa fa-plus-square"
|
||||
aria-hidden="true"
|
||||
style={{ fontSize: "25px", color: `${iconColor}` }}
|
||||
></i>
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
isNewFol ? "dropdown-menu show" : "dropdown-menu"
|
||||
}
|
||||
aria-labelledby="dropdownMenuButton"
|
||||
aria-expanded={isNewFol ? "true" : "false"}
|
||||
>
|
||||
{" "}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<span
|
||||
className="dropdown-item itemColor"
|
||||
onClick={() => setIsFolder(true)}
|
||||
>
|
||||
<i
|
||||
style={{ marginRight: "5px" }}
|
||||
className="fa fa-plus"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Create folder
|
||||
</span>
|
||||
<span
|
||||
className="dropdown-item itemColor"
|
||||
onClick={() => navigate("/form/sHAnZphf69")}
|
||||
>
|
||||
<i
|
||||
style={{ marginRight: "5px" }}
|
||||
className="fas fa-pen-nib"
|
||||
></i>
|
||||
Sign Yourself
|
||||
</span>
|
||||
<span
|
||||
className="dropdown-item itemColor"
|
||||
onClick={() => navigate("/form/8mZzFxbG1z")}
|
||||
>
|
||||
{" "}
|
||||
<i
|
||||
style={{ marginRight: "5px" }}
|
||||
className="fa fa-file-signature"
|
||||
></i>
|
||||
Request Signatures{" "}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sort" data-tut="reactourSecond">
|
||||
<i
|
||||
className="fa-light fa-plus-square"
|
||||
aria-hidden="true"
|
||||
style={{ fontSize: "25px", color: `${iconColor}` }}
|
||||
></i>
|
||||
</div>
|
||||
<div
|
||||
id="menu-container"
|
||||
className={isShowSort ? "dropdown show" : "dropdown"}
|
||||
onClick={() => setIsShowSort(!isShowSort)}
|
||||
className={isNewFol ? "dropdown-menu show" : "dropdown-menu"}
|
||||
aria-labelledby="dropdownMenuButton"
|
||||
aria-expanded={isNewFol ? "true" : "false"}
|
||||
>
|
||||
<div
|
||||
data-tut="reactourThird"
|
||||
className=" sort "
|
||||
data-toggle="dropdown"
|
||||
>
|
||||
<i
|
||||
className="fa fa-sort-amount-asc"
|
||||
aria-hidden="true"
|
||||
style={{
|
||||
marginRight: "5px",
|
||||
fontSize: "14px",
|
||||
color: `${iconColor}`
|
||||
}}
|
||||
></i>
|
||||
<div className="flex flex-col">
|
||||
<span
|
||||
style={{
|
||||
fontSize: "15px",
|
||||
color: `${iconColor}`
|
||||
}}
|
||||
className="dropdown-item text-[10px] md:text-[13px]"
|
||||
onClick={() => setIsFolder(true)}
|
||||
>
|
||||
{selectedSort}
|
||||
<i
|
||||
className="fa-light fa-plus mr-[5px]"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Create folder
|
||||
</span>
|
||||
<span
|
||||
className="dropdown-item text-[10px] md:text-[13px]"
|
||||
onClick={() => navigate("/form/sHAnZphf69")}
|
||||
>
|
||||
<i className="fa-light fa-pen-nib mr-[5px]"></i>
|
||||
Sign Yourself
|
||||
</span>
|
||||
<span
|
||||
className="dropdown-item text-[10px] md:text-[13px]"
|
||||
onClick={() => navigate("/form/8mZzFxbG1z")}
|
||||
>
|
||||
<i className="fa-light fa-file-signature mr-[5px]"></i>
|
||||
Request Signatures
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
isShowSort ? "dropdown-menu show" : "dropdown-menu"
|
||||
}
|
||||
aria-labelledby="dropdownMenuButton"
|
||||
aria-expanded={isShowSort ? "true" : "false"}
|
||||
>
|
||||
{sortingValue.map((value, ind) => {
|
||||
return (
|
||||
<span
|
||||
key={ind}
|
||||
onClick={() => {
|
||||
setSelectedSort(value);
|
||||
sortingData(value, null, pdfData);
|
||||
}}
|
||||
className="dropdown-item itemColor"
|
||||
style={{
|
||||
paddingLeft: selectedSort !== value && "33px"
|
||||
}}
|
||||
>
|
||||
{selectedSort === value && (
|
||||
<i
|
||||
className="fa fa-check"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "5px" }}
|
||||
></i>
|
||||
)}
|
||||
{value}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
|
||||
<hr className="hrStyle" />
|
||||
{sortOrder.map((order, ind) => {
|
||||
return (
|
||||
<span
|
||||
key={ind}
|
||||
onClick={() => {
|
||||
setSortingOrder(order);
|
||||
sortingData(null, order, pdfData);
|
||||
}}
|
||||
className="dropdown-item itemColor"
|
||||
style={{
|
||||
paddingLeft: sortingOrder !== order && "33px"
|
||||
}}
|
||||
>
|
||||
{sortingOrder === order && (
|
||||
<i
|
||||
className="fa fa-check"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "5px" }}
|
||||
></i>
|
||||
)}
|
||||
{order}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="menu-container"
|
||||
className={isShowSort ? "dropdown show" : "dropdown"}
|
||||
onClick={() => setIsShowSort(!isShowSort)}
|
||||
>
|
||||
<div
|
||||
data-tut="reactourThird"
|
||||
className="sort "
|
||||
data-toggle="dropdown"
|
||||
>
|
||||
<i
|
||||
className="fa-light fa-sort-amount-asc mr-[5px] text-[14px]"
|
||||
aria-hidden="true"
|
||||
style={{ color: `${iconColor}` }}
|
||||
></i>
|
||||
<span style={{ fontSize: "15px", color: `${iconColor}` }}>
|
||||
{selectedSort}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
isShowSort ? "dropdown-menu show" : "dropdown-menu"
|
||||
}
|
||||
aria-labelledby="dropdownMenuButton"
|
||||
aria-expanded={isShowSort ? "true" : "false"}
|
||||
>
|
||||
{sortingValue.map((value, ind) => {
|
||||
return (
|
||||
<span
|
||||
key={ind}
|
||||
onClick={() => {
|
||||
setSelectedSort(value);
|
||||
sortingData(value, null, pdfData);
|
||||
}}
|
||||
className="dropdown-item text-[10px] md:text-[13px]"
|
||||
style={{
|
||||
paddingLeft: selectedSort !== value && "31px"
|
||||
}}
|
||||
>
|
||||
{selectedSort === value && (
|
||||
<i
|
||||
className="fa-light fa-check"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
)}
|
||||
<span className="ml-[5px]">{value}</span>
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
|
||||
<div>
|
||||
{isList ? (
|
||||
<div className="sort" onClick={() => setIsList(!isList)}>
|
||||
<i
|
||||
onClick={() => setIsList(!isList)}
|
||||
className="fa fa-th-large"
|
||||
style={{ fontSize: "24px", color: `${iconColor}` }}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
data-tut="reactourForth"
|
||||
className="sort"
|
||||
<hr className="hrStyle" />
|
||||
{sortOrder.map((order, ind) => {
|
||||
return (
|
||||
<span
|
||||
key={ind}
|
||||
onClick={() => {
|
||||
setSortingOrder(order);
|
||||
sortingData(null, order, pdfData);
|
||||
}}
|
||||
className="dropdown-item text-[10px] md:text-[13px]"
|
||||
style={{
|
||||
paddingLeft: sortingOrder !== order && "31px"
|
||||
}}
|
||||
>
|
||||
{sortingOrder === order && (
|
||||
<i
|
||||
className="fa-light fa-check"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
)}
|
||||
<span className="ml-[5px]">{order}</span>
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{isList ? (
|
||||
<div className="sort" onClick={() => setIsList(!isList)}>
|
||||
<i
|
||||
onClick={() => setIsList(!isList)}
|
||||
>
|
||||
<i
|
||||
className="fa fa-list"
|
||||
aria-hidden="true"
|
||||
style={{ fontSize: "23px", color: `${iconColor}` }}
|
||||
></i>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
className="fa-light fa-th-large"
|
||||
style={{ fontSize: "24px", color: `${iconColor}` }}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
data-tut="reactourForth"
|
||||
className="sort"
|
||||
onClick={() => setIsList(!isList)}
|
||||
>
|
||||
<i
|
||||
className="fa-light fa-list"
|
||||
aria-hidden="true"
|
||||
style={{ fontSize: "23px", color: `${iconColor}` }}
|
||||
></i>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{pdfData && pdfData.length === 0 ? (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "50vh",
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<span style={{ fontWeight: "bold" }}>No Data Found!</span>
|
||||
</div>
|
||||
) : (
|
||||
<div data-tut="reactourFifth">
|
||||
<React.Suspense fallback={<Loader />}>
|
||||
<DriveBody
|
||||
dataTutSixth="reactourSixth"
|
||||
dataTutSeventh="reactourSeventh"
|
||||
pdfData={pdfData}
|
||||
setFolderName={setFolderName}
|
||||
setIsLoading={setIsLoading}
|
||||
setDocId={setDocId}
|
||||
getPdfDocumentList={getPdfDocumentList}
|
||||
isDocId={docId}
|
||||
setPdfData={setPdfData}
|
||||
isList={isList}
|
||||
setIsAlert={setIsAlert}
|
||||
setSkip={setSkip}
|
||||
sortingData={sortingData}
|
||||
/>
|
||||
{loading && (
|
||||
<div style={{ textAlign: "center" }}>Loading...</div>
|
||||
)}
|
||||
</React.Suspense>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{pdfData && pdfData.length === 0 ? (
|
||||
<div className="flex justify-center items-center w-full h-[50vh]">
|
||||
<span className="text-base-content font-bold">
|
||||
No Data Found!
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<div data-tut="reactourFifth">
|
||||
<React.Suspense fallback={<AppLoader />}>
|
||||
<DriveBody
|
||||
dataTutSixth="reactourSixth"
|
||||
dataTutSeventh="reactourSeventh"
|
||||
pdfData={pdfData}
|
||||
setFolderName={setFolderName}
|
||||
setIsLoading={setIsLoading}
|
||||
setDocId={setDocId}
|
||||
getPdfDocumentList={getPdfDocumentList}
|
||||
isDocId={docId}
|
||||
setPdfData={setPdfData}
|
||||
isList={isList}
|
||||
setIsAlert={setIsAlert}
|
||||
setSkip={setSkip}
|
||||
sortingData={sortingData}
|
||||
/>
|
||||
{loading && (
|
||||
<div className="text-center pb-[20px]">Loading...</div>
|
||||
)}
|
||||
</React.Suspense>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,13 +4,11 @@ import Title from "../components/Title";
|
||||
|
||||
const PageNotFound = ({ prefix }) => {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-screen w-full bg-white rounded">
|
||||
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
|
||||
<Title title={"Page Not Found"} />
|
||||
<div className="text-center">
|
||||
<h1 className="text-[60px] lg:text-[120px] font-semibold text-black">
|
||||
404
|
||||
</h1>
|
||||
<p className="text-[30px] lg:text-[50px] text-black">
|
||||
<h1 className="text-[60px] lg:text-[120px] font-semibold">404</h1>
|
||||
<p className="text-[30px] lg:text-[50px]">
|
||||
{prefix ? prefix : "Page"} Not Found
|
||||
</p>
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import "../styles/pgsignup.css";
|
||||
import Parse from "parse";
|
||||
import axios from "axios";
|
||||
import { useDispatch } from "react-redux";
|
||||
@@ -8,6 +7,7 @@ import { useNavigate, useLocation } from "react-router-dom";
|
||||
import { appInfo } from "../constant/appinfo";
|
||||
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
const PgSignUp = () => {
|
||||
const navigate = useNavigate();
|
||||
@@ -127,7 +127,9 @@ const PgSignUp = () => {
|
||||
user.set("username", zohoRes.data.result.email);
|
||||
user.set("password", obj.password);
|
||||
user.set("email", zohoRes.data.result.email);
|
||||
user.set("phone", zohoRes.data.result.phone);
|
||||
if (zohoRes?.data?.result?.phone) {
|
||||
user.set("phone", zohoRes.data.result.phone);
|
||||
}
|
||||
user.set("name", zohoRes.data.result.name);
|
||||
|
||||
const res = await user.signUp();
|
||||
@@ -140,7 +142,7 @@ const PgSignUp = () => {
|
||||
company: zohoRes.data.result.company,
|
||||
name: zohoRes.data.result.name,
|
||||
email: zohoRes.data.result.email,
|
||||
phone: zohoRes.data.result.phone,
|
||||
phone: zohoRes?.data?.result?.phone || "",
|
||||
role: obj.role
|
||||
},
|
||||
subscription: zohoRes.data.result.subscription
|
||||
@@ -406,108 +408,101 @@ const PgSignUp = () => {
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="bg-white">
|
||||
<div className="w-full h-screen">
|
||||
<Title title={"Pgsignup page"} />
|
||||
{isLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="flex justify-center items-center h-[100vh]">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<form id="signup" className="pgsignup-content" onSubmit={handleSubmit}>
|
||||
<div className="pgsignup-container">
|
||||
<h1 className="text-2xl md:text-3xl font-bold">Choose Password</h1>
|
||||
<hr className="hrt" />
|
||||
<label htmlFor="password">
|
||||
<b className="text-[13px]">Password</b>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Enter Password"
|
||||
name="password"
|
||||
className="inputt"
|
||||
value={formData.password}
|
||||
onChange={handlePassowordChange}
|
||||
required
|
||||
/>
|
||||
|
||||
<label htmlFor="confirmPassword">
|
||||
<b className="text-[13px]">Confirm Password</b>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Confirm Password"
|
||||
name="confirmPassword"
|
||||
className="confirmInputt"
|
||||
style={{
|
||||
border: validationMessage
|
||||
? validationMessage === "Passwords match!"
|
||||
? "2px solid green"
|
||||
: "2px solid red"
|
||||
: "2px solid transparent",
|
||||
outline: "none"
|
||||
}}
|
||||
value={formData.confirmPassword}
|
||||
onChange={handleConFirmPassowordChange}
|
||||
required
|
||||
/>
|
||||
<div
|
||||
className="icon"
|
||||
style={{
|
||||
margin: validationMessage ? "0 2px 0 2px" : "0 2px 22px 2px",
|
||||
color:
|
||||
validationMessage === "Passwords match!" ? "green" : "red",
|
||||
fontSize: 11
|
||||
}}
|
||||
>
|
||||
{validationMessage}
|
||||
</div>
|
||||
{formData.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 className="py-10 lg:p-16 flex justify-center">
|
||||
<form
|
||||
id="signup"
|
||||
className="w-[90%] md:w-[55%] bg-base-100 text-base-content op-card shadow-md"
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<div className="p-[16px]">
|
||||
<h1 className="text-2xl md:text-3xl font-bold">
|
||||
Choose Password
|
||||
</h1>
|
||||
<hr className="border-[1px] border-[#cecece] mb-[5px]" />
|
||||
<label htmlFor="password">
|
||||
<b className="text-[13px]">Password</b>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Enter Password"
|
||||
name="password"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
value={formData.password}
|
||||
onChange={handlePassowordChange}
|
||||
required
|
||||
/>
|
||||
<label htmlFor="confirmPassword">
|
||||
<b className="text-[13px]">Confirm Password</b>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Confirm Password"
|
||||
name="confirmPassword"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
style={{
|
||||
border: validationMessage
|
||||
? validationMessage === "Passwords match!"
|
||||
? "1px solid green"
|
||||
: "1px solid red"
|
||||
: ""
|
||||
}}
|
||||
value={formData.confirmPassword}
|
||||
onChange={handleConFirmPassowordChange}
|
||||
required
|
||||
/>
|
||||
<div
|
||||
className={`${
|
||||
validationMessage === "Passwords match!"
|
||||
? "text-[green]"
|
||||
: "text-[red]"
|
||||
} ml-[13px] text-[11px]`}
|
||||
>
|
||||
{validationMessage}
|
||||
</div>
|
||||
)}
|
||||
<div className="clearfix">
|
||||
<button type="submit" className="signupbtn">
|
||||
{formData.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>
|
||||
)}
|
||||
<button
|
||||
type="submit"
|
||||
className="op-btn op-btn-primary w-full mt-[8px]"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,8 @@ import checkmark from "../assets/images/checkmark.png";
|
||||
import plansArr from "../json/plansArr";
|
||||
import Title from "../components/Title";
|
||||
import Parse from "parse";
|
||||
import { openInNewTab } from "../constant/Utils";
|
||||
import Loader from "../primitives/Loader";
|
||||
const listItemStyle = {
|
||||
paddingLeft: "20px", // Add padding to create space for the image
|
||||
backgroundImage: `url(${checkmark})`, // Set your image as the list style image
|
||||
@@ -16,8 +18,17 @@ const PlanSubscriptions = () => {
|
||||
const navigate = useNavigate();
|
||||
const [yearlyVisible, setYearlyVisible] = useState(false);
|
||||
const [isLoader, setIsLoader] = useState(true);
|
||||
|
||||
const userDetails = JSON.parse(localStorage.getItem("userDetails"));
|
||||
const extUser =
|
||||
localStorage.getItem("Extand_Class") &&
|
||||
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||
const user = {
|
||||
name: extUser?.Name,
|
||||
email: extUser?.Email,
|
||||
company: extUser?.Company,
|
||||
phone: extUser?.Phone
|
||||
};
|
||||
const userDetails = JSON.parse(localStorage.getItem("userDetails")) || user;
|
||||
// console.log("userDetails ", userDetails);
|
||||
const name =
|
||||
userDetails && userDetails.name
|
||||
? "first_name=" + encodeURIComponent(userDetails.name)
|
||||
@@ -75,55 +86,33 @@ const PlanSubscriptions = () => {
|
||||
<>
|
||||
<Title title={"Subscriptions"} />
|
||||
{isLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="flex items-center justify-center h-screen">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: "white",
|
||||
overflowY: "auto",
|
||||
maxHeight: "100%"
|
||||
}}
|
||||
>
|
||||
<div className="overflow-y-auto max-h-full">
|
||||
<div className="block my-2">
|
||||
<div className="flex flex-col justify-center items-center w-full">
|
||||
<div className="mb-6 mt-2 flex flex-row border-[1px] p-2 border-gray-300 rounded text-sm">
|
||||
<span
|
||||
<div
|
||||
role="tablist"
|
||||
className="op-tabs op-tabs-boxed bg-base-100 my-2 shadow-lg transition-all"
|
||||
>
|
||||
<a
|
||||
onClick={() => setYearlyVisible(false)}
|
||||
className={`${
|
||||
!yearlyVisible
|
||||
? "bg-[#002862] text-white"
|
||||
: "bg-white text-black"
|
||||
} px-4 py-1 rounded cursor-pointer`}
|
||||
role="tab"
|
||||
className={`${!yearlyVisible ? "op-tab-active" : ""} op-tab`}
|
||||
>
|
||||
Monthly
|
||||
</span>
|
||||
<span
|
||||
</a>
|
||||
<a
|
||||
onClick={() => setYearlyVisible(true)}
|
||||
className={`${
|
||||
yearlyVisible
|
||||
? "bg-[#002862] text-white"
|
||||
: "bg-white text-black"
|
||||
} px-4 py-1 rounded cursor-pointer`}
|
||||
role="tab"
|
||||
className={`${yearlyVisible ? "op-tab-active" : ""} op-tab`}
|
||||
>
|
||||
Yearly (10% off)
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<ul className="flex flex-col md:flex-row h-full bg-white justify-center">
|
||||
<ul className="op-card flex flex-col md:flex-row h-full bg-base-100 justify-center shadow-lg">
|
||||
{plansArr.map((item) => (
|
||||
<li
|
||||
className="flex flex-col text-center border-collapse border-[1px] border-gray-300 max-w-[250px]"
|
||||
@@ -198,9 +187,7 @@ const PlanSubscriptions = () => {
|
||||
<ul className="mx-1 p-3 text-left break-words text-sm list-none">
|
||||
{item.benefits.map((subitem, index) => (
|
||||
<li style={listItemStyle} key={index} className="m-1">
|
||||
<span style={{ position: "relative" }}>
|
||||
{subitem}
|
||||
</span>
|
||||
<span className="relative">{subitem}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
@@ -208,22 +195,23 @@ const PlanSubscriptions = () => {
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="text-sm flex justify-center items-center">
|
||||
<hr className="border-[1px] border-gray-300 w-[20%]" />
|
||||
<span className="px-2 text-gray-500 cursor-default">or</span>
|
||||
<hr className="border-[1px] border-gray-300 w-[20%]" />
|
||||
<div className="text-sm flex justify-center items-center mt-3 mb-2">
|
||||
<hr className="border-[2px] border-gray-350 w-[20%]" />
|
||||
<span className="px-2 text-base-content cursor-default">or</span>
|
||||
<hr className="border-[2px] border-gray-350 w-[20%]" />
|
||||
</div>
|
||||
<div className="flex flex-col justify-center w-full items-center">
|
||||
<div className="flex flex-col justify-center items-center">
|
||||
<h3 className="text-[#002862] mt-1 mb-2">
|
||||
Host it yourself for free
|
||||
</h3>
|
||||
<NavLink
|
||||
to={"https://github.com/OpenSignLabs/OpenSign"}
|
||||
className="bg-[#002862] w-[200px] text-center text-white py-2 rounded uppercase hover:no-underline hover:text-white cursor-pointer"
|
||||
target={"_blank"}
|
||||
<div
|
||||
className="op-btn op-btn-primary w-[200px]"
|
||||
onClick={() =>
|
||||
openInNewTab("https://github.com/OpenSignLabs/OpenSign")
|
||||
}
|
||||
>
|
||||
Visit Github
|
||||
</NavLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useParams } from "react-router-dom";
|
||||
import Title from "../components/Title";
|
||||
import PageNotFound from "./PageNotFound";
|
||||
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
const Report = () => {
|
||||
const { id } = useParams();
|
||||
@@ -173,21 +174,8 @@ const Report = () => {
|
||||
<>
|
||||
<Title title={reportName} />
|
||||
{isLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="h-[100vh] flex justify-center items-center">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
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";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
const SSOVerify = () => {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const [isModal, setIsModal] = useState(false);
|
||||
const [message, setMessage] = useState("Verifying SSO...");
|
||||
const [isLoader, setIsLoader] = useState(false);
|
||||
const [userDetails, setUserDetails] = useState({
|
||||
name: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
Destination: "",
|
||||
Company: ""
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
linkUserWithSSO();
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
// `linkUserWithSSO` is used to sign in or sign up a user using an SSO code and check if the user is present in the extended class
|
||||
const linkUserWithSSO = async () => {
|
||||
const param = new URLSearchParams(location.search);
|
||||
const code = param?.get("code");
|
||||
const state = param?.get("state");
|
||||
try {
|
||||
// The `ssosign` cloud function is used to sign in or sign up a user
|
||||
const ssosign = await Parse.Cloud.run("ssosign", {
|
||||
code: code,
|
||||
email: state
|
||||
});
|
||||
localStorage.setItem("accesstoken", ssosign.sessiontoken);
|
||||
// `checkExtUser` checks if the user is present in the extended class `contracts_Users` and if not, initiates the new user flow
|
||||
await checkExtUser(ssosign);
|
||||
} catch (err) {
|
||||
setMessage("Error: " + err.message);
|
||||
console.log("err", err.message);
|
||||
}
|
||||
};
|
||||
const checkExtUser = async (ssosign) => {
|
||||
const params = { email: ssosign?.email };
|
||||
try {
|
||||
// `isextenduser` checks if the current user is present in the extended class
|
||||
const extRes = await Parse.Cloud.run("isextenduser", params);
|
||||
if (extRes?.isUserExist) {
|
||||
// `getUserDetails` retrieves the current user's details from the extended class
|
||||
const extRes = await Parse.Cloud.run("getUserDetails", params);
|
||||
if (ssosign && ssosign.sessiontoken) {
|
||||
const LocalUserDetails = {
|
||||
name: extRes.Name,
|
||||
email: extRes.email,
|
||||
phone: extRes?.get("Phone") || "",
|
||||
company: extRes.get("Company")
|
||||
};
|
||||
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
||||
thirdpartyLoginfn(ssosign.sessiontoken);
|
||||
}
|
||||
} else {
|
||||
setIsModal(true);
|
||||
setUserDetails((prev) => ({
|
||||
...prev,
|
||||
name: ssosign.name,
|
||||
email: ssosign.email,
|
||||
phone: ssosign?.phone || ""
|
||||
}));
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err in isextenduser or getuserdetails cloud function", err);
|
||||
setMessage("Error: " + err.message);
|
||||
}
|
||||
};
|
||||
// `handleSubmitbtn` is used to create a user in the extended class
|
||||
const handleSubmitbtn = async (e) => {
|
||||
e.preventDefault();
|
||||
setIsLoader(true);
|
||||
let phone;
|
||||
if (userDetails?.phone) {
|
||||
phone = validateInput(userDetails?.phone);
|
||||
} else {
|
||||
phone = true;
|
||||
}
|
||||
if (userDetails.Destination && userDetails.Company && phone) {
|
||||
const payload = { sessionToken: localStorage.getItem("accesstoken") };
|
||||
if (payload && payload.sessionToken) {
|
||||
const params = {
|
||||
userDetails: {
|
||||
name: userDetails.name,
|
||||
email: userDetails.email,
|
||||
phone: userDetails?.phone || "",
|
||||
role: "contracts_User",
|
||||
company: userDetails.Company,
|
||||
jobTitle: userDetails.Destination
|
||||
}
|
||||
};
|
||||
try {
|
||||
const userSignUp = await Parse.Cloud.run("usersignup", params);
|
||||
if (userSignUp && userSignUp.sessionToken) {
|
||||
const LocalUserDetails = params.userDetails;
|
||||
localStorage.setItem(
|
||||
"userDetails",
|
||||
JSON.stringify(LocalUserDetails)
|
||||
);
|
||||
await thirdpartyLoginfn(userSignUp.sessionToken);
|
||||
setIsLoader(false);
|
||||
} else {
|
||||
alert(userSignUp.message);
|
||||
setIsLoader(false);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("error in usersignup", err);
|
||||
localStorage.removeItem("accesstoken");
|
||||
alert("Something went wrong.");
|
||||
setIsLoader(false);
|
||||
}
|
||||
} else {
|
||||
localStorage.removeItem("accesstoken");
|
||||
alert("Internal server error.");
|
||||
setIsLoader(false);
|
||||
}
|
||||
} else {
|
||||
alert("Please fill required details correctly.");
|
||||
setIsLoader(false);
|
||||
}
|
||||
};
|
||||
// `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) {
|
||||
localStorage.setItem("accesstoken", sessionToken);
|
||||
const _user = JSON.parse(JSON.stringify(validUser));
|
||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
||||
if (_user.ProfilePic) {
|
||||
localStorage.setItem("profileImg", _user.ProfilePic);
|
||||
} else {
|
||||
localStorage.setItem("profileImg", "");
|
||||
}
|
||||
// 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
|
||||
);
|
||||
if (_extUser.TenantId) {
|
||||
const obj = {
|
||||
tenentId: _extUser.TenantId.objectId,
|
||||
tenentName: _extUser.TenantId.TenantName || ""
|
||||
};
|
||||
localStorage.setItem("TenantId", obj.tenentId);
|
||||
tenentInfo.push(obj);
|
||||
dispatch(showTenant(obj.tenentName || ""));
|
||||
localStorage.setItem("TenantName", obj.tenentName || "");
|
||||
}
|
||||
localStorage.setItem("PageLanding", roleSetting.pageId);
|
||||
localStorage.setItem("defaultmenuid", roleSetting.menuId);
|
||||
localStorage.setItem("pageType", roleSetting.pageType);
|
||||
if (isEnableSubscription) {
|
||||
const res = await fetchSubscription();
|
||||
const plan = res.plan;
|
||||
const billingDate = res.billingDate;
|
||||
if (plan === "freeplan") {
|
||||
navigate(redirectUrl);
|
||||
} else if (billingDate) {
|
||||
if (new Date(billingDate) > new Date()) {
|
||||
localStorage.removeItem("userDetails");
|
||||
navigate(redirectUrl);
|
||||
} else {
|
||||
navigate(`/subscription`, {
|
||||
replace: true
|
||||
});
|
||||
}
|
||||
} else {
|
||||
navigate(`/subscription`, {
|
||||
replace: true
|
||||
});
|
||||
}
|
||||
} else {
|
||||
navigate(redirectUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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 (err) {
|
||||
console.log("err in usergroups", err);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Err in become method", err);
|
||||
}
|
||||
};
|
||||
// `handleCloseModal` is triggered when the user wants to close the new user flow modal
|
||||
const handleCloseModal = () => {
|
||||
setIsModal(false);
|
||||
if (Parse?.User?.current()) {
|
||||
Parse.User.logOut();
|
||||
}
|
||||
};
|
||||
|
||||
// `validateInput` is used to verify the phone pattern
|
||||
function validateInput(input) {
|
||||
if (input) {
|
||||
const pattern = /^(?!.*\+.*\+)[\d+-]*$/;
|
||||
return pattern.test(input);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<div className="w-full h-screen flex flex-col justify-center items-center text-sm md:text-xl ">
|
||||
{message === "Verifying SSO..." && <Loader />}
|
||||
<div className="text-base-content">{message}</div>
|
||||
</div>
|
||||
<ModalUi isOpen={isModal} title="Additional Info" showClose={false}>
|
||||
<div className="relative">
|
||||
{isLoader && (
|
||||
<div className="absolute w-full h-full bg-black bg-opacity-25 flex justify-center items-center">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
<form
|
||||
className="px-4 py-3 text-base-content"
|
||||
onSubmit={handleSubmitbtn}
|
||||
>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="Company" className="block text-xs font-semibold">
|
||||
Phone <span className="text-[13px] text-[red]">*</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"
|
||||
id="Phone"
|
||||
value={userDetails.phone}
|
||||
onChange={(e) =>
|
||||
setUserDetails({
|
||||
...userDetails,
|
||||
phone: e.target.value
|
||||
})
|
||||
}
|
||||
disabled={isLoader}
|
||||
required
|
||||
/>
|
||||
<p className="text-[10px] text-[red] ml-2">
|
||||
{!validateInput(userDetails.phone) && "Invalid phone value"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="Company" className="block text-xs font-semibold">
|
||||
Company <span className="text-[13px] text-[red]">*</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"
|
||||
id="Company"
|
||||
value={userDetails.Company}
|
||||
onChange={(e) =>
|
||||
setUserDetails({
|
||||
...userDetails,
|
||||
Company: e.target.value
|
||||
})
|
||||
}
|
||||
disabled={isLoader}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="JobTitle" className="block text-xs font-semibold">
|
||||
Job Title
|
||||
<span className="text-[13px] text-[red]">*</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"
|
||||
id="JobTitle"
|
||||
value={userDetails.Destination}
|
||||
onChange={(e) =>
|
||||
setUserDetails({
|
||||
...userDetails,
|
||||
Destination: e.target.value
|
||||
})
|
||||
}
|
||||
disabled={isLoader}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Login
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-ghost ml-2"
|
||||
onClick={handleCloseModal}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</ModalUi>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SSOVerify;
|
||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react";
|
||||
import Parse from "parse";
|
||||
import axios from "axios";
|
||||
import Title from "../components/Title";
|
||||
import { useNavigate, NavLink, useLocation } from "react-router-dom";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import login_img from "../assets/images/login_img.svg";
|
||||
import { useWindowSize } from "../hook/useWindowSize";
|
||||
import Alert from "../primitives/Alert";
|
||||
@@ -11,7 +11,8 @@ import { useDispatch } from "react-redux";
|
||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { getAppLogo } from "../constant/Utils";
|
||||
import { getAppLogo, openInNewTab } from "../constant/Utils";
|
||||
import Loader from "../primitives/Loader";
|
||||
const Signup = () => {
|
||||
const { width } = useWindowSize();
|
||||
const navigate = useNavigate();
|
||||
@@ -33,7 +34,7 @@ const Signup = () => {
|
||||
const [lengthValid, setLengthValid] = useState(false);
|
||||
const [caseDigitValid, setCaseDigitValid] = useState(false);
|
||||
const [specialCharValid, setSpecialCharValid] = useState(false);
|
||||
|
||||
const [isAuthorize, setIsAuthorize] = useState(false);
|
||||
const togglePasswordVisibility = () => setShowPassword(!showPassword);
|
||||
|
||||
const clearStorage = async () => {
|
||||
@@ -501,80 +502,58 @@ const Signup = () => {
|
||||
setSpecialCharValid(/[!@#$%^&*()\-_=+{};:,<.>]/.test(newPassword));
|
||||
};
|
||||
return (
|
||||
<div className="bg-white">
|
||||
<div className="">
|
||||
{state.loading && (
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
width: "100vw",
|
||||
height: "100vh",
|
||||
backgroundColor: "rgba(0,0,0,0.2)",
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 2
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
fontSize: "50px",
|
||||
color: "#3ac9d6",
|
||||
top: "50%",
|
||||
left: "45%"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="fixed w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-50">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Title title={"Signup page"} />
|
||||
|
||||
{appInfo && appInfo.applogo ? (
|
||||
<div>
|
||||
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
||||
<div className="md:p-10 lg:p-16">
|
||||
<div className="md:p-4 lg:p-10 p-4 bg-base-100 text-base-content op-card">
|
||||
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
||||
{image && (
|
||||
<img src={image} className="object-contain h-full" alt="logo" />
|
||||
)}
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-2">
|
||||
<div className="">
|
||||
<div>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<h2 className="text-[30px] mt-6">Create Account !</h2>
|
||||
<div className="outline outline-1 outline-slate-300/50 shadow-md rounded my-4">
|
||||
<div className="w-full my-4 op-card bg-base-100 shadow-md outline outline-1 outline-slate-300/50">
|
||||
<div className="px-6 py-4 text-xs">
|
||||
<label className="block ">
|
||||
Name{" "}
|
||||
<span style={{ color: "red", fontSize: 13 }}>*</span>
|
||||
Name <span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
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 style={{ color: "red", fontSize: 13 }}>*</span>
|
||||
Email <span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="email"
|
||||
type="text"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
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)}
|
||||
onChange={(e) =>
|
||||
setEmail(e.target.value?.toLowerCase())
|
||||
}
|
||||
required
|
||||
/>
|
||||
<hr className="my-2 border-none" />
|
||||
<label>
|
||||
Phone{" "}
|
||||
<span style={{ color: "red", fontSize: 13 }}>*</span>
|
||||
Phone <span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="tel"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
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
|
||||
@@ -582,11 +561,11 @@ const Signup = () => {
|
||||
<hr className="my-2 border-none" />
|
||||
<label>
|
||||
Company{" "}
|
||||
<span style={{ color: "red", fontSize: 13 }}>*</span>
|
||||
<span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
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
|
||||
@@ -594,11 +573,11 @@ const Signup = () => {
|
||||
<hr className="my-2 border-none" />
|
||||
<label>
|
||||
Job Title{" "}
|
||||
<span style={{ color: "red", fontSize: 13 }}>*</span>
|
||||
<span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
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
|
||||
@@ -606,21 +585,19 @@ const Signup = () => {
|
||||
<hr className="my-2 border-none" />
|
||||
<label>
|
||||
Password{" "}
|
||||
<span style={{ color: "red", fontSize: 13 }}>*</span>
|
||||
<span className="text-[red] text-[13px]">*</span>
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={showPassword ? "text" : "password"}
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
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 ${
|
||||
showPassword ? "text-[#007bff]" : "text-black"
|
||||
}`}
|
||||
className={`absolute top-[50%] right-[10px] -translate-y-[50%] cursor-pointer text-base-content`}
|
||||
onClick={togglePasswordVisibility}
|
||||
>
|
||||
{showPassword ? (
|
||||
@@ -658,34 +635,62 @@ const Signup = () => {
|
||||
{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>
|
||||
</div>
|
||||
<div className="flex flex-col md:flex-row justify-between items-stretch gap-8 text-center text-xs font-bold mt-2">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-center text-xs font-bold mt-2">
|
||||
<button
|
||||
type="submit"
|
||||
className="rounded-sm bg-[#3ac9d6] text-white w-full py-3 shadow uppercase"
|
||||
className="op-btn op-btn-primary"
|
||||
disabled={state.loading}
|
||||
>
|
||||
{state.loading ? "Loading..." : "Register"}
|
||||
</button>
|
||||
<NavLink
|
||||
className="rounded-sm cursor-pointer bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] w-full py-3 shadow uppercase"
|
||||
to={location.search ? "/" + location.search : "/"}
|
||||
style={width < 768 ? { textAlign: "center" } : {}}
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-secondary"
|
||||
disabled={state.loading}
|
||||
onClick={() =>
|
||||
navigate(location.search ? "/" + location.search : "/")
|
||||
}
|
||||
>
|
||||
Login
|
||||
</NavLink>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{width >= 768 && (
|
||||
<div className="self-center">
|
||||
<div className="mx-auto md:w-[300px] lg:w-[400px] xl:w-[500px]">
|
||||
<img src={login_img} alt="bisec" width="100%" />
|
||||
<img src={login_img} alt="loader" width="100%" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -694,16 +699,9 @@ const Signup = () => {
|
||||
<Alert type={state.alertType}>{state.alertMsg}</Alert>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
fontSize: "50px",
|
||||
color: "#3ac9d6",
|
||||
top: "50%",
|
||||
left: "45%"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="fixed w-full h-full flex justify-center items-center z-50">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -2,10 +2,10 @@ import React, { useState, useRef, useEffect } from "react";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
import "../styles/signature.css";
|
||||
import Parse from "parse";
|
||||
import { isEnableSubscription, themeColor } from "../constant/const";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import Confetti from "react-confetti";
|
||||
import axios from "axios";
|
||||
import Loader from "../primitives/LoaderWithMsg";
|
||||
import loader from "../assets/images/loader2.gif";
|
||||
import LoaderWithMsg from "../primitives/LoaderWithMsg";
|
||||
import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage";
|
||||
import { DndProvider } from "react-dnd";
|
||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||
@@ -17,7 +17,6 @@ import {
|
||||
contractDocument,
|
||||
embedDocId,
|
||||
multiSignEmbed,
|
||||
pdfNewWidthFun,
|
||||
onImageSelect,
|
||||
calculateInitialWidthHeight,
|
||||
defaultWidthHeight,
|
||||
@@ -31,6 +30,7 @@ import {
|
||||
getTenantDetails,
|
||||
checkIsSubscribed,
|
||||
convertPdfArrayBuffer,
|
||||
textInputWidget,
|
||||
fetchImageBase64,
|
||||
changeImageWH,
|
||||
handleSendOTP
|
||||
@@ -46,8 +46,11 @@ import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
||||
import Title from "../components/Title";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
||||
import { useSelector } from "react-redux";
|
||||
import TextFontSetting from "../components/pdf/TextFontSetting";
|
||||
import VerifyEmail from "../components/pdf/VerifyEmail";
|
||||
|
||||
import PdfZoom from "../components/pdf/PdfZoom";
|
||||
import Loader from "../primitives/Loader";
|
||||
//For signYourself inProgress section signer can add sign and complete doc sign.
|
||||
function SignYourSelf() {
|
||||
const [pdfDetails, setPdfDetails] = useState([]);
|
||||
@@ -68,11 +71,12 @@ 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 [signKey, setSignKey] = useState();
|
||||
const [imgWH, setImgWH] = useState({});
|
||||
const [isCeleb, setIsCeleb] = useState(false);
|
||||
const [pdfNewWidth, setPdfNewWidth] = useState();
|
||||
const [pdfOriginalWidth, setPdfOriginalWidth] = useState();
|
||||
const [pdfOriginalWH, setPdfOriginalWH] = useState([]);
|
||||
const [successEmail, setSuccessEmail] = useState(false);
|
||||
const imageRef = useRef(null);
|
||||
const [myInitial, setMyInitial] = useState("");
|
||||
@@ -98,22 +102,24 @@ function SignYourSelf() {
|
||||
const [showAlreadySignDoc, setShowAlreadySignDoc] = useState({
|
||||
status: false
|
||||
});
|
||||
const [isTextSetting, setIsTextSetting] = useState(false);
|
||||
const [currWidgetsDetails, setCurrWidgetsDetails] = useState({});
|
||||
const [isCheckbox, setIsCheckbox] = useState(false);
|
||||
const [widgetType, setWidgetType] = useState("");
|
||||
const [pdfLoadFail, setPdfLoadFail] = useState({
|
||||
status: false,
|
||||
type: "load"
|
||||
});
|
||||
const [pdfLoad, setPdfLoad] = useState(false);
|
||||
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
|
||||
const [isDontShow, setIsDontShow] = useState(false);
|
||||
const [extUserId, setExtUserId] = useState("");
|
||||
const [isCompleted, setIsCompleted] = useState(false);
|
||||
const [isCelebration, setIsCelebration] = useState(false);
|
||||
const [pdfArrayBuffer, setPdfArrayBuffer] = useState("");
|
||||
const [activeMailAdapter, setActiveMailAdapter] = useState("");
|
||||
const [isEmailVerified, setIsEmailVerified] = useState(true);
|
||||
const [isVerifyModal, setIsVerifyModal] = useState(false);
|
||||
const [otp, setOtp] = useState("");
|
||||
const [zoomPercent, setZoomPercent] = useState(0);
|
||||
const isHeader = useSelector((state) => state.showHeader);
|
||||
const [scale, setScale] = useState(1);
|
||||
const divRef = useRef(null);
|
||||
const nodeRef = useRef(null);
|
||||
const [, drop] = useDrop({
|
||||
@@ -123,10 +129,7 @@ function SignYourSelf() {
|
||||
isOver: !!monitor.isOver()
|
||||
})
|
||||
});
|
||||
const isMobile = window.innerWidth < 767;
|
||||
|
||||
const pdfRef = useRef();
|
||||
|
||||
const [{ isDragSign }, dragSignature] = useDrag({
|
||||
type: "BOX",
|
||||
item: {
|
||||
@@ -154,7 +157,6 @@ function SignYourSelf() {
|
||||
return object.pageNumber === pageNumber;
|
||||
});
|
||||
// rowlevel={JSON.parse(localStorage.getItem("rowlevel"))}
|
||||
|
||||
const rowLevel =
|
||||
localStorage.getItem("rowlevel") &&
|
||||
JSON.parse(localStorage.getItem("rowlevel"));
|
||||
@@ -182,17 +184,25 @@ function SignYourSelf() {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (divRef.current) {
|
||||
const pdfWidth = pdfNewWidthFun(divRef);
|
||||
setPdfNewWidth(pdfWidth);
|
||||
setContainerWH({
|
||||
width: divRef.current.offsetWidth,
|
||||
height: divRef.current.offsetHeight
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [divRef.current]);
|
||||
const updateSize = () => {
|
||||
if (divRef.current) {
|
||||
const pdfWidth = divRef.current.offsetWidth;
|
||||
setPdfNewWidth(pdfWidth);
|
||||
setContainerWH({
|
||||
width: divRef.current.offsetWidth,
|
||||
height: divRef.current.offsetHeight
|
||||
});
|
||||
setScale(1);
|
||||
setZoomPercent(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Use setTimeout to wait for the transition to complete
|
||||
const timer = setTimeout(updateSize, 100); // match the transition duration
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [divRef.current, isHeader]);
|
||||
//function for get document details for perticular signer with signer'object id
|
||||
const getDocumentDetails = async (showComplete) => {
|
||||
let isCompleted;
|
||||
@@ -214,14 +224,17 @@ function SignYourSelf() {
|
||||
} else {
|
||||
setHandleError("Error: Something went wrong!");
|
||||
}
|
||||
|
||||
isCompleted = documentData[0].IsCompleted && documentData[0].IsCompleted;
|
||||
if (isCompleted) {
|
||||
setIsCelebration(true);
|
||||
setTimeout(() => {
|
||||
setIsCelebration(false);
|
||||
}, 5000);
|
||||
setIsCompleted(true);
|
||||
setPdfUrl(documentData[0].SignedUrl);
|
||||
const alreadySign = {
|
||||
status: true,
|
||||
mssg: "You have successfully signed the document!"
|
||||
mssg: "Congratulations! 🎉 This document has been successfully signed by you!"
|
||||
};
|
||||
if (showComplete) {
|
||||
setShowAlreadySignDoc(alreadySign);
|
||||
@@ -438,61 +451,69 @@ function SignYourSelf() {
|
||||
);
|
||||
const dragTypeValue = item?.text ? item.text : monitor.type;
|
||||
const widgetValue = getWidgetValue(dragTypeValue);
|
||||
const widgetWidth = defaultWidthHeight(dragTypeValue).width;
|
||||
const widgetHeight = defaultWidthHeight(dragTypeValue).height;
|
||||
const widgetTypeExist = ["name", "company", "job title", "email"].includes(
|
||||
dragTypeValue
|
||||
);
|
||||
const getPdfPageWidth = pdfOriginalWH.find(
|
||||
(data) => data.pageNumber === pageNumber
|
||||
);
|
||||
const containerScale = containerWH?.width / getPdfPageWidth?.width || 1;
|
||||
//adding and updating drop position in array when user drop signature button in div
|
||||
if (item === "onclick") {
|
||||
const getWidth = widgetTypeExist
|
||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
|
||||
: dragTypeValue === "initials"
|
||||
? defaultWidthHeight(dragTypeValue).width
|
||||
: "";
|
||||
const getHeight = widgetTypeExist
|
||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getHeight
|
||||
: dragTypeValue === "initials"
|
||||
? defaultWidthHeight(dragTypeValue).height
|
||||
: "";
|
||||
dropObj = {
|
||||
xPosition: containerWH.width / 2 - widgetWidth / 2,
|
||||
yPosition: containerWH.height / 2 - widgetHeight / 2,
|
||||
isDrag: false,
|
||||
xPosition: containerWH.width / 2,
|
||||
yPosition: containerWH.height / 2,
|
||||
isStamp:
|
||||
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
|
||||
key: key,
|
||||
type: dragTypeValue,
|
||||
yBottom: window.innerHeight / 2 - 60,
|
||||
|
||||
Width: widgetTypeExist
|
||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
|
||||
: dragTypeValue === "initials"
|
||||
? defaultWidthHeight(dragTypeValue).width
|
||||
: "",
|
||||
Height: widgetTypeExist
|
||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getHeight
|
||||
: dragTypeValue === "initials"
|
||||
? defaultWidthHeight(dragTypeValue).height
|
||||
: "",
|
||||
scale: containerScale,
|
||||
Width: getWidth / (containerScale * scale),
|
||||
Height: getHeight / (containerScale * scale),
|
||||
options: addWidgetOptions(dragTypeValue)
|
||||
};
|
||||
|
||||
dropData.push(dropObj);
|
||||
} else {
|
||||
//This method returns the offset of the current pointer (mouse) position relative to the client viewport.
|
||||
const offset = monitor.getClientOffset();
|
||||
//adding and updating drop position in array when user drop signature button in div
|
||||
const containerRect = document
|
||||
.getElementById("container")
|
||||
.getBoundingClientRect();
|
||||
//`containerRect.left`, The distance from the left of the viewport to the left side of the element.
|
||||
//`containerRect.top` The distance from the top of the viewport to the top of the element.
|
||||
|
||||
const x = offset.x - containerRect.left;
|
||||
const y = offset.y - containerRect.top;
|
||||
|
||||
const getXPosition = signBtnPosition[0] ? x - signBtnPosition[0].xPos : x;
|
||||
const getYPosition = signBtnPosition[0] ? y - signBtnPosition[0].yPos : y;
|
||||
const getWidth = widgetTypeExist
|
||||
? calculateInitialWidthHeight(widgetValue).getWidth
|
||||
: defaultWidthHeight(dragTypeValue).width;
|
||||
const getHeight = widgetTypeExist
|
||||
? calculateInitialWidthHeight(widgetValue).getHeight
|
||||
: defaultWidthHeight(dragTypeValue).height;
|
||||
dropObj = {
|
||||
xPosition: signBtnPosition[0] ? x - signBtnPosition[0].xPos : x,
|
||||
yPosition: signBtnPosition[0] ? y - signBtnPosition[0].yPos : y,
|
||||
// isDrag: false,
|
||||
xPosition: getXPosition / (containerScale * scale),
|
||||
yPosition: getYPosition / (containerScale * scale),
|
||||
isStamp:
|
||||
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
|
||||
key: key,
|
||||
type: dragTypeValue,
|
||||
Width: widgetTypeExist
|
||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
|
||||
: defaultWidthHeight(dragTypeValue).width,
|
||||
Height: widgetTypeExist
|
||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getHeight
|
||||
: defaultWidthHeight(dragTypeValue).height,
|
||||
options: addWidgetOptions(dragTypeValue)
|
||||
Width: getWidth / (containerScale * scale),
|
||||
Height: getHeight / (containerScale * scale),
|
||||
options: addWidgetOptions(dragTypeValue),
|
||||
scale: containerScale
|
||||
};
|
||||
|
||||
dropData.push(dropObj);
|
||||
@@ -502,16 +523,12 @@ function SignYourSelf() {
|
||||
return object.pageNumber === pageNumber;
|
||||
});
|
||||
const updateData = filterDropPos[0].pos;
|
||||
|
||||
// if (updateData.length > dropData.length) {
|
||||
const newSignPos = updateData.concat(dropData);
|
||||
let xyPos = {
|
||||
pageNumber: pageNumber,
|
||||
pos: newSignPos
|
||||
};
|
||||
xyPostion.splice(index, 1, xyPos);
|
||||
|
||||
// }
|
||||
} else {
|
||||
const xyPos = {
|
||||
pageNumber: pageNumber,
|
||||
@@ -535,6 +552,18 @@ function SignYourSelf() {
|
||||
setIsInitial(true);
|
||||
} else if (dragTypeValue === "checkbox") {
|
||||
setIsCheckbox(true);
|
||||
} else if (
|
||||
[
|
||||
textInputWidget,
|
||||
textWidget,
|
||||
"name",
|
||||
"company",
|
||||
"job title",
|
||||
"email"
|
||||
].includes(dragTypeValue)
|
||||
) {
|
||||
setFontSize(12);
|
||||
setFontColor("black");
|
||||
}
|
||||
setWidgetType(dragTypeValue);
|
||||
setSelectWidgetId(key);
|
||||
@@ -649,10 +678,6 @@ function SignYourSelf() {
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
setIsCeleb(true);
|
||||
setTimeout(() => {
|
||||
setIsCeleb(false);
|
||||
}, 3000);
|
||||
setIsUiLoading(true);
|
||||
const existingPdfBytes = pdfArrayBuffer;
|
||||
// Load a PDFDocument from the existing PDF bytes
|
||||
@@ -669,13 +694,14 @@ function SignYourSelf() {
|
||||
const pdfBytes = await multiSignEmbed(
|
||||
xyPostion,
|
||||
pdfDoc,
|
||||
pdfOriginalWidth,
|
||||
isSignYourSelfFlow,
|
||||
containerWH
|
||||
scale
|
||||
);
|
||||
// console.log("pdf", pdfBytes);
|
||||
//function for call to embed signature in pdf and get digital signature pdf
|
||||
await signPdfFun(pdfBytes, documentId);
|
||||
if (pdfBytes) {
|
||||
await signPdfFun(pdfBytes, documentId);
|
||||
}
|
||||
} catch (err) {
|
||||
setIsUiLoading(false);
|
||||
if (err && err.message.includes("is encrypted.")) {
|
||||
@@ -781,22 +807,18 @@ function SignYourSelf() {
|
||||
setDragKey(key);
|
||||
setIsDragging(true);
|
||||
};
|
||||
|
||||
//function for set and update x and y postion after drag and drop signature tab
|
||||
const handleStop = (event, dragElement) => {
|
||||
if (isDragging && dragElement) {
|
||||
event.preventDefault();
|
||||
const containerRect = document
|
||||
.getElementById("container")
|
||||
.getBoundingClientRect();
|
||||
|
||||
const ybottom = containerRect.height - dragElement.y;
|
||||
|
||||
const getPdfPageWidth = pdfOriginalWH.find(
|
||||
(data) => data.pageNumber === pageNumber
|
||||
);
|
||||
const containerScale = containerWH.width / getPdfPageWidth?.width || 1;
|
||||
if (dragKey >= 0) {
|
||||
const filterDropPos = xyPostion.filter(
|
||||
(data) => data.pageNumber === pageNumber
|
||||
);
|
||||
|
||||
if (filterDropPos.length > 0) {
|
||||
const getXYdata = xyPostion[index].pos;
|
||||
const getPosData = getXYdata;
|
||||
@@ -804,10 +826,8 @@ function SignYourSelf() {
|
||||
if (url.key === dragKey) {
|
||||
return {
|
||||
...url,
|
||||
xPosition: dragElement.x,
|
||||
yPosition: dragElement.y,
|
||||
isDrag: true,
|
||||
yBottom: ybottom
|
||||
xPosition: dragElement.x / (containerScale * scale),
|
||||
yPosition: dragElement.y / (containerScale * scale)
|
||||
};
|
||||
}
|
||||
return url;
|
||||
@@ -827,26 +847,24 @@ function SignYourSelf() {
|
||||
setIsDragging(false);
|
||||
}, 200);
|
||||
};
|
||||
|
||||
//function for get pdf page details
|
||||
const pageDetails = async (pdf) => {
|
||||
const load = {
|
||||
status: true
|
||||
};
|
||||
setPdfLoadFail(load);
|
||||
pdf.getPage(1).then((pdfPage) => {
|
||||
const pageWidth = pdfPage.view[2];
|
||||
|
||||
setPdfOriginalWidth(pageWidth);
|
||||
});
|
||||
let pdfWHObj = [];
|
||||
const totalPages = pdf?.numPages;
|
||||
for (let index = 0; index < totalPages; index++) {
|
||||
const getPage = await pdf.getPage(index + 1);
|
||||
const scale = 1;
|
||||
const { width, height } = getPage.getViewport({ scale });
|
||||
pdfWHObj.push({ pageNumber: index + 1, width, height });
|
||||
}
|
||||
setPdfOriginalWH(pdfWHObj);
|
||||
setPdfLoad(true);
|
||||
};
|
||||
|
||||
//function for change page numver of pdf
|
||||
function changePage(offset) {
|
||||
setSignBtnPosition([]);
|
||||
setPageNumber((prevPageNumber) => prevPageNumber + offset);
|
||||
}
|
||||
|
||||
//function for image upload or update
|
||||
const onImageChange = (event) => {
|
||||
if (event.target.files && event.target.files[0]) {
|
||||
@@ -896,18 +914,30 @@ function SignYourSelf() {
|
||||
|
||||
setXyPostion(getUpdatePosition);
|
||||
};
|
||||
//function for capture position on hover signature button
|
||||
//function for capture position on hover or touch widgets button
|
||||
const handleDivClick = (e) => {
|
||||
const isTouchEvent = e.type.startsWith("touch");
|
||||
const divRect = e.currentTarget.getBoundingClientRect();
|
||||
const mouseX = e.clientX - divRect.left;
|
||||
const mouseY = e.clientY - divRect.top;
|
||||
|
||||
const xyPosition = {
|
||||
xPos: mouseX,
|
||||
yPos: mouseY
|
||||
};
|
||||
|
||||
setXYSignature(xyPosition);
|
||||
let mouseX, mouseY;
|
||||
if (isTouchEvent) {
|
||||
const touch = e.touches[0]; // Get the first touch point
|
||||
mouseX = touch.clientX - divRect.left;
|
||||
mouseY = touch.clientY - divRect.top;
|
||||
setSignBtnPosition([
|
||||
{
|
||||
xPos: mouseX,
|
||||
yPos: mouseY
|
||||
}
|
||||
]);
|
||||
} else {
|
||||
mouseX = e.clientX - divRect.left;
|
||||
mouseY = e.clientY - divRect.top;
|
||||
const xyPosition = {
|
||||
xPos: mouseX,
|
||||
yPos: mouseY
|
||||
};
|
||||
setXYSignature(xyPosition);
|
||||
}
|
||||
};
|
||||
|
||||
//function for capture position of x and y on hover signature button last position
|
||||
@@ -955,7 +985,7 @@ function SignYourSelf() {
|
||||
};
|
||||
const tourConfig = [
|
||||
{
|
||||
selector: '[data-tut="reactourFirst"]',
|
||||
selector: '[data-tut="addWidgets"]',
|
||||
content: () => (
|
||||
<TourContentWithBtn
|
||||
message={`Select and drag your preferred widgets onto the PDF to customize your document before signing. Choose the perfect spots for each modification to tailor the document to your needs.`}
|
||||
@@ -1083,47 +1113,71 @@ function SignYourSelf() {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleCloseModal = () => {
|
||||
setCurrWidgetsDetails({});
|
||||
setIsCheckbox(false);
|
||||
};
|
||||
const handleTextSettingModal = (value) => {
|
||||
setIsTextSetting(value);
|
||||
};
|
||||
const handleSaveFontSize = () => {
|
||||
const getPageNumer = xyPostion.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 || currWidgetsDetails?.options?.fontSize,
|
||||
fontColor: fontColor || currWidgetsDetails?.options?.fontColor
|
||||
}
|
||||
};
|
||||
}
|
||||
return position;
|
||||
});
|
||||
const updateXYposition = xyPostion.map((obj, ind) => {
|
||||
if (ind === index) {
|
||||
return { ...obj, pos: addSignPos };
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
setXyPostion(updateXYposition);
|
||||
setFontSize();
|
||||
setFontColor();
|
||||
handleTextSettingModal(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<Title title={"Self Sign"} />
|
||||
{isLoading.isLoad ? (
|
||||
<Loader isLoading={isLoading} />
|
||||
<LoaderWithMsg isLoading={isLoading} />
|
||||
) : handleError ? (
|
||||
<HandleError handleError={handleError} />
|
||||
) : (
|
||||
<div>
|
||||
{isUiLoading && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
height: "100vh",
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
zIndex: "999",
|
||||
backgroundColor: "#e6f2f2",
|
||||
opacity: 0.8
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="no img"
|
||||
src={loader}
|
||||
style={{ width: "100px", height: "100px" }}
|
||||
/>
|
||||
<div className="absolute h-[100vh] w-full z-[999] flex flex-col justify-center items-center bg-[#e6f2f2] bg-opacity-80">
|
||||
<Loader />
|
||||
<span style={{ fontSize: "13px", fontWeight: "bold" }}>
|
||||
This might take some time
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{isCelebration && (
|
||||
<div className="relative z-[1000]">
|
||||
<Confetti width={window.innerWidth} height={window.innerHeight} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="signatureContainer" ref={divRef}>
|
||||
<div className="relative op-card overflow-hidden flex flex-col md:flex-row justify-between bg-base-300">
|
||||
{!isEmailVerified && (
|
||||
<VerifyEmail
|
||||
isVerifyModal={isVerifyModal}
|
||||
@@ -1137,7 +1191,7 @@ function SignYourSelf() {
|
||||
/>
|
||||
)}
|
||||
{/* this component used for UI interaction and show their functionality */}
|
||||
{pdfLoadFail && !checkTourStatus && (
|
||||
{pdfLoad && !checkTourStatus && (
|
||||
<Tour
|
||||
onRequestClose={closeTour}
|
||||
steps={tourConfig}
|
||||
@@ -1158,242 +1212,233 @@ function SignYourSelf() {
|
||||
setPageNumber={setPageNumber}
|
||||
setSignBtnPosition={setSignBtnPosition}
|
||||
pageNumber={pageNumber}
|
||||
containerWH={containerWH}
|
||||
/>
|
||||
<div className=" w-full md:w-[57%] flex mr-4">
|
||||
<PdfZoom
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
containerWH={containerWH}
|
||||
setZoomPercent={setZoomPercent}
|
||||
zoomPercent={zoomPercent}
|
||||
/>
|
||||
<div className=" w-full md:w-[95%] ">
|
||||
<ModalUi
|
||||
isOpen={isAlert.isShow}
|
||||
title={isAlert?.header || "Alert"}
|
||||
handleClose={() => {
|
||||
setIsAlert({
|
||||
isShow: false,
|
||||
alertMessage: ""
|
||||
});
|
||||
}}
|
||||
>
|
||||
<div className="p-[20px] h-full">
|
||||
<p>{isAlert.alertMessage}</p>
|
||||
</div>
|
||||
</ModalUi>
|
||||
|
||||
{/* pdf render view */}
|
||||
<div
|
||||
style={{
|
||||
marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px",
|
||||
marginRight: !isMobile && pdfOriginalWidth > 500 && "20px"
|
||||
}}
|
||||
>
|
||||
<ModalUi
|
||||
headerColor={"#dc3545"}
|
||||
isOpen={isAlert.isShow}
|
||||
title={isAlert?.header || "Alert"}
|
||||
handleClose={() => {
|
||||
setIsAlert({
|
||||
isShow: false,
|
||||
alertMessage: ""
|
||||
});
|
||||
}}
|
||||
>
|
||||
<div style={{ height: "100%", padding: 20 }}>
|
||||
<p>{isAlert.alertMessage}</p>
|
||||
{/* this modal is used show this document is already sign */}
|
||||
<ModalUi
|
||||
isOpen={showAlreadySignDoc.status}
|
||||
title={"Document signed"}
|
||||
handleClose={() => {
|
||||
setShowAlreadySignDoc({ status: false });
|
||||
}}
|
||||
>
|
||||
<div className="p-[20px] h-full">
|
||||
<p>{showAlreadySignDoc.mssg}</p>
|
||||
|
||||
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
|
||||
<button
|
||||
className="op-btn op-btn-ghost shadow-md"
|
||||
onClick={() => setShowAlreadySignDoc({ status: false })}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</ModalUi>
|
||||
<DropdownWidgetOption
|
||||
type="checkbox"
|
||||
title="Checkbox"
|
||||
showDropdown={isCheckbox}
|
||||
setShowDropdown={setIsCheckbox}
|
||||
handleSaveWidgetsOptions={handleSaveWidgetsOptions}
|
||||
currWidgetsDetails={currWidgetsDetails}
|
||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||
isSignYourself={true}
|
||||
handleClose={handleCloseModal}
|
||||
/>
|
||||
<PlaceholderCopy
|
||||
isPageCopy={isPageCopy}
|
||||
setIsPageCopy={setIsPageCopy}
|
||||
xyPostion={xyPostion}
|
||||
setXyPostion={setXyPostion}
|
||||
allPages={allPages}
|
||||
pageNumber={pageNumber}
|
||||
signKey={signKey}
|
||||
/>
|
||||
{/* this is modal of signature pad */}
|
||||
<SignPad
|
||||
isSignPad={isSignPad}
|
||||
isStamp={isStamp}
|
||||
setIsImageSelect={setIsImageSelect}
|
||||
setIsSignPad={setIsSignPad}
|
||||
setImage={setImage}
|
||||
isImageSelect={isImageSelect}
|
||||
imageRef={imageRef}
|
||||
onImageChange={onImageChange}
|
||||
setSignature={setSignature}
|
||||
image={image}
|
||||
onSaveImage={saveImage}
|
||||
onSaveSign={saveSign}
|
||||
defaultSign={defaultSignImg}
|
||||
myInitial={myInitial}
|
||||
isInitial={isInitial}
|
||||
setIsInitial={setIsInitial}
|
||||
setIsStamp={setIsStamp}
|
||||
widgetType={widgetType}
|
||||
currWidgetsDetails={currWidgetsDetails}
|
||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||
/>
|
||||
{/*render email component to send email after finish signature on document */}
|
||||
<EmailComponent
|
||||
isEmail={isEmail}
|
||||
pdfUrl={pdfUrl}
|
||||
setIsEmail={setIsEmail}
|
||||
pdfName={pdfDetails[0] && pdfDetails[0].Name}
|
||||
setSuccessEmail={setSuccessEmail}
|
||||
sender={jsonSender}
|
||||
setIsAlert={setIsAlert}
|
||||
extUserId={extUserId}
|
||||
activeMailAdapter={activeMailAdapter}
|
||||
/>
|
||||
{/* pdf header which contain funish back button */}
|
||||
<Header
|
||||
pageNumber={pageNumber}
|
||||
allPages={allPages}
|
||||
changePage={changePage}
|
||||
pdfUrl={pdfUrl}
|
||||
embedWidgetsData={embedWidgetsData}
|
||||
pdfDetails={pdfDetails}
|
||||
isShowHeader={true}
|
||||
currentSigner={true}
|
||||
alreadySign={pdfUrl ? true : false}
|
||||
isSignYourself={true}
|
||||
setIsEmail={setIsEmail}
|
||||
isCompleted={isCompleted}
|
||||
/>
|
||||
<div
|
||||
ref={divRef}
|
||||
data-tut="reactourSecond"
|
||||
className="h-full md:h-[95%]"
|
||||
>
|
||||
{containerWH?.width && containerWH?.height && (
|
||||
<RenderPdf
|
||||
pageNumber={pageNumber}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pdfNewWidth={pdfNewWidth}
|
||||
drop={drop}
|
||||
successEmail={successEmail}
|
||||
nodeRef={nodeRef}
|
||||
handleTabDrag={handleTabDrag}
|
||||
handleStop={handleStop}
|
||||
isDragging={isDragging}
|
||||
setIsSignPad={setIsSignPad}
|
||||
setIsStamp={setIsStamp}
|
||||
handleDeleteSign={handleDeleteSign}
|
||||
setSignKey={setSignKey}
|
||||
pdfDetails={pdfDetails}
|
||||
setIsDragging={setIsDragging}
|
||||
xyPostion={xyPostion}
|
||||
pdfRef={pdfRef}
|
||||
pdfUrl={pdfUrl}
|
||||
numPages={numPages}
|
||||
pageDetails={pageDetails}
|
||||
pdfLoad={pdfLoad}
|
||||
setPdfLoad={setPdfLoad}
|
||||
setXyPostion={setXyPostion}
|
||||
index={index}
|
||||
containerWH={containerWH}
|
||||
setIsPageCopy={setIsPageCopy}
|
||||
setIsInitial={setIsInitial}
|
||||
setWidgetType={setWidgetType}
|
||||
setSelectWidgetId={setSelectWidgetId}
|
||||
selectWidgetId={selectWidgetId}
|
||||
setIsCheckbox={setIsCheckbox}
|
||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||
setValidateAlert={setValidateAlert}
|
||||
handleTextSettingModal={handleTextSettingModal}
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</ModalUi>
|
||||
|
||||
{/* this modal is used show this document is already sign */}
|
||||
<ModalUi
|
||||
isOpen={showAlreadySignDoc.status}
|
||||
title={"Sign Documents"}
|
||||
handleClose={() => {
|
||||
setShowAlreadySignDoc({ status: false });
|
||||
}}
|
||||
>
|
||||
<div style={{ height: "100%", padding: 20 }}>
|
||||
<p>{showAlreadySignDoc.mssg}</p>
|
||||
|
||||
<div
|
||||
style={{
|
||||
height: "1px",
|
||||
backgroundColor: "#9f9f9f",
|
||||
width: "100%",
|
||||
marginTop: "15px",
|
||||
marginBottom: "15px"
|
||||
}}
|
||||
></div>
|
||||
<button
|
||||
className="finishBtn cancelBtn"
|
||||
onClick={() => setShowAlreadySignDoc({ status: false })}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</ModalUi>
|
||||
<DropdownWidgetOption
|
||||
type="checkbox"
|
||||
title="Checkbox"
|
||||
showDropdown={isCheckbox}
|
||||
setShowDropdown={setIsCheckbox}
|
||||
handleSaveWidgetsOptions={handleSaveWidgetsOptions}
|
||||
currWidgetsDetails={currWidgetsDetails}
|
||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||
isSignYourself={true}
|
||||
handleClose={handleCloseModal}
|
||||
/>
|
||||
<PlaceholderCopy
|
||||
isPageCopy={isPageCopy}
|
||||
setIsPageCopy={setIsPageCopy}
|
||||
xyPostion={xyPostion}
|
||||
setXyPostion={setXyPostion}
|
||||
allPages={allPages}
|
||||
pageNumber={pageNumber}
|
||||
signKey={signKey}
|
||||
/>
|
||||
{/* this is modal of signature pad */}
|
||||
<SignPad
|
||||
isSignPad={isSignPad}
|
||||
isStamp={isStamp}
|
||||
setIsImageSelect={setIsImageSelect}
|
||||
setIsSignPad={setIsSignPad}
|
||||
setImage={setImage}
|
||||
isImageSelect={isImageSelect}
|
||||
imageRef={imageRef}
|
||||
onImageChange={onImageChange}
|
||||
setSignature={setSignature}
|
||||
image={image}
|
||||
onSaveImage={saveImage}
|
||||
onSaveSign={saveSign}
|
||||
defaultSign={defaultSignImg}
|
||||
myInitial={myInitial}
|
||||
isInitial={isInitial}
|
||||
setIsInitial={setIsInitial}
|
||||
setIsStamp={setIsStamp}
|
||||
widgetType={widgetType}
|
||||
currWidgetsDetails={currWidgetsDetails}
|
||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||
/>
|
||||
{/*render email component to send email after finish signature on document */}
|
||||
<EmailComponent
|
||||
isEmail={isEmail}
|
||||
pdfUrl={pdfUrl}
|
||||
isCeleb={isCeleb}
|
||||
setIsEmail={setIsEmail}
|
||||
pdfName={pdfDetails[0] && pdfDetails[0].Name}
|
||||
setSuccessEmail={setSuccessEmail}
|
||||
sender={jsonSender}
|
||||
setIsAlert={setIsAlert}
|
||||
extUserId={extUserId}
|
||||
activeMailAdapter={activeMailAdapter}
|
||||
/>
|
||||
{/* pdf header which contain funish back button */}
|
||||
<Header
|
||||
pageNumber={pageNumber}
|
||||
allPages={allPages}
|
||||
changePage={changePage}
|
||||
pdfUrl={pdfUrl}
|
||||
embedWidgetsData={embedWidgetsData}
|
||||
pdfDetails={pdfDetails}
|
||||
isShowHeader={true}
|
||||
currentSigner={true}
|
||||
alreadySign={pdfUrl ? true : false}
|
||||
isSignYourself={true}
|
||||
setIsEmail={setIsEmail}
|
||||
isCompleted={isCompleted}
|
||||
/>
|
||||
|
||||
<div data-tut="reactourSecond">
|
||||
{containerWH && (
|
||||
<RenderPdf
|
||||
pageNumber={pageNumber}
|
||||
pdfOriginalWidth={pdfOriginalWidth}
|
||||
pdfNewWidth={pdfNewWidth}
|
||||
drop={drop}
|
||||
successEmail={successEmail}
|
||||
nodeRef={nodeRef}
|
||||
handleTabDrag={handleTabDrag}
|
||||
handleStop={handleStop}
|
||||
isDragging={isDragging}
|
||||
setIsSignPad={setIsSignPad}
|
||||
setIsStamp={setIsStamp}
|
||||
handleDeleteSign={handleDeleteSign}
|
||||
setSignKey={setSignKey}
|
||||
pdfDetails={pdfDetails}
|
||||
setIsDragging={setIsDragging}
|
||||
xyPostion={xyPostion}
|
||||
pdfRef={pdfRef}
|
||||
pdfUrl={pdfUrl}
|
||||
numPages={numPages}
|
||||
pageDetails={pageDetails}
|
||||
setPdfLoadFail={setPdfLoadFail}
|
||||
pdfLoadFail={pdfLoadFail}
|
||||
setXyPostion={setXyPostion}
|
||||
index={index}
|
||||
containerWH={containerWH}
|
||||
setIsPageCopy={setIsPageCopy}
|
||||
setIsInitial={setIsInitial}
|
||||
setWidgetType={setWidgetType}
|
||||
setSelectWidgetId={setSelectWidgetId}
|
||||
selectWidgetId={selectWidgetId}
|
||||
setIsCheckbox={setIsCheckbox}
|
||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||
setValidateAlert={setValidateAlert}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/*if document is not completed then render signature and stamp button in the right side */}
|
||||
{/*else document is completed then render signed by signer name in the right side */}
|
||||
<div
|
||||
style={{
|
||||
maxHeight: window.innerHeight - 70 + "px",
|
||||
backgroundColor: "white"
|
||||
}}
|
||||
className="autoSignScroll"
|
||||
>
|
||||
{!isCompleted ? (
|
||||
<div>
|
||||
<WidgetComponent
|
||||
dataTut="reactourFirst"
|
||||
pdfUrl={pdfUrl}
|
||||
dragSignature={dragSignature}
|
||||
signRef={signRef}
|
||||
handleDivClick={handleDivClick}
|
||||
handleMouseLeave={handleMouseLeave}
|
||||
isDragSign={isDragSign}
|
||||
themeColor={themeColor}
|
||||
dragStamp={dragStamp}
|
||||
dragRef={dragRef}
|
||||
isDragStamp={isDragStamp}
|
||||
handleAllDelete={handleAllDelete}
|
||||
xyPostion={xyPostion}
|
||||
isSignYourself={true}
|
||||
addPositionOfSignature={addPositionOfSignature}
|
||||
isMailSend={false}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<Signedby pdfDetails={pdfDetails[0]} />
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full md:w-[23%] bg-base-100 overflow-y-auto hide-scrollbar">
|
||||
<div className={`max-h-screen`}>
|
||||
{!isCompleted ? (
|
||||
<div>
|
||||
<WidgetComponent
|
||||
pdfUrl={pdfUrl}
|
||||
dragSignature={dragSignature}
|
||||
signRef={signRef}
|
||||
handleDivClick={handleDivClick}
|
||||
handleMouseLeave={handleMouseLeave}
|
||||
isDragSign={isDragSign}
|
||||
dragStamp={dragStamp}
|
||||
dragRef={dragRef}
|
||||
isDragStamp={isDragStamp}
|
||||
handleAllDelete={handleAllDelete}
|
||||
xyPostion={xyPostion}
|
||||
isSignYourself={true}
|
||||
addPositionOfSignature={addPositionOfSignature}
|
||||
isMailSend={false}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<Signedby pdfDetails={pdfDetails[0]} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<ModalUi
|
||||
headerColor={"#dc3545"}
|
||||
isOpen={validateAlert}
|
||||
title={"Validation alert"}
|
||||
handleClose={() => {
|
||||
setValidateAlert(false);
|
||||
}}
|
||||
>
|
||||
<div style={{ height: "100%", padding: 20 }}>
|
||||
<div className="p-[20px] h-full">
|
||||
<p>
|
||||
The input does not meet the criteria set by the regular expression.
|
||||
</p>
|
||||
|
||||
<div
|
||||
style={{
|
||||
height: "1px",
|
||||
backgroundColor: "#9f9f9f",
|
||||
width: "100%",
|
||||
marginTop: "15px",
|
||||
marginBottom: "15px"
|
||||
}}
|
||||
></div>
|
||||
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
|
||||
<button
|
||||
onClick={() => setValidateAlert(false)}
|
||||
type="button"
|
||||
className="finishBtn cancelBtn"
|
||||
className="op-btn op-btn-ghost shadow-md"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</ModalUi>
|
||||
<TextFontSetting
|
||||
isTextSetting={isTextSetting}
|
||||
setIsTextSetting={setIsTextSetting}
|
||||
fontSize={fontSize}
|
||||
setFontSize={setFontSize}
|
||||
fontColor={fontColor}
|
||||
setFontColor={setFontColor}
|
||||
handleSaveFontSize={handleSaveFontSize}
|
||||
currWidgetsDetails={currWidgetsDetails}
|
||||
/>
|
||||
</DndProvider>
|
||||
);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,8 @@
|
||||
import React, { useState, useEffect } 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";
|
||||
@@ -8,10 +12,11 @@ import sanitizeFileName from "../primitives/sanitizeFileName";
|
||||
import axios from "axios";
|
||||
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||
import Tooltip from "../primitives/Tooltip";
|
||||
import { isEnableSubscription, rejectBtn, submitBtn } from "../constant/const";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import { checkIsSubscribed, handleSendOTP } from "../constant/Utils";
|
||||
import Upgrade from "../primitives/Upgrade";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import Loader from "../primitives/Loader";
|
||||
|
||||
function UserProfile() {
|
||||
const navigate = useNavigate();
|
||||
@@ -27,6 +32,10 @@ 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 [company, setCompany] = useState(
|
||||
extendUser && extendUser?.[0]?.Company
|
||||
);
|
||||
@@ -37,6 +46,7 @@ function UserProfile() {
|
||||
const [otp, setOtp] = useState("");
|
||||
const [otpLoader, setOtpLoader] = useState(false);
|
||||
const [isEmailVerified, setIsEmailVerified] = useState(false);
|
||||
// const [userNameError, setUserNameError] = useState("");
|
||||
useEffect(() => {
|
||||
getUserDetail();
|
||||
}, []);
|
||||
@@ -74,46 +84,72 @@ 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 handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setIsLoader(true);
|
||||
let phn = Phone;
|
||||
|
||||
try {
|
||||
const tour = Parse.Object.extend("_User");
|
||||
const query = new Parse.Query(tour);
|
||||
|
||||
await query.get(UserProfile.objectId).then((object) => {
|
||||
object.set("name", name);
|
||||
object.set("ProfilePic", Image);
|
||||
object.set("phone", phn);
|
||||
|
||||
object.save().then(
|
||||
async (response) => {
|
||||
if (response) {
|
||||
let res = response.toJSON();
|
||||
let rr = JSON.stringify(res);
|
||||
localStorage.setItem("UserInformation", rr);
|
||||
SetName(res.name);
|
||||
SetPhone(res.phone);
|
||||
setImage(res.ProfilePic);
|
||||
localStorage.setItem("username", res.name);
|
||||
localStorage.setItem("profileImg", res.ProfilePic);
|
||||
await updateExtUser({ Name: res.name, Phone: res.phone });
|
||||
alert("Profile updated successfully.");
|
||||
setEditMode(false);
|
||||
navigate("/dashboard/35KBoSgoAK");
|
||||
let phn = Phone,
|
||||
res = "";
|
||||
//condition to call cloud function when user change publicUserName
|
||||
// if (previousPublicUserName.current !== publicUserName) {
|
||||
// res = await handleCheckPublicUserName();
|
||||
// }
|
||||
if (!res) {
|
||||
setIsLoader(true);
|
||||
try {
|
||||
const userQuery = Parse.Object.extend("_User");
|
||||
const query = new Parse.Query(userQuery);
|
||||
await query.get(UserProfile.objectId).then((object) => {
|
||||
object.set("name", name);
|
||||
object.set("ProfilePic", Image);
|
||||
object.set("phone", phn || "");
|
||||
object.save().then(
|
||||
async (response) => {
|
||||
if (response) {
|
||||
let res = response.toJSON();
|
||||
let rr = JSON.stringify(res);
|
||||
localStorage.setItem("UserInformation", rr);
|
||||
SetName(res.name);
|
||||
SetPhone(res?.phone || "");
|
||||
setImage(res.ProfilePic);
|
||||
localStorage.setItem("username", res.name);
|
||||
localStorage.setItem("profileImg", res.ProfilePic);
|
||||
await updateExtUser({
|
||||
Name: res.name,
|
||||
Phone: res?.phone || ""
|
||||
});
|
||||
alert("Profile updated successfully.");
|
||||
setEditMode(false);
|
||||
setIsLoader(false);
|
||||
//navigate("/dashboard/35KBoSgoAK");
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
alert("Something went wrong.");
|
||||
console.error("Error while updating tour", error);
|
||||
setIsLoader(false);
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
alert("Something went wrong.");
|
||||
console.error("Error while updating tour", error);
|
||||
setIsLoader(false);
|
||||
}
|
||||
);
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("err", error);
|
||||
);
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("err", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -122,14 +158,15 @@ function UserProfile() {
|
||||
const extClass = localStorage.getItem("extended_class");
|
||||
const extData = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||
const ExtUserId = extData[0].objectId;
|
||||
|
||||
const body = {
|
||||
Phone: obj.Phone,
|
||||
Phone: obj?.Phone || "",
|
||||
Name: obj.Name,
|
||||
HeaderDocId: isDisableDocId,
|
||||
JobTitle: jobTitle,
|
||||
Company: company
|
||||
// UserName: publicUserName || ""
|
||||
};
|
||||
|
||||
await axios.put(
|
||||
parseBaseUrl + "classes/" + extClass + "/" + ExtUserId,
|
||||
body,
|
||||
@@ -147,7 +184,6 @@ function UserProfile() {
|
||||
|
||||
const json = JSON.parse(JSON.stringify([res]));
|
||||
const extRes = JSON.stringify(json);
|
||||
|
||||
localStorage.setItem("Extand_Class", extRes);
|
||||
// console.log("updateRes ", updateRes);
|
||||
};
|
||||
@@ -241,29 +277,45 @@ function UserProfile() {
|
||||
setOtpLoader(false);
|
||||
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 handleCancel = () => {
|
||||
setEditMode(false);
|
||||
SetName(localStorage.getItem("username"));
|
||||
SetPhone(UserProfile && UserProfile.phone);
|
||||
setImage(localStorage.getItem("profileImg"));
|
||||
// setPublicUserName(extendUser && extendUser?.[0]?.UserName);
|
||||
setCompany(extendUser && extendUser?.[0]?.Company);
|
||||
setJobTitle(extendUser?.[0]?.JobTitle);
|
||||
setIsDisableDocId(extendUser?.[0]?.HeaderDocId);
|
||||
};
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Title title={"Profile"} />
|
||||
{isLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="h-[100vh] flex justify-center items-center">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex justify-center items-center w-full">
|
||||
<div className="bg-white flex flex-col justify-center shadow rounded w-[450px]">
|
||||
<div className="flex justify-center items-center w-full relative">
|
||||
{/* {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">
|
||||
<img
|
||||
@@ -275,7 +327,7 @@ function UserProfile() {
|
||||
{editmode && (
|
||||
<input
|
||||
type="file"
|
||||
className="max-w-[270px] text-sm py-1 px-2 mt-4 border-[1px] border-[#15b4e9] text-black rounded"
|
||||
className="op-file-input op-file-input-bordered op-file-input-sm max-w-[270px] mt-4 text-sm"
|
||||
accept="image/png, image/gif, image/jpeg"
|
||||
onChange={(e) => {
|
||||
let files = e.target.files;
|
||||
@@ -301,7 +353,7 @@ function UserProfile() {
|
||||
<ul className="w-full flex flex-col p-2 text-sm">
|
||||
<li
|
||||
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
|
||||
editmode ? "py-1" : "py-2"
|
||||
editmode ? "py-1.5" : "py-2"
|
||||
}`}
|
||||
>
|
||||
<span className="font-semibold">Name:</span>{" "}
|
||||
@@ -309,7 +361,7 @@ function UserProfile() {
|
||||
<input
|
||||
type="text"
|
||||
value={name}
|
||||
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-sm"
|
||||
onChange={(e) => SetName(e.target.value)}
|
||||
/>
|
||||
) : (
|
||||
@@ -318,14 +370,14 @@ function UserProfile() {
|
||||
</li>
|
||||
<li
|
||||
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
|
||||
editmode ? "py-1" : "py-2"
|
||||
editmode ? "py-1.5" : "py-2"
|
||||
}`}
|
||||
>
|
||||
<span className="font-semibold">Phone:</span>{" "}
|
||||
{editmode ? (
|
||||
<input
|
||||
type="text"
|
||||
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-sm"
|
||||
onChange={(e) => SetPhone(e.target.value)}
|
||||
value={Phone}
|
||||
/>
|
||||
@@ -339,7 +391,7 @@ function UserProfile() {
|
||||
</li>
|
||||
<li
|
||||
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
|
||||
editmode ? "py-1" : "py-2"
|
||||
editmode ? "py-1.5" : "py-2"
|
||||
}`}
|
||||
>
|
||||
<span className="font-semibold">Company:</span>{" "}
|
||||
@@ -347,7 +399,7 @@ function UserProfile() {
|
||||
<input
|
||||
type="text"
|
||||
value={company}
|
||||
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-sm"
|
||||
onChange={(e) => setCompany(e.target.value)}
|
||||
/>
|
||||
) : (
|
||||
@@ -356,7 +408,7 @@ function UserProfile() {
|
||||
</li>
|
||||
<li
|
||||
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
|
||||
editmode ? "py-1" : "py-2"
|
||||
editmode ? "py-1.5" : "py-2"
|
||||
}`}
|
||||
>
|
||||
<span className="font-semibold">Job title:</span>{" "}
|
||||
@@ -364,7 +416,7 @@ function UserProfile() {
|
||||
<input
|
||||
type="text"
|
||||
value={jobTitle}
|
||||
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-sm"
|
||||
onChange={(e) => setJobTitle(e.target.value)}
|
||||
/>
|
||||
) : (
|
||||
@@ -390,6 +442,37 @@ 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"
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
value={extendUser?.[0]?.UserName}
|
||||
disabled
|
||||
placeholder="enter user name"
|
||||
className="op-input op-input-bordered op-input-xs"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
)} */}
|
||||
<li className="border-y-[1px] border-gray-300 break-all">
|
||||
<div className="flex justify-between items-center py-2">
|
||||
<span
|
||||
@@ -404,27 +487,23 @@ function UserProfile() {
|
||||
url={
|
||||
"https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid"
|
||||
}
|
||||
/>{" "}
|
||||
/>
|
||||
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||
</span>{" "}
|
||||
</span>
|
||||
<label
|
||||
className={
|
||||
className={`${
|
||||
isSubscribe || !isEnableSubscription
|
||||
? `${
|
||||
editmode ? "cursor-pointer" : ""
|
||||
} relative inline-flex items-center mb-0`
|
||||
: "relative inline-flex items-center mb-0 pointer-events-none opacity-50"
|
||||
}
|
||||
? `${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}
|
||||
type="checkbox"
|
||||
value=""
|
||||
className="sr-only peer"
|
||||
/>
|
||||
<div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-1 peer-focus:ring-black rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-black peer-checked:bg-blue-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
{!isEnableSubscription && (
|
||||
@@ -436,44 +515,29 @@ function UserProfile() {
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
<div className="flex justify-center pt-2 pb-3 md:pt-3 md:pb-4">
|
||||
{editmode ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSubmit}
|
||||
className="rounded shadow focus:outline-none border-[2px] border-[#15b4e9] bg-white text-[#15b4e9] px-4 py-2 mr-4"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setEditMode(true);
|
||||
}}
|
||||
className="rounded shadow focus:outline-none text-white bg-[#e7505a] px-4 py-2 mr-4"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
)}
|
||||
<div className="flex justify-center gap-2 pt-2 pb-3 md:pt-3 md:pb-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (editmode) {
|
||||
setEditMode(false);
|
||||
} else {
|
||||
navigate("/changepassword");
|
||||
}
|
||||
}}
|
||||
className={`rounded shadow focus:outline-none text-white bg-[#3598dc] ${
|
||||
editmode ? "px-4 py-2 " : "p-2"
|
||||
onClick={(e) =>
|
||||
editmode ? handleSubmit(e) : setEditMode(true)
|
||||
}
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
{editmode ? "Save" : "Edit"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
editmode ? handleCancel() : navigate("/changepassword")
|
||||
}
|
||||
className={`op-btn ${
|
||||
editmode ? "op-btn-ghost" : "op-btn-secondary"
|
||||
}`}
|
||||
>
|
||||
{editmode ? "Cancel" : "Change Password"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isVerifyModal && (
|
||||
<ModalUi
|
||||
isOpen
|
||||
@@ -481,43 +545,29 @@ function UserProfile() {
|
||||
handleClose={handleCloseVerifyModal}
|
||||
>
|
||||
{otpLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "150px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="h-[150px] flex justify-center items-center">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={(e) => handleVerifyEmail(e)}>
|
||||
<div className="px-6 py-3">
|
||||
<div className="px-6 py-3 text-base-content">
|
||||
<label className="mb-2">Enter OTP</label>
|
||||
<input
|
||||
required
|
||||
type="tel"
|
||||
pattern="[0-9]{4}"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
||||
placeholder="Enter OTP received over email"
|
||||
value={otp}
|
||||
onChange={(e) => setOtp(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<hr />
|
||||
<div className="px-6 my-3">
|
||||
<button type="submit" className={submitBtn}>
|
||||
<div className="px-6 mb-3">
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Verify
|
||||
</button>
|
||||
<button
|
||||
className={`${rejectBtn} ml-2`}
|
||||
className="op-btn op-btn-secondary ml-2"
|
||||
onClick={(e) => handleResend(e)}
|
||||
>
|
||||
Resend
|
||||
|
||||
+118
-151
@@ -1,27 +1,32 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Title from "../components/Title";
|
||||
import axios from "axios";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Alert from "../primitives/Alert";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import { isEnableSubscription, rejectBtn, submitBtn } from "../constant/const";
|
||||
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";
|
||||
import Tour from "reactour";
|
||||
const tourSteps = [
|
||||
{
|
||||
selector: '[data-tut="webhooksubscribe"]',
|
||||
content: "Upgrade now to set webhook"
|
||||
}
|
||||
];
|
||||
function Webhook() {
|
||||
const navigation = useNavigate();
|
||||
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
|
||||
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
|
||||
const [webhook, setWebhook] = useState();
|
||||
const [isLoader, setIsLoader] = useState(true);
|
||||
const [isGenerate, setIsGenerate] = useState(false);
|
||||
const [isErr, setIsErr] = useState(false);
|
||||
const [isModal, setIsModal] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||
const [isTour, setIsTour] = useState(false);
|
||||
useEffect(() => {
|
||||
fetchWebhook();
|
||||
// eslint-disable-next-line
|
||||
@@ -59,31 +64,22 @@ function Webhook() {
|
||||
"X-Parse-Application-Id": parseAppId,
|
||||
sessiontoken: localStorage.getItem("accesstoken")
|
||||
};
|
||||
await axios.post(url, params, { headers: headers }).then((res) => {
|
||||
if (res.data && res.data.result && res.data.result.Webhook) {
|
||||
setWebhook(res.data.result.Webhook);
|
||||
setIsGenerate(true);
|
||||
setTimeout(() => {
|
||||
setIsGenerate(false);
|
||||
}, 1500);
|
||||
setIsLoader(false);
|
||||
} else {
|
||||
console.error("Error while generating webhook");
|
||||
setIsLoader(false);
|
||||
setIsErr(true);
|
||||
setTimeout(() => {
|
||||
setIsErr(false);
|
||||
}, 1500);
|
||||
}
|
||||
});
|
||||
const res = await axios.post(url, params, { headers: headers });
|
||||
if (res.data && res.data.result && res.data.result.Webhook) {
|
||||
setWebhook(res.data.result.Webhook);
|
||||
setIsAlert({ type: "success", msg: "Webhook added successfully." });
|
||||
} else {
|
||||
console.error("Error while generating webhook");
|
||||
setIsAlert({ type: "danger", msg: "Something went wrong." });
|
||||
}
|
||||
} catch (error) {
|
||||
setIsAlert({ type: "danger", msg: "Something went wrong." });
|
||||
console.log("err while generating webhook", error);
|
||||
} finally {
|
||||
setIsLoader(false);
|
||||
setIsErr(true);
|
||||
setTimeout(() => {
|
||||
setIsErr(false);
|
||||
setIsAlert({ type: "success", msg: "" });
|
||||
}, 1500);
|
||||
|
||||
console.log("err", error);
|
||||
}
|
||||
} else {
|
||||
setError("The webhook url should always start with https://");
|
||||
@@ -93,141 +89,112 @@ function Webhook() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleModal = () => setIsModal(!isModal);
|
||||
const handleModal = () => {
|
||||
if (!isSubscribe && isEnableSubscription) {
|
||||
setIsTour(true);
|
||||
} else {
|
||||
setIsModal(!isModal);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Title title={"Webhook"} />
|
||||
{isGenerate && <Alert type="success">Webhook added successfully!</Alert>}
|
||||
{isErr && <Alert type="danger">Something went wrong!</Alert>}
|
||||
|
||||
{isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
|
||||
{isLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="h-[100vh] flex justify-center items-center">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<div className="bg-white flex flex-col justify-center shadow rounded">
|
||||
{!isEnableSubscription && <PremiumAlertHeader />}
|
||||
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||
OpenSign™ Webhook{" "}
|
||||
<Tooltip
|
||||
url={"https://docs.opensignlabs.com/docs/API-docs/get-webhook"}
|
||||
isSubscribe={true}
|
||||
/>
|
||||
</h1>
|
||||
<ul
|
||||
className={
|
||||
isSubscribe || !isEnableSubscription
|
||||
? "w-full flex flex-col p-2 text-sm "
|
||||
: "w-full flex flex-col p-2 text-sm opacity-20 pointer-events-none select-none"
|
||||
}
|
||||
>
|
||||
<li
|
||||
className={`flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
|
||||
>
|
||||
<div className="w-[70%] flex-col md:flex-row flex items-center gap-5 ">
|
||||
<span className="">Webhook:</span>{" "}
|
||||
<span id="token" className=" md:text-end cursor-pointer">
|
||||
{webhook ? webhook : "_____"}
|
||||
</span>
|
||||
</div>
|
||||
<>
|
||||
<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
|
||||
url={"https://docs.opensignlabs.com/docs/API-docs/get-webhook"}
|
||||
isSubscribe={true}
|
||||
/>
|
||||
</h1>
|
||||
<ul className={"w-full flex flex-col p-2 text-sm"}>
|
||||
<li className="flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2">
|
||||
<div className="w-[70%] flex-col md:flex-row flex items-center gap-5">
|
||||
<span className="">Webhook:</span>{" "}
|
||||
<span id="token" className=" md:text-end cursor-pointer">
|
||||
{webhook ? webhook : "_____"}
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleModal}
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
{webhook ? "Update Webhook" : "Add Webhook"}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="flex items-center justify-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleModal}
|
||||
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base focus:outline-none"
|
||||
onClick={() =>
|
||||
openInNewTab(
|
||||
"https://docs.opensignlabs.com/docs/API-docs/save-update-webhook"
|
||||
)
|
||||
}
|
||||
className="op-btn op-btn-secondary mt-2 mb-3 px-7"
|
||||
>
|
||||
{webhook ? "Update Webhook" : "Add Webhook"}
|
||||
View Docs
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div className="flex items-center justify-center ">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
openInNewTab(
|
||||
"https://docs.opensignlabs.com/docs/API-docs/save-update-webhook"
|
||||
)
|
||||
}
|
||||
className="rounded hover:bg-[#15b4e9] border-[1px] my-2 border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
|
||||
>
|
||||
View Docs
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{!isSubscribe && isEnableSubscription && (
|
||||
<>
|
||||
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||
Upgrade to PRO Plan
|
||||
</h1>
|
||||
<ul className={"w-full flex flex-col p-2 text-sm "}>
|
||||
<li
|
||||
className={`flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
|
||||
>
|
||||
<div className="w-[70%] flex-col md:flex-row flex items-center gap-3 ">
|
||||
<span className="">$29.99/month:</span>{" "}
|
||||
<span id="token" className=" md:text-end cursor-pointer">
|
||||
First 100 documents included, then just $0.15 per
|
||||
document.
|
||||
</span>
|
||||
</div>
|
||||
{!isSubscribe && isEnableSubscription && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigation("/subscription")}
|
||||
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
|
||||
>
|
||||
Upgrade Now
|
||||
</button>
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
<ModalUi
|
||||
isOpen={isModal}
|
||||
title={"Regenerate Token"}
|
||||
handleClose={handleModal}
|
||||
>
|
||||
{error && <Alert type="danger">{error}</Alert>}
|
||||
<div className="m-[20px]">
|
||||
<div className="text-lg font-normal text-black">
|
||||
<label className="text-sm ml-2">Webhook</label>
|
||||
<input
|
||||
value={webhook}
|
||||
onChange={(e) => setWebhook(e.target.value)}
|
||||
placeholder="Enter webhook url"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
/>
|
||||
</div>
|
||||
<hr className="bg-[#ccc] mt-4 " />
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<button
|
||||
onClick={handleSubmit}
|
||||
className={submitBtn + "ml-[2px]"}
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button onClick={handleModal} className={rejectBtn}>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalUi>
|
||||
</div>
|
||||
<ModalUi
|
||||
isOpen={isModal}
|
||||
title={"Regenerate Token"}
|
||||
handleClose={handleModal}
|
||||
>
|
||||
{error && <Alert type="danger">{error}</Alert>}
|
||||
<div className="m-[20px]">
|
||||
<div className="text-lg font-normal text-base-content">
|
||||
<label className="text-sm ml-2">Webhook</label>
|
||||
<input
|
||||
value={webhook}
|
||||
onChange={(e) => setWebhook(e.target.value)}
|
||||
placeholder="Enter webhook url"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
</div>
|
||||
<hr className="bg-[#ccc] mt-3" />
|
||||
<div className="flex items-center mt-3 gap-2">
|
||||
<button
|
||||
onClick={handleSubmit}
|
||||
className="op-btn op-btn-primary ml-[2px]"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
onClick={handleModal}
|
||||
className="op-btn op-btn-secondary"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalUi>
|
||||
</div>
|
||||
{!isSubscribe && isEnableSubscription && (
|
||||
<div data-tut="webhooksubscribe">
|
||||
<SubscribeCard />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Tour
|
||||
onRequestClose={() => setIsTour(false)}
|
||||
steps={tourSteps}
|
||||
isOpen={isTour}
|
||||
closeWithMask={false}
|
||||
disableKeyboardNavigation={["esc"]}
|
||||
scrollOffset={-100}
|
||||
rounded={5}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// below code is used to handle undefined Promise.withResolvers for safari
|
||||
if (typeof Promise.withResolvers === "undefined") {
|
||||
Promise.withResolvers = function () {
|
||||
let resolve, reject;
|
||||
const promise = new Promise((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
return { promise, resolve, reject };
|
||||
};
|
||||
}
|
||||
|
||||
// Usage:
|
||||
// const { promise, resolve, reject } = Promise.withResolvers()
|
||||
// console.log(promise, resolve, reject) // Promise { <pending> } [Function (anonymous)] [Function (anonymous)]
|
||||
// ... Do something async and then call resolve or reject!
|
||||
+38
-40
@@ -1,8 +1,8 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Parse from "parse";
|
||||
import axios from "axios";
|
||||
import "../styles/AddUser.css";
|
||||
const AddUser = (props) => {
|
||||
import Loader from "./Loader";
|
||||
const AddContact = (props) => {
|
||||
const [name, setName] = useState("");
|
||||
const [phone, setPhone] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
@@ -21,7 +21,7 @@ const AddUser = (props) => {
|
||||
);
|
||||
if (savedUserDetails && addYourself) {
|
||||
setName(savedUserDetails.name);
|
||||
setPhone(savedUserDetails.phone);
|
||||
setPhone(savedUserDetails?.phone || "");
|
||||
setEmail(savedUserDetails.email);
|
||||
}
|
||||
}, [addYourself]);
|
||||
@@ -50,7 +50,9 @@ const AddUser = (props) => {
|
||||
try {
|
||||
const contactQuery = new Parse.Object("contracts_Contactbook");
|
||||
contactQuery.set("Name", name);
|
||||
contactQuery.set("Phone", phone);
|
||||
if (phone) {
|
||||
contactQuery.set("Phone", phone);
|
||||
}
|
||||
contactQuery.set("Email", email);
|
||||
contactQuery.set("UserRole", "contracts_Guest");
|
||||
|
||||
@@ -68,8 +70,10 @@ const AddUser = (props) => {
|
||||
_user.set("name", name);
|
||||
_user.set("username", email);
|
||||
_user.set("email", email);
|
||||
_user.set("phone", phone);
|
||||
_user.set("password", phone);
|
||||
_user.set("password", email);
|
||||
if (phone) {
|
||||
_user.set("phone", phone);
|
||||
}
|
||||
|
||||
const user = await _user.save();
|
||||
if (user) {
|
||||
@@ -191,40 +195,36 @@ const AddUser = (props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="addusercontainer">
|
||||
<div className="h-full px-[20px] py-[10px]">
|
||||
{isLoader && (
|
||||
<div className="loaderdiv">
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
<div className="form-wrapper">
|
||||
<div style={{ fontSize: 14, fontWeight: "700" }}>Add User</div>
|
||||
|
||||
<div className="w-full mx-auto p-[8px]">
|
||||
<div className="text-[14px] font-[700]">Add Contact</div>
|
||||
{isUserExist && (
|
||||
<div className="form-section">
|
||||
<div className="mb-[0.75rem] flex items-center mt-1">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="addYourself"
|
||||
checked={addYourself}
|
||||
onChange={handleAddYourselfChange}
|
||||
className="form-checkbox"
|
||||
className="op-checkbox op-checkbox-sm"
|
||||
/>
|
||||
<label htmlFor="addYourself" className="checkbox-label ">
|
||||
<label
|
||||
htmlFor="addYourself"
|
||||
className="ml-[0.5rem] text-base-content mb-0"
|
||||
>
|
||||
Add Yourself
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="form-section">
|
||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
||||
<form className="text-base-content" onSubmit={handleSubmit}>
|
||||
<div className="mb-[0.75rem]">
|
||||
<label htmlFor="name" className="text-[13px]">
|
||||
Name
|
||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
||||
<span className="text-[13px] text-[red]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
@@ -233,48 +233,46 @@ const AddUser = (props) => {
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
required
|
||||
disabled={addYourself}
|
||||
className="addUserInput"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label htmlFor="email" style={{ fontSize: 13 }}>
|
||||
<div className="mb-[0.75rem]">
|
||||
<label htmlFor="email" className="text-[13px]">
|
||||
Email
|
||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
||||
<span className="text-[13px] text-[red]"> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
onChange={(e) => setEmail(e.target.value?.toLowerCase())}
|
||||
required
|
||||
disabled={addYourself}
|
||||
className="addUserInput"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs lowercase"
|
||||
/>
|
||||
</div>
|
||||
<div className="form-section">
|
||||
<label htmlFor="phone" style={{ fontSize: 13 }}>
|
||||
<div className="mb-[0.75rem]">
|
||||
<label htmlFor="phone" className="text-[13px]">
|
||||
Phone
|
||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="phone"
|
||||
value={phone}
|
||||
onChange={(e) => setPhone(e.target.value)}
|
||||
required
|
||||
disabled={addYourself}
|
||||
className="addUserInput"
|
||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="buttoncontainer">
|
||||
<button type="submit" className="submitbutton">
|
||||
<div className="mt-6 flex justify-start gap-2">
|
||||
<button type="submit" className="op-btn op-btn-primary">
|
||||
Submit
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleReset()}
|
||||
className="resetbutton"
|
||||
className="op-btn op-btn-secondary"
|
||||
>
|
||||
Reset
|
||||
</button>
|
||||
@@ -285,4 +283,4 @@ const AddUser = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default AddUser;
|
||||
export default AddContact;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user