mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-04 16:58:05 +02:00
Compare commits
338
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e71924a264 | ||
|
|
4ae9748004 | ||
|
|
eda6113792 | ||
|
|
4f1509c836 | ||
|
|
dfcf32ef3e | ||
|
|
4a95257ee2 | ||
|
|
ee1e13ef61 | ||
|
|
c9c099ffc5 | ||
|
|
a80f4fb3c9 | ||
|
|
941f3ac47f | ||
|
|
80d3200d57 | ||
|
|
55926e25d2 | ||
|
|
a31f3ebad7 | ||
|
|
dc9c32c6ee | ||
|
|
dac3aac2a1 | ||
|
|
40196e823c | ||
|
|
7708b7e938 | ||
|
|
8bbc5a9bc6 | ||
|
|
4dbdfb1b77 | ||
|
|
05c51edce3 | ||
|
|
379e8cd95e | ||
|
|
9fd00d4427 | ||
|
|
ca114cf124 | ||
|
|
75128784db | ||
|
|
722f0e277e | ||
|
|
7089998966 | ||
|
|
52211ddfa4 | ||
|
|
2b8b762d35 | ||
|
|
04c228cd36 | ||
|
|
915f8e7700 | ||
|
|
218cea00b5 | ||
|
|
f38f5ea670 | ||
|
|
a9c08c8a9f | ||
|
|
9406c4f718 | ||
|
|
791d8beb06 | ||
|
|
57a9f3aca0 | ||
|
|
ae8bf187c8 | ||
|
|
88f2ab1f8e | ||
|
|
76f5136073 | ||
|
|
0f84cd8949 | ||
|
|
adfdf7606f | ||
|
|
ce671d4294 | ||
|
|
2e7cf7a9df | ||
|
|
f699d93e44 | ||
|
|
531ef4d0b2 | ||
|
|
4c6dbb6690 | ||
|
|
0beb60d1b5 | ||
|
|
893c9d7c42 | ||
|
|
b7a22d94db | ||
|
|
3d854756d1 | ||
|
|
251e7058f1 | ||
|
|
368eb24217 | ||
|
|
f89ef54b82 | ||
|
|
b9d9f8772b | ||
|
|
f2ee03e850 | ||
|
|
92e59a0072 | ||
|
|
5394c0b520 | ||
|
|
e4a9c6f8c2 | ||
|
|
e559d037c3 | ||
|
|
c9909a0869 | ||
|
|
988fc1bbfd | ||
|
|
1831bbcd70 | ||
|
|
ced9bbdbd5 | ||
|
|
15d57d937b | ||
|
|
555979869d | ||
|
|
4e6477297e | ||
|
|
e9e06fc53b | ||
|
|
ecb2818589 | ||
|
|
c442689573 | ||
|
|
88919f2634 | ||
|
|
1a1bc41283 | ||
|
|
4188caed33 | ||
|
|
50557d8bc5 | ||
|
|
0f1ef0406e | ||
|
|
ffc742b460 | ||
|
|
0c04cc6ce6 | ||
|
|
4e6dfed838 | ||
|
|
fdc0524ad2 | ||
|
|
096d5962a3 | ||
|
|
9ea36f94a7 | ||
|
|
2b66df992f | ||
|
|
ff3c31975e | ||
|
|
beaa5eca69 | ||
|
|
b98040faac | ||
|
|
fbbff0df61 | ||
|
|
07d5f393c0 | ||
|
|
8220b15a29 | ||
|
|
7cf638b2be | ||
|
|
9852c87be7 | ||
|
|
30fb8f31e3 | ||
|
|
ec4d875547 | ||
|
|
1268f65516 | ||
|
|
6551b2537a | ||
|
|
43eee63df2 | ||
|
|
4caf9f598a | ||
|
|
107eaca8f0 | ||
|
|
cc11848346 | ||
|
|
b138ccf625 | ||
|
|
27ff7baa6d | ||
|
|
c8ecd34bd3 | ||
|
|
d4a4eb3248 | ||
|
|
f782733397 | ||
|
|
7720eddc47 | ||
|
|
71170a373a | ||
|
|
8f080080a7 | ||
|
|
71b2958c14 | ||
|
|
f69aafcbfa | ||
|
|
5f6a423697 | ||
|
|
5d245927c4 | ||
|
|
17c96fb849 | ||
|
|
b7c28cdf36 | ||
|
|
d05aa0d350 | ||
|
|
875dc086bf | ||
|
|
4719ebd52a | ||
|
|
c8a436a7df | ||
|
|
8d6f4dd64e | ||
|
|
63486927d6 | ||
|
|
c36a70f8d3 | ||
|
|
39472d6874 | ||
|
|
6207e99cc0 | ||
|
|
bdc163199d | ||
|
|
e7a04ede65 | ||
|
|
f6aee4148d | ||
|
|
6cb30a6597 | ||
|
|
34fcfc8f30 | ||
|
|
bc89b33468 | ||
|
|
af9af347e6 | ||
|
|
6f46279b52 | ||
|
|
8f93ed8b8e | ||
|
|
df91363ff4 | ||
|
|
e40e59714d | ||
|
|
a43d95afc3 | ||
|
|
8fa4b5ab22 | ||
|
|
68a030145f | ||
|
|
4f48657623 | ||
|
|
3fc41f4255 | ||
|
|
ff2f7f6586 | ||
|
|
93f33d73d9 | ||
|
|
402c176277 | ||
|
|
79b05b4a66 | ||
|
|
fb9e37e71c | ||
|
|
cd7a741d53 | ||
|
|
5fdc90b4f9 | ||
|
|
e775840abb | ||
|
|
d7df54dfa1 | ||
|
|
646d165d37 | ||
|
|
ba0a80cca4 | ||
|
|
9d59858542 | ||
|
|
aaff0a5697 | ||
|
|
1bb7cee238 | ||
|
|
d330e662d3 | ||
|
|
b530ff76c4 | ||
|
|
b20aa33a04 | ||
|
|
e59a166445 | ||
|
|
980e713735 | ||
|
|
7a5228bbab | ||
|
|
5a26e5c2ee | ||
|
|
a64da4cd85 | ||
|
|
c2dccf17ce | ||
|
|
181d6bf1e4 | ||
|
|
e80bcfc586 | ||
|
|
a07be3b5dc | ||
|
|
af2666c83d | ||
|
|
cad9929b56 | ||
|
|
3b79da527d | ||
|
|
3eaba55823 | ||
|
|
e2eddb6362 | ||
|
|
de5b8160a2 | ||
|
|
83df969751 | ||
|
|
d885570dd8 | ||
|
|
f3de883e39 | ||
|
|
6da22d23a8 | ||
|
|
49461a43bb | ||
|
|
d4414f99af | ||
|
|
52f37b0a37 | ||
|
|
ce949e4029 | ||
|
|
19d3465a13 | ||
|
|
a0e1425c74 | ||
|
|
a5d8379b18 | ||
|
|
9ac487ea5b | ||
|
|
9cc9a93c3d | ||
|
|
4f2b0313de | ||
|
|
806894b24b | ||
|
|
cbb737f96b | ||
|
|
5407f8156a | ||
|
|
a0c2fd09ae | ||
|
|
48b744c8ba | ||
|
|
812b946d85 | ||
|
|
27eca2b470 | ||
|
|
ab6c88bebd | ||
|
|
d547e0552a | ||
|
|
03fc0b84cb | ||
|
|
b0825634ee | ||
|
|
9675e051bd | ||
|
|
981654a2aa | ||
|
|
8c97ea0da0 | ||
|
|
6c80911c90 | ||
|
|
740b5ea719 | ||
|
|
76c958fb7a | ||
|
|
28c53fd115 | ||
|
|
6d9fc8b3df | ||
|
|
a044f4eceb | ||
|
|
1f35efcd51 | ||
|
|
c587abddae | ||
|
|
d7f4c9a329 | ||
|
|
8a3e6f5781 | ||
|
|
cfbebc4989 | ||
|
|
99ec772d64 | ||
|
|
1f60b0bbcb | ||
|
|
c8fb9a5b09 | ||
|
|
d6f117c7bf | ||
|
|
a765668354 | ||
|
|
da053658e8 | ||
|
|
cb5bcd72e4 | ||
|
|
d4d53623ef | ||
|
|
8a31b008d2 | ||
|
|
fa4541b59f | ||
|
|
aae6b32828 | ||
|
|
7158d6735b | ||
|
|
f04fd16c9e | ||
|
|
f4b896d5e6 | ||
|
|
d2f814e6f8 | ||
|
|
87cec67e60 | ||
|
|
041c46f38e | ||
|
|
54a7628f75 | ||
|
|
7cbbc16390 | ||
|
|
14532bf6db | ||
|
|
7bfe18e718 | ||
|
|
07903a07a8 | ||
|
|
14fe3b2b98 | ||
|
|
fa2756ff3f | ||
|
|
9d4841b4dc | ||
|
|
4b74b08825 | ||
|
|
6457cfc958 | ||
|
|
30081c893b | ||
|
|
e69890a47e | ||
|
|
9d31162eec | ||
|
|
0031cc7418 | ||
|
|
57132892b5 | ||
|
|
be084d1570 | ||
|
|
03d29a9ebd | ||
|
|
e9a837b534 | ||
|
|
36c601f9fa | ||
|
|
af41234484 | ||
|
|
bcaf03a770 | ||
|
|
9429b009ce | ||
|
|
3395785cbc | ||
|
|
97c048c7af | ||
|
|
726eb2ffe6 | ||
|
|
a9f22d3a10 | ||
|
|
5a6437e371 | ||
|
|
4ffc98b371 | ||
|
|
16c73d4f91 | ||
|
|
96aff5230f | ||
|
|
b298571be8 | ||
|
|
7b7b10c9a5 | ||
|
|
56beed5ad5 | ||
|
|
8c8ef0ea53 | ||
|
|
90377d98c0 | ||
|
|
d167e474d8 | ||
|
|
0cfacfe057 | ||
|
|
fbda5231d0 | ||
|
|
bd4d333d59 | ||
|
|
07878207de | ||
|
|
b2352877b9 | ||
|
|
669ba9e8cb | ||
|
|
5fa8a76219 | ||
|
|
476dcf051c | ||
|
|
db96dbba6a | ||
|
|
e9c6509970 | ||
|
|
b26c7dfa8f | ||
|
|
3f251761d6 | ||
|
|
bc9d489ee8 | ||
|
|
271563ba9f | ||
|
|
82aba20e83 | ||
|
|
12f60c9be5 | ||
|
|
1c98a354c7 | ||
|
|
9ca7aee859 | ||
|
|
937b306128 | ||
|
|
69a2ab0ce2 | ||
|
|
b720711217 | ||
|
|
bf56348c62 | ||
|
|
f993817cb6 | ||
|
|
1c2b4794f3 | ||
|
|
523d210503 | ||
|
|
39da8bd636 | ||
|
|
fbea98bbe6 | ||
|
|
5d89f724f4 | ||
|
|
0313b6f3ab | ||
|
|
fe92111dc9 | ||
|
|
9a03bfb9e7 | ||
|
|
882db6acc9 | ||
|
|
5596468b03 | ||
|
|
eb66de1220 | ||
|
|
f97896f6a6 | ||
|
|
cfb47f880e | ||
|
|
eba87776a0 | ||
|
|
dda0e6d676 | ||
|
|
8d514644c1 | ||
|
|
0870a34391 | ||
|
|
38118986a3 | ||
|
|
1b4e5247ad | ||
|
|
3ef2eeef93 | ||
|
|
4d5682e79b | ||
|
|
24100d203f | ||
|
|
86946a2c21 | ||
|
|
54f3e4cc6f | ||
|
|
d9360b2d8c | ||
|
|
abb47118c0 | ||
|
|
9e4e55bb8d | ||
|
|
498f720507 | ||
|
|
b9bc9cb75e | ||
|
|
3b65917422 | ||
|
|
862dd78cd5 | ||
|
|
d0bc48d119 | ||
|
|
37462ba282 | ||
|
|
99e7f5862a | ||
|
|
048e529bb5 | ||
|
|
5b8b06f3a1 | ||
|
|
3c7d025802 | ||
|
|
4f8b46da14 | ||
|
|
0b386a882e | ||
|
|
6329d58a67 | ||
|
|
af0d780ac0 | ||
|
|
45c2c863ef | ||
|
|
3372e16409 | ||
|
|
a04fad9c1f | ||
|
|
a8a89dc9bd | ||
|
|
a0305a745a | ||
|
|
f06b702360 | ||
|
|
6f104c4ee6 | ||
|
|
c721580516 | ||
|
|
1fe1381fe2 | ||
|
|
870a25dad1 | ||
|
|
e4e5d5c6d7 | ||
|
|
7e45f23b6c | ||
|
|
719f61f612 | ||
|
|
908edda14b |
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
# Note that any data in staging will get cleared from time to time and you may have to sign up again and again
|
# 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
|
# Set it to the URL form where the app home page will be accessed
|
||||||
PUBLIC_URL=http://localhost:3000
|
PUBLIC_URL=https://localhost:3001
|
||||||
# Set it to true if you want to generate the Sourcemap for debugging
|
# Set it to true if you want to generate the Sourcemap for debugging
|
||||||
GENERATE_SOURCEMAP=false
|
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)
|
# 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)
|
||||||
|
|||||||
Generated
+1586
-1261
File diff suppressed because it is too large
Load Diff
+28
-26
@@ -4,16 +4,17 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formkit/auto-animate": "^0.8.2",
|
"@formkit/auto-animate": "^0.8.2",
|
||||||
"@lottiefiles/dotlottie-react": "^0.8.7",
|
"@lottiefiles/dotlottie-react": "^0.9.0",
|
||||||
"@pdf-lib/fontkit": "^1.1.1",
|
"@pdf-lib/fontkit": "^1.1.1",
|
||||||
"@radix-ui/themes": "^3.1.1",
|
"@radix-ui/themes": "^3.1.3",
|
||||||
"@react-pdf/renderer": "^3.4.4",
|
"@react-pdf/renderer": "^4.0.0",
|
||||||
"@reduxjs/toolkit": "^2.2.7",
|
"@reduxjs/toolkit": "^2.2.7",
|
||||||
"axios": "^1.7.3",
|
"axios": "^1.7.7",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"i18next": "^23.12.2",
|
"i18next": "^23.15.1",
|
||||||
"i18next-browser-languagedetector": "^8.0.0",
|
"i18next-browser-languagedetector": "^8.0.0",
|
||||||
"i18next-http-backend": "^2.5.2",
|
"i18next-http-backend": "^2.6.1",
|
||||||
|
"jszip": "^3.10.1",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"nth-check": "^2.1.1",
|
"nth-check": "^2.1.1",
|
||||||
@@ -25,7 +26,7 @@
|
|||||||
"react-bootstrap": "^2.10.4",
|
"react-bootstrap": "^2.10.4",
|
||||||
"react-confetti": "^6.1.0",
|
"react-confetti": "^6.1.0",
|
||||||
"react-cookie": "^7.2.0",
|
"react-cookie": "^7.2.0",
|
||||||
"react-datepicker": "^7.3.0",
|
"react-datepicker": "^7.4.0",
|
||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
"react-dnd-html5-backend": "^16.0.1",
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
"react-dnd-multi-backend": "^8.0.3",
|
"react-dnd-multi-backend": "^8.0.3",
|
||||||
@@ -33,17 +34,18 @@
|
|||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-gtm-module": "^2.0.11",
|
"react-gtm-module": "^2.0.11",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
"react-i18next": "^15.0.1",
|
"react-i18next": "^15.0.2",
|
||||||
"react-konva": "^18.2.10",
|
"react-konva": "^18.2.10",
|
||||||
"react-pdf": "^9.1.0",
|
"react-pdf": "^9.1.1",
|
||||||
"react-quill-new": "^3.2.2",
|
"react-quill-new": "^3.3.2",
|
||||||
"react-redux": "^9.1.2",
|
"react-redux": "^9.1.2",
|
||||||
"react-rnd": "^10.4.11",
|
"react-rnd": "^10.4.13",
|
||||||
"react-router-dom": "^6.26.0",
|
"react-router-dom": "^6.26.2",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-scrollbars-custom": "^4.1.1",
|
"react-scrollbars-custom": "^4.1.1",
|
||||||
"react-select": "^5.8.0",
|
"react-select": "^5.8.1",
|
||||||
"react-signature-canvas": "^1.0.6",
|
"react-signature-canvas": "^1.0.6",
|
||||||
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
"react-tooltip": "^5.28.0",
|
"react-tooltip": "^5.28.0",
|
||||||
"react-web-share": "^2.0.2",
|
"react-web-share": "^2.0.2",
|
||||||
"reactour": "^1.19.4",
|
"reactour": "^1.19.4",
|
||||||
@@ -52,14 +54,14 @@
|
|||||||
"regex-parser": "^2.3.0",
|
"regex-parser": "^2.3.0",
|
||||||
"serve": "^14.2.3",
|
"serve": "^14.2.3",
|
||||||
"styled-components": "^5.3.0",
|
"styled-components": "^5.3.0",
|
||||||
"web-vitals": "^4.2.2",
|
"web-vitals": "^4.2.3",
|
||||||
"ws": "^8.18.0"
|
"ws": "^8.18.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build-webpack": "webpack --config webpack.config.js",
|
"build-webpack": "webpack --config webpack.config.js",
|
||||||
"build": "npm run version && npm run build-webpack && react-scripts build",
|
"build": "npm run version && npm run build-webpack && react-scripts build",
|
||||||
"build-watch": "webpack --config webpack.config.js --watch",
|
"build-watch": "webpack --config webpack.config.js --watch",
|
||||||
"start-dev": "concurrently \"npm run build-watch\" \"react-scripts start\"",
|
"start-dev": "react-scripts start",
|
||||||
"start": "serve -s build",
|
"start": "serve -s build",
|
||||||
"version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
|
"version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
|
||||||
"version-win": "powershell -Command \"Invoke-RestMethod -Uri 'https://api.github.com/repos/opensignlabs/opensign/releases/latest' | Select-Object -ExpandProperty tag_name | Out-File -FilePath ./public/version.txt\"",
|
"version-win": "powershell -Command \"Invoke-RestMethod -Uri 'https://api.github.com/repos/opensignlabs/opensign/releases/latest' | Select-Object -ExpandProperty tag_name | Out-File -FilePath ./public/version.txt\"",
|
||||||
@@ -94,27 +96,27 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.25.2",
|
"@babel/core": "^7.25.2",
|
||||||
"@babel/preset-env": "^7.25.3",
|
"@babel/preset-env": "^7.25.4",
|
||||||
"@babel/preset-react": "^7.24.7",
|
"@babel/preset-react": "^7.24.7",
|
||||||
"@babel/runtime-corejs2": "^7.25.0",
|
"@babel/runtime-corejs2": "^7.25.6",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.20",
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.2.1",
|
||||||
"clean-webpack-plugin": "^4.0.0",
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
"commitizen": "^4.3.0",
|
"commitizen": "^4.3.0",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^9.0.1",
|
||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.2",
|
||||||
"daisyui": "^4.12.10",
|
"daisyui": "^4.12.10",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"dotenv-webpack": "^8.1.0",
|
"dotenv-webpack": "^8.1.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^9.11.1",
|
||||||
"eslint-plugin-prettier": "^5.2.1",
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
"eslint-plugin-react": "^7.34.3",
|
"eslint-plugin-react": "^7.36.1",
|
||||||
"lint-staged": "^15.2.8",
|
"lint-staged": "^15.2.10",
|
||||||
"mini-css-extract-plugin": "^2.9.0",
|
"mini-css-extract-plugin": "^2.9.1",
|
||||||
"postcss": "^8.4.41",
|
"postcss": "^8.4.47",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"pretty-quick": "^4.0.0",
|
"pretty-quick": "^4.0.0",
|
||||||
"tailwindcss": "^3.4.9",
|
"tailwindcss": "^3.4.13",
|
||||||
"terser-webpack-plugin": "^5.3.10",
|
"terser-webpack-plugin": "^5.3.10",
|
||||||
"webpack-cli": "^5.1.4"
|
"webpack-cli": "^5.1.4"
|
||||||
},
|
},
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
|
|||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import Title from "./Title";
|
import Title from "./Title";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
import { copytoData } from "../constant/Utils";
|
import { copytoData, fetchSubscriptionInfo } from "../constant/Utils";
|
||||||
import { isEnableSubscription } from "../constant/const";
|
import { isEnableSubscription } from "../constant/const";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
function generatePassword(length) {
|
function generatePassword(length) {
|
||||||
@@ -27,15 +27,64 @@ const AddUser = (props) => {
|
|||||||
password: "",
|
password: "",
|
||||||
role: ""
|
role: ""
|
||||||
});
|
});
|
||||||
|
const [amount, setAmount] = useState({ quantity: 1, price: 0 });
|
||||||
|
const [planInfo, setPlanInfo] = useState({
|
||||||
|
priceperUser: 0,
|
||||||
|
price: 0,
|
||||||
|
totalAllowedUser: 0,
|
||||||
|
adminId: ""
|
||||||
|
});
|
||||||
|
const [isFormLoader, setIsFormLoader] = useState(false);
|
||||||
const [isLoader, setIsLoader] = useState(false);
|
const [isLoader, setIsLoader] = useState(false);
|
||||||
const [teamList, setTeamList] = useState([]);
|
const [teamList, setTeamList] = useState([]);
|
||||||
|
const [allowedUser, setAllowedUser] = useState(0);
|
||||||
|
const [err, setErr] = useState("");
|
||||||
const role = ["OrgAdmin", "Editor", "User"];
|
const role = ["OrgAdmin", "Editor", "User"];
|
||||||
|
const extUser =
|
||||||
|
localStorage.getItem("Extand_Class") &&
|
||||||
|
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getTeamList();
|
getTeamList();
|
||||||
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getTeamList = async () => {
|
const getTeamList = async () => {
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
try {
|
||||||
|
setIsLoader(true);
|
||||||
|
const resSub = await fetchSubscriptionInfo();
|
||||||
|
if (!resSub.error) {
|
||||||
|
setPlanInfo((prev) => ({
|
||||||
|
...prev,
|
||||||
|
priceperUser: resSub.price,
|
||||||
|
totalAllowedUser: resSub.totalAllowedUser,
|
||||||
|
adminId: resSub.adminId
|
||||||
|
}));
|
||||||
|
setAmount((prev) => ({ ...prev, price: resSub.price }));
|
||||||
|
const res = await Parse.Cloud.run("allowedusers");
|
||||||
|
if (props.setFormHeader) {
|
||||||
|
if (res > 0) {
|
||||||
|
props.setFormHeader(t("add-user"));
|
||||||
|
} else {
|
||||||
|
props.setFormHeader(
|
||||||
|
resSub.adminId !== extUser?.objectId
|
||||||
|
? "Unauthorized"
|
||||||
|
: t("Add-seats")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setAllowedUser(res);
|
||||||
|
} else {
|
||||||
|
setAllowedUser(0);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setAllowedUser(0);
|
||||||
|
console.log("Err in alloweduser", err);
|
||||||
|
setErr(err.message);
|
||||||
|
} finally {
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
setFormdata((prev) => ({ ...prev, password: generatePassword(12) }));
|
setFormdata((prev) => ({ ...prev, password: generatePassword(12) }));
|
||||||
const teamRes = await Parse.Cloud.run("getteams", { active: true });
|
const teamRes = await Parse.Cloud.run("getteams", { active: true });
|
||||||
if (teamRes.length > 0) {
|
if (teamRes.length > 0) {
|
||||||
@@ -67,14 +116,12 @@ const AddUser = (props) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const localUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
const localUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
setIsLoader(true);
|
setIsFormLoader(true);
|
||||||
const res = await checkUserExist();
|
const res = await checkUserExist();
|
||||||
if (res) {
|
if (res) {
|
||||||
props.setIsAlert({ type: "danger", msg: t("user-already-exist") });
|
props.setIsAlert({ type: "danger", msg: t("user-already-exist") });
|
||||||
setIsLoader(false);
|
setIsFormLoader(false);
|
||||||
setTimeout(() => {
|
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1000);
|
||||||
props.setIsAlert({ type: "success", msg: "" });
|
|
||||||
}, 1000);
|
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const extUser = new Parse.Object("contracts_Users");
|
const extUser = new Parse.Object("contracts_Users");
|
||||||
@@ -157,14 +204,8 @@ const AddUser = (props) => {
|
|||||||
props.handleUserData(parseData);
|
props.handleUserData(parseData);
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsLoader(false);
|
setIsFormLoader(false);
|
||||||
setFormdata({
|
setFormdata({ name: "", email: "", phone: "", team: "", role: "" });
|
||||||
name: "",
|
|
||||||
email: "",
|
|
||||||
phone: "",
|
|
||||||
team: "",
|
|
||||||
role: ""
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err ", err);
|
console.log("err ", err);
|
||||||
@@ -204,19 +245,13 @@ const AddUser = (props) => {
|
|||||||
}
|
}
|
||||||
props.handleUserData(parseData);
|
props.handleUserData(parseData);
|
||||||
}
|
}
|
||||||
setIsLoader(false);
|
setIsFormLoader(false);
|
||||||
setFormdata({
|
setFormdata({ name: "", email: "", phone: "", team: "", role: "" });
|
||||||
name: "",
|
|
||||||
email: "",
|
|
||||||
phone: "",
|
|
||||||
team: "",
|
|
||||||
role: ""
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err", err);
|
console.log("err", err);
|
||||||
setIsLoader(false);
|
setIsFormLoader(false);
|
||||||
props.setIsAlert({
|
props.setIsAlert({
|
||||||
type: "danger",
|
type: "danger",
|
||||||
msg: t("something-went-wrong-mssg")
|
msg: t("something-went-wrong-mssg")
|
||||||
@@ -229,13 +264,7 @@ const AddUser = (props) => {
|
|||||||
|
|
||||||
// Define a function to handle the "add yourself" checkbox
|
// Define a function to handle the "add yourself" checkbox
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
setFormdata({
|
setFormdata({ name: "", email: "", phone: "", team: "", role: "" });
|
||||||
name: "",
|
|
||||||
email: "",
|
|
||||||
phone: "",
|
|
||||||
team: "",
|
|
||||||
role: ""
|
|
||||||
});
|
|
||||||
if (props.closePopup) {
|
if (props.closePopup) {
|
||||||
props.closePopup();
|
props.closePopup();
|
||||||
}
|
}
|
||||||
@@ -245,10 +274,7 @@ const AddUser = (props) => {
|
|||||||
if (name === "email") {
|
if (name === "email") {
|
||||||
value = value?.toLowerCase()?.replace(/\s/g, "");
|
value = value?.toLowerCase()?.replace(/\s/g, "");
|
||||||
}
|
}
|
||||||
setFormdata((prev) => ({
|
setFormdata((prev) => ({ ...prev, [name]: value }));
|
||||||
...prev,
|
|
||||||
[name]: value
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const copytoclipboard = (text) => {
|
const copytoclipboard = (text) => {
|
||||||
@@ -256,163 +282,271 @@ const AddUser = (props) => {
|
|||||||
props.setIsAlert({ type: "success", msg: t("copied") });
|
props.setIsAlert({ type: "success", msg: t("copied") });
|
||||||
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1500); // Reset copied state after 1.5 seconds
|
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1500); // Reset copied state after 1.5 seconds
|
||||||
};
|
};
|
||||||
|
const handlePricePerUser = (e) => {
|
||||||
|
const quantity = e.target.value;
|
||||||
|
const price = e.target?.value > 0 ? planInfo.priceperUser * quantity : 0;
|
||||||
|
setAmount((prev) => ({ ...prev, quantity: quantity, price: price }));
|
||||||
|
};
|
||||||
|
const handleAddOnSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setIsFormLoader(true);
|
||||||
|
try {
|
||||||
|
const resAddon = await Parse.Cloud.run("buyaddonusers", {
|
||||||
|
users: amount.quantity
|
||||||
|
});
|
||||||
|
if (resAddon) {
|
||||||
|
const _resAddon = JSON.parse(JSON.stringify(resAddon));
|
||||||
|
if (_resAddon.status === "success") {
|
||||||
|
setAllowedUser(amount.quantity);
|
||||||
|
setPlanInfo((obj) => ({ ...obj, totalAllowedUser: _resAddon.addon }));
|
||||||
|
}
|
||||||
|
if (props.handleBuyUsers) {
|
||||||
|
props.handleBuyUsers(amount.quantity, _resAddon.addon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err in buy addon", err);
|
||||||
|
props.setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 2000);
|
||||||
|
setIsFormLoader(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="shadow-md rounded-box my-[1px] p-3 bg-[#ffffff]">
|
<div className="shadow-md rounded-box my-[1px] p-3 bg-base-100 relative">
|
||||||
<Title title={"Add User"} />
|
<Title title={t("add-user")} />
|
||||||
{isLoader && (
|
{isFormLoader && (
|
||||||
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30 z-50 rounded-box">
|
<div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50">
|
||||||
<Loader />
|
<Loader />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="w-full mx-auto">
|
{!isLoader ? (
|
||||||
<form onSubmit={handleSubmit}>
|
<>
|
||||||
{/* <h1 className="text-[20px] font-semibold mb-4">Add User</h1> */}
|
{err ? (
|
||||||
<div className="mb-3">
|
<div className="flex justify-center items-center h-[70px] text-[18px]">
|
||||||
<label
|
{err}
|
||||||
htmlFor="name"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
{t("name")}
|
|
||||||
<span className="text-[red] text-[13px]"> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="name"
|
|
||||||
value={formdata.name}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
|
||||||
required
|
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="email"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
{t("email")}
|
|
||||||
<span className="text-[red] text-[13px]"> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
name="email"
|
|
||||||
value={formdata.email}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
|
||||||
required
|
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="email"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
{t("password")}
|
|
||||||
</label>
|
|
||||||
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm text-base-content w-full h-full text-[13px]">
|
|
||||||
<div className="break-all">{formdata?.password}</div>
|
|
||||||
<i
|
|
||||||
onClick={() => copytoclipboard(formdata?.password)}
|
|
||||||
className="fa-light fa-copy rounded-full hover:bg-base-300 p-[8px] cursor-pointer "
|
|
||||||
></i>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="text-[12px] ml-2 mb-0 text-[red] select-none">
|
) : (
|
||||||
{t("password-generateed")}
|
<div className="w-full mx-auto">
|
||||||
</div>
|
{!isEnableSubscription || allowedUser > 0 ? (
|
||||||
</div>
|
<form onSubmit={handleSubmit}>
|
||||||
<div className="mb-3">
|
{isEnableSubscription && (
|
||||||
<label
|
<p className="flex justify-center mb-1">
|
||||||
htmlFor="phone"
|
{t("remaing-users")}{" "}
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
<span
|
||||||
>
|
className={`${
|
||||||
{t("phone")}
|
allowedUser < 2 ? "op-text-accent" : "op-text-primary"
|
||||||
{/* <span className="text-[red] text-[13px]"> *</span> */}
|
} font-medium ml-1`}
|
||||||
</label>
|
>
|
||||||
<input
|
{allowedUser} {t("of")} {planInfo.totalAllowedUser}
|
||||||
type="text"
|
</span>
|
||||||
name="phone"
|
</p>
|
||||||
placeholder="optional"
|
)}
|
||||||
value={formdata.phone}
|
<div className="mb-3">
|
||||||
onChange={(e) => handleChange(e)}
|
<label
|
||||||
// required
|
htmlFor="name"
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
/>
|
>
|
||||||
</div>
|
{t("name")}
|
||||||
{isEnableSubscription && (
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
<div className="mb-3">
|
</label>
|
||||||
<label
|
<input
|
||||||
htmlFor="phone"
|
type="text"
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
name="name"
|
||||||
>
|
value={formdata.name}
|
||||||
Team<span className="text-[red] text-[13px]"> *</span>
|
onChange={(e) => handleChange(e)}
|
||||||
</label>
|
onInvalid={(e) =>
|
||||||
<select
|
e.target.setCustomValidity(t("input-required"))
|
||||||
value={formdata.team}
|
}
|
||||||
onChange={(e) => handleChange(e)}
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
name="team"
|
required
|
||||||
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
onInvalid={(e) =>
|
/>
|
||||||
e.target.setCustomValidity(t("input-required"))
|
</div>
|
||||||
}
|
<div className="mb-3">
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
<label
|
||||||
required
|
htmlFor="email"
|
||||||
>
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
<option defaultValue={""} value={""}>
|
>
|
||||||
select
|
{t("email")}
|
||||||
</option>
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
{teamList.length > 0 &&
|
</label>
|
||||||
teamList.map((x) => (
|
<input
|
||||||
<option key={x.objectId} value={x.objectId}>
|
type="email"
|
||||||
{x.Name}
|
name="email"
|
||||||
</option>
|
value={formdata.email}
|
||||||
))}
|
onChange={(e) => handleChange(e)}
|
||||||
</select>
|
required
|
||||||
|
onInvalid={(e) =>
|
||||||
|
e.target.setCustomValidity(t("input-required"))
|
||||||
|
}
|
||||||
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
|
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 className="block text-xs text-gray-700 font-semibold">
|
||||||
|
{t("password")}
|
||||||
|
</label>
|
||||||
|
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm text-base-content w-full h-full text-[13px]">
|
||||||
|
<div className="break-all">{formdata?.password}</div>
|
||||||
|
<i
|
||||||
|
onClick={() => copytoclipboard(formdata?.password)}
|
||||||
|
className="fa-light fa-copy rounded-full hover:bg-base-300 p-[8px] cursor-pointer "
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
<div className="text-[12px] ml-2 mb-0 text-[red] select-none">
|
||||||
|
{t("password-generateed")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label
|
||||||
|
htmlFor="phone"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("phone")}
|
||||||
|
{/* <span className="text-[red] text-[13px]"> *</span> */}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="phone"
|
||||||
|
placeholder="optional"
|
||||||
|
value={formdata.phone}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
// required
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{isEnableSubscription && (
|
||||||
|
<div className="mb-3">
|
||||||
|
<label
|
||||||
|
htmlFor="phone"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("team")}
|
||||||
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
name="team"
|
||||||
|
value={formdata.team}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
onInvalid={(e) =>
|
||||||
|
e.target.setCustomValidity(t("input-required"))
|
||||||
|
}
|
||||||
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<option defaultValue={""} value={""}>
|
||||||
|
{t("Select")}
|
||||||
|
</option>
|
||||||
|
{teamList.length > 0 &&
|
||||||
|
teamList.map((x) => (
|
||||||
|
<option key={x.objectId} value={x.objectId}>
|
||||||
|
{x.Name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="mb-3">
|
||||||
|
<label
|
||||||
|
htmlFor="phone"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("Role")}
|
||||||
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={formdata.role}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
name="role"
|
||||||
|
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
onInvalid={(e) =>
|
||||||
|
e.target.setCustomValidity(t("input-required"))
|
||||||
|
}
|
||||||
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<option defaultValue={""} value={""}>
|
||||||
|
{t("Select")}
|
||||||
|
</option>
|
||||||
|
{role.length > 0 &&
|
||||||
|
role.map((x) => (
|
||||||
|
<option key={x} value={x}>
|
||||||
|
{x}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center mt-3 gap-2 text-white">
|
||||||
|
<button type="submit" className="op-btn op-btn-primary">
|
||||||
|
{t("submit")}
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleReset()}
|
||||||
|
className="op-btn op-btn-secondary"
|
||||||
|
>
|
||||||
|
{t("cancel")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{planInfo.adminId !== extUser?.objectId ? (
|
||||||
|
<div className="mb-3 mt-1 flex justify-center text-center items-center font-medium break-all">
|
||||||
|
{t("unauthorized-modal", {
|
||||||
|
adminEmail: extUser?.TenantId?.EmailAddress
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<form onSubmit={handleAddOnSubmit}>
|
||||||
|
<p className="flex justify-center text-center mx-2 mb-3 text-base op-text-accent font-medium">
|
||||||
|
{t("additional-users")}
|
||||||
|
</p>
|
||||||
|
<div className="mb-3 flex justify-between">
|
||||||
|
<label
|
||||||
|
htmlFor="quantity"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("Quantity-of-users")}
|
||||||
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
name="quantity"
|
||||||
|
value={amount.quantity}
|
||||||
|
onChange={(e) => handlePricePerUser(e)}
|
||||||
|
className="w-1/4 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3 flex justify-between">
|
||||||
|
<label className="block text-xs text-gray-700 font-semibold">
|
||||||
|
{t("Price")} (1 * {planInfo.priceperUser})
|
||||||
|
</label>
|
||||||
|
<div className="w-1/4 flex justify-center items-center text-sm">
|
||||||
|
USD {amount.price}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr className="text-base-content mb-3" />
|
||||||
|
<button className="op-btn op-btn-primary w-full">
|
||||||
|
{t("Proceed")}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="mb-3">
|
</>
|
||||||
<label
|
) : (
|
||||||
htmlFor="phone"
|
<div className="w-full h-[200px] inset-0 flex justify-center items-center z-50">
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
<Loader />
|
||||||
>
|
</div>
|
||||||
Role<span className="text-[red] text-[13px]"> *</span>
|
)}
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
value={formdata.role}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
name="role"
|
|
||||||
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
|
||||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<option defaultValue={""} value={""}>
|
|
||||||
select
|
|
||||||
</option>
|
|
||||||
{role.length > 0 &&
|
|
||||||
role.map((x) => (
|
|
||||||
<option key={x} value={x}>
|
|
||||||
{x}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center mt-3 gap-2 text-white">
|
|
||||||
<button type="submit" className="op-btn op-btn-primary">
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
type="button"
|
|
||||||
onClick={() => handleReset()}
|
|
||||||
className="op-btn op-btn-secondary"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,9 +3,14 @@ import axios from "axios";
|
|||||||
import SuggestionInput from "./shared/fields/SuggestionInput";
|
import SuggestionInput from "./shared/fields/SuggestionInput";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import Parse from "parse";
|
||||||
|
import ModalUi from "../primitives/ModalUi";
|
||||||
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
import { fetchSubscription } from "../constant/Utils";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
const BulkSendUi = (props) => {
|
const BulkSendUi = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const navigate = useNavigate();
|
||||||
const [forms, setForms] = useState([]);
|
const [forms, setForms] = useState([]);
|
||||||
const [formId, setFormId] = useState(2);
|
const [formId, setFormId] = useState(2);
|
||||||
const formRef = useRef(null);
|
const formRef = useRef(null);
|
||||||
@@ -13,6 +18,22 @@ const BulkSendUi = (props) => {
|
|||||||
const [isSubmit, setIsSubmit] = useState(false);
|
const [isSubmit, setIsSubmit] = useState(false);
|
||||||
const [allowedForm, setAllowedForm] = useState(0);
|
const [allowedForm, setAllowedForm] = useState(0);
|
||||||
const [isSignatureExist, setIsSignatureExist] = useState();
|
const [isSignatureExist, setIsSignatureExist] = useState();
|
||||||
|
const [isBulkAvailable, setIsBulkAvailable] = useState(false);
|
||||||
|
const quantityList = [500, 1000, 5000, 50000];
|
||||||
|
const [amount, setAmount] = useState({
|
||||||
|
price: (75.0).toFixed(2),
|
||||||
|
quantity: 500,
|
||||||
|
priceperbulksend: 0.15,
|
||||||
|
totalcredits: 0
|
||||||
|
});
|
||||||
|
const [isQuotaReached, setIsQuotaReached] = useState(false);
|
||||||
|
const [isLoader, setIsLoader] = useState(false);
|
||||||
|
const [isFreePlan, setIsFreePlan] = useState(false);
|
||||||
|
const [admin, setAdmin] = useState({
|
||||||
|
objectId: "",
|
||||||
|
email: "",
|
||||||
|
isAdmin: true
|
||||||
|
});
|
||||||
const allowedSigners = 50;
|
const allowedSigners = 50;
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
signatureExist();
|
signatureExist();
|
||||||
@@ -20,14 +41,71 @@ const BulkSendUi = (props) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
//function to check atleast one signature field exist
|
//function to check atleast one signature field exist
|
||||||
const signatureExist = () => {
|
const signatureExist = async () => {
|
||||||
const getPlaceholder = props.item?.Placeholders;
|
if (isEnableSubscription) {
|
||||||
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
|
setIsLoader(true);
|
||||||
placeholderObj?.placeHolder?.some((holder) =>
|
try {
|
||||||
holder?.pos?.some((posItem) => posItem?.type === "signature")
|
const subscription = await fetchSubscription();
|
||||||
)
|
const extUser =
|
||||||
);
|
localStorage.getItem("Extand_Class") &&
|
||||||
setIsSignatureExist(checkIsSignatureExistt);
|
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
|
if (
|
||||||
|
subscription?.adminId &&
|
||||||
|
extUser?.objectId === subscription?.adminId
|
||||||
|
) {
|
||||||
|
setAdmin((obj) => ({
|
||||||
|
...obj,
|
||||||
|
objectId: subscription?.adminId,
|
||||||
|
isAdmin: true
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
setAdmin((obj) => ({
|
||||||
|
...obj,
|
||||||
|
isAdmin: false,
|
||||||
|
email: extUser?.TenantId?.EmailAddress
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
setAdmin((obj) => ({ ...obj, objectId: subscription?.adminId }));
|
||||||
|
if (subscription?.plan === "freeplan") {
|
||||||
|
setIsFreePlan(true);
|
||||||
|
}
|
||||||
|
const resCredits = await Parse.Cloud.run("allowedcredits");
|
||||||
|
if (resCredits) {
|
||||||
|
const allowedcredits = resCredits?.allowedcredits || 0;
|
||||||
|
const addoncredits = resCredits?.addoncredits || 0;
|
||||||
|
const totalcredits = allowedcredits + addoncredits;
|
||||||
|
if (totalcredits > 0) {
|
||||||
|
if (subscription?.plan !== "freeplan") {
|
||||||
|
setIsBulkAvailable(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setAmount((obj) => ({ ...obj, totalcredits: totalcredits }));
|
||||||
|
}
|
||||||
|
const getPlaceholder = props.item?.Placeholders;
|
||||||
|
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
|
||||||
|
placeholderObj?.placeHolder?.some((holder) =>
|
||||||
|
holder?.pos?.some((posItem) => posItem?.type === "signature")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
setIsSignatureExist(checkIsSignatureExistt);
|
||||||
|
setIsLoader(false);
|
||||||
|
} catch (err) {
|
||||||
|
setIsLoader(false);
|
||||||
|
alert(t("something-went-wrong-mssg"));
|
||||||
|
console.log("Err", err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsBulkAvailable(true);
|
||||||
|
setAdmin((obj) => ({ ...obj, isAdmin: true }));
|
||||||
|
const getPlaceholder = props.item?.Placeholders;
|
||||||
|
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
|
||||||
|
placeholderObj?.placeHolder?.some((holder) =>
|
||||||
|
holder?.pos?.some((posItem) => posItem?.type === "signature")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
setIsSignatureExist(checkIsSignatureExistt);
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (scrollOnNextUpdate && formRef.current) {
|
if (scrollOnNextUpdate && formRef.current) {
|
||||||
@@ -76,29 +154,33 @@ const BulkSendUi = (props) => {
|
|||||||
const handleAddForm = (e) => {
|
const handleAddForm = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
// Check if the quick send limit has been reached
|
// Check if the quick send limit has been reached
|
||||||
if (forms?.length < allowedForm) {
|
if (isEnableSubscription && forms.length >= amount.totalcredits) {
|
||||||
if (props?.Placeholders.length > 0) {
|
setIsQuotaReached(true);
|
||||||
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 {
|
} else {
|
||||||
// If the limit has been reached, throw an error with the appropriate message
|
if (forms?.length < allowedForm) {
|
||||||
alert(t("quick-send-alert-4"));
|
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(t("quick-send-alert-4"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -162,13 +244,9 @@ const BulkSendUi = (props) => {
|
|||||||
: [...existSigner]
|
: [...existSigner]
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Documents.push({
|
Documents.push({ ...props.item, Placeholders: updatedPlaceholders });
|
||||||
...props.item,
|
|
||||||
Placeholders: updatedPlaceholders
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//console.log("Documents ", Documents);
|
|
||||||
await batchQuery(Documents);
|
await batchQuery(Documents);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -180,9 +258,7 @@ const BulkSendUi = (props) => {
|
|||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
};
|
};
|
||||||
const params = {
|
const params = { Documents: JSON.stringify(Documents) };
|
||||||
Documents: JSON.stringify(Documents)
|
|
||||||
};
|
|
||||||
try {
|
try {
|
||||||
const res = await axios.post(functionsUrl, params, { headers: headers });
|
const res = await axios.post(functionsUrl, params, { headers: headers });
|
||||||
// console.log("res ", res);
|
// console.log("res ", res);
|
||||||
@@ -196,83 +272,231 @@ const BulkSendUi = (props) => {
|
|||||||
setIsSubmit(false);
|
setIsSubmit(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const handleAddOnQuickSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setIsSubmit(true);
|
||||||
|
try {
|
||||||
|
const resAddon = await Parse.Cloud.run("buycredits", {
|
||||||
|
credits: amount.quantity
|
||||||
|
});
|
||||||
|
if (resAddon) {
|
||||||
|
const _resAddon = JSON.parse(JSON.stringify(resAddon));
|
||||||
|
if (_resAddon.status === "success") {
|
||||||
|
setIsBulkAvailable(true);
|
||||||
|
handleCloseQuotaReached();
|
||||||
|
setAmount((obj) => ({
|
||||||
|
...obj,
|
||||||
|
quantity: 500,
|
||||||
|
priceperbulksend: 0.15,
|
||||||
|
price: (75.0).toFixed(2),
|
||||||
|
totalcredits: obj?.totalcredits + _resAddon.addon
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err in buy addon", err);
|
||||||
|
alert(t("something-went-wrong-mssg"));
|
||||||
|
} finally {
|
||||||
|
setIsSubmit(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handlePricePerQuick = async (e) => {
|
||||||
|
const quantity = e.target?.value;
|
||||||
|
const price =
|
||||||
|
quantity > 0
|
||||||
|
? (Math.round(quantity * amount.priceperbulksend * 100) / 100).toFixed(
|
||||||
|
2
|
||||||
|
)
|
||||||
|
: 500 * amount.priceperbulksend;
|
||||||
|
setAmount((prev) => ({ ...prev, quantity: quantity, price: price }));
|
||||||
|
};
|
||||||
|
const handleCloseQuotaReached = () => {
|
||||||
|
setIsQuotaReached(false);
|
||||||
|
};
|
||||||
|
const handleNavigation = () => {
|
||||||
|
navigate("/subscription");
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isSubmit && (
|
{isLoader ? (
|
||||||
<div className="absolute z-[999] h-full w-full flex justify-center items-center bg-black bg-opacity-30">
|
<div className="w-full h-[100px] flex justify-center items-center z-[999]">
|
||||||
<Loader />
|
<Loader />
|
||||||
</div>
|
</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>{t("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>{t("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">
|
|
||||||
{t("quick-send-alert-1")}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
|
|
||||||
{t("quick-send-alert-2")}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
) : (
|
) : (
|
||||||
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
|
<>
|
||||||
{t("quick-send-alert-3")}
|
{isSubmit && (
|
||||||
</div>
|
<div className="absolute z-[999] h-full w-full flex justify-center items-center bg-black bg-opacity-30">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isBulkAvailable ? (
|
||||||
|
<>
|
||||||
|
{props.Placeholders?.length > 0 ? (
|
||||||
|
isSignatureExist ? (
|
||||||
|
<>
|
||||||
|
{props.Placeholders?.some((x) => !x.signerObjId) ? (
|
||||||
|
<div>
|
||||||
|
<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">
|
||||||
|
{isEnableSubscription && (
|
||||||
|
<button
|
||||||
|
onClick={handleAddForm}
|
||||||
|
className="op-btn op-btn-primary focus:outline-none"
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-plus"></i>{" "}
|
||||||
|
<span>{t("add-new")}</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="op-btn op-btn-accent focus:outline-none"
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-paper-plane"></i>{" "}
|
||||||
|
<span>{t("send")}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<ModalUi
|
||||||
|
isOpen={isQuotaReached}
|
||||||
|
handleClose={() => handleCloseQuotaReached()}
|
||||||
|
>
|
||||||
|
<div className="p-4 flex justify-center items-center flex-col gap-y-3">
|
||||||
|
<p className="text-center text-base-content">
|
||||||
|
{t("quota-err-quicksend")}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={() => setIsBulkAvailable(false)}
|
||||||
|
className=" op-btn op-btn-primary w-[200px]"
|
||||||
|
>
|
||||||
|
{t("buy-credits")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
|
||||||
|
{t("quick-send-alert-1")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
|
||||||
|
{t("quick-send-alert-2")}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
|
||||||
|
{t("quick-send-alert-3")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{isFreePlan ? (
|
||||||
|
<div className="w-full h-[130px] flex flex-col justify-center items-center text-center p-4">
|
||||||
|
<p className="text-base font-medium mb-2.5">
|
||||||
|
{t("bulk-send-subcription-alert")}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={() => handleNavigation()}
|
||||||
|
className="op-btn op-btn-primary"
|
||||||
|
>
|
||||||
|
{t("upgrade-now")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{admin?.isAdmin ? (
|
||||||
|
<form onSubmit={handleAddOnQuickSubmit} className="p-3">
|
||||||
|
<p className="flex justify-center text-center mx-2 mb-3 text-base op-text-accent font-medium">
|
||||||
|
{t("additional-credits")}
|
||||||
|
</p>
|
||||||
|
<div className="mb-3 flex justify-between">
|
||||||
|
<label
|
||||||
|
htmlFor="quantity"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("quantity-of-credits")}
|
||||||
|
<span className="text-[red] text-[13px]">*</span>
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={amount.quantity}
|
||||||
|
onChange={(e) => handlePricePerQuick(e)}
|
||||||
|
name="quantity"
|
||||||
|
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-1/4 text-xs"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
{quantityList.length > 0 &&
|
||||||
|
quantityList.map((x) => (
|
||||||
|
<option key={x} value={x}>
|
||||||
|
{x}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3 flex justify-between">
|
||||||
|
<label className="block text-xs text-gray-700 font-semibold">
|
||||||
|
{t("Price")} (1 * {amount.priceperbulksend})
|
||||||
|
</label>
|
||||||
|
<div className="w-1/4 flex justify-center items-center text-sm">
|
||||||
|
USD {amount.price}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr className="text-base-content mb-3" />
|
||||||
|
<button className="op-btn op-btn-primary w-full mt-2">
|
||||||
|
{t("Proceed")}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
) : (
|
||||||
|
<div className="mx-8 mt-4 mb-8 flex justify-center text-center items-center font-medium break-all">
|
||||||
|
{t("unauthorized-modal", { adminEmail: admin?.email })}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,30 +6,42 @@ import Parse from "parse";
|
|||||||
import { useWindowSize } from "../hook/useWindowSize";
|
import { useWindowSize } from "../hook/useWindowSize";
|
||||||
import {
|
import {
|
||||||
checkIsSubscribed,
|
checkIsSubscribed,
|
||||||
checkIsSubscribedTeam,
|
|
||||||
getAppLogo,
|
getAppLogo,
|
||||||
openInNewTab,
|
openInNewTab,
|
||||||
saveLanguageInLocal
|
saveLanguageInLocal
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import { isEnableSubscription, isStaging } from "../constant/const";
|
import { isEnableSubscription, isStaging } from "../constant/const";
|
||||||
|
import { validplan } from "../json/plansArr";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import ModalUi from "../primitives/ModalUi";
|
||||||
|
import QuotaCard from "../primitives/QuotaCard";
|
||||||
|
|
||||||
const Header = ({ showSidebar }) => {
|
const Header = ({ showSidebar }) => {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
let username = localStorage.getItem("username");
|
const current_notification_version = "1"; // Update this with each new feature release
|
||||||
|
// Get the dismissed version from local storage
|
||||||
|
const dismissedVersion = localStorage.getItem("notificationDismissedVersion");
|
||||||
|
const username = localStorage.getItem("username") || "";
|
||||||
const image = localStorage.getItem("profileImg") || dp;
|
const image = localStorage.getItem("profileImg") || dp;
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [isSubscribe, setIsSubscribe] = useState(true);
|
const [isSubscribe, setIsSubscribe] = useState(true);
|
||||||
const [isPro, setIsPro] = useState(false);
|
const [isTeam, setIsTeam] = useState({ plan: "", isValid: false });
|
||||||
const [isTeam, setIsTeam] = useState(false);
|
|
||||||
const [applogo, setAppLogo] = useState(
|
const [applogo, setAppLogo] = useState(
|
||||||
localStorage.getItem("appLogo") || " "
|
localStorage.getItem("appLogo") || " "
|
||||||
);
|
);
|
||||||
|
const [emailUsed, setEmailUsed] = useState(0);
|
||||||
|
const [isModal, setIsModal] = useState(false);
|
||||||
|
const [showNotification, setShowNotification] = useState(
|
||||||
|
(!dismissedVersion || dismissedVersion !== current_notification_version) &&
|
||||||
|
true
|
||||||
|
);
|
||||||
const toggleDropdown = () => {
|
const toggleDropdown = () => {
|
||||||
setIsOpen(!isOpen);
|
setIsOpen(!isOpen);
|
||||||
|
if (width <= 768) {
|
||||||
|
showSidebar();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
checkSubscription();
|
checkSubscription();
|
||||||
@@ -37,9 +49,8 @@ const Header = ({ showSidebar }) => {
|
|||||||
}, []);
|
}, []);
|
||||||
async function checkSubscription() {
|
async function checkSubscription() {
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const getIsSubscribe = await checkIsSubscribed();
|
const subscribe = await checkIsSubscribed();
|
||||||
const getIsTeam = await checkIsSubscribedTeam();
|
if (subscribe.isValid) {
|
||||||
if (getIsSubscribe) {
|
|
||||||
const applogo = await getAppLogo();
|
const applogo = await getAppLogo();
|
||||||
if (applogo?.logo) {
|
if (applogo?.logo) {
|
||||||
setAppLogo(applogo?.logo);
|
setAppLogo(applogo?.logo);
|
||||||
@@ -47,20 +58,31 @@ const Header = ({ showSidebar }) => {
|
|||||||
setAppLogo(localStorage.getItem("appLogo") || "");
|
setAppLogo(localStorage.getItem("appLogo") || "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setIsPro(getIsSubscribe);
|
setIsTeam(subscribe);
|
||||||
setIsTeam(getIsTeam);
|
setIsSubscribe(subscribe.isValid);
|
||||||
setIsSubscribe(getIsSubscribe);
|
try {
|
||||||
|
const extUser = await Parse.Cloud.run("getUserDetails");
|
||||||
|
const MonthlyFreeEmails = extUser?.get("MonthlyFreeEmails") || 0;
|
||||||
|
setEmailUsed(MonthlyFreeEmails);
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in while fetching monthlyfreeEmails", err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const applogo = await getAppLogo();
|
||||||
|
if (applogo?.logo) {
|
||||||
|
setAppLogo(applogo?.logo);
|
||||||
|
} else {
|
||||||
|
setAppLogo(localStorage.getItem("appLogo") || "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeDropdown = () => {
|
const closeDropdown = async () => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
if (Parse?.User?.current()) {
|
try {
|
||||||
try {
|
await Parse.User.logOut();
|
||||||
Parse.User.logOut();
|
} catch (err) {
|
||||||
} catch (err) {
|
console.log("Err while logging out", err);
|
||||||
console.log("Err", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let appdata = localStorage.getItem("userSettings");
|
let appdata = localStorage.getItem("userSettings");
|
||||||
let applogo = localStorage.getItem("appLogo");
|
let applogo = localStorage.getItem("appLogo");
|
||||||
@@ -103,129 +125,174 @@ const Header = ({ showSidebar }) => {
|
|||||||
window.open("https://console.opensignlabs.com/");
|
window.open("https://console.opensignlabs.com/");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const handleNavigation = () => {
|
||||||
|
navigate("/subscription");
|
||||||
|
};
|
||||||
|
const handleMailUsed = () => {
|
||||||
|
setIsModal(!isModal);
|
||||||
|
};
|
||||||
|
// Handle dismissing the notification
|
||||||
|
const dismissNotification = () => {
|
||||||
|
// Store the current version as dismissed in local storage
|
||||||
|
localStorage.setItem(
|
||||||
|
"notificationDismissedVersion",
|
||||||
|
current_notification_version
|
||||||
|
);
|
||||||
|
setShowNotification(false);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="op-navbar bg-base-100 shadow">
|
<div>
|
||||||
<div className="flex-none">
|
{isEnableSubscription && showNotification && (
|
||||||
<button
|
<div className="flex justify-between items-center shadow py-1 bg-[#CAE4FA] p-1">
|
||||||
className="op-btn op-btn-square op-btn-ghost focus:outline-none hover:bg-transparent op-btn-sm no-animation"
|
<div className="text-center text-[14px] ml-auto">
|
||||||
onClick={showSidebar}
|
{t("header-news")} —
|
||||||
>
|
<span
|
||||||
<i className="fa-light fa-bars text-xl text-base-content"></i>
|
className="cursor-pointer font-medium underline text-blue-800"
|
||||||
</button>
|
onClick={() => navigate("/profile")}
|
||||||
</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"
|
|
||||||
src={applogo}
|
|
||||||
alt="img"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="profile-menu" className="flex-none gap-2">
|
|
||||||
{!isSubscribe && (
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
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")}
|
|
||||||
>
|
>
|
||||||
{t("upgrade-now")}
|
{" " + t("header-news-btn") + "."}
|
||||||
</button>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
{!isTeam && isPro && (
|
|
||||||
<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">
|
|
||||||
{t("pro")}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{isTeam && (
|
|
||||||
<div className="w-[35px] h-[35px] bg-white rounded-full ring-[1px] text-[13px] ring-offset-2 ring-[#002862] text-[#002862] overflow-hidden font-semibold flex items-center justify-center">
|
|
||||||
{t("team")}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div>
|
|
||||||
<FullScreenButton />
|
|
||||||
</div>
|
|
||||||
{width >= 768 && (
|
|
||||||
<div
|
<div
|
||||||
onClick={toggleDropdown}
|
className="ml-auto mr-1 cursor-pointer"
|
||||||
className="cursor-pointer w-[35px] h-[35px] rounded-full ring-[1px] ring-offset-2 ring-gray-400 overflow-hidden"
|
onClick={() => dismissNotification()}
|
||||||
>
|
>
|
||||||
|
<i className="fa-light fa-xmark"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<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
|
<img
|
||||||
className="w-[35px] h-[35px] object-contain"
|
className="object-contain h-full w-auto"
|
||||||
src={image}
|
src={applogo}
|
||||||
alt="img"
|
alt="img"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
{width >= 768 && (
|
<div id="profile-menu" className="flex-none gap-2">
|
||||||
<div
|
{!isSubscribe && (
|
||||||
onClick={toggleDropdown}
|
<div>
|
||||||
className="cursor-pointer text-base-content text-sm"
|
<button
|
||||||
>
|
className="text-xs md:text-sm shadow op-btn op-btn-outline op-btn-sm md:op-btn-md op-btn-accent"
|
||||||
{username && username}
|
onClick={() => handleNavigation()}
|
||||||
|
>
|
||||||
|
{t("upgrade-now")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isTeam.isValid && !validplan[isTeam.plan] && (
|
||||||
|
<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">
|
||||||
|
{t("pro")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{validplan[isTeam.plan] && (
|
||||||
|
<div className="w-[35px] h-[35px] bg-white rounded-full ring-[1px] text-[13px] ring-offset-2 ring-[#002862] text-[#002862] overflow-hidden font-semibold flex items-center justify-center">
|
||||||
|
{t("team")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div>
|
||||||
|
<FullScreenButton />
|
||||||
</div>
|
</div>
|
||||||
)}
|
{width >= 768 && (
|
||||||
<div className="op-dropdown op-dropdown-end" id="profile-menu">
|
<div
|
||||||
<div
|
onClick={toggleDropdown}
|
||||||
tabIndex={0}
|
className="cursor-pointer w-[35px] h-[35px] rounded-full ring-[1px] ring-offset-2 ring-gray-400 overflow-hidden"
|
||||||
role="button"
|
>
|
||||||
className="op-btn op-btn-ghost op-btn-xs w-[10px] h-[20px] hover:bg-transparent"
|
<img
|
||||||
>
|
className="w-[35px] h-[35px] object-contain"
|
||||||
<i
|
src={image}
|
||||||
|
alt="img"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{width >= 768 && (
|
||||||
|
<div
|
||||||
|
onClick={toggleDropdown}
|
||||||
|
className="cursor-pointer text-base-content text-sm"
|
||||||
|
>
|
||||||
|
{username && username}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="op-dropdown op-dropdown-end" id="profile-menu">
|
||||||
|
<div
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
role="button"
|
role="button"
|
||||||
onClick={toggleDropdown}
|
className="op-btn op-btn-ghost op-btn-xs w-[10px] h-[20px] hover:bg-transparent"
|
||||||
className="fa-light fa-angle-down text-base-content"
|
>
|
||||||
></i>
|
<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> {t("docs")}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
onClick={() => {
|
||||||
|
setIsOpen(false);
|
||||||
|
navigate("/profile");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<i className="fa-light fa-user"></i> {t("profile")}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
onClick={() => {
|
||||||
|
setIsOpen(false);
|
||||||
|
navigate("/changepassword");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<i className="fa-light fa-lock"></i> {t("change-password")}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
{isEnableSubscription && (
|
||||||
|
<li onClick={() => handleConsoleRedirect()}>
|
||||||
|
<span>
|
||||||
|
<i className="fa-light fa-id-card"></i> Console
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
{isEnableSubscription && isTeam?.plan === "freeplan" && (
|
||||||
|
<li className="cursor-pointer" onClick={handleMailUsed}>
|
||||||
|
<span>
|
||||||
|
<i className="fa-light fa-envelope"></i>
|
||||||
|
{emailUsed}/15 {t("sent-this-month")}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
<li onClick={closeDropdown}>
|
||||||
|
<span>
|
||||||
|
<i className="fa-light fa-arrow-right-from-bracket"></i>{" "}
|
||||||
|
{t("log-out")}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</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> {t("docs")}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
onClick={() => {
|
|
||||||
setIsOpen(false);
|
|
||||||
navigate("/profile");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
<i className="fa-light fa-user"></i> {t("profile")}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
onClick={() => {
|
|
||||||
setIsOpen(false);
|
|
||||||
navigate("/changepassword");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
<i className="fa-light fa-lock"></i> {t("change-password")}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
onClick={() => {
|
|
||||||
handleConsoleRedirect();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<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>{" "}
|
|
||||||
{t("log-out")}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ModalUi isOpen={isModal}>
|
||||||
|
<QuotaCard isPaidInfo={true} handlClose={handleMailUsed} />
|
||||||
|
</ModalUi>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,8 +47,10 @@ const GoogleSignInBtn = ({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
const clearStorage = async () => {
|
const clearStorage = async () => {
|
||||||
if (Parse.User.current()) {
|
try {
|
||||||
await Parse.User.logOut();
|
await Parse.User.logOut();
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err while logging out", err);
|
||||||
}
|
}
|
||||||
let baseUrl = localStorage.getItem("baseUrl");
|
let baseUrl = localStorage.getItem("baseUrl");
|
||||||
let appid = localStorage.getItem("parseAppId");
|
let appid = localStorage.getItem("parseAppId");
|
||||||
@@ -160,10 +162,13 @@ const GoogleSignInBtn = ({
|
|||||||
alert(t("fill-required-details!"));
|
alert(t("fill-required-details!"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleCloseModal = () => {
|
const handleCloseModal = async () => {
|
||||||
setIsModal(false);
|
setIsModal(false);
|
||||||
Parse.User.logOut();
|
try {
|
||||||
|
await Parse.User.logOut();
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err while logging out", err);
|
||||||
|
}
|
||||||
let appdata = localStorage.getItem("userSettings");
|
let appdata = localStorage.getItem("userSettings");
|
||||||
let applogo = localStorage.getItem("appLogo");
|
let applogo = localStorage.getItem("appLogo");
|
||||||
let defaultmenuid = localStorage.getItem("defaultmenuid");
|
let defaultmenuid = localStorage.getItem("defaultmenuid");
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ModalUi from "../primitives/ModalUi";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
function RotateAlert(props) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<ModalUi
|
||||||
|
isOpen={props.isRotate}
|
||||||
|
title={t("Rotation-alert")}
|
||||||
|
handleClose={() => props.setIsRotate({ status: false, degree: 0 })}
|
||||||
|
>
|
||||||
|
{" "}
|
||||||
|
<div className="p-[20px] h-full">
|
||||||
|
<p>{t("rotate-alert-mssg")}</p>
|
||||||
|
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
|
||||||
|
<div className="flex gap-1">
|
||||||
|
<button
|
||||||
|
onClick={() => props.setIsRotate({ status: false, degree: 0 })}
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-ghost shadow-md"
|
||||||
|
>
|
||||||
|
{t("no")}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => props.handleRemoveWidgets()}
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-primary"
|
||||||
|
>
|
||||||
|
{t("yes")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RotateAlert;
|
||||||
@@ -9,6 +9,7 @@ import * as HoverCard from "@radix-ui/react-hover-card";
|
|||||||
import ModalUi from "../../primitives/ModalUi";
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
import FolderModal from "../shared/fields/FolderModal";
|
import FolderModal from "../shared/fields/FolderModal";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { handleDownloadPdf } from "../../constant/Utils";
|
||||||
|
|
||||||
function DriveBody(props) {
|
function DriveBody(props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -100,16 +101,17 @@ function DriveBody(props) {
|
|||||||
|
|
||||||
//function for navigate user to microapp-signature component
|
//function for navigate user to microapp-signature component
|
||||||
const checkPdfStatus = async (data) => {
|
const checkPdfStatus = async (data) => {
|
||||||
const signerExist = data.Signers && data.Signers;
|
const signerExist = data?.Signers;
|
||||||
const isDecline = data.IsDeclined && data.IsDeclined;
|
const isDecline = data?.IsDeclined;
|
||||||
const isPlaceholder = data.Placeholders && data.Placeholders;
|
const isPlaceholder = data?.Placeholders;
|
||||||
const signedUrl = data.SignedUrl;
|
const signedUrl = data?.SignedUrl;
|
||||||
|
const isSignYourself = data?.IsSignyourself;
|
||||||
//checking if document has completed and request signature flow
|
//checking if document has completed and request signature flow
|
||||||
if (data?.IsCompleted && signerExist?.length > 0) {
|
if (data?.IsCompleted && signerExist?.length > 0) {
|
||||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||||
}
|
}
|
||||||
//checking if document has completed and signyour-self flow
|
//checking if document has completed and signyour-self flow
|
||||||
else if (!signerExist && !isPlaceholder) {
|
else if ((!signerExist && !isPlaceholder) || isSignYourself) {
|
||||||
navigate(`/signaturePdf/${data.objectId}`);
|
navigate(`/signaturePdf/${data.objectId}`);
|
||||||
}
|
}
|
||||||
//checking if document has declined by someone
|
//checking if document has declined by someone
|
||||||
@@ -136,12 +138,10 @@ function DriveBody(props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMenuItemClick = (selectType, data) => {
|
const handleMenuItemClick = async (selectType, data) => {
|
||||||
switch (selectType) {
|
switch (selectType) {
|
||||||
case "Download": {
|
case "Download": {
|
||||||
const pdfName = data && data.Name;
|
await handleDownloadPdf([data]);
|
||||||
const pdfUrl = data && data.SignedUrl ? data.SignedUrl : data.URL;
|
|
||||||
saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "Rename": {
|
case "Rename": {
|
||||||
@@ -357,7 +357,7 @@ function DriveBody(props) {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
handleMenuItemClick("Download", data);
|
handleMenuItemClick("Download", data);
|
||||||
}}
|
}}
|
||||||
className="fa-light fa-download mr-[8px] op-text-primary"
|
className="fa-light fa-download mr-[8px] op-text-primary cursor-pointer"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</td>
|
</td>
|
||||||
@@ -370,7 +370,11 @@ function DriveBody(props) {
|
|||||||
{/* folder */}
|
{/* folder */}
|
||||||
<div
|
<div
|
||||||
data-tut={props.dataTutSeventh}
|
data-tut={props.dataTutSeventh}
|
||||||
onClick={() => handleOnclikFolder(data)}
|
onClick={() => {
|
||||||
|
if (!rename) {
|
||||||
|
handleOnclikFolder(data);
|
||||||
|
}
|
||||||
|
}}
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@@ -383,7 +387,6 @@ function DriveBody(props) {
|
|||||||
{rename === data.objectId ? (
|
{rename === data.objectId ? (
|
||||||
<input
|
<input
|
||||||
onFocus={() => {
|
onFocus={() => {
|
||||||
inputRef.current.setSelectionRange(0, 0);
|
|
||||||
const input = inputRef.current;
|
const input = inputRef.current;
|
||||||
if (input) {
|
if (input) {
|
||||||
input.select();
|
input.select();
|
||||||
@@ -395,9 +398,8 @@ function DriveBody(props) {
|
|||||||
onKeyDown={(e) => handleEnterPress(e, data)}
|
onKeyDown={(e) => handleEnterPress(e, data)}
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
defaultValue={renameValue}
|
defaultValue={renameValue}
|
||||||
// value={renameValue}
|
|
||||||
onChange={(e) => setRenameValue(e.target.value)}
|
onChange={(e) => setRenameValue(e.target.value)}
|
||||||
className="w-[100px] border-[1.5px] border-black rounded-sm text-[10px]"
|
className="op-input op-input-bordered op-input-xs w-[100px] focus:outline-none hover:border-base-content text-[10px]"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span className="fileName">{data.Name}</span>
|
<span className="fileName">{data.Name}</span>
|
||||||
@@ -423,7 +425,11 @@ function DriveBody(props) {
|
|||||||
</ContextMenu.Root>
|
</ContextMenu.Root>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<HoverCard.Root openDelay={0} closeDelay={100}>
|
<HoverCard.Root
|
||||||
|
open={rename ? false : undefined}
|
||||||
|
openDelay={0}
|
||||||
|
closeDelay={100}
|
||||||
|
>
|
||||||
<HoverCard.Trigger asChild>
|
<HoverCard.Trigger asChild>
|
||||||
<div>
|
<div>
|
||||||
<ContextMenu.Root>
|
<ContextMenu.Root>
|
||||||
@@ -432,7 +438,11 @@ function DriveBody(props) {
|
|||||||
{/* pdf */}
|
{/* pdf */}
|
||||||
<div
|
<div
|
||||||
data-tut={props.dataTutSixth}
|
data-tut={props.dataTutSixth}
|
||||||
onClick={() => checkPdfStatus(data)}
|
onClick={() => {
|
||||||
|
if (!rename) {
|
||||||
|
checkPdfStatus(data);
|
||||||
|
}
|
||||||
|
}}
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@@ -447,7 +457,6 @@ function DriveBody(props) {
|
|||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
type="text"
|
type="text"
|
||||||
onFocus={() => {
|
onFocus={() => {
|
||||||
inputRef.current.setSelectionRange(0, 0);
|
|
||||||
const input = inputRef.current;
|
const input = inputRef.current;
|
||||||
if (input) {
|
if (input) {
|
||||||
input.select();
|
input.select();
|
||||||
@@ -457,9 +466,8 @@ function DriveBody(props) {
|
|||||||
onKeyDown={(e) => handleEnterPress(e, data)}
|
onKeyDown={(e) => handleEnterPress(e, data)}
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
defaultValue={renameValue}
|
defaultValue={renameValue}
|
||||||
// value={renameValue}
|
|
||||||
onChange={(e) => setRenameValue(e.target.value)}
|
onChange={(e) => setRenameValue(e.target.value)}
|
||||||
className="w-[100px] border-[1.5px] border-black rounded-sm text-[10px]"
|
className="op-input op-input-bordered op-input-xs w-[100px] focus:outline-none hover:border-base-content text-[10px]"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span className="fileName">{data.Name}</span>
|
<span className="fileName">{data.Name}</span>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ function DraftDocument() {
|
|||||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||||
}
|
}
|
||||||
//checking if document has completed and signyour-self flow
|
//checking if document has completed and signyour-self flow
|
||||||
else if (!signerExist && !isPlaceholder) {
|
else if ((!signerExist && !isPlaceholder) || data?.IsSignyourself) {
|
||||||
navigate(`/signaturePdf/${data.objectId}`);
|
navigate(`/signaturePdf/${data.objectId}`);
|
||||||
}
|
}
|
||||||
//checking if document has declined by someone
|
//checking if document has declined by someone
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import ModalUi from "../../primitives/ModalUi";
|
|||||||
import { radioButtonWidget } from "../../constant/Utils";
|
import { radioButtonWidget } from "../../constant/Utils";
|
||||||
import Upgrade from "../../primitives/Upgrade";
|
import Upgrade from "../../primitives/Upgrade";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { fontColorArr, fontsizeArr } from "../../constant/Utils";
|
||||||
|
|
||||||
function DropdownWidgetOption(props) {
|
function DropdownWidgetOption(props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [dropdownOptionList, setDropdownOptionList] = useState([
|
const [dropdownOptionList, setDropdownOptionList] = useState([
|
||||||
@@ -330,6 +332,55 @@ function DropdownWidgetOption(props) {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
<div className="flex items-center mt-3 mb-3">
|
||||||
|
<span>{t("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 ||
|
||||||
|
"12"
|
||||||
|
}
|
||||||
|
onChange={(e) => props.setFontSize(e.target.value)}
|
||||||
|
>
|
||||||
|
{fontsizeArr.map((size, ind) => {
|
||||||
|
return (
|
||||||
|
<option className="text-[13px]" value={size} key={ind}>
|
||||||
|
{size}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
<div className="flex flex-row gap-1 items-center ml-4 ">
|
||||||
|
<span>{t("color")} : </span>
|
||||||
|
<select
|
||||||
|
value={
|
||||||
|
props.fontColor ||
|
||||||
|
props.currWidgetsDetails?.options?.fontColor ||
|
||||||
|
"black"
|
||||||
|
}
|
||||||
|
onChange={(e) => props.setFontColor(e.target.value)}
|
||||||
|
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
|
||||||
|
>
|
||||||
|
{fontColorArr.map((color, ind) => {
|
||||||
|
return (
|
||||||
|
<option value={color} key={ind}>
|
||||||
|
{t(`color-type.${color}`)}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
background:
|
||||||
|
props.fontColor ||
|
||||||
|
props.currWidgetsDetails?.options?.fontColor ||
|
||||||
|
"black"
|
||||||
|
}}
|
||||||
|
className="w-5 h-[19px] ml-1"
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{["checkbox", radioButtonWidget].includes(props.type) && (
|
{["checkbox", radioButtonWidget].includes(props.type) && (
|
||||||
<div className="flex flex-row gap-5 my-2 items-center text-center">
|
<div className="flex flex-row gap-5 my-2 items-center text-center">
|
||||||
{!props.isSignYourself && (
|
{!props.isSignYourself && (
|
||||||
@@ -362,6 +413,7 @@ function DropdownWidgetOption(props) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
props.type === "checkbox" && !props.isSignYourself
|
props.type === "checkbox" && !props.isSignYourself
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { checkIsSubscribed, getFileName } from "../../constant/Utils";
|
|||||||
import Upgrade from "../../primitives/Upgrade";
|
import Upgrade from "../../primitives/Upgrade";
|
||||||
import { isEnableSubscription } from "../../constant/const";
|
import { isEnableSubscription } from "../../constant/const";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Tooltip } from "react-tooltip";
|
||||||
|
|
||||||
// import SelectFolder from "../../premitives/SelectFolder";
|
// import SelectFolder from "../../premitives/SelectFolder";
|
||||||
|
|
||||||
const EditTemplate = ({ template, onSuccess }) => {
|
const EditTemplate = ({ template, onSuccess }) => {
|
||||||
@@ -14,7 +16,8 @@ const EditTemplate = ({ template, onSuccess }) => {
|
|||||||
Description: template?.Description || "",
|
Description: template?.Description || "",
|
||||||
SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false",
|
SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false",
|
||||||
AutomaticReminders: template?.AutomaticReminders || false,
|
AutomaticReminders: template?.AutomaticReminders || false,
|
||||||
RemindOnceInEvery: template?.RemindOnceInEvery || 5
|
RemindOnceInEvery: template?.RemindOnceInEvery || 5,
|
||||||
|
IsEnableOTP: template?.IsEnableOTP ? `${template?.IsEnableOTP}` : "false"
|
||||||
});
|
});
|
||||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -23,8 +26,8 @@ const EditTemplate = ({ template, onSuccess }) => {
|
|||||||
}, []);
|
}, []);
|
||||||
const fetchSubscription = async () => {
|
const fetchSubscription = async () => {
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const getIsSubscribe = await checkIsSubscribed();
|
const subscribe = await checkIsSubscribed();
|
||||||
setIsSubscribe(getIsSubscribe);
|
setIsSubscribe(subscribe.isValid);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleStrInput = (e) => {
|
const handleStrInput = (e) => {
|
||||||
@@ -41,7 +44,7 @@ const EditTemplate = ({ template, onSuccess }) => {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const isChecked = formData.SendinOrder === "true" ? true : false;
|
const isChecked = formData.SendinOrder === "true" ? true : false;
|
||||||
const AutoReminder = formData?.AutomaticReminders || false;
|
const AutoReminder = formData?.AutomaticReminders || false;
|
||||||
|
const IsEnableOTP = formData.IsEnableOTP === "true" ? true : false;
|
||||||
let reminderDate = {};
|
let reminderDate = {};
|
||||||
if (AutoReminder) {
|
if (AutoReminder) {
|
||||||
const RemindOnceInEvery = parseInt(formData?.RemindOnceInEvery);
|
const RemindOnceInEvery = parseInt(formData?.RemindOnceInEvery);
|
||||||
@@ -49,7 +52,12 @@ const EditTemplate = ({ template, onSuccess }) => {
|
|||||||
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
||||||
reminderDate = { NextReminderDate: ReminderDate };
|
reminderDate = { NextReminderDate: ReminderDate };
|
||||||
}
|
}
|
||||||
const data = { ...formData, SendinOrder: isChecked, ...reminderDate };
|
const data = {
|
||||||
|
...formData,
|
||||||
|
SendinOrder: isChecked,
|
||||||
|
IsEnableOTP: IsEnableOTP,
|
||||||
|
...reminderDate
|
||||||
|
};
|
||||||
onSuccess(data);
|
onSuccess(data);
|
||||||
};
|
};
|
||||||
const handleAutoReminder = () => {
|
const handleAutoReminder = () => {
|
||||||
@@ -184,6 +192,70 @@ const EditTemplate = ({ template, onSuccess }) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{isEnableSubscription && (
|
||||||
|
<div className="text-xs mt-2">
|
||||||
|
<label className="block">
|
||||||
|
<span className={isSubscribe ? "" : " text-gray-300"}>
|
||||||
|
{t("isenable-otp")}{" "}
|
||||||
|
<a data-tooltip-id="isenableotp-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>{" "}
|
||||||
|
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||||
|
</span>
|
||||||
|
<Tooltip id="isenableotp-tooltip" className="z-50">
|
||||||
|
<div className="max-w-[200px] md:max-w-[450px]">
|
||||||
|
<p className="font-bold">{t("isenable-otp")}</p>
|
||||||
|
<p>{t("isenable-otp-help.p1")}</p>
|
||||||
|
<p className="p-[5px]">
|
||||||
|
<ol className="list-disc">
|
||||||
|
<li>
|
||||||
|
<span className="font-bold">{t("yes")}: </span>
|
||||||
|
<span>{t("isenable-otp-help.p2")}</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span className="font-bold">{t("no")}: </span>
|
||||||
|
<span>{t("isenable-otp-help.p3")}</span>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</p>
|
||||||
|
<p>{t("isenable-otp-help.p4")}</p>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
className={`${
|
||||||
|
isSubscribe ? "" : "pointer-events-none opacity-50"
|
||||||
|
} flex items-center gap-2 ml-2 mb-1 `}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={"true"}
|
||||||
|
className="op-radio op-radio-xs"
|
||||||
|
name="IsEnableOTP"
|
||||||
|
checked={formData.IsEnableOTP === "true"}
|
||||||
|
onChange={handleStrInput}
|
||||||
|
/>
|
||||||
|
<div className="text-center">{t("yes")}</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`${
|
||||||
|
isSubscribe ? "" : "pointer-events-none opacity-50"
|
||||||
|
} flex items-center gap-2 ml-2 mb-1 `}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={"false"}
|
||||||
|
name="IsEnableOTP"
|
||||||
|
className="op-radio op-radio-xs"
|
||||||
|
checked={formData.IsEnableOTP === "false"}
|
||||||
|
onChange={handleStrInput}
|
||||||
|
/>
|
||||||
|
<div className="text-center">{t("no")}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="mt-[1rem] flex justify-start">
|
<div className="mt-[1rem] flex justify-start">
|
||||||
<button type="submit" className="op-btn op-btn-primary">
|
<button type="submit" className="op-btn op-btn-primary">
|
||||||
{t("submit")}
|
{t("submit")}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { handleDownloadPdf, handleToPrint } from "../../constant/Utils";
|
import { handleToPrint } from "../../constant/Utils";
|
||||||
import { themeColor, emailRegex } from "../../constant/const";
|
import { themeColor, emailRegex } from "../../constant/const";
|
||||||
import Loader from "../../primitives/Loader";
|
import Loader from "../../primitives/Loader";
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
@@ -15,7 +15,8 @@ function EmailComponent({
|
|||||||
sender,
|
sender,
|
||||||
setIsAlert,
|
setIsAlert,
|
||||||
extUserId,
|
extUserId,
|
||||||
activeMailAdapter
|
activeMailAdapter,
|
||||||
|
setIsDownloadModal
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [emailList, setEmailList] = useState([]);
|
const [emailList, setEmailList] = useState([]);
|
||||||
@@ -29,12 +30,34 @@ function EmailComponent({
|
|||||||
const pdfName = pdfDetails[0]?.Name;
|
const pdfName = pdfDetails[0]?.Name;
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
let sendMail;
|
let sendMail;
|
||||||
|
|
||||||
|
const docId = !pdfDetails?.[0]?.IsEnableOTP
|
||||||
|
? pdfDetails?.[0]?.objectId
|
||||||
|
: "";
|
||||||
|
let presignedUrl = pdfUrl;
|
||||||
|
try {
|
||||||
|
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
|
||||||
|
const axiosRes = await axios.post(
|
||||||
|
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
||||||
|
{ url: pdfUrl, docId: docId },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"content-type": "Application/json",
|
||||||
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
|
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
presignedUrl = axiosRes.data.result;
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in getsignedurl", err);
|
||||||
|
}
|
||||||
for (let i = 0; i < emailList.length; i++) {
|
for (let i = 0; i < emailList.length; i++) {
|
||||||
try {
|
try {
|
||||||
const imgPng =
|
const imgPng =
|
||||||
"https://qikinnovation.ams3.digitaloceanspaces.com/logo.png";
|
"https://qikinnovation.ams3.digitaloceanspaces.com/logo.png";
|
||||||
|
|
||||||
let url = `${localStorage.getItem("baseUrl")}functions/sendmailv3/`;
|
let url = `${localStorage.getItem("baseUrl")}functions/sendmailv3`;
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
@@ -46,7 +69,7 @@ function EmailComponent({
|
|||||||
mailProvider: activeMailAdapter,
|
mailProvider: activeMailAdapter,
|
||||||
extUserId: extUserId,
|
extUserId: extUserId,
|
||||||
pdfName: pdfName,
|
pdfName: pdfName,
|
||||||
url: pdfUrl,
|
url: presignedUrl,
|
||||||
recipient: emailList[i],
|
recipient: emailList[i],
|
||||||
subject: `${sender.name} has signed the doc - ${pdfName}`,
|
subject: `${sender.name} has signed the doc - ${pdfName}`,
|
||||||
from: sender.email,
|
from: sender.email,
|
||||||
@@ -74,26 +97,15 @@ function EmailComponent({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sendMail?.data?.result?.status === "success") {
|
||||||
if (sendMail && sendMail.data.result.status === "success") {
|
|
||||||
setSuccessEmail(true);
|
setSuccessEmail(true);
|
||||||
|
setIsEmail(false);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setSuccessEmail(false);
|
setSuccessEmail(false);
|
||||||
setIsEmail(false);
|
|
||||||
setEmailValue("");
|
setEmailValue("");
|
||||||
setEmailList([]);
|
setEmailList([]);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
|
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
} else if (sendMail && sendMail.data.result.status === "error") {
|
|
||||||
setIsLoading(false);
|
|
||||||
setIsEmail(false);
|
|
||||||
setIsAlert({
|
|
||||||
isShow: true,
|
|
||||||
alertMessage: t("something-went-wrong-mssg")
|
|
||||||
});
|
|
||||||
setEmailValue("");
|
|
||||||
setEmailList([]);
|
|
||||||
} else {
|
} else {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
setIsEmail(false);
|
setIsEmail(false);
|
||||||
@@ -140,6 +152,11 @@ function EmailComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const handleClose = () => {
|
||||||
|
setIsEmail(false);
|
||||||
|
setEmailValue("");
|
||||||
|
setEmailList([]);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{/* isEmail */}
|
{/* isEmail */}
|
||||||
@@ -165,7 +182,9 @@ function EmailComponent({
|
|||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
{!isAndroid && (
|
{!isAndroid && (
|
||||||
<button
|
<button
|
||||||
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
|
onClick={(e) =>
|
||||||
|
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
|
||||||
|
}
|
||||||
className="op-btn op-btn-neutral op-btn-sm text-[15px]"
|
className="op-btn op-btn-neutral op-btn-sm text-[15px]"
|
||||||
>
|
>
|
||||||
<i className="fa-light fa-print" aria-hidden="true"></i>
|
<i className="fa-light fa-print" aria-hidden="true"></i>
|
||||||
@@ -174,9 +193,10 @@ function EmailComponent({
|
|||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
className="op-btn op-btn-primary op-btn-sm text-[15px] ml-2"
|
className="op-btn op-btn-primary op-btn-sm text-[15px] ml-2"
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
|
handleClose();
|
||||||
}
|
setIsDownloadModal(true);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<i className="fa-light fa-download" aria-hidden="true"></i>
|
<i className="fa-light fa-download" aria-hidden="true"></i>
|
||||||
{t("download")}
|
{t("download")}
|
||||||
@@ -272,11 +292,7 @@ function EmailComponent({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="op-btn op-btn-ghost ml-2"
|
className="op-btn op-btn-ghost ml-2"
|
||||||
onClick={() => {
|
onClick={() => handleClose()}
|
||||||
setIsEmail(false);
|
|
||||||
setEmailValue("");
|
|
||||||
setEmailList([]);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{t("close")}
|
{t("close")}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -0,0 +1,267 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||||
|
import { tomorrow } from "react-syntax-highlighter/dist/esm/styles/prism";
|
||||||
|
import { copytoData } from "../../constant/Utils";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
function EmbedTab(props) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const tabName = [
|
||||||
|
{ title: "React/Next.js", icon: "fa-brands fa-react", color: "#61dafb" },
|
||||||
|
{ title: "JavaScript", icon: "fa-brands fa-js", color: "#ffd43b" },
|
||||||
|
{ title: "Angular", icon: "fa-brands fa-angular", color: "#ff5733" }
|
||||||
|
];
|
||||||
|
const [activeTab, setActiveTab] = useState(0);
|
||||||
|
// State to track if the code has been copied
|
||||||
|
const [isCopied, setIsCopied] = useState(false);
|
||||||
|
const reactCode = [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
title: "Installation",
|
||||||
|
codeString: `
|
||||||
|
npm install @opensign/react`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: "Usage",
|
||||||
|
codeString: `
|
||||||
|
import React from "react";
|
||||||
|
import Opensign from "@opensign/react";
|
||||||
|
|
||||||
|
export function App() {
|
||||||
|
return (
|
||||||
|
<div className="app">
|
||||||
|
<Opensign
|
||||||
|
onLoad={() => console.log("success")}
|
||||||
|
onLoadError={(error) => console.log(error)}
|
||||||
|
templateId= {"${props.templateId}"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
`
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const angularCode = [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
title: "Installation",
|
||||||
|
codeString: `
|
||||||
|
npm install @opensign/angular`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: "Usage",
|
||||||
|
codeString: `
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import {OpensignComponent} from "@opensign/angular"
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector:'app-root',
|
||||||
|
standalone: true,
|
||||||
|
imports: [OpensignComponent],
|
||||||
|
template: '<opensign templateId={"${props.templateId}"}
|
||||||
|
(onLoad)="handleLoad()"
|
||||||
|
(onLoadError)="handleError($event)"
|
||||||
|
></opensign>',
|
||||||
|
})
|
||||||
|
export class AppComponent{
|
||||||
|
handleLoad() {
|
||||||
|
console.log("success");
|
||||||
|
}
|
||||||
|
handleError(error: string) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
`
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const jsCodeString = `
|
||||||
|
<script
|
||||||
|
src= "https://app.opensignlabs.com/static/js/public-template.bundle.js"
|
||||||
|
id="opensign-script"
|
||||||
|
templateId=${props.templateId}
|
||||||
|
></script>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const handleCopy = (code, ind) => {
|
||||||
|
copytoData(code);
|
||||||
|
setIsCopied({ ...isCopied, [ind]: true });
|
||||||
|
setTimeout(() => setIsCopied(false), 3000);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mt-4 border-t-[1px]">
|
||||||
|
<div className="flex justify-center items-center mt-2">
|
||||||
|
<div role="tablist" className="op-tabs op-tabs-bordered">
|
||||||
|
{tabName.map((tabData, ind) => (
|
||||||
|
<div
|
||||||
|
onClick={() => setActiveTab(ind)}
|
||||||
|
key={ind}
|
||||||
|
role="tab"
|
||||||
|
className={`${
|
||||||
|
activeTab === ind ? "op-tab-active" : ""
|
||||||
|
} op-tab flex items-center`}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className={`${tabData.icon}`}
|
||||||
|
style={{ color: tabData.color }}
|
||||||
|
></i>
|
||||||
|
<span className="ml-1 text-[10px] font-medium md:font-normal md:text-[15px]">
|
||||||
|
{tabData.title}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{activeTab === 0 ? (
|
||||||
|
<div className="mt-4">
|
||||||
|
{reactCode.map((data, ind) => {
|
||||||
|
return (
|
||||||
|
<div key={ind}>
|
||||||
|
<p className="font-medium text-[18px]">
|
||||||
|
{t(`${data.title}`)}
|
||||||
|
</p>
|
||||||
|
<p className="text-[13px] mt-2">
|
||||||
|
{t("public-template-mssg-1")}
|
||||||
|
</p>
|
||||||
|
<div className="relative p-1">
|
||||||
|
<div
|
||||||
|
onClick={() => handleCopy(data.codeString, ind)}
|
||||||
|
className="absolute top-[20px] right-[20px] cursor-pointer"
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-copy text-white mr-[2px]" />
|
||||||
|
<span className=" text-white">
|
||||||
|
{isCopied[ind] ? t("copied-code") : t("copy-code")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<SyntaxHighlighter
|
||||||
|
customStyle={{
|
||||||
|
borderRadius: "15px"
|
||||||
|
}}
|
||||||
|
language="javascript"
|
||||||
|
style={tomorrow}
|
||||||
|
>
|
||||||
|
{data.codeString}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
<p className="font-medium text-[15px]">
|
||||||
|
{t("public-template-mssg-3")}
|
||||||
|
</p>
|
||||||
|
<p className="my-[6px]">
|
||||||
|
{" "}
|
||||||
|
{t("public-template-mssg-4")}
|
||||||
|
<a
|
||||||
|
href="https://www.npmjs.com/package/@opensign/react"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="cursor-pointer text-blue-700 "
|
||||||
|
>
|
||||||
|
{" "}
|
||||||
|
OpenSign React package{" "}
|
||||||
|
</a>
|
||||||
|
{t("public-template-mssg-5")}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : activeTab === 1 ? (
|
||||||
|
<div className="mt-4">
|
||||||
|
<div>
|
||||||
|
{/* <p className="font-medium text-[18px]">{t(`${data.title}`)}</p> */}
|
||||||
|
|
||||||
|
<div className="relative p-1">
|
||||||
|
<div
|
||||||
|
onClick={() => handleCopy(jsCodeString, 0)}
|
||||||
|
className="absolute top-[20px] right-[20px] cursor-pointer"
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-copy text-white mr-[2px]" />
|
||||||
|
<span className=" text-white">
|
||||||
|
{isCopied[0] ? t("copied-code") : t("copy-code")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<SyntaxHighlighter
|
||||||
|
customStyle={{
|
||||||
|
borderRadius: "15px"
|
||||||
|
}}
|
||||||
|
language="javascript"
|
||||||
|
style={tomorrow}
|
||||||
|
>
|
||||||
|
{jsCodeString}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
activeTab === 2 && (
|
||||||
|
<div className="mt-4">
|
||||||
|
{angularCode.map((data, ind) => {
|
||||||
|
return (
|
||||||
|
<div key={ind}>
|
||||||
|
<p className="font-medium text-[18px]">
|
||||||
|
{t(`${data.title}`)}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p className="text-[13px] mt-2">
|
||||||
|
{t("angular-npm-mssg-1")}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="relative p-1">
|
||||||
|
<div
|
||||||
|
onClick={() => handleCopy(data.codeString, ind)}
|
||||||
|
className="absolute top-[20px] right-[20px] cursor-pointer"
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-copy text-white mr-[2px]" />
|
||||||
|
<span className=" text-white">
|
||||||
|
{isCopied[ind] ? t("copied-code") : t("copy-code")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<SyntaxHighlighter
|
||||||
|
customStyle={{
|
||||||
|
borderRadius: "15px"
|
||||||
|
}}
|
||||||
|
language="javascript"
|
||||||
|
style={tomorrow}
|
||||||
|
>
|
||||||
|
{data.codeString}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
<p className="font-medium text-[15px]">
|
||||||
|
{t("public-template-mssg-3")}
|
||||||
|
</p>
|
||||||
|
<p className="my-[6px]">
|
||||||
|
{" "}
|
||||||
|
{t("public-template-mssg-4")}
|
||||||
|
<a
|
||||||
|
href="https://www.npmjs.com/package/@opensign/angular"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="cursor-pointer text-blue-700 "
|
||||||
|
>
|
||||||
|
{" "}
|
||||||
|
OpenSign Angular package{" "}
|
||||||
|
</a>
|
||||||
|
{t("public-template-mssg-5")}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EmbedTab;
|
||||||
@@ -34,7 +34,13 @@ function Header({
|
|||||||
setIsEmail,
|
setIsEmail,
|
||||||
completeBtnTitle,
|
completeBtnTitle,
|
||||||
setIsEditTemplate,
|
setIsEditTemplate,
|
||||||
isPublicTemplate
|
isPublicTemplate,
|
||||||
|
clickOnZoomIn,
|
||||||
|
clickOnZoomOut,
|
||||||
|
handleRotationFun,
|
||||||
|
isDisableRotate,
|
||||||
|
templateId,
|
||||||
|
setIsDownloadModal
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const filterPrefill =
|
const filterPrefill =
|
||||||
@@ -48,7 +54,6 @@ function Header({
|
|||||||
const currentDecline = { currnt: "Sure", isDeclined: true };
|
const currentDecline = { currnt: "Sure", isDeclined: true };
|
||||||
setIsDecline(currentDecline);
|
setIsDecline(currentDecline);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex py-[5px]">
|
<div className="flex py-[5px]">
|
||||||
{isMobile && isShowHeader ? (
|
{isMobile && isShowHeader ? (
|
||||||
@@ -73,7 +78,7 @@ function Header({
|
|||||||
allPages={allPages}
|
allPages={allPages}
|
||||||
changePage={changePage}
|
changePage={changePage}
|
||||||
/>
|
/>
|
||||||
{pdfUrl && alreadySign ? (
|
{isCompleted || alreadySign ? (
|
||||||
<DropdownMenu.Root>
|
<DropdownMenu.Root>
|
||||||
<DropdownMenu.Trigger asChild>
|
<DropdownMenu.Trigger asChild>
|
||||||
<div className="op-link op-link-primary no-underline text-[16px] font-semibold pr-[3px] pl-[5px]">
|
<div className="op-link op-link-primary no-underline text-[16px] font-semibold pr-[3px] pl-[5px]">
|
||||||
@@ -90,9 +95,13 @@ function Header({
|
|||||||
>
|
>
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Item
|
||||||
className="DropdownMenuItem"
|
className="DropdownMenuItem"
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
|
if (isCompleted) {
|
||||||
}
|
setIsDownloadModal(true);
|
||||||
|
} else {
|
||||||
|
handleDownloadPdf(pdfDetails, setIsDownloading);
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
<i
|
<i
|
||||||
@@ -138,7 +147,7 @@ function Header({
|
|||||||
<DropdownMenu.Item
|
<DropdownMenu.Item
|
||||||
className="DropdownMenuItem"
|
className="DropdownMenuItem"
|
||||||
onClick={(e) =>
|
onClick={(e) =>
|
||||||
handleToPrint(e, pdfUrl, setIsDownloading)
|
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
@@ -184,13 +193,7 @@ function Header({
|
|||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
data-tut="reactourThird"
|
data-tut="reactourThird"
|
||||||
onClick={() => {
|
onClick={() => embedWidgetsData()}
|
||||||
if (!pdfUrl) {
|
|
||||||
embedWidgetsData();
|
|
||||||
} else if (isPdfRequestFiles) {
|
|
||||||
embedWidgetsData();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="border-none font-[650] text-[14px] op-link op-link-primary no-underline"
|
className="border-none font-[650] text-[14px] op-link op-link-primary no-underline"
|
||||||
>
|
>
|
||||||
{t("finish")}
|
{t("finish")}
|
||||||
@@ -207,30 +210,86 @@ function Header({
|
|||||||
</DropdownMenu.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
<DropdownMenu.Portal>
|
<DropdownMenu.Portal>
|
||||||
<DropdownMenu.Content
|
<DropdownMenu.Content
|
||||||
className="bg-white shadow-md rounded-full px-3 py-2"
|
className="bg-white shadow-md rounded-md px-3 py-2"
|
||||||
sideOffset={5}
|
sideOffset={5}
|
||||||
>
|
>
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Item
|
||||||
className="flex flex-row justify-center items-center text-[13px] focus:outline-none cursor-pointer"
|
className="DropdownMenuItem"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
handleDownloadPdf(
|
handleDownloadPdf(pdfDetails, setIsDownloading)
|
||||||
pdfDetails,
|
|
||||||
pdfUrl,
|
|
||||||
setIsDownloading
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<i
|
<div className="flex flex-row">
|
||||||
className="fa-light fa-arrow-down mr-[3px]"
|
<i
|
||||||
aria-hidden="true"
|
className="fa-light fa-arrow-down mr-[3px]"
|
||||||
></i>
|
aria-hidden="true"
|
||||||
<span className="font-[500]">{t("download")}</span>
|
></i>
|
||||||
|
<span className="font-[500]">
|
||||||
|
{t("download")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
{!isDisableRotate && (
|
||||||
|
<>
|
||||||
|
<DropdownMenu.Item
|
||||||
|
className="DropdownMenuItem"
|
||||||
|
onClick={() => handleRotationFun(90)}
|
||||||
|
>
|
||||||
|
<div className="flex flex-row">
|
||||||
|
<i className="fa-light fa-rotate-right text-gray-500 2xl:text-[30px] mr-[3px]"></i>
|
||||||
|
<span className="font-[500]">
|
||||||
|
{t("rotate-right")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
<DropdownMenu.Item
|
||||||
|
className="DropdownMenuItem"
|
||||||
|
onClick={() => handleRotationFun(-90)}
|
||||||
|
>
|
||||||
|
<div className="flex flex-row">
|
||||||
|
<i className="fa-light fa-rotate-left text-gray-500 2xl:text-[30px] mr-[3px]"></i>
|
||||||
|
<span className="font-[500]">
|
||||||
|
{t("rotate-left")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<DropdownMenu.Item
|
||||||
|
className="DropdownMenuItem"
|
||||||
|
onClick={() => clickOnZoomIn()}
|
||||||
|
>
|
||||||
|
<div className="flex flex-row">
|
||||||
|
<i className="fa-light fa-magnifying-glass-plus text-gray-500 2xl:text-[30px] mr-[3px]"></i>
|
||||||
|
<span className="font-[500]">{t("zoom-in")}</span>
|
||||||
|
</div>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
<DropdownMenu.Item
|
||||||
|
className="DropdownMenuItem"
|
||||||
|
onClick={() => clickOnZoomOut()}
|
||||||
|
>
|
||||||
|
<div className="flex flex-row">
|
||||||
|
<i className="fa-light fa-magnifying-glass-minus text-gray-500 2xl:text-[30px] mr-[3px]"></i>
|
||||||
|
<span className="font-[500]">
|
||||||
|
{t("zoom-out")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
</DropdownMenu.Portal>
|
</DropdownMenu.Portal>
|
||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{isPublicTemplate && (
|
||||||
|
<div
|
||||||
|
data-tut="reactourThird"
|
||||||
|
onClick={() => embedWidgetsData()}
|
||||||
|
className="border-none font-[650] text-[14px] op-link op-link-primary no-underline"
|
||||||
|
>
|
||||||
|
{t("sign-now")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -298,7 +357,9 @@ function Header({
|
|||||||
alreadySign ? (
|
alreadySign ? (
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
<button
|
<button
|
||||||
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
|
onClick={(e) =>
|
||||||
|
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
|
||||||
|
}
|
||||||
type="button"
|
type="button"
|
||||||
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
|
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
|
||||||
>
|
>
|
||||||
@@ -326,9 +387,13 @@ function Header({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow"
|
className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow"
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
|
if (isCompleted) {
|
||||||
}
|
setIsDownloadModal(true);
|
||||||
|
} else {
|
||||||
|
handleDownloadPdf(pdfDetails, setIsDownloading);
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
className="fa-light fa-download py-[3px]"
|
className="fa-light fa-download py-[3px]"
|
||||||
@@ -339,15 +404,32 @@ function Header({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex" data-tut="reactourFifth">
|
<div className="flex" data-tut="reactourFifth">
|
||||||
<button
|
{!templateId && (
|
||||||
onClick={() => window.history.go(-2)}
|
<button
|
||||||
type="button"
|
onClick={() => window.history.go(-2)}
|
||||||
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
type="button"
|
||||||
>
|
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||||
{t("back")}
|
>
|
||||||
</button>
|
{t("back")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
{currentSigner && (
|
{currentSigner && (
|
||||||
<>
|
<>
|
||||||
|
{templateId && (
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
handleDownloadPdf(
|
||||||
|
pdfDetails,
|
||||||
|
pdfUrl,
|
||||||
|
setIsDownloading
|
||||||
|
)
|
||||||
|
}
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||||
|
>
|
||||||
|
<span className="hidden lg:block">{t("download")}</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<button
|
<button
|
||||||
className="op-btn op-btn-secondary op-btn-sm mr-[3px] shadow"
|
className="op-btn op-btn-secondary op-btn-sm mr-[3px] shadow"
|
||||||
onClick={() => handleDeclinePdfAlert()}
|
onClick={() => handleDeclinePdfAlert()}
|
||||||
@@ -361,16 +443,18 @@ function Header({
|
|||||||
>
|
>
|
||||||
{t("finish")}
|
{t("finish")}
|
||||||
</button>
|
</button>
|
||||||
<button
|
{!templateId && (
|
||||||
type="button"
|
<button
|
||||||
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
|
type="button"
|
||||||
onClick={() =>
|
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
|
||||||
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
|
onClick={() =>
|
||||||
}
|
handleDownloadPdf(pdfDetails, setIsDownloading)
|
||||||
>
|
}
|
||||||
<i className="fa-light fa-arrow-down font-semibold lg:hidden"></i>
|
>
|
||||||
<span className="hidden lg:block">{t("download")}</span>
|
<i className="fa-light fa-arrow-down font-semibold lg:hidden"></i>
|
||||||
</button>
|
<span className="hidden lg:block">{t("download")}</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -392,7 +476,9 @@ function Header({
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
|
onClick={(e) =>
|
||||||
|
handleToPrint(e, pdfUrl, setIsDownloading, pdfDetails)
|
||||||
|
}
|
||||||
type="button"
|
type="button"
|
||||||
className="op-btn op-btn-neutral op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
|
className="op-btn op-btn-neutral op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
|
||||||
>
|
>
|
||||||
@@ -402,9 +488,9 @@ function Header({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="op-btn op-btn-primary op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
|
className="op-btn op-btn-primary op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
|
setIsDownloadModal(true);
|
||||||
}
|
}}
|
||||||
>
|
>
|
||||||
<i className="fa-light fa-download" aria-hidden="true"></i>
|
<i className="fa-light fa-download" aria-hidden="true"></i>
|
||||||
<span className="hidden lg:block ml-1">{t("download")}</span>
|
<span className="hidden lg:block ml-1">{t("download")}</span>
|
||||||
@@ -423,9 +509,7 @@ function Header({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="op-btn op-btn-primary op-btn-sm shadow"
|
className="op-btn op-btn-primary op-btn-sm shadow"
|
||||||
onClick={() => {
|
onClick={() => embedWidgetsData()}
|
||||||
embedWidgetsData();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{t("sign-now")}
|
{t("sign-now")}
|
||||||
</button>
|
</button>
|
||||||
@@ -442,11 +526,7 @@ function Header({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="op-btn op-btn-primary op-btn-sm mr-[3px]"
|
className="op-btn op-btn-primary op-btn-sm mr-[3px]"
|
||||||
onClick={() => {
|
onClick={() => embedWidgetsData()}
|
||||||
if (!pdfUrl) {
|
|
||||||
embedWidgetsData();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{t("finish")}
|
{t("finish")}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -3,44 +3,37 @@ import { useTranslation } from "react-i18next";
|
|||||||
|
|
||||||
function PdfZoom(props) {
|
function PdfZoom(props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
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 (
|
return (
|
||||||
// md:mt-[41px] xl:mt-[63px]mt=[]
|
<span className="hidden md:flex flex-col gap-1 text-center md:w-[5%] mt-[43px] 2xl:mt-[63px]">
|
||||||
<span className="hidden md:flex flex-col gap-1 text-center md:w-[5%] mt-[50px] 2xl:mt-[63px]">
|
|
||||||
<span
|
<span
|
||||||
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
|
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
|
||||||
onClick={onClickZoomIn}
|
onClick={() => props.clickOnZoomIn()}
|
||||||
title={t("zoom-in")}
|
title={t("zoom-in")}
|
||||||
>
|
>
|
||||||
<i className="fa-light fa-magnifying-glass-plus text-gray-500 2xl:text-[30px]"></i>
|
<i className="fa-light fa-magnifying-glass-plus text-gray-500 2xl:text-[30px]"></i>
|
||||||
</span>
|
</span>
|
||||||
<span
|
{!props?.isDisableRotate && (
|
||||||
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
|
<>
|
||||||
onClick={handleReset}
|
<span
|
||||||
title={t("reset")}
|
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
|
||||||
>
|
onClick={() => props.handleRotationFun(90)}
|
||||||
<i className="fa-light fa-magnifying-glass-arrows-rotate text-gray-500 2xl:text-[30px]"></i>
|
title={t("rotate-right")}
|
||||||
</span>
|
>
|
||||||
|
<i className="fa-light fa-rotate-right text-gray-500 2xl:text-[30px]"></i>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
|
||||||
|
title={t("rotate-left")}
|
||||||
|
onClick={() => props.handleRotationFun(-90)}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-rotate-left text-gray-500 2xl:text-[30px]"></i>
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<span
|
<span
|
||||||
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px]"
|
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px]"
|
||||||
onClick={onClickZoomOut}
|
onClick={() => props.clickOnZoomOut()}
|
||||||
style={{
|
style={{
|
||||||
cursor: props.zoomPercent > 0 ? "pointer" : "default"
|
cursor: props.zoomPercent > 0 ? "pointer" : "default"
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import PlaceholderBorder from "./PlaceholderBorder";
|
|||||||
import { Rnd } from "react-rnd";
|
import { Rnd } from "react-rnd";
|
||||||
import {
|
import {
|
||||||
defaultWidthHeight,
|
defaultWidthHeight,
|
||||||
|
fontColorArr,
|
||||||
|
fontsizeArr,
|
||||||
getContainerScale,
|
getContainerScale,
|
||||||
handleCopyNextToWidget,
|
handleCopyNextToWidget,
|
||||||
isTabAndMobile,
|
isTabAndMobile,
|
||||||
@@ -15,6 +17,8 @@ import {
|
|||||||
import PlaceholderType from "./PlaceholderType";
|
import PlaceholderType from "./PlaceholderType";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import "../../styles/opensigndrive.css";
|
import "../../styles/opensigndrive.css";
|
||||||
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
const selectFormat = (data) => {
|
const selectFormat = (data) => {
|
||||||
switch (data) {
|
switch (data) {
|
||||||
@@ -89,9 +93,10 @@ const getDefaultdate = (selectedDate, format = "dd-MM-yyyy") => {
|
|||||||
const getDefaultFormat = (dateFormat) => dateFormat || "MM/dd/yyyy";
|
const getDefaultFormat = (dateFormat) => dateFormat || "MM/dd/yyyy";
|
||||||
|
|
||||||
function Placeholder(props) {
|
function Placeholder(props) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const [placeholderBorder, setPlaceholderBorder] = useState({ w: 0, h: 0 });
|
const [placeholderBorder, setPlaceholderBorder] = useState({ w: 0, h: 0 });
|
||||||
const [isDraggingEnabled, setDraggingEnabled] = useState(true);
|
const [isDraggingEnabled, setDraggingEnabled] = useState(true);
|
||||||
const [isShowDateFormat, setIsShowDateFormat] = useState(false);
|
const [isDateModal, setIsDateModal] = useState(false);
|
||||||
const [containerScale, setContainerScale] = useState();
|
const [containerScale, setContainerScale] = useState();
|
||||||
const [selectDate, setSelectDate] = useState({
|
const [selectDate, setSelectDate] = useState({
|
||||||
date:
|
date:
|
||||||
@@ -111,6 +116,7 @@ function Placeholder(props) {
|
|||||||
: ""
|
: ""
|
||||||
});
|
});
|
||||||
const [dateFormat, setDateFormat] = useState([]);
|
const [dateFormat, setDateFormat] = useState([]);
|
||||||
|
const [clickonWidget, setClickonWidget] = useState({});
|
||||||
const [startDate, setStartDate] = useState(
|
const [startDate, setStartDate] = useState(
|
||||||
props.pos.type === "date" &&
|
props.pos.type === "date" &&
|
||||||
getDefaultdate(
|
getDefaultdate(
|
||||||
@@ -200,20 +206,6 @@ function Placeholder(props) {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [selectDate]);
|
}, [selectDate]);
|
||||||
|
|
||||||
//it detect outside click of date dropdown menu
|
|
||||||
useEffect(() => {
|
|
||||||
const closeMenuOnOutsideClick = (e) => {
|
|
||||||
if (isShowDateFormat && !e.target.closest("#menu-container")) {
|
|
||||||
setIsShowDateFormat(!isShowDateFormat);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
document.addEventListener("click", closeMenuOnOutsideClick);
|
|
||||||
return () => {
|
|
||||||
// Cleanup the event listener when the component unmounts
|
|
||||||
document.removeEventListener("click", closeMenuOnOutsideClick);
|
|
||||||
};
|
|
||||||
}, [isShowDateFormat]);
|
|
||||||
|
|
||||||
//`handleWidgetIdandPopup` is used to set current widget id and open relative popup
|
//`handleWidgetIdandPopup` is used to set current widget id and open relative popup
|
||||||
const handleWidgetIdandPopup = () => {
|
const handleWidgetIdandPopup = () => {
|
||||||
if (props.setSelectWidgetId) {
|
if (props.setSelectWidgetId) {
|
||||||
@@ -338,7 +330,6 @@ function Placeholder(props) {
|
|||||||
|
|
||||||
//condition for only placeholder and template flow
|
//condition for only placeholder and template flow
|
||||||
if (props.data && props?.pos?.type !== textWidget) {
|
if (props.data && props?.pos?.type !== textWidget) {
|
||||||
props.setSignerObjId(props?.data?.signerObjId);
|
|
||||||
props.setUniqueId(props?.data?.Id);
|
props.setUniqueId(props?.data?.Id);
|
||||||
const checkIndex = props.xyPostion.findIndex(
|
const checkIndex = props.xyPostion.findIndex(
|
||||||
(data) => data.Id === props.data.Id
|
(data) => data.Id === props.data.Id
|
||||||
@@ -369,7 +360,6 @@ function Placeholder(props) {
|
|||||||
//and on save or cancel button of copy all page popup i have set this temp signer Id in unique id
|
//and on save or cancel button of copy all page popup i have set this temp signer Id in unique id
|
||||||
|
|
||||||
if (props.data && props?.pos?.type !== textWidget) {
|
if (props.data && props?.pos?.type !== textWidget) {
|
||||||
props.setSignerObjId(props?.data?.signerObjId);
|
|
||||||
props.setUniqueId(props?.data?.Id);
|
props.setUniqueId(props?.data?.Id);
|
||||||
const checkIndex = props.xyPostion.findIndex(
|
const checkIndex = props.xyPostion.findIndex(
|
||||||
(data) => data.Id === props.data.Id
|
(data) => data.Id === props.data.Id
|
||||||
@@ -378,7 +368,6 @@ function Placeholder(props) {
|
|||||||
props.setIsSelectId(checkIndex || 0);
|
props.setIsSelectId(checkIndex || 0);
|
||||||
} else if (props.data && props.pos.type === textWidget) {
|
} else if (props.data && props.pos.type === textWidget) {
|
||||||
props.setTempSignerId(props.uniqueId);
|
props.setTempSignerId(props.uniqueId);
|
||||||
props.setSignerObjId(props?.data?.signerObjId);
|
|
||||||
props.setUniqueId(props?.data?.Id);
|
props.setUniqueId(props?.data?.Id);
|
||||||
const checkIndex = props.xyPostion.findIndex(
|
const checkIndex = props.xyPostion.findIndex(
|
||||||
(data) => data.Id === props.data.Id
|
(data) => data.Id === props.data.Id
|
||||||
@@ -430,7 +419,11 @@ function Placeholder(props) {
|
|||||||
props.setXyPostion,
|
props.setXyPostion,
|
||||||
props.data && props.data.Id,
|
props.data && props.data.Id,
|
||||||
false,
|
false,
|
||||||
data?.format
|
data?.format,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
props.fontSize || props.pos?.options?.fontSize || "12",
|
||||||
|
props.fontColor || props.pos?.options?.fontColor || "black"
|
||||||
);
|
);
|
||||||
setSelectDate({ date: date, format: data?.format });
|
setSelectDate({ date: date, format: data?.format });
|
||||||
};
|
};
|
||||||
@@ -522,17 +515,12 @@ function Placeholder(props) {
|
|||||||
)}
|
)}
|
||||||
{/* setting icon only for date widgets */}
|
{/* setting icon only for date widgets */}
|
||||||
{props.pos.type === "date" && selectDate && (
|
{props.pos.type === "date" && selectDate && (
|
||||||
<div
|
<i
|
||||||
id="menu-container"
|
|
||||||
style={{
|
|
||||||
zIndex: "99",
|
|
||||||
top: "-19px",
|
|
||||||
right: props.isPlaceholder ? "60px" : "44px"
|
|
||||||
}}
|
|
||||||
className={`${isShowDateFormat ? "show" : ""} dropdown icon`}
|
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
setIsShowDateFormat(!isShowDateFormat);
|
props.setCurrWidgetsDetails(props.pos);
|
||||||
|
setIsDateModal(!isDateModal);
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
setClickonWidget(props.pos);
|
||||||
if (props.data) {
|
if (props.data) {
|
||||||
props.setSignKey(props.pos.key);
|
props.setSignKey(props.pos.key);
|
||||||
props.setUniqueId(props.data.Id);
|
props.setUniqueId(props.data.Id);
|
||||||
@@ -543,8 +531,9 @@ function Placeholder(props) {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onTouchEnd={(e) => {
|
onTouchEnd={(e) => {
|
||||||
|
props.setCurrWidgetsDetails(props.pos);
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIsShowDateFormat(!isShowDateFormat);
|
setIsDateModal(!isDateModal);
|
||||||
if (props.data) {
|
if (props.data) {
|
||||||
props.setSignKey(props.pos.key);
|
props.setSignKey(props.pos.key);
|
||||||
props.setUniqueId(props.data.Id);
|
props.setUniqueId(props.data.Id);
|
||||||
@@ -554,44 +543,15 @@ function Placeholder(props) {
|
|||||||
props.setIsSelectId(checkIndex || 0);
|
props.setIsSelectId(checkIndex || 0);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
style={{
|
||||||
<i
|
zIndex: "99",
|
||||||
className="fa-light fa-gear icon"
|
top: "-18px",
|
||||||
style={{
|
right: props.isPlaceholder ? "50px" : "30px",
|
||||||
color: "#188ae2",
|
color: "#188ae2",
|
||||||
fontSize: "14px"
|
fontSize: "14px"
|
||||||
}}
|
}}
|
||||||
></i>
|
className="fa-light fa-gear icon"
|
||||||
<div
|
></i>
|
||||||
className={
|
|
||||||
isShowDateFormat ? "dropdown-menu show" : "dropdown-menu"
|
|
||||||
}
|
|
||||||
aria-labelledby="dropdownMenuButton"
|
|
||||||
aria-expanded={isShowDateFormat ? "true" : "false"}
|
|
||||||
>
|
|
||||||
{dateFormat.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
key={ind}
|
|
||||||
onTouchEnd={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
setIsShowDateFormat(!isShowDateFormat);
|
|
||||||
setSelectDate(data);
|
|
||||||
handleSaveDate(data);
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
setIsShowDateFormat(!isShowDateFormat);
|
|
||||||
setSelectDate(data);
|
|
||||||
handleSaveDate(data);
|
|
||||||
}}
|
|
||||||
className="dropdown-item text-[13px]"
|
|
||||||
>
|
|
||||||
{data?.date ? data?.date : "nodata"}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
{/* copy icon for all widgets */}
|
{/* copy icon for all widgets */}
|
||||||
<i
|
<i
|
||||||
@@ -705,228 +665,320 @@ function Placeholder(props) {
|
|||||||
return "all-scroll";
|
return "all-scroll";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Rnd
|
<>
|
||||||
id={props.pos.key}
|
<Rnd
|
||||||
data-tut={props.pos.key === props.unSignedWidgetId ? "IsSigned" : ""}
|
id={props.pos.key}
|
||||||
key={props.pos.key}
|
data-tut={props.pos.key === props.unSignedWidgetId ? "IsSigned" : ""}
|
||||||
lockAspectRatio={
|
key={props.pos.key}
|
||||||
![
|
lockAspectRatio={
|
||||||
textWidget,
|
![
|
||||||
"email",
|
textWidget,
|
||||||
"name",
|
"email",
|
||||||
"company",
|
"name",
|
||||||
"job title",
|
"company",
|
||||||
textInputWidget
|
"job title",
|
||||||
].includes(props.pos.type) &&
|
textInputWidget
|
||||||
(props.pos.Width
|
].includes(props.pos.type) &&
|
||||||
? props.pos.Width / props.pos.Height
|
(props.pos.Width
|
||||||
: defaultWidthHeight(props.pos.type).width /
|
? props.pos.Width / props.pos.Height
|
||||||
defaultWidthHeight(props.pos.type).height)
|
: defaultWidthHeight(props.pos.type).width /
|
||||||
}
|
defaultWidthHeight(props.pos.type).height)
|
||||||
enableResizing={{
|
}
|
||||||
top: false,
|
enableResizing={{
|
||||||
right: false,
|
top: false,
|
||||||
bottom: false,
|
right: false,
|
||||||
left: false,
|
bottom: false,
|
||||||
topRight: false,
|
left: false,
|
||||||
bottomRight:
|
topRight: false,
|
||||||
props.data && props.isNeedSign
|
bottomRight:
|
||||||
? props.data?.signerObjId === props.signerObjId &&
|
props.data && props.isNeedSign
|
||||||
props.pos.type !== "checkbox" &&
|
? props.data?.signerObjId === props.signerObjId &&
|
||||||
props.pos.type !== radioButtonWidget
|
props.pos.type !== "checkbox" &&
|
||||||
? true
|
props.pos.type !== radioButtonWidget
|
||||||
: false
|
? true
|
||||||
: props.pos.type !== radioButtonWidget &&
|
: false
|
||||||
props.pos.type !== "checkbox" &&
|
: props.pos.type !== radioButtonWidget &&
|
||||||
props.pos.key === props.selectWidgetId &&
|
props.pos.type !== "checkbox" &&
|
||||||
true,
|
props.pos.key === props.selectWidgetId &&
|
||||||
bottomLeft: false,
|
true,
|
||||||
topLeft: false
|
bottomLeft: false,
|
||||||
}}
|
topLeft: false
|
||||||
bounds="parent"
|
}}
|
||||||
className="signYourselfBlock"
|
bounds="parent"
|
||||||
style={{
|
className="signYourselfBlock"
|
||||||
border: "1px solid #007bff",
|
style={{
|
||||||
borderRadius: "2px",
|
border: "1px solid #007bff",
|
||||||
textAlign:
|
borderRadius: "2px",
|
||||||
props.pos.type !== "name" &&
|
textAlign:
|
||||||
props.pos.type !== "company" &&
|
props.pos.type !== "name" &&
|
||||||
props.pos.type !== "job title" &&
|
props.pos.type !== "company" &&
|
||||||
"center",
|
props.pos.type !== "job title" &&
|
||||||
cursor: getCursor(),
|
"center",
|
||||||
zIndex:
|
cursor: getCursor(),
|
||||||
props.pos.type === "date"
|
zIndex:
|
||||||
? props.pos.key === props.selectWidgetId
|
props.pos.type === "date"
|
||||||
? 99 + 1
|
? props.pos.key === props.selectWidgetId
|
||||||
: 99
|
? 99 + 1
|
||||||
: props?.pos?.zIndex
|
: 99
|
||||||
? props.pos.zIndex
|
: props?.pos?.zIndex
|
||||||
: "5",
|
? props.pos.zIndex
|
||||||
background: props.data ? props.data.blockColor : "rgb(203 233 237)"
|
: "5",
|
||||||
}}
|
background: props.data ? props.data.blockColor : "rgb(203 233 237)"
|
||||||
onDrag={() => {
|
}}
|
||||||
setDraggingEnabled(true);
|
onDrag={() => {
|
||||||
props.handleTabDrag && props.handleTabDrag(props.pos.key);
|
setDraggingEnabled(true);
|
||||||
}}
|
props.handleTabDrag && props.handleTabDrag(props.pos.key);
|
||||||
size={{
|
}}
|
||||||
width:
|
size={{
|
||||||
props.pos.type === radioButtonWidget || props.pos.type === "checkbox"
|
width:
|
||||||
? "auto"
|
props.pos.type === radioButtonWidget ||
|
||||||
: props.posWidth(props.pos, props.isSignYourself),
|
props.pos.type === "checkbox"
|
||||||
height:
|
? "auto"
|
||||||
props.pos.type === radioButtonWidget || props.pos.type === "checkbox"
|
: props.posWidth(props.pos, props.isSignYourself),
|
||||||
? "auto"
|
height:
|
||||||
: props.posHeight(props.pos, props.isSignYourself)
|
props.pos.type === radioButtonWidget ||
|
||||||
}}
|
props.pos.type === "checkbox"
|
||||||
onResizeStart={() => {
|
? "auto"
|
||||||
setDraggingEnabled(true);
|
: props.posHeight(props.pos, props.isSignYourself)
|
||||||
props.setIsResize && props.setIsResize(true);
|
}}
|
||||||
}}
|
onResizeStart={() => {
|
||||||
onResizeStop={(e, direction, ref) => {
|
setDraggingEnabled(true);
|
||||||
props.setIsResize && props.setIsResize(false);
|
props.setIsResize && props.setIsResize(true);
|
||||||
props.handleSignYourselfImageResize &&
|
}}
|
||||||
props.handleSignYourselfImageResize(
|
onResizeStop={(e, direction, ref) => {
|
||||||
ref,
|
props.setIsResize && props.setIsResize(false);
|
||||||
props.pos.key,
|
props.handleSignYourselfImageResize &&
|
||||||
props.xyPostion,
|
props.handleSignYourselfImageResize(
|
||||||
props.setXyPostion,
|
ref,
|
||||||
props.index,
|
props.pos.key,
|
||||||
containerScale,
|
props.xyPostion,
|
||||||
props.scale,
|
props.setXyPostion,
|
||||||
props.data && props.data.Id,
|
props.index,
|
||||||
props.isResize
|
containerScale,
|
||||||
);
|
props.scale,
|
||||||
}}
|
props.data && props.data.Id,
|
||||||
disableDragging={
|
props.isResize
|
||||||
props.isNeedSign
|
);
|
||||||
? true
|
}}
|
||||||
: props.isPlaceholder && ![textWidget].includes(props.pos.type)
|
disableDragging={
|
||||||
? false
|
props.isNeedSign
|
||||||
: !isDraggingEnabled
|
? true
|
||||||
}
|
: props.isPlaceholder && ![textWidget].includes(props.pos.type)
|
||||||
onDragStop={(event, dragElement) =>
|
? false
|
||||||
props.handleStop &&
|
: !isDraggingEnabled
|
||||||
props.handleStop(event, dragElement, props.data?.Id, props.pos?.key)
|
}
|
||||||
}
|
onDragStop={(event, dragElement) =>
|
||||||
position={{
|
props.handleStop &&
|
||||||
x: xPos(props.pos, props.isSignYourself),
|
props.handleStop(event, dragElement, props.data?.Id, props.pos?.key)
|
||||||
y: yPos(props.pos, props.isSignYourself)
|
}
|
||||||
}}
|
position={{
|
||||||
onResize={(e, direction, ref) => {
|
x: xPos(props.pos, props.isSignYourself),
|
||||||
setPlaceholderBorder({
|
y: yPos(props.pos, props.isSignYourself)
|
||||||
w: ref.offsetWidth / (props.scale * containerScale),
|
}}
|
||||||
h: ref.offsetHeight / (props.scale * containerScale)
|
onResize={(e, direction, ref) => {
|
||||||
});
|
setPlaceholderBorder({
|
||||||
}}
|
w: ref.offsetWidth / (props.scale * containerScale),
|
||||||
onClick={() => handleOnClickPlaceholder()}
|
h: ref.offsetHeight / (props.scale * containerScale)
|
||||||
>
|
});
|
||||||
{props.isShowBorder &&
|
}}
|
||||||
props.pos.type !== radioButtonWidget &&
|
onClick={() => handleOnClickPlaceholder()}
|
||||||
props.pos.type !== "checkbox" &&
|
>
|
||||||
props.pos.key === props.selectWidgetId ? (
|
{props.isShowBorder &&
|
||||||
<BorderResize right={-12} top={-11} />
|
|
||||||
) : props.data && props.isNeedSign && props.pos.type !== "checkbox" ? (
|
|
||||||
props.data?.signerObjId === props.signerObjId &&
|
|
||||||
props.pos.type !== radioButtonWidget &&
|
|
||||||
props.pos.type !== "checkbox" ? (
|
|
||||||
<BorderResize />
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
props.pos.type !== radioButtonWidget &&
|
props.pos.type !== radioButtonWidget &&
|
||||||
props.pos.type !== "checkbox" &&
|
props.pos.type !== "checkbox" &&
|
||||||
props.pos.key === props.selectWidgetId && <BorderResize />
|
props.pos.key === props.selectWidgetId ? (
|
||||||
)}
|
<BorderResize right={-12} top={-11} />
|
||||||
|
) : props.data && props.isNeedSign && props.pos.type !== "checkbox" ? (
|
||||||
|
props.data?.signerObjId === props.signerObjId &&
|
||||||
|
props.pos.type !== radioButtonWidget &&
|
||||||
|
props.pos.type !== "checkbox" ? (
|
||||||
|
<BorderResize />
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
props.pos.type !== radioButtonWidget &&
|
||||||
|
props.pos.type !== "checkbox" &&
|
||||||
|
props.pos.key === props.selectWidgetId && <BorderResize />
|
||||||
|
)}
|
||||||
|
|
||||||
{props.isShowBorder && props.pos.key === props.selectWidgetId && (
|
{props.isShowBorder && props.pos.key === props.selectWidgetId && (
|
||||||
<PlaceholderBorder
|
<PlaceholderBorder
|
||||||
setDraggingEnabled={setDraggingEnabled}
|
|
||||||
pos={props.pos}
|
|
||||||
isPlaceholder={props.isPlaceholder}
|
|
||||||
getCheckboxRenderWidth={getCheckboxRenderWidth}
|
|
||||||
scale={props.scale}
|
|
||||||
containerScale={containerScale}
|
|
||||||
placeholderBorder={placeholderBorder}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isTabAndMobile ? (
|
|
||||||
<div
|
|
||||||
className="flex items-stretch"
|
|
||||||
style={{
|
|
||||||
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),
|
|
||||||
height:
|
|
||||||
props.pos.type === radioButtonWidget ||
|
|
||||||
props.pos.type === "checkbox"
|
|
||||||
? "auto"
|
|
||||||
: props.posHeight(props.pos, props.isSignYourself),
|
|
||||||
zIndex: "10"
|
|
||||||
}}
|
|
||||||
onTouchEnd={() => handleOnClickPlaceholder()}
|
|
||||||
onClick={() => handleOnClickPlaceholder()}
|
|
||||||
>
|
|
||||||
{props.pos.key === props.selectWidgetId && <PlaceholderIcon />}
|
|
||||||
|
|
||||||
<PlaceholderType
|
|
||||||
pos={props.pos}
|
|
||||||
xyPostion={props.xyPostion}
|
|
||||||
index={props.index}
|
|
||||||
setXyPostion={props.setXyPostion}
|
|
||||||
data={props.data}
|
|
||||||
setSignKey={props.setSignKey}
|
|
||||||
isShowDropdown={props?.isShowDropdown}
|
|
||||||
isPlaceholder={props.isPlaceholder}
|
|
||||||
isSignYourself={props.isSignYourself}
|
|
||||||
signerObjId={props.signerObjId}
|
|
||||||
handleUserName={props.handleUserName}
|
|
||||||
setDraggingEnabled={setDraggingEnabled}
|
setDraggingEnabled={setDraggingEnabled}
|
||||||
pdfDetails={props?.pdfDetails && props?.pdfDetails[0]}
|
pos={props.pos}
|
||||||
isNeedSign={props.isNeedSign}
|
isPlaceholder={props.isPlaceholder}
|
||||||
setSelectDate={setSelectDate}
|
getCheckboxRenderWidth={getCheckboxRenderWidth}
|
||||||
selectDate={selectDate}
|
scale={props.scale}
|
||||||
setValidateAlert={props.setValidateAlert}
|
containerScale={containerScale}
|
||||||
setStartDate={setStartDate}
|
placeholderBorder={placeholderBorder}
|
||||||
startDate={startDate}
|
|
||||||
handleSaveDate={handleSaveDate}
|
|
||||||
xPos={props.xPos}
|
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
{isTabAndMobile ? (
|
||||||
|
<div
|
||||||
|
className="flex items-stretch"
|
||||||
|
style={{
|
||||||
|
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),
|
||||||
|
height:
|
||||||
|
props.pos.type === radioButtonWidget ||
|
||||||
|
props.pos.type === "checkbox"
|
||||||
|
? "auto"
|
||||||
|
: props.posHeight(props.pos, props.isSignYourself),
|
||||||
|
zIndex: "10"
|
||||||
|
}}
|
||||||
|
onTouchEnd={() => handleOnClickPlaceholder()}
|
||||||
|
onClick={() => handleOnClickPlaceholder()}
|
||||||
|
>
|
||||||
|
{props.pos.key === props.selectWidgetId && <PlaceholderIcon />}
|
||||||
|
|
||||||
|
<PlaceholderType
|
||||||
|
pos={props.pos}
|
||||||
|
xyPostion={props.xyPostion}
|
||||||
|
index={props.index}
|
||||||
|
setXyPostion={props.setXyPostion}
|
||||||
|
data={props.data}
|
||||||
|
setSignKey={props.setSignKey}
|
||||||
|
isShowDropdown={props?.isShowDropdown}
|
||||||
|
isPlaceholder={props.isPlaceholder}
|
||||||
|
isSignYourself={props.isSignYourself}
|
||||||
|
signerObjId={props.signerObjId}
|
||||||
|
handleUserName={props.handleUserName}
|
||||||
|
setDraggingEnabled={setDraggingEnabled}
|
||||||
|
pdfDetails={props?.pdfDetails && props?.pdfDetails[0]}
|
||||||
|
isNeedSign={props.isNeedSign}
|
||||||
|
setSelectDate={setSelectDate}
|
||||||
|
selectDate={selectDate}
|
||||||
|
setValidateAlert={props.setValidateAlert}
|
||||||
|
setStartDate={setStartDate}
|
||||||
|
startDate={startDate}
|
||||||
|
handleSaveDate={handleSaveDate}
|
||||||
|
xPos={props.xPos}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{props.pos.key === props.selectWidgetId && <PlaceholderIcon />}
|
||||||
|
<PlaceholderType
|
||||||
|
pos={props.pos}
|
||||||
|
xyPostion={props.xyPostion}
|
||||||
|
index={props.index}
|
||||||
|
setXyPostion={props.setXyPostion}
|
||||||
|
data={props.data}
|
||||||
|
setSignKey={props.setSignKey}
|
||||||
|
isShowDropdown={props?.isShowDropdown}
|
||||||
|
isPlaceholder={props.isPlaceholder}
|
||||||
|
isSignYourself={props.isSignYourself}
|
||||||
|
signerObjId={props.signerObjId}
|
||||||
|
handleUserName={props.handleUserName}
|
||||||
|
setDraggingEnabled={setDraggingEnabled}
|
||||||
|
pdfDetails={props?.pdfDetails && props?.pdfDetails[0]}
|
||||||
|
isNeedSign={props.isNeedSign}
|
||||||
|
setSelectDate={setSelectDate}
|
||||||
|
selectDate={selectDate}
|
||||||
|
setValidateAlert={props.setValidateAlert}
|
||||||
|
setStartDate={setStartDate}
|
||||||
|
startDate={startDate}
|
||||||
|
handleSaveDate={handleSaveDate}
|
||||||
|
xPos={props.xPos}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Rnd>
|
||||||
|
<ModalUi isOpen={isDateModal} title={t("widget-info")} showClose={false}>
|
||||||
|
<div className="h-[100%] p-[20px]">
|
||||||
|
<div className="flex flex-row items-center">
|
||||||
|
<span>{t("format")} : </span>
|
||||||
|
<div className="flex">
|
||||||
|
<select
|
||||||
|
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
|
||||||
|
defaultValue={""}
|
||||||
|
onChange={(e) => {
|
||||||
|
const selectedIndex = e.target.value;
|
||||||
|
e.stopPropagation();
|
||||||
|
setSelectDate(dateFormat[selectedIndex]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value="" disabled>
|
||||||
|
{t("select-date-format")}
|
||||||
|
</option>
|
||||||
|
{dateFormat.map((data, ind) => {
|
||||||
|
return (
|
||||||
|
<option className="text-[13px]" value={ind} key={ind}>
|
||||||
|
{data?.date ? data?.date : "nodata"}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<span className="text-xs text-gray-400 ml-1">
|
||||||
|
{selectDate.format}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center mt-4 md:mt-2">
|
||||||
|
<span>{t("font-size")} :</span>
|
||||||
|
<select
|
||||||
|
className="ml-[3px] md:ml:[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
|
||||||
|
value={props.fontSize || clickonWidget.options?.fontSize || "12"}
|
||||||
|
onChange={(e) => props.setFontSize(e.target.value)}
|
||||||
|
>
|
||||||
|
{fontsizeArr.map((size, ind) => {
|
||||||
|
return (
|
||||||
|
<option className="text-[13px]" value={size} key={ind}>
|
||||||
|
{size}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
<div className="flex flex-row gap-1 items-center ml-2 md:ml-4 ">
|
||||||
|
<span>{t("color")}: </span>
|
||||||
|
<select
|
||||||
|
value={
|
||||||
|
props.fontColor || clickonWidget.options?.fontColor || "black"
|
||||||
|
}
|
||||||
|
onChange={(e) => props.setFontColor(e.target.value)}
|
||||||
|
className="ml-[4px] md: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}>
|
||||||
|
{t(`color-type.${color}`)}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
background:
|
||||||
|
props.fontColor || props.pos.options?.fontColor || "black"
|
||||||
|
}}
|
||||||
|
className="w-5 h-[19px] ml-1"
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-primary"
|
||||||
|
onClick={() => {
|
||||||
|
setIsDateModal(false);
|
||||||
|
handleSaveDate(selectDate);
|
||||||
|
props.setFontColor("");
|
||||||
|
props.setFontSize("");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("save")}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
</ModalUi>
|
||||||
<>
|
</>
|
||||||
{props.pos.key === props.selectWidgetId && <PlaceholderIcon />}
|
|
||||||
<PlaceholderType
|
|
||||||
pos={props.pos}
|
|
||||||
xyPostion={props.xyPostion}
|
|
||||||
index={props.index}
|
|
||||||
setXyPostion={props.setXyPostion}
|
|
||||||
data={props.data}
|
|
||||||
setSignKey={props.setSignKey}
|
|
||||||
isShowDropdown={props?.isShowDropdown}
|
|
||||||
isPlaceholder={props.isPlaceholder}
|
|
||||||
isSignYourself={props.isSignYourself}
|
|
||||||
signerObjId={props.signerObjId}
|
|
||||||
handleUserName={props.handleUserName}
|
|
||||||
setDraggingEnabled={setDraggingEnabled}
|
|
||||||
pdfDetails={props?.pdfDetails && props?.pdfDetails[0]}
|
|
||||||
isNeedSign={props.isNeedSign}
|
|
||||||
setSelectDate={setSelectDate}
|
|
||||||
selectDate={selectDate}
|
|
||||||
setValidateAlert={props.setValidateAlert}
|
|
||||||
setStartDate={setStartDate}
|
|
||||||
startDate={startDate}
|
|
||||||
handleSaveDate={handleSaveDate}
|
|
||||||
xPos={props.xPos}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Rnd>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
import { randomId, textWidget } from "../../constant/Utils";
|
import {
|
||||||
|
handleCopyNextToWidget,
|
||||||
|
randomId,
|
||||||
|
textWidget
|
||||||
|
} from "../../constant/Utils";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
function PlaceholderCopy(props) {
|
function PlaceholderCopy(props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const copyType = ["All pages", "All pages but last", "All pages but first"];
|
const copyType = [
|
||||||
const [selectCopyType, setSelectCopyType] = useState("");
|
{ id: 1, type: "All pages" },
|
||||||
|
{ id: 2, type: "All pages but last" },
|
||||||
|
{ id: 3, type: "All pages but first" },
|
||||||
|
{ id: 4, type: "Next to current widget" }
|
||||||
|
];
|
||||||
|
const [selectCopyType, setSelectCopyType] = useState(1);
|
||||||
//function for get copy placeholder position
|
//function for get copy placeholder position
|
||||||
const getCopyPlaceholderPosition = (
|
const getCopyPlaceholderPosition = (
|
||||||
type,
|
type,
|
||||||
@@ -20,7 +29,7 @@ function PlaceholderCopy(props) {
|
|||||||
(data) => data.xPosition !== currentPlaceholder.xPosition
|
(data) => data.xPosition !== currentPlaceholder.xPosition
|
||||||
);
|
);
|
||||||
//copy all page placeholder at requested position except first page
|
//copy all page placeholder at requested position except first page
|
||||||
if (newPageNumber === 1 && type === "first") {
|
if (newPageNumber === 1 && type === 3) {
|
||||||
if (filterPosition && filterPosition.length > 0) {
|
if (filterPosition && filterPosition.length > 0) {
|
||||||
return {
|
return {
|
||||||
pageNumber: newPageNumber,
|
pageNumber: newPageNumber,
|
||||||
@@ -29,7 +38,7 @@ function PlaceholderCopy(props) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//copy all page placeholder at requested position except last page
|
//copy all page placeholder at requested position except last page
|
||||||
else if (newPageNumber === props.allPages && type === "last") {
|
else if (newPageNumber === props.allPages && type === 2) {
|
||||||
if (existPlaceholderPosition) {
|
if (existPlaceholderPosition) {
|
||||||
return {
|
return {
|
||||||
pageNumber: newPageNumber,
|
pageNumber: newPageNumber,
|
||||||
@@ -172,25 +181,65 @@ function PlaceholderCopy(props) {
|
|||||||
|
|
||||||
//function for getting selected type placeholder copy
|
//function for getting selected type placeholder copy
|
||||||
const handleApplyCopy = () => {
|
const handleApplyCopy = () => {
|
||||||
if (selectCopyType === "All pages") {
|
if (selectCopyType === 4) {
|
||||||
copyPlaceholder("all");
|
const signerPosition = props.xyPostion;
|
||||||
} else if (selectCopyType === "All pages but last") {
|
let currentXYposition;
|
||||||
copyPlaceholder("last");
|
const signerId = props.signerObjId ? props.signerObjId : props.Id;
|
||||||
} else if (selectCopyType === "All pages but first") {
|
if (signerId) {
|
||||||
copyPlaceholder("first");
|
const filterSignerPosition = signerPosition.filter(
|
||||||
|
(item) => item?.Id === signerId
|
||||||
|
);
|
||||||
|
currentXYposition = filterSignerPosition[0].placeHolder.filter(
|
||||||
|
(data) => data.pageNumber === props?.pageNumber
|
||||||
|
);
|
||||||
|
//get current placeholder position data which user want to copy
|
||||||
|
currentXYposition = currentXYposition[0].pos.find(
|
||||||
|
(position) => position.key === props.signKey
|
||||||
|
);
|
||||||
|
//function to create new widget next to just widget
|
||||||
|
handleCopyNextToWidget(
|
||||||
|
currentXYposition,
|
||||||
|
props.widgetType,
|
||||||
|
props.xyPostion,
|
||||||
|
props.pageNumber,
|
||||||
|
props.setXyPostion,
|
||||||
|
props?.Id
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const getIndex = props?.xyPostion.findIndex(
|
||||||
|
(data) => data.pageNumber === props.pageNumber
|
||||||
|
);
|
||||||
|
const placeholderPosition = props?.xyPostion[getIndex];
|
||||||
|
//get current placeholder position data which user want to copy
|
||||||
|
currentXYposition = placeholderPosition.pos.find(
|
||||||
|
(pos) => pos.key === props.signKey
|
||||||
|
);
|
||||||
|
//function to create new widget next to just widget
|
||||||
|
handleCopyNextToWidget(
|
||||||
|
currentXYposition,
|
||||||
|
props.widgetType,
|
||||||
|
props.xyPostion,
|
||||||
|
getIndex,
|
||||||
|
props.setXyPostion
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
copyPlaceholder(selectCopyType);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleUniqueId = () => {
|
const handleUniqueId = () => {
|
||||||
if (props.widgetType === textWidget) {
|
const signerId = props.signerObjId ? props.signerObjId : props.Id;
|
||||||
|
if (signerId && props.widgetType === textWidget) {
|
||||||
props.setUniqueId(props?.tempSignerId);
|
props.setUniqueId(props?.tempSignerId);
|
||||||
props.setTempSignerId("");
|
props.setTempSignerId("");
|
||||||
}
|
}
|
||||||
props.setIsPageCopy(false);
|
props.setIsPageCopy(false);
|
||||||
|
setSelectCopyType(1);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen={props.isPageCopy}
|
isOpen={props.isPageCopy}
|
||||||
title={t("copy-to-all-pages")}
|
title={t("copy-title")}
|
||||||
handleClose={() => handleUniqueId()}
|
handleClose={() => handleUniqueId()}
|
||||||
>
|
>
|
||||||
<div className="h-full p-[20px] text-base-content">
|
<div className="h-full p-[20px] text-base-content">
|
||||||
@@ -201,11 +250,11 @@ function PlaceholderCopy(props) {
|
|||||||
<input
|
<input
|
||||||
className="mr-[8px] op-radio op-radio-xs"
|
className="mr-[8px] op-radio op-radio-xs"
|
||||||
type="radio"
|
type="radio"
|
||||||
value={data}
|
value={data.id}
|
||||||
onChange={() => setSelectCopyType(data)}
|
onChange={() => setSelectCopyType(data.id)}
|
||||||
checked={selectCopyType === data}
|
checked={selectCopyType === data.id}
|
||||||
/>
|
/>
|
||||||
{t(`copy-type.${data}`)}
|
{t(`copy-type.${data.type}`)}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ function PlaceholderType(props) {
|
|||||||
const [textValue, setTextValue] = useState();
|
const [textValue, setTextValue] = useState();
|
||||||
const [selectedCheckbox, setSelectedCheckbox] = useState([]);
|
const [selectedCheckbox, setSelectedCheckbox] = useState([]);
|
||||||
const years = range(1990, getYear(new Date()) + 16, 1);
|
const years = range(1990, getYear(new Date()) + 16, 1);
|
||||||
|
const fontSize = (props.pos.options?.fontSize || "12") + "px";
|
||||||
|
const fontColor = props.pos.options?.fontColor || "black";
|
||||||
const months = [
|
const months = [
|
||||||
"January",
|
"January",
|
||||||
"February",
|
"February",
|
||||||
@@ -143,7 +145,12 @@ function PlaceholderType(props) {
|
|||||||
|
|
||||||
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
|
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
|
||||||
<div
|
<div
|
||||||
className={`${selectWidgetCls} text-[12px] overflow-hidden`}
|
style={{
|
||||||
|
fontSize: fontSize,
|
||||||
|
color: fontColor,
|
||||||
|
fontFamily: "Arial, sans-serif"
|
||||||
|
}}
|
||||||
|
className={`${selectWidgetCls} overflow-hidden`}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
>
|
>
|
||||||
@@ -343,9 +350,13 @@ function PlaceholderType(props) {
|
|||||||
return (
|
return (
|
||||||
<div key={ind} className="flex items-center text-center gap-0.5">
|
<div key={ind} className="flex items-center text-center gap-0.5">
|
||||||
<input
|
<input
|
||||||
|
style={{
|
||||||
|
width: fontSize,
|
||||||
|
height: fontSize
|
||||||
|
}}
|
||||||
className={`${
|
className={`${
|
||||||
ind === 0 ? "mt-0" : "mt-[5px]"
|
ind === 0 ? "mt-0" : "mt-[5px]"
|
||||||
} flex justify-center op-checkbox op-checkbox-xs rounded-[0.350rem]`}
|
} flex justify-center op-checkbox rounded-[1px] `}
|
||||||
onBlur={handleInputBlur}
|
onBlur={handleInputBlur}
|
||||||
disabled={
|
disabled={
|
||||||
props.isNeedSign &&
|
props.isNeedSign &&
|
||||||
@@ -379,7 +390,15 @@ function PlaceholderType(props) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{!props.pos.options?.isHideLabel && (
|
{!props.pos.options?.isHideLabel && (
|
||||||
<label className="text-xs mb-0 text-center">{data}</label>
|
<label
|
||||||
|
style={{
|
||||||
|
fontSize: fontSize,
|
||||||
|
color: fontColor
|
||||||
|
}}
|
||||||
|
className="text-xs mb-0 text-center"
|
||||||
|
>
|
||||||
|
{data}
|
||||||
|
</label>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -410,20 +429,16 @@ function PlaceholderType(props) {
|
|||||||
}}
|
}}
|
||||||
className={textWidgetCls}
|
className={textWidgetCls}
|
||||||
style={{
|
style={{
|
||||||
fontSize: props.pos.options?.fontSize
|
fontSize: fontSize,
|
||||||
? props.pos.options?.fontSize + "px"
|
color: fontColor
|
||||||
: "12px",
|
|
||||||
color: props.pos.options?.fontColor || "black"
|
|
||||||
}}
|
}}
|
||||||
cols="50"
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: props.pos.options?.fontSize
|
fontSize: fontSize,
|
||||||
? props.pos.options?.fontSize + "px"
|
color: fontColor,
|
||||||
: "12px",
|
|
||||||
color: props.pos.options?.fontColor || "black",
|
|
||||||
overflow: "hidden"
|
overflow: "hidden"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -433,6 +448,10 @@ function PlaceholderType(props) {
|
|||||||
case "dropdown":
|
case "dropdown":
|
||||||
return props.data?.signerObjId === props.signerObjId ? (
|
return props.data?.signerObjId === props.signerObjId ? (
|
||||||
<select
|
<select
|
||||||
|
style={{
|
||||||
|
fontSize: fontSize,
|
||||||
|
color: fontColor
|
||||||
|
}}
|
||||||
className={`${selectWidgetCls} text-[12px] bg-inherit`}
|
className={`${selectWidgetCls} text-[12px] bg-inherit`}
|
||||||
id="myDropdown"
|
id="myDropdown"
|
||||||
value={selectOption}
|
value={selectOption}
|
||||||
@@ -450,20 +469,41 @@ function PlaceholderType(props) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Default/Title option */}
|
{/* Default/Title option */}
|
||||||
<option value="" disabled hidden>
|
<option
|
||||||
|
style={{
|
||||||
|
fontSize: fontSize,
|
||||||
|
color: fontColor
|
||||||
|
}}
|
||||||
|
value=""
|
||||||
|
disabled
|
||||||
|
hidden
|
||||||
|
>
|
||||||
{props?.pos?.options?.name}
|
{props?.pos?.options?.name}
|
||||||
</option>
|
</option>
|
||||||
|
|
||||||
{props.pos?.options?.values?.map((data, ind) => {
|
{props.pos?.options?.values?.map((data, ind) => {
|
||||||
return (
|
return (
|
||||||
<option key={ind} value={data}>
|
<option
|
||||||
|
style={{
|
||||||
|
fontSize: fontSize,
|
||||||
|
color: fontColor
|
||||||
|
}}
|
||||||
|
key={ind}
|
||||||
|
value={data}
|
||||||
|
>
|
||||||
{data}
|
{data}
|
||||||
</option>
|
</option>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</select>
|
</select>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-[12px] overflow-hidden">
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: fontSize,
|
||||||
|
color: fontColor
|
||||||
|
}}
|
||||||
|
className=" overflow-hidden"
|
||||||
|
>
|
||||||
{props.pos?.options?.name
|
{props.pos?.options?.name
|
||||||
? props.pos.options.name
|
? props.pos.options.name
|
||||||
: widgetTypeTraslation}
|
: widgetTypeTraslation}
|
||||||
@@ -511,20 +551,16 @@ function PlaceholderType(props) {
|
|||||||
}}
|
}}
|
||||||
className={textWidgetCls}
|
className={textWidgetCls}
|
||||||
style={{
|
style={{
|
||||||
fontSize: props.pos.options?.fontSize
|
fontSize: fontSize,
|
||||||
? props.pos.options?.fontSize + "px"
|
color: fontColor
|
||||||
: "12px",
|
|
||||||
color: props.pos.options?.fontColor || "black"
|
|
||||||
}}
|
}}
|
||||||
cols="50"
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: props.pos.options?.fontSize
|
fontSize: fontSize,
|
||||||
? props.pos.options?.fontSize + "px"
|
color: fontColor,
|
||||||
: "12px",
|
|
||||||
color: props.pos.options?.fontColor || "black",
|
|
||||||
fontFamily: "Arial, sans-serif",
|
fontFamily: "Arial, sans-serif",
|
||||||
overflow: "hidden"
|
overflow: "hidden"
|
||||||
}}
|
}}
|
||||||
@@ -555,20 +591,16 @@ function PlaceholderType(props) {
|
|||||||
}}
|
}}
|
||||||
className={textWidgetCls}
|
className={textWidgetCls}
|
||||||
style={{
|
style={{
|
||||||
fontSize: props.pos.options?.fontSize
|
fontSize: fontSize,
|
||||||
? props.pos.options?.fontSize + "px"
|
color: fontColor
|
||||||
: "12px",
|
|
||||||
color: props.pos.options?.fontColor || "black"
|
|
||||||
}}
|
}}
|
||||||
cols="50"
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: props.pos.options?.fontSize
|
fontSize: fontSize,
|
||||||
? props.pos.options?.fontSize + "px"
|
color: fontColor,
|
||||||
: "12px",
|
|
||||||
color: props.pos.options?.fontColor || "black",
|
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
fontFamily: "Arial, sans-serif"
|
fontFamily: "Arial, sans-serif"
|
||||||
}}
|
}}
|
||||||
@@ -599,20 +631,16 @@ function PlaceholderType(props) {
|
|||||||
}}
|
}}
|
||||||
className={textWidgetCls}
|
className={textWidgetCls}
|
||||||
style={{
|
style={{
|
||||||
fontSize: props.pos.options?.fontSize
|
fontSize: fontSize,
|
||||||
? props.pos.options?.fontSize + "px"
|
color: fontColor
|
||||||
: "12px",
|
|
||||||
color: props.pos.options?.fontColor || "black"
|
|
||||||
}}
|
}}
|
||||||
cols="50"
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: props.pos.options?.fontSize
|
fontSize: fontSize,
|
||||||
? props.pos.options?.fontSize + "px"
|
color: fontColor,
|
||||||
: "12px",
|
|
||||||
color: props.pos.options?.fontColor || "black",
|
|
||||||
fontFamily: "Arial, sans-serif",
|
fontFamily: "Arial, sans-serif",
|
||||||
overflow: "hidden"
|
overflow: "hidden"
|
||||||
}}
|
}}
|
||||||
@@ -680,7 +708,14 @@ function PlaceholderType(props) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-[12px] text-black items-center overflow-hidden">
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: fontSize,
|
||||||
|
color: fontColor,
|
||||||
|
fontFamily: "Arial, sans-serif"
|
||||||
|
}}
|
||||||
|
className="items-center overflow-hidden"
|
||||||
|
>
|
||||||
<span>
|
<span>
|
||||||
{props.selectDate
|
{props.selectDate
|
||||||
? props.selectDate?.format
|
? props.selectDate?.format
|
||||||
@@ -732,10 +767,8 @@ function PlaceholderType(props) {
|
|||||||
}}
|
}}
|
||||||
className={textWidgetCls}
|
className={textWidgetCls}
|
||||||
style={{
|
style={{
|
||||||
fontSize: props.pos.options?.fontSize
|
fontSize: fontSize,
|
||||||
? props.pos.options?.fontSize + "px"
|
color: fontColor,
|
||||||
: "12px",
|
|
||||||
color: props.pos.options?.fontColor || "black",
|
|
||||||
fontFamily: "Arial, sans-serif"
|
fontFamily: "Arial, sans-serif"
|
||||||
}}
|
}}
|
||||||
cols="50"
|
cols="50"
|
||||||
@@ -743,10 +776,8 @@ function PlaceholderType(props) {
|
|||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: props.pos.options?.fontSize
|
fontSize: fontSize,
|
||||||
? props.pos.options?.fontSize + "px"
|
color: fontColor,
|
||||||
: "12px",
|
|
||||||
color: props.pos.options?.fontColor || "black",
|
|
||||||
fontFamily: "Arial, sans-serif",
|
fontFamily: "Arial, sans-serif",
|
||||||
overflow: "hidden"
|
overflow: "hidden"
|
||||||
}}
|
}}
|
||||||
@@ -761,9 +792,12 @@ function PlaceholderType(props) {
|
|||||||
return (
|
return (
|
||||||
<div key={ind} className="flex items-center text-center gap-0.5">
|
<div key={ind} className="flex items-center text-center gap-0.5">
|
||||||
<input
|
<input
|
||||||
className={`${
|
style={{
|
||||||
ind === 0 ? "mt-0" : "mt-[5px]"
|
width: fontSize,
|
||||||
} ${"w-[15px] h-[15px]"} flex justify-center op-radio`}
|
height: fontSize,
|
||||||
|
marginTop: ind > 0 ? "10px" : "0px"
|
||||||
|
}}
|
||||||
|
className={`flex justify-center op-radio`}
|
||||||
type="radio"
|
type="radio"
|
||||||
disabled={
|
disabled={
|
||||||
props.isNeedSign &&
|
props.isNeedSign &&
|
||||||
@@ -778,7 +812,15 @@ function PlaceholderType(props) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{!props.pos.options?.isHideLabel && (
|
{!props.pos.options?.isHideLabel && (
|
||||||
<label className="text-xs mb-0">{data}</label>
|
<label
|
||||||
|
style={{
|
||||||
|
fontSize: fontSize,
|
||||||
|
color: fontColor
|
||||||
|
}}
|
||||||
|
className="text-xs mb-0"
|
||||||
|
>
|
||||||
|
{data}
|
||||||
|
</label>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -808,10 +850,8 @@ function PlaceholderType(props) {
|
|||||||
className={textWidgetCls}
|
className={textWidgetCls}
|
||||||
style={{
|
style={{
|
||||||
fontFamily: "Arial, sans-serif",
|
fontFamily: "Arial, sans-serif",
|
||||||
fontSize: props.pos.options?.fontSize
|
fontSize: fontSize,
|
||||||
? props.pos.options?.fontSize + "px"
|
color: fontColor
|
||||||
: "12px",
|
|
||||||
color: props.pos.options?.fontColor || "black"
|
|
||||||
}}
|
}}
|
||||||
cols="50"
|
cols="50"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const RecipientList = (props) => {
|
|||||||
//function for onhover signer name change background color
|
//function for onhover signer name change background color
|
||||||
const inputRef = useRef(null);
|
const inputRef = useRef(null);
|
||||||
const isWidgetExist = (Id) => {
|
const isWidgetExist = (Id) => {
|
||||||
return props.signerPos.some((x) => x.Id === Id);
|
return props.signerPos.some((x) => x.Id === Id && x.placeHolder);
|
||||||
};
|
};
|
||||||
|
|
||||||
//handle drag start
|
//handle drag start
|
||||||
@@ -63,9 +63,7 @@ const RecipientList = (props) => {
|
|||||||
remainingItems.splice(index, 0, ...draggedItem);
|
remainingItems.splice(index, 0, ...draggedItem);
|
||||||
//set current draggable recipient details,objectId,index,contract_className ... after replace recipient list
|
//set current draggable recipient details,objectId,index,contract_className ... after replace recipient list
|
||||||
props?.setSignersData(remainingItems);
|
props?.setSignersData(remainingItems);
|
||||||
props?.setSignerObjId(remainingItems[index]?.objectId || "");
|
|
||||||
props?.setIsSelectId(index);
|
props?.setIsSelectId(index);
|
||||||
props?.setContractName(remainingItems[index]?.className || "");
|
|
||||||
props?.setUniqueId(remainingItems[index]?.Id);
|
props?.setUniqueId(remainingItems[index]?.Id);
|
||||||
props?.setRoleName(remainingItems[index]?.Role);
|
props?.setRoleName(remainingItems[index]?.Role);
|
||||||
props?.setBlockColor(remainingItems[index]?.blockColor);
|
props?.setBlockColor(remainingItems[index]?.blockColor);
|
||||||
@@ -121,9 +119,7 @@ const RecipientList = (props) => {
|
|||||||
}}
|
}}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
props.setSignerObjId(obj?.objectId || "");
|
|
||||||
props.setIsSelectId(ind);
|
props.setIsSelectId(ind);
|
||||||
props.setContractName(obj?.className || "");
|
|
||||||
props.setUniqueId(obj.Id);
|
props.setUniqueId(obj.Id);
|
||||||
props.setRoleName(obj.Role);
|
props.setRoleName(obj.Role);
|
||||||
props.setBlockColor(obj?.blockColor);
|
props.setBlockColor(obj?.blockColor);
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ function RenderAllPdfPage({
|
|||||||
pageNumber,
|
pageNumber,
|
||||||
signerPos,
|
signerPos,
|
||||||
signerObjectId,
|
signerObjectId,
|
||||||
containerWH
|
containerWH,
|
||||||
|
pdfRotateBase64
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [signPageNumber, setSignPageNumber] = useState([]);
|
const [signPageNumber, setSignPageNumber] = useState([]);
|
||||||
@@ -66,6 +67,7 @@ function RenderAllPdfPage({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
const pdfDataBase64 = `data:application/pdf;base64,${pdfRotateBase64}`;
|
||||||
return (
|
return (
|
||||||
<div ref={pageContainer} className="hidden w-[20%] bg-base-100 md:block">
|
<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">
|
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
|
||||||
@@ -78,7 +80,7 @@ function RenderAllPdfPage({
|
|||||||
<Document
|
<Document
|
||||||
loading={t("loading-doc")}
|
loading={t("loading-doc")}
|
||||||
onLoadSuccess={onDocumentLoad}
|
onLoadSuccess={onDocumentLoad}
|
||||||
file={signPdfUrl}
|
file={(pdfRotateBase64 && pdfDataBase64) || signPdfUrl}
|
||||||
>
|
>
|
||||||
{Array.from(new Array(allPages), (el, index) => (
|
{Array.from(new Array(allPages), (el, index) => (
|
||||||
<div
|
<div
|
||||||
@@ -95,16 +97,16 @@ function RenderAllPdfPage({
|
|||||||
>
|
>
|
||||||
{signerPos && addSignatureBookmark(index)}
|
{signerPos && addSignatureBookmark(index)}
|
||||||
|
|
||||||
<div className="relative z-[1] overflow-hidden">
|
{/* <div className="relative z-[1] overflow-hidden"> */}
|
||||||
<Page
|
<Page
|
||||||
key={`page_${index + 1}`}
|
key={`page_${index + 1}`}
|
||||||
pageNumber={index + 1}
|
pageNumber={index + 1}
|
||||||
width={pageWidth - 60}
|
width={pageWidth - 60}
|
||||||
scale={1}
|
scale={1}
|
||||||
renderAnnotationLayer={false}
|
renderAnnotationLayer={false}
|
||||||
renderTextLayer={false}
|
renderTextLayer={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
{/* </div> */}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</Document>
|
</Document>
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ function RenderPdf({
|
|||||||
setUniqueId,
|
setUniqueId,
|
||||||
signersdata,
|
signersdata,
|
||||||
setIsPageCopy,
|
setIsPageCopy,
|
||||||
setSignerObjId,
|
|
||||||
setShowDropdown,
|
setShowDropdown,
|
||||||
setIsInitial,
|
setIsInitial,
|
||||||
setIsValidate,
|
setIsValidate,
|
||||||
@@ -61,10 +60,16 @@ function RenderPdf({
|
|||||||
scale,
|
scale,
|
||||||
setIsSelectId,
|
setIsSelectId,
|
||||||
ispublicTemplate,
|
ispublicTemplate,
|
||||||
handleUserDetails
|
handleUserDetails,
|
||||||
|
pdfRotateBase64,
|
||||||
|
fontSize,
|
||||||
|
setFontSize,
|
||||||
|
fontColor,
|
||||||
|
setFontColor
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const isMobile = window.innerWidth < 767;
|
const isMobile = window.innerWidth < 767;
|
||||||
|
|
||||||
//check isGuestSigner is present in local if yes than handle login flow header in mobile view
|
//check isGuestSigner is present in local if yes than handle login flow header in mobile view
|
||||||
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
||||||
|
|
||||||
@@ -248,155 +253,180 @@ function RenderPdf({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const pdfDataBase64 = `data:application/pdf;base64,${pdfRotateBase64}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{successEmail && (
|
{successEmail && (
|
||||||
<Alert type={"success"}>{t("success-email-alert")}</Alert>
|
<Alert type={"success"}>{t("success-email-alert")}</Alert>
|
||||||
)}
|
)}
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
<div
|
<RSC
|
||||||
data-tut="reactourForth"
|
style={{
|
||||||
className={`${
|
position: "relative",
|
||||||
isGuestSigner ? "30px" : ""
|
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
|
||||||
} border-[0.1px] border-[#ebe8e8]`}
|
height: window.innerHeight - 200,
|
||||||
ref={drop}
|
zIndex: 0
|
||||||
id="container"
|
}}
|
||||||
|
className="h-full"
|
||||||
|
noScrollY={false}
|
||||||
|
noScrollX={scale === 1 ? true : false}
|
||||||
>
|
>
|
||||||
{containerWH?.width &&
|
<div
|
||||||
pdfOriginalWH.length > 0 &&
|
data-tut="reactourForth"
|
||||||
(pdfRequest
|
className={`${
|
||||||
? signerPos.map((data, key) => {
|
isGuestSigner ? "30px" : ""
|
||||||
return (
|
} border-[0.1px] border-[#ebe8e8] overflow-x-auto`}
|
||||||
<React.Fragment key={key}>
|
style={{
|
||||||
{checkSignedSigners(data)}
|
width: containerWH?.width && containerWH?.width * scale
|
||||||
</React.Fragment>
|
}}
|
||||||
);
|
ref={drop}
|
||||||
})
|
id="container"
|
||||||
: placeholder // placeholder mobile
|
>
|
||||||
? signerPos.map((data, ind) => {
|
{containerWH?.width &&
|
||||||
|
pdfOriginalWH.length > 0 &&
|
||||||
|
(pdfRequest
|
||||||
|
? signerPos.map((data, key) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={ind}>
|
<React.Fragment key={key}>
|
||||||
{data.placeHolder.map((placeData, index) => {
|
{checkSignedSigners(data)}
|
||||||
return (
|
|
||||||
<React.Fragment key={index}>
|
|
||||||
{placeData.pageNumber === pageNumber &&
|
|
||||||
placeData.pos.map((pos) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={pos.key}>
|
|
||||||
<Placeholder
|
|
||||||
pos={pos}
|
|
||||||
setIsPageCopy={setIsPageCopy}
|
|
||||||
setSignKey={setSignKey}
|
|
||||||
handleDeleteSign={handleDeleteSign}
|
|
||||||
setIsStamp={setIsStamp}
|
|
||||||
handleTabDrag={handleTabDrag}
|
|
||||||
handleStop={handleStop}
|
|
||||||
handleSignYourselfImageResize={
|
|
||||||
handleImageResize
|
|
||||||
}
|
|
||||||
index={pageNumber}
|
|
||||||
xyPostion={signerPos}
|
|
||||||
setXyPostion={setSignerPos}
|
|
||||||
setSignerObjId={setSignerObjId}
|
|
||||||
data={data}
|
|
||||||
setIsResize={setIsResize}
|
|
||||||
setShowDropdown={setShowDropdown}
|
|
||||||
isShowBorder={true}
|
|
||||||
isPlaceholder={true}
|
|
||||||
setUniqueId={setUniqueId}
|
|
||||||
handleLinkUser={handleLinkUser}
|
|
||||||
handleUserName={handleUserName}
|
|
||||||
isSignYourself={false}
|
|
||||||
posWidth={posWidth}
|
|
||||||
posHeight={posHeight}
|
|
||||||
isDragging={isDragging}
|
|
||||||
setIsValidate={setIsValidate}
|
|
||||||
setWidgetType={setWidgetType}
|
|
||||||
setIsRadio={setIsRadio}
|
|
||||||
setIsCheckbox={setIsCheckbox}
|
|
||||||
setCurrWidgetsDetails={
|
|
||||||
setCurrWidgetsDetails
|
|
||||||
}
|
|
||||||
setSelectWidgetId={setSelectWidgetId}
|
|
||||||
selectWidgetId={selectWidgetId}
|
|
||||||
handleNameModal={handleNameModal}
|
|
||||||
setTempSignerId={setTempSignerId}
|
|
||||||
uniqueId={uniqueId}
|
|
||||||
handleTextSettingModal={
|
|
||||||
handleTextSettingModal
|
|
||||||
}
|
|
||||||
scale={scale}
|
|
||||||
containerWH={containerWH}
|
|
||||||
pdfOriginalWH={pdfOriginalWH}
|
|
||||||
pageNumber={pageNumber}
|
|
||||||
setIsSelectId={setIsSelectId}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
: xyPostion.map((data, ind) => {
|
: placeholder // placeholder mobile
|
||||||
return (
|
? signerPos?.map((data, ind) => {
|
||||||
<React.Fragment key={ind}>
|
return (
|
||||||
{data.pageNumber === pageNumber &&
|
<React.Fragment key={ind}>
|
||||||
data.pos.map((pos) => {
|
{data?.placeHolder &&
|
||||||
return (
|
data?.placeHolder.map((placeData, index) => {
|
||||||
pos && (
|
return (
|
||||||
<Placeholder
|
<React.Fragment key={index}>
|
||||||
pos={pos}
|
{placeData.pageNumber === pageNumber &&
|
||||||
setIsPageCopy={setIsPageCopy}
|
placeData.pos.map((pos) => {
|
||||||
setSignKey={setSignKey}
|
return (
|
||||||
handleDeleteSign={handleDeleteSign}
|
<React.Fragment key={pos.key}>
|
||||||
setIsStamp={setIsStamp}
|
<Placeholder
|
||||||
handleTabDrag={handleTabDrag}
|
pos={pos}
|
||||||
handleStop={handleStop}
|
setIsPageCopy={setIsPageCopy}
|
||||||
handleSignYourselfImageResize={
|
setSignKey={setSignKey}
|
||||||
handleSignYourselfImageResize
|
handleDeleteSign={handleDeleteSign}
|
||||||
}
|
setIsStamp={setIsStamp}
|
||||||
index={index}
|
handleTabDrag={handleTabDrag}
|
||||||
xyPostion={xyPostion}
|
handleStop={handleStop}
|
||||||
setXyPostion={setXyPostion}
|
handleSignYourselfImageResize={
|
||||||
containerWH={containerWH}
|
handleImageResize
|
||||||
setIsSignPad={setIsSignPad}
|
}
|
||||||
isShowBorder={true}
|
index={pageNumber}
|
||||||
isSignYourself={true}
|
xyPostion={signerPos}
|
||||||
posWidth={posWidth}
|
setXyPostion={setSignerPos}
|
||||||
posHeight={posHeight}
|
data={data}
|
||||||
pdfDetails={pdfDetails[0]}
|
setIsResize={setIsResize}
|
||||||
isDragging={isDragging}
|
setShowDropdown={setShowDropdown}
|
||||||
setIsInitial={setIsInitial}
|
isShowBorder={true}
|
||||||
setWidgetType={setWidgetType}
|
isPlaceholder={true}
|
||||||
setSelectWidgetId={setSelectWidgetId}
|
setUniqueId={setUniqueId}
|
||||||
selectWidgetId={selectWidgetId}
|
handleLinkUser={handleLinkUser}
|
||||||
handleUserName={handleUserName}
|
handleUserName={handleUserName}
|
||||||
setIsCheckbox={setIsCheckbox}
|
isSignYourself={false}
|
||||||
setValidateAlert={setValidateAlert}
|
posWidth={posWidth}
|
||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
posHeight={posHeight}
|
||||||
handleTextSettingModal={
|
isDragging={isDragging}
|
||||||
handleTextSettingModal
|
setIsValidate={setIsValidate}
|
||||||
}
|
setWidgetType={setWidgetType}
|
||||||
scale={scale}
|
setIsRadio={setIsRadio}
|
||||||
pdfOriginalWH={pdfOriginalWH}
|
setIsCheckbox={setIsCheckbox}
|
||||||
pageNumber={pageNumber}
|
setCurrWidgetsDetails={
|
||||||
/>
|
setCurrWidgetsDetails
|
||||||
)
|
}
|
||||||
);
|
setSelectWidgetId={
|
||||||
})}
|
setSelectWidgetId
|
||||||
</React.Fragment>
|
}
|
||||||
);
|
selectWidgetId={selectWidgetId}
|
||||||
}))}
|
handleNameModal={handleNameModal}
|
||||||
|
setTempSignerId={setTempSignerId}
|
||||||
|
uniqueId={uniqueId}
|
||||||
|
handleTextSettingModal={
|
||||||
|
handleTextSettingModal
|
||||||
|
}
|
||||||
|
scale={scale}
|
||||||
|
containerWH={containerWH}
|
||||||
|
pdfOriginalWH={pdfOriginalWH}
|
||||||
|
pageNumber={pageNumber}
|
||||||
|
setIsSelectId={setIsSelectId}
|
||||||
|
fontSize={fontSize}
|
||||||
|
setFontSize={setFontSize}
|
||||||
|
fontColor={fontColor}
|
||||||
|
setFontColor={setFontColor}
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: !pdfDetails?.[0]?.IsCompleted &&
|
||||||
|
xyPostion.map((data, ind) => {
|
||||||
|
return (
|
||||||
|
<React.Fragment key={ind}>
|
||||||
|
{data.pageNumber === pageNumber &&
|
||||||
|
data.pos.map((pos) => {
|
||||||
|
return (
|
||||||
|
pos && (
|
||||||
|
<Placeholder
|
||||||
|
pos={pos}
|
||||||
|
setIsPageCopy={setIsPageCopy}
|
||||||
|
setSignKey={setSignKey}
|
||||||
|
handleDeleteSign={handleDeleteSign}
|
||||||
|
setIsStamp={setIsStamp}
|
||||||
|
handleTabDrag={handleTabDrag}
|
||||||
|
handleStop={handleStop}
|
||||||
|
handleSignYourselfImageResize={
|
||||||
|
handleSignYourselfImageResize
|
||||||
|
}
|
||||||
|
index={index}
|
||||||
|
xyPostion={xyPostion}
|
||||||
|
setXyPostion={setXyPostion}
|
||||||
|
containerWH={containerWH}
|
||||||
|
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}
|
||||||
|
pdfOriginalWH={pdfOriginalWH}
|
||||||
|
pageNumber={pageNumber}
|
||||||
|
fontSize={fontSize}
|
||||||
|
setFontSize={setFontSize}
|
||||||
|
fontColor={fontColor}
|
||||||
|
setFontColor={setFontColor}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}))}
|
||||||
|
|
||||||
{/* this component for render pdf document is in middle of the component */}
|
|
||||||
<div className="flex items-center justify-center">
|
|
||||||
<Document
|
<Document
|
||||||
onLoadError={() => {
|
onLoadError={() => setPdfLoad(false)}
|
||||||
setPdfLoad(false);
|
|
||||||
}}
|
|
||||||
loading={t("loading-doc")}
|
loading={t("loading-doc")}
|
||||||
onLoadSuccess={pageDetails}
|
onLoadSuccess={pageDetails}
|
||||||
// ref={pdfRef}'
|
// ref={pdfRef}'
|
||||||
@@ -405,9 +435,14 @@ function RenderPdf({
|
|||||||
setSelectWidgetId("");
|
setSelectWidgetId("");
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
file={pdfDetails[0]?.SignedUrl || pdfDetails[0]?.URL}
|
file={
|
||||||
|
(pdfRotateBase64 && pdfDataBase64) ||
|
||||||
|
pdfDetails[0]?.SignedUrl ||
|
||||||
|
pdfDetails[0].URL
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Page
|
<Page
|
||||||
|
scale={scale || 1}
|
||||||
key={index}
|
key={index}
|
||||||
pageNumber={pageNumber}
|
pageNumber={pageNumber}
|
||||||
width={containerWH.width}
|
width={containerWH.width}
|
||||||
@@ -419,7 +454,7 @@ function RenderPdf({
|
|||||||
/>
|
/>
|
||||||
</Document>
|
</Document>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</RSC>
|
||||||
) : (
|
) : (
|
||||||
<RSC
|
<RSC
|
||||||
style={{
|
style={{
|
||||||
@@ -453,71 +488,78 @@ function RenderPdf({
|
|||||||
? signerPos.map((data, ind) => {
|
? signerPos.map((data, ind) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={ind}>
|
<React.Fragment key={ind}>
|
||||||
{data.placeHolder.map((placeData, index) => {
|
{data?.placeHolder &&
|
||||||
return (
|
data?.placeHolder.map((placeData, index) => {
|
||||||
<React.Fragment key={index}>
|
return (
|
||||||
{placeData.pageNumber === pageNumber &&
|
<React.Fragment key={index}>
|
||||||
placeData.pos.map((pos) => {
|
{placeData.pageNumber === pageNumber &&
|
||||||
return (
|
placeData.pos.map((pos) => {
|
||||||
<React.Fragment key={pos.key}>
|
return (
|
||||||
<Placeholder
|
<React.Fragment key={pos.key}>
|
||||||
pos={pos}
|
<Placeholder
|
||||||
setIsPageCopy={setIsPageCopy}
|
pos={pos}
|
||||||
setSignKey={setSignKey}
|
setIsPageCopy={setIsPageCopy}
|
||||||
handleDeleteSign={handleDeleteSign}
|
setSignKey={setSignKey}
|
||||||
setIsStamp={setIsStamp}
|
handleDeleteSign={handleDeleteSign}
|
||||||
handleTabDrag={handleTabDrag}
|
setIsStamp={setIsStamp}
|
||||||
handleStop={handleStop}
|
handleTabDrag={handleTabDrag}
|
||||||
handleSignYourselfImageResize={
|
handleStop={handleStop}
|
||||||
handleImageResize
|
handleSignYourselfImageResize={
|
||||||
}
|
handleImageResize
|
||||||
index={pageNumber}
|
}
|
||||||
xyPostion={signerPos}
|
index={pageNumber}
|
||||||
setXyPostion={setSignerPos}
|
xyPostion={signerPos}
|
||||||
setSignerObjId={setSignerObjId}
|
setXyPostion={setSignerPos}
|
||||||
data={data}
|
data={data}
|
||||||
setIsResize={setIsResize}
|
setIsResize={setIsResize}
|
||||||
setShowDropdown={setShowDropdown}
|
setShowDropdown={setShowDropdown}
|
||||||
isShowBorder={true}
|
isShowBorder={true}
|
||||||
isPlaceholder={true}
|
isPlaceholder={true}
|
||||||
setUniqueId={setUniqueId}
|
setUniqueId={setUniqueId}
|
||||||
handleLinkUser={handleLinkUser}
|
handleLinkUser={handleLinkUser}
|
||||||
handleUserName={handleUserName}
|
handleUserName={handleUserName}
|
||||||
isSignYourself={false}
|
isSignYourself={false}
|
||||||
posWidth={posWidth}
|
posWidth={posWidth}
|
||||||
posHeight={posHeight}
|
posHeight={posHeight}
|
||||||
isDragging={isDragging}
|
isDragging={isDragging}
|
||||||
setIsValidate={setIsValidate}
|
setIsValidate={setIsValidate}
|
||||||
setWidgetType={setWidgetType}
|
setWidgetType={setWidgetType}
|
||||||
setIsRadio={setIsRadio}
|
setIsRadio={setIsRadio}
|
||||||
setIsCheckbox={setIsCheckbox}
|
setIsCheckbox={setIsCheckbox}
|
||||||
setCurrWidgetsDetails={
|
setCurrWidgetsDetails={
|
||||||
setCurrWidgetsDetails
|
setCurrWidgetsDetails
|
||||||
}
|
}
|
||||||
setSelectWidgetId={setSelectWidgetId}
|
setSelectWidgetId={
|
||||||
selectWidgetId={selectWidgetId}
|
setSelectWidgetId
|
||||||
handleNameModal={handleNameModal}
|
}
|
||||||
setTempSignerId={setTempSignerId}
|
selectWidgetId={selectWidgetId}
|
||||||
uniqueId={uniqueId}
|
handleNameModal={handleNameModal}
|
||||||
handleTextSettingModal={
|
setTempSignerId={setTempSignerId}
|
||||||
handleTextSettingModal
|
uniqueId={uniqueId}
|
||||||
}
|
handleTextSettingModal={
|
||||||
scale={scale}
|
handleTextSettingModal
|
||||||
containerWH={containerWH}
|
}
|
||||||
pdfOriginalWH={pdfOriginalWH}
|
scale={scale}
|
||||||
pageNumber={pageNumber}
|
containerWH={containerWH}
|
||||||
setIsSelectId={setIsSelectId}
|
pdfOriginalWH={pdfOriginalWH}
|
||||||
/>
|
pageNumber={pageNumber}
|
||||||
</React.Fragment>
|
setIsSelectId={setIsSelectId}
|
||||||
);
|
fontSize={fontSize}
|
||||||
})}
|
setFontSize={setFontSize}
|
||||||
</React.Fragment>
|
fontColor={fontColor}
|
||||||
);
|
setFontColor={setFontColor}
|
||||||
})}
|
/>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
: xyPostion.map((data, ind) => {
|
: !pdfDetails?.[0]?.IsCompleted &&
|
||||||
|
xyPostion?.map((data, ind) => {
|
||||||
// signyourself flow
|
// signyourself flow
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={ind}>
|
<React.Fragment key={ind}>
|
||||||
@@ -565,6 +607,10 @@ function RenderPdf({
|
|||||||
containerWH={containerWH}
|
containerWH={containerWH}
|
||||||
pdfOriginalWH={pdfOriginalWH}
|
pdfOriginalWH={pdfOriginalWH}
|
||||||
pageNumber={pageNumber}
|
pageNumber={pageNumber}
|
||||||
|
fontSize={fontSize}
|
||||||
|
setFontSize={setFontSize}
|
||||||
|
fontColor={fontColor}
|
||||||
|
setFontColor={setFontColor}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
@@ -575,9 +621,7 @@ function RenderPdf({
|
|||||||
|
|
||||||
{/* this component for render pdf document is in middle of the component */}
|
{/* this component for render pdf document is in middle of the component */}
|
||||||
<Document
|
<Document
|
||||||
onLoadError={() => {
|
onLoadError={() => setPdfLoad(false)}
|
||||||
setPdfLoad(false);
|
|
||||||
}}
|
|
||||||
loading={t("loading-doc")}
|
loading={t("loading-doc")}
|
||||||
onLoadSuccess={pageDetails}
|
onLoadSuccess={pageDetails}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -586,7 +630,11 @@ function RenderPdf({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
// ref={pdfRef}
|
// ref={pdfRef}
|
||||||
file={pdfDetails[0]?.SignedUrl || pdfDetails[0].URL}
|
file={
|
||||||
|
(pdfRotateBase64 && pdfDataBase64) ||
|
||||||
|
pdfDetails[0]?.SignedUrl ||
|
||||||
|
pdfDetails[0].URL
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Page
|
<Page
|
||||||
key={index}
|
key={index}
|
||||||
|
|||||||
@@ -21,15 +21,15 @@ function SelectLanguage(props) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
!props.isProfile && " mt-3 pb-2 md:pb-0 "
|
!props.isProfile && " mt-[9px] pb-2 md:pb-0 "
|
||||||
} flex justify-center items-center `}
|
} flex justify-center items-center `}
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
value={lang}
|
value={lang}
|
||||||
onChange={handleChangeLang}
|
onChange={handleChangeLang}
|
||||||
className={`${
|
className={`${
|
||||||
!props.isProfile && " md:w-[15%] w-[50%]"
|
!props.isProfile ? " md:w-[15%] w-[50%]" : "w-[180px]"
|
||||||
} op-select op-select-bordered bg-white op-select-sm`}
|
} op-select op-select-bordered bg-white op-select-sm `}
|
||||||
>
|
>
|
||||||
<option disabled selected>
|
<option disabled selected>
|
||||||
select
|
select
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ function SignPad({
|
|||||||
const [isTab, setIsTab] = useState("draw");
|
const [isTab, setIsTab] = useState("draw");
|
||||||
const [isSignImg, setIsSignImg] = useState("");
|
const [isSignImg, setIsSignImg] = useState("");
|
||||||
const [signValue, setSignValue] = useState("");
|
const [signValue, setSignValue] = useState("");
|
||||||
const [textWidth, setTextWidth] = useState(null);
|
const [textWidth, setTextWidth] = useState(0);
|
||||||
const [textHeight, setTextHeight] = useState(null);
|
const [textHeight, setTextHeight] = useState(0);
|
||||||
const [signatureType, setSignatureType] = useState("draw");
|
const [signatureType, setSignatureType] = useState("draw");
|
||||||
const fontOptions = [
|
const fontOptions = [
|
||||||
{ value: "Fasthand" },
|
{ value: "Fasthand" },
|
||||||
@@ -51,7 +51,7 @@ function SignPad({
|
|||||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
);
|
);
|
||||||
const jsonSender = JSON.parse(senderUser);
|
const jsonSender = JSON.parse(senderUser);
|
||||||
const currentUserName = jsonSender && jsonSender.name;
|
const currentUserName = jsonSender && jsonSender?.name;
|
||||||
|
|
||||||
//function for clear signature image
|
//function for clear signature image
|
||||||
const handleClear = () => {
|
const handleClear = () => {
|
||||||
@@ -137,7 +137,7 @@ function SignPad({
|
|||||||
(isTab === "draw" && isSignImg) ||
|
(isTab === "draw" && isSignImg) ||
|
||||||
(isTab === "image" && image) ||
|
(isTab === "image" && image) ||
|
||||||
(isTab === "mysignature" && isDefaultSign) ||
|
(isTab === "mysignature" && isDefaultSign) ||
|
||||||
(isTab === "type" && textWidth)
|
(isTab === "type" && signValue)
|
||||||
? false
|
? false
|
||||||
: image
|
: image
|
||||||
? false
|
? false
|
||||||
@@ -169,10 +169,10 @@ function SignPad({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const trimmedName = currentUserName && currentUserName.trim();
|
const trimmedName = currentUserName && currentUserName?.trim();
|
||||||
const firstCharacter = trimmedName?.charAt(0);
|
const firstCharacter = trimmedName?.charAt(0);
|
||||||
const userName = isInitial ? firstCharacter : currentUserName;
|
const userName = isInitial ? firstCharacter : currentUserName;
|
||||||
setSignValue(userName);
|
setSignValue(userName || "");
|
||||||
setFontSelect("Fasthand");
|
setFontSelect("Fasthand");
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
@@ -200,8 +200,10 @@ function SignPad({
|
|||||||
canvasRef.current.fromDataURL(isSignImg);
|
canvasRef.current.fromDataURL(isSignImg);
|
||||||
}
|
}
|
||||||
if (isTab === "type") {
|
if (isTab === "type") {
|
||||||
const trimmedName = signValue ? signValue.trim() : currentUserName.trim();
|
const trimmedName = signValue
|
||||||
const firstCharacter = trimmedName.charAt(0);
|
? signValue?.trim()
|
||||||
|
: currentUserName?.trim();
|
||||||
|
const firstCharacter = trimmedName?.charAt(0);
|
||||||
const userName = isInitial ? firstCharacter : signValue;
|
const userName = isInitial ? firstCharacter : signValue;
|
||||||
setSignValue(userName);
|
setSignValue(userName);
|
||||||
convertToImg(fontSelect, userName);
|
convertToImg(fontSelect, userName);
|
||||||
|
|||||||
@@ -56,9 +56,7 @@ function VerifyEmail(props) {
|
|||||||
<button
|
<button
|
||||||
className="op-btn op-btn-primary"
|
className="op-btn op-btn-primary"
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={() => {
|
onClick={() => props.handleVerifyBtn()}
|
||||||
props.handleVerifyBtn();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{t("send-otp")}
|
{t("send-otp")}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ function WidgetComponent({
|
|||||||
addPositionOfSignature,
|
addPositionOfSignature,
|
||||||
signersdata,
|
signersdata,
|
||||||
isSelectListId,
|
isSelectListId,
|
||||||
setSignerObjId,
|
|
||||||
setIsSelectId,
|
setIsSelectId,
|
||||||
setContractName,
|
|
||||||
isSigners,
|
isSigners,
|
||||||
dataTut,
|
dataTut,
|
||||||
isMailSend,
|
isMailSend,
|
||||||
@@ -360,9 +358,7 @@ function WidgetComponent({
|
|||||||
signerPos={signerPos}
|
signerPos={signerPos}
|
||||||
signersdata={signersdata}
|
signersdata={signersdata}
|
||||||
isSelectListId={isSelectListId}
|
isSelectListId={isSelectListId}
|
||||||
setSignerObjId={setSignerObjId}
|
|
||||||
setIsSelectId={setIsSelectId}
|
setIsSelectId={setIsSelectId}
|
||||||
setContractName={setContractName}
|
|
||||||
setUniqueId={setUniqueId}
|
setUniqueId={setUniqueId}
|
||||||
setRoleName={setRoleName}
|
setRoleName={setRoleName}
|
||||||
handleDeleteUser={handleDeleteUser}
|
handleDeleteUser={handleDeleteUser}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import Select from "react-select";
|
import AsyncSelect from "react-select/async";
|
||||||
import AddSigner from "../../AddSigner";
|
import AddSigner from "../../AddSigner";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import Tooltip from "../../../primitives/Tooltip";
|
import Tooltip from "../../../primitives/Tooltip";
|
||||||
@@ -35,7 +35,6 @@ const AddSignerModal = ({ isOpen, children }) => {
|
|||||||
const SignersInput = (props) => {
|
const SignersInput = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [state, setState] = useState(undefined);
|
const [state, setState] = useState(undefined);
|
||||||
// const [editFormData, setEditFormData] = useState([]);
|
|
||||||
const [selected, setSelected] = useState([]);
|
const [selected, setSelected] = useState([]);
|
||||||
const [isModal, setIsModel] = useState(false);
|
const [isModal, setIsModel] = useState(false);
|
||||||
const onChange = (selectedOptions) => setSelected(selectedOptions);
|
const onChange = (selectedOptions) => setSelected(selectedOptions);
|
||||||
@@ -46,40 +45,6 @@ const SignersInput = (props) => {
|
|||||||
setSelected(newValue);
|
setSelected(newValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
const GetSelectListData = async () => {
|
|
||||||
try {
|
|
||||||
const currentUser = Parse.User.current();
|
|
||||||
const contactbook = new Parse.Query("contracts_Contactbook");
|
|
||||||
contactbook.equalTo(
|
|
||||||
"CreatedBy",
|
|
||||||
Parse.User.createWithoutData(currentUser.id)
|
|
||||||
);
|
|
||||||
contactbook.notEqualTo("IsDeleted", true);
|
|
||||||
const contactRes = await contactbook.find();
|
|
||||||
if (contactRes) {
|
|
||||||
const res = JSON.parse(JSON.stringify(contactRes));
|
|
||||||
let list = [];
|
|
||||||
|
|
||||||
// let _selected = [];
|
|
||||||
res.forEach((x) => {
|
|
||||||
let obj = {
|
|
||||||
label: x.Name,
|
|
||||||
value: x.objectId,
|
|
||||||
isChecked: true
|
|
||||||
};
|
|
||||||
|
|
||||||
list.push(obj);
|
|
||||||
});
|
|
||||||
setState(list);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log("err", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
GetSelectListData();
|
|
||||||
}, []);
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.isReset && props.isReset === true) {
|
if (props.isReset && props.isReset === true) {
|
||||||
setSelected([]);
|
setSelected([]);
|
||||||
@@ -118,7 +83,46 @@ const SignersInput = (props) => {
|
|||||||
setSelected([data]);
|
setSelected([data]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const loadOptions = async (inputValue) => {
|
||||||
|
try {
|
||||||
|
const currentUser = Parse.User.current();
|
||||||
|
const contactbook = new Parse.Query("contracts_Contactbook");
|
||||||
|
contactbook.equalTo(
|
||||||
|
"CreatedBy",
|
||||||
|
Parse.User.createWithoutData(currentUser.id)
|
||||||
|
);
|
||||||
|
if (inputValue.length > 1) {
|
||||||
|
contactbook.matches("Name", new RegExp(inputValue, "i"));
|
||||||
|
}
|
||||||
|
contactbook.notEqualTo("IsDeleted", true);
|
||||||
|
const contactRes = await contactbook.find();
|
||||||
|
if (contactRes) {
|
||||||
|
const res = JSON.parse(JSON.stringify(contactRes));
|
||||||
|
//compareArrays is a function where compare between two array (total signersList and dcument signers list)
|
||||||
|
//and filter signers from total signer's list which already present in document's signers list
|
||||||
|
const compareArrays = (res, signerObj) => {
|
||||||
|
return res.filter(
|
||||||
|
(item1) =>
|
||||||
|
!signerObj.find((item2) => item2.objectId === item1.objectId)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//get update signer's List if signersdata is present
|
||||||
|
const updateSignersList =
|
||||||
|
props?.signersData && compareArrays(res, props?.signersData);
|
||||||
|
|
||||||
|
const result = updateSignersList ? updateSignersList : res;
|
||||||
|
setState(result);
|
||||||
|
return await result.map((item) => ({
|
||||||
|
label: item.Name,
|
||||||
|
value: item.objectId,
|
||||||
|
isChecked: true
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log("err", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="text-xs mt-2 ">
|
<div className="text-xs mt-2 ">
|
||||||
<label className="block relative">
|
<label className="block relative">
|
||||||
@@ -130,16 +134,20 @@ const SignersInput = (props) => {
|
|||||||
</label>
|
</label>
|
||||||
<div className="flex gap-x-[5px]">
|
<div className="flex gap-x-[5px]">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<Select
|
<AsyncSelect
|
||||||
onSortEnd={onSortEnd}
|
onSortEnd={onSortEnd}
|
||||||
distance={4}
|
distance={4}
|
||||||
isMulti
|
isMulti
|
||||||
|
cacheOptions
|
||||||
|
defaultOptions
|
||||||
options={state || []}
|
options={state || []}
|
||||||
value={selected}
|
value={selected}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
closeMenuOnSelect={false}
|
closeMenuOnSelect={false}
|
||||||
required={props.required}
|
required={props.required}
|
||||||
|
loadingMessage={() => t("loading")}
|
||||||
noOptionsMessage={() => t("contact-not-found")}
|
noOptionsMessage={() => t("contact-not-found")}
|
||||||
|
loadOptions={loadOptions}
|
||||||
unstyled
|
unstyled
|
||||||
classNames={{
|
classNames={{
|
||||||
control: () =>
|
control: () =>
|
||||||
|
|||||||
+352
-119
@@ -1,7 +1,7 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { rgb } from "pdf-lib";
|
import { PDFDocument, rgb, degrees } from "pdf-lib";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import { appInfo } from "./appinfo";
|
import { appInfo } from "./appinfo";
|
||||||
import { saveAs } from "file-saver";
|
import { saveAs } from "file-saver";
|
||||||
@@ -33,14 +33,15 @@ export const openInNewTab = (url, target) => {
|
|||||||
export async function fetchSubscription(
|
export async function fetchSubscription(
|
||||||
extUserId,
|
extUserId,
|
||||||
contactObjId,
|
contactObjId,
|
||||||
isGuestSign = false
|
isGuestSign = false,
|
||||||
|
isPublic = false
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const Extand_Class = localStorage.getItem("Extand_Class");
|
const Extand_Class = localStorage.getItem("Extand_Class");
|
||||||
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
||||||
// console.log("extClass ", extClass);
|
// console.log("extClass ", extClass);
|
||||||
let extUser;
|
let extUser;
|
||||||
if (extClass && extClass.length > 0) {
|
if (extClass && extClass.length > 0 && !isPublic) {
|
||||||
extUser = extClass[0].objectId;
|
extUser = extClass[0].objectId;
|
||||||
} else {
|
} else {
|
||||||
extUser = extUserId;
|
extUser = extUserId;
|
||||||
@@ -54,20 +55,70 @@ export async function fetchSubscription(
|
|||||||
};
|
};
|
||||||
const params = isGuestSign
|
const params = isGuestSign
|
||||||
? { contactId: contactObjId }
|
? { contactId: contactObjId }
|
||||||
: { extUserId: extUser };
|
: { extUserId: extUser, ispublic: isPublic };
|
||||||
const tenatRes = await axios.post(url, params, { headers: headers });
|
const tenatRes = await axios.post(url, params, { headers: headers });
|
||||||
let plan, status, billingDate;
|
let plan, status, billingDate, adminId;
|
||||||
if (isGuestSign) {
|
if (isGuestSign) {
|
||||||
plan = tenatRes.data?.result?.result?.plan;
|
plan = tenatRes.data?.result?.result?.plan;
|
||||||
status = tenatRes.data?.result?.result?.isSubscribed;
|
status = tenatRes.data?.result?.result?.isSubscribed;
|
||||||
} else {
|
} else {
|
||||||
plan = tenatRes.data?.result?.result?.PlanCode;
|
plan = tenatRes.data?.result?.result?.PlanCode;
|
||||||
billingDate = tenatRes.data?.result?.result?.Next_billing_date?.iso;
|
billingDate = tenatRes.data?.result?.result?.Next_billing_date?.iso;
|
||||||
|
const allowedUsers = tenatRes.data?.result?.result?.AllowedUsers || 0;
|
||||||
|
adminId = tenatRes?.data?.result?.result?.ExtUserPtr?.objectId;
|
||||||
|
localStorage.setItem("allowedUsers", allowedUsers);
|
||||||
}
|
}
|
||||||
return { plan, billingDate, status };
|
return { plan, billingDate, status, adminId };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Err in fetch subscription", err);
|
console.log("Err in fetch subscription", err);
|
||||||
return { plan: "", billingDate: "" };
|
return { plan: "", billingDate: "", status: "", adminId: "" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchSubscriptionInfo() {
|
||||||
|
try {
|
||||||
|
const Extand_Class = localStorage.getItem("Extand_Class");
|
||||||
|
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
||||||
|
// console.log("extClass ", extClass);
|
||||||
|
if (extClass && extClass.length > 0) {
|
||||||
|
const extUser = extClass[0].objectId;
|
||||||
|
const baseURL = localStorage.getItem("baseUrl");
|
||||||
|
const url = `${baseURL}functions/getsubscriptions`;
|
||||||
|
const headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
|
};
|
||||||
|
const params = { extUserId: extUser };
|
||||||
|
const tenatRes = await axios.post(url, params, { headers: headers });
|
||||||
|
|
||||||
|
const price =
|
||||||
|
tenatRes.data?.result?.result?.SubscriptionDetails?.data?.subscription
|
||||||
|
?.plan?.price;
|
||||||
|
const totalPrice =
|
||||||
|
tenatRes.data?.result?.result?.SubscriptionDetails?.data?.subscription
|
||||||
|
?.amount;
|
||||||
|
const planId =
|
||||||
|
tenatRes.data?.result?.result?.SubscriptionDetails?.data?.subscription
|
||||||
|
?.subscription_id;
|
||||||
|
const plan_code = tenatRes.data?.result?.result?.PlanCode;
|
||||||
|
const totalAllowedUser = tenatRes.data?.result?.result?.AllowedUsers || 0;
|
||||||
|
const adminId =
|
||||||
|
tenatRes?.data?.result?.result?.ExtUserPtr?.objectId || "";
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: "success",
|
||||||
|
price: price,
|
||||||
|
totalPrice: totalPrice,
|
||||||
|
planId: planId,
|
||||||
|
plan_code: plan_code,
|
||||||
|
totalAllowedUser: totalAllowedUser,
|
||||||
|
adminId: adminId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err in fetch subscription", err);
|
||||||
|
return { status: "error", error: err };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//function to get subcripition details from subscription class
|
//function to get subcripition details from subscription class
|
||||||
@@ -75,41 +126,22 @@ export async function checkIsSubscribed() {
|
|||||||
try {
|
try {
|
||||||
const res = await fetchSubscription();
|
const res = await fetchSubscription();
|
||||||
if (res.plan === "freeplan") {
|
if (res.plan === "freeplan") {
|
||||||
return false;
|
return { plan: res.plan, isValid: false, adminId: res?.adminId };
|
||||||
} else if (res.billingDate) {
|
|
||||||
if (new Date(res.billingDate) > new Date()) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log("Err in fetch subscription", err);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//function to get subcripition details from subscription class
|
|
||||||
export async function checkIsSubscribedTeam() {
|
|
||||||
try {
|
|
||||||
const res = await fetchSubscription();
|
|
||||||
if (res.plan === "freeplan") {
|
|
||||||
return false;
|
|
||||||
} else if (res.billingDate) {
|
} else if (res.billingDate) {
|
||||||
const plan = validplan[res.plan] || false;
|
const plan = validplan[res.plan] || false;
|
||||||
if (plan && new Date(res.billingDate) > new Date()) {
|
if (plan && new Date(res.billingDate) > new Date()) {
|
||||||
return true;
|
return { plan: res.plan, isValid: true, adminId: res?.adminId };
|
||||||
|
} else if (new Date(res.billingDate) > new Date()) {
|
||||||
|
return { plan: res.plan, isValid: true, adminId: res?.adminId };
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return { plan: res.plan, isValid: false, adminId: res?.adminId };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return { plan: res.plan, isValid: false, adminId: res?.adminId };
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Err in fetch subscription", err);
|
console.log("Err in fetch subscription", err);
|
||||||
return false;
|
return { plan: "no-plan", isValid: false, adminId: "" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -630,7 +662,12 @@ export const randomId = () => {
|
|||||||
return randomDigit;
|
return randomDigit;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createDocument = async (template, placeholders, signerData) => {
|
export const createDocument = async (
|
||||||
|
template,
|
||||||
|
placeholders,
|
||||||
|
signerData,
|
||||||
|
pdfUrl
|
||||||
|
) => {
|
||||||
if (template && template.length > 0) {
|
if (template && template.length > 0) {
|
||||||
const Doc = template[0];
|
const Doc = template[0];
|
||||||
|
|
||||||
@@ -653,7 +690,7 @@ export const createDocument = async (template, placeholders, signerData) => {
|
|||||||
}
|
}
|
||||||
const data = {
|
const data = {
|
||||||
Name: Doc.Name,
|
Name: Doc.Name,
|
||||||
URL: Doc.URL,
|
URL: pdfUrl,
|
||||||
SignedUrl: Doc.SignedUrl,
|
SignedUrl: Doc.SignedUrl,
|
||||||
SentToOthers: Doc.SentToOthers,
|
SentToOthers: Doc.SentToOthers,
|
||||||
Description: Doc.Description,
|
Description: Doc.Description,
|
||||||
@@ -672,7 +709,8 @@ export const createDocument = async (template, placeholders, signerData) => {
|
|||||||
Signers: signers,
|
Signers: signers,
|
||||||
SendinOrder: Doc?.SendinOrder || false,
|
SendinOrder: Doc?.SendinOrder || false,
|
||||||
AutomaticReminders: Doc?.AutomaticReminders || false,
|
AutomaticReminders: Doc?.AutomaticReminders || false,
|
||||||
RemindOnceInEvery: parseInt(Doc?.RemindOnceInEvery || 5)
|
RemindOnceInEvery: parseInt(Doc?.RemindOnceInEvery || 5),
|
||||||
|
IsEnableOTP: Doc?.IsEnableOTP || false
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -762,7 +800,9 @@ export const onChangeInput = (
|
|||||||
initial,
|
initial,
|
||||||
dateFormat,
|
dateFormat,
|
||||||
isDefaultEmpty,
|
isDefaultEmpty,
|
||||||
isRadio
|
isRadio,
|
||||||
|
fontSize,
|
||||||
|
fontColor
|
||||||
) => {
|
) => {
|
||||||
const isSigners = xyPostion.some((data) => data.signerPtr);
|
const isSigners = xyPostion.some((data) => data.signerPtr);
|
||||||
let filterSignerPos;
|
let filterSignerPos;
|
||||||
@@ -789,6 +829,8 @@ export const onChangeInput = (
|
|||||||
options: {
|
options: {
|
||||||
...position.options,
|
...position.options,
|
||||||
response: value,
|
response: value,
|
||||||
|
fontSize: fontSize,
|
||||||
|
fontColor: fontColor,
|
||||||
validation: {
|
validation: {
|
||||||
type: "date-format",
|
type: "date-format",
|
||||||
format: dateFormat // This indicates the required date format explicitly.
|
format: dateFormat // This indicates the required date format explicitly.
|
||||||
@@ -835,7 +877,6 @@ export const onChangeInput = (
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let getXYdata = xyPostion[index].pos;
|
let getXYdata = xyPostion[index].pos;
|
||||||
|
|
||||||
const updatePosition = getXYdata.map((positionData) => {
|
const updatePosition = getXYdata.map((positionData) => {
|
||||||
if (positionData.key === signKey) {
|
if (positionData.key === signKey) {
|
||||||
if (dateFormat) {
|
if (dateFormat) {
|
||||||
@@ -844,6 +885,8 @@ export const onChangeInput = (
|
|||||||
options: {
|
options: {
|
||||||
...positionData.options,
|
...positionData.options,
|
||||||
response: value,
|
response: value,
|
||||||
|
fontSize: fontSize,
|
||||||
|
fontColor: fontColor,
|
||||||
validation: {
|
validation: {
|
||||||
type: "date-format",
|
type: "date-format",
|
||||||
format: dateFormat // This indicates the required date format explicitly.
|
format: dateFormat // This indicates the required date format explicitly.
|
||||||
@@ -1043,13 +1086,18 @@ export const embedDocId = async (pdfDoc, documentId, allPages) => {
|
|||||||
const textContent = documentId && `OpenSign™ DocumentId: ${documentId} `;
|
const textContent = documentId && `OpenSign™ DocumentId: ${documentId} `;
|
||||||
const pages = pdfDoc.getPages();
|
const pages = pdfDoc.getPages();
|
||||||
const page = pages[i];
|
const page = pages[i];
|
||||||
page.drawText(textContent, {
|
const getObj = compensateRotation(
|
||||||
x: 10,
|
page.getRotation().angle,
|
||||||
y: page.getHeight() - 10,
|
10,
|
||||||
size: fontSize,
|
5,
|
||||||
|
1,
|
||||||
|
page.getSize(),
|
||||||
|
fontSize,
|
||||||
|
rgb(0.5, 0.5, 0.5),
|
||||||
font,
|
font,
|
||||||
color: rgb(0.5, 0.5, 0.5)
|
page
|
||||||
});
|
);
|
||||||
|
page.drawText(textContent, getObj);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1243,6 +1291,21 @@ const calculateFontSize = (position, containerScale, signyourself) => {
|
|||||||
return font / containerScale;
|
return font / containerScale;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getWidgetsFontColor = (type) => {
|
||||||
|
switch (type) {
|
||||||
|
case "red":
|
||||||
|
return rgb(1, 0, 0);
|
||||||
|
case "black":
|
||||||
|
return rgb(0, 0, 0);
|
||||||
|
case "blue":
|
||||||
|
return rgb(0, 0, 1);
|
||||||
|
case "yellow":
|
||||||
|
return rgb(0.9, 1, 0);
|
||||||
|
default:
|
||||||
|
return rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
//function for embed multiple signature using pdf-lib
|
//function for embed multiple signature using pdf-lib
|
||||||
export const multiSignEmbed = async (
|
export const multiSignEmbed = async (
|
||||||
widgets,
|
widgets,
|
||||||
@@ -1351,6 +1414,9 @@ export const multiSignEmbed = async (
|
|||||||
return resizePos;
|
return resizePos;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const color = position?.options?.fontColor;
|
||||||
|
const updateColorInRgb = getWidgetsFontColor(color);
|
||||||
|
const fontSize = parseInt(position?.options?.fontSize || 13);
|
||||||
const widgetTypeExist = [
|
const widgetTypeExist = [
|
||||||
textWidget,
|
textWidget,
|
||||||
textInputWidget,
|
textInputWidget,
|
||||||
@@ -1361,11 +1427,11 @@ export const multiSignEmbed = async (
|
|||||||
"email"
|
"email"
|
||||||
].includes(position.type);
|
].includes(position.type);
|
||||||
if (position.type === "checkbox") {
|
if (position.type === "checkbox") {
|
||||||
let checkboxOptionGapFromTop, isCheck;
|
let checkboxGapFromTop, isCheck;
|
||||||
let y = yPos(position);
|
let y = yPos(position);
|
||||||
const optionsFontSize = 13;
|
const optionsFontSize = fontSize || 13;
|
||||||
const checkboxSize = 18;
|
const checkboxSize = fontSize;
|
||||||
const checkboxTextGapFromLeft = 22;
|
const checkboxTextGapFromLeft = fontSize + 5 || 22;
|
||||||
if (position?.options?.values.length > 0) {
|
if (position?.options?.values.length > 0) {
|
||||||
position?.options?.values.forEach((item, ind) => {
|
position?.options?.values.forEach((item, ind) => {
|
||||||
const checkboxRandomId = "checkbox" + randomId();
|
const checkboxRandomId = "checkbox" + randomId();
|
||||||
@@ -1382,9 +1448,9 @@ export const multiSignEmbed = async (
|
|||||||
const checkbox = form.createCheckBox(checkboxRandomId);
|
const checkbox = form.createCheckBox(checkboxRandomId);
|
||||||
|
|
||||||
if (ind > 0) {
|
if (ind > 0) {
|
||||||
y = y + checkboxOptionGapFromTop;
|
y = y + checkboxGapFromTop;
|
||||||
} else {
|
} else {
|
||||||
checkboxOptionGapFromTop = 26;
|
checkboxGapFromTop = fontSize + 5 || 26;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!position?.options?.isHideLabel) {
|
if (!position?.options?.isHideLabel) {
|
||||||
@@ -1396,7 +1462,7 @@ export const multiSignEmbed = async (
|
|||||||
1,
|
1,
|
||||||
page.getSize(),
|
page.getSize(),
|
||||||
optionsFontSize,
|
optionsFontSize,
|
||||||
rgb(0, 0, 0),
|
updateColorInRgb,
|
||||||
font,
|
font,
|
||||||
page
|
page
|
||||||
);
|
);
|
||||||
@@ -1427,20 +1493,6 @@ export const multiSignEmbed = async (
|
|||||||
signyourself
|
signyourself
|
||||||
);
|
);
|
||||||
parseInt(fontSize);
|
parseInt(fontSize);
|
||||||
|
|
||||||
const color = position?.options?.fontColor;
|
|
||||||
let updateColorInRgb;
|
|
||||||
if (color === "red") {
|
|
||||||
updateColorInRgb = rgb(1, 0, 0);
|
|
||||||
} else if (color === "black") {
|
|
||||||
updateColorInRgb = rgb(0, 0, 0);
|
|
||||||
} else if (color === "blue") {
|
|
||||||
updateColorInRgb = rgb(0, 0, 1);
|
|
||||||
} else if (color === "yellow") {
|
|
||||||
updateColorInRgb = rgb(0.9, 1, 0);
|
|
||||||
} else {
|
|
||||||
updateColorInRgb = rgb(0, 0, 0);
|
|
||||||
}
|
|
||||||
let textContent;
|
let textContent;
|
||||||
if (position?.options?.response) {
|
if (position?.options?.response) {
|
||||||
textContent = position.options?.response;
|
textContent = position.options?.response;
|
||||||
@@ -1519,6 +1571,8 @@ export const multiSignEmbed = async (
|
|||||||
y += 18; // Adjust the line height as needed
|
y += 18; // Adjust the line height as needed
|
||||||
}
|
}
|
||||||
} else if (position.type === "dropdown") {
|
} else if (position.type === "dropdown") {
|
||||||
|
const fontsize = parseInt(position?.options?.fontSize) || 12;
|
||||||
|
|
||||||
const dropdownRandomId = "dropdown" + randomId();
|
const dropdownRandomId = "dropdown" + randomId();
|
||||||
const dropdown = form.createDropdown(dropdownRandomId);
|
const dropdown = form.createDropdown(dropdownRandomId);
|
||||||
dropdown.addOptions(position?.options?.values);
|
dropdown.addOptions(position?.options?.values);
|
||||||
@@ -1527,31 +1581,41 @@ export const multiSignEmbed = async (
|
|||||||
} else if (position?.options?.defaultValue) {
|
} else if (position?.options?.defaultValue) {
|
||||||
dropdown.select(position?.options?.defaultValue);
|
dropdown.select(position?.options?.defaultValue);
|
||||||
}
|
}
|
||||||
|
// Define the default appearance string
|
||||||
|
// Example format: `/FontName FontSize Tf 0 g` where:
|
||||||
|
// - `/FontName` is the name of the font (e.g., `/Helv` for Helvetica)
|
||||||
|
// - `FontSize` is the size you want to set (e.g., 12)
|
||||||
|
// - `Tf` specifies the font and size
|
||||||
|
// - `0 g` sets the text color to black
|
||||||
|
const defaultAppearance = `/Helv ${fontsize} Tf 0 g`;
|
||||||
|
// Set the default appearance for the dropdown field
|
||||||
|
dropdown.acroField.setDefaultAppearance(defaultAppearance);
|
||||||
|
dropdown.setFontSize(fontsize);
|
||||||
const dropdownObj = {
|
const dropdownObj = {
|
||||||
x: xPos(position),
|
x: xPos(position),
|
||||||
y: yPos(position),
|
y: yPos(position),
|
||||||
width: widgetWidth,
|
width: widgetWidth,
|
||||||
height: widgetHeight
|
height: widgetHeight
|
||||||
};
|
};
|
||||||
dropdown.defaultUpdateAppearances(font);
|
|
||||||
const dropdownOption = getWidgetPosition(page, dropdownObj, 1);
|
const dropdownOption = getWidgetPosition(page, dropdownObj, 1);
|
||||||
const dropdownSelected = { ...dropdownOption, font: font };
|
const dropdownSelected = { ...dropdownOption, font: font };
|
||||||
|
dropdown.defaultUpdateAppearances(font);
|
||||||
dropdown.addToPage(page, dropdownSelected);
|
dropdown.addToPage(page, dropdownSelected);
|
||||||
dropdown.enableReadOnly();
|
dropdown.enableReadOnly();
|
||||||
} else if (position.type === radioButtonWidget) {
|
} else if (position.type === radioButtonWidget) {
|
||||||
const radioRandomId = "radio" + randomId();
|
const radioRandomId = "radio" + randomId();
|
||||||
const radioGroup = form.createRadioGroup(radioRandomId);
|
const radioGroup = form.createRadioGroup(radioRandomId);
|
||||||
let radioOptionGapFromTop;
|
let radioOptionGapFromTop;
|
||||||
const optionsFontSize = 16;
|
const optionsFontSize = fontSize || 13;
|
||||||
const radioTextGapFromLeft = 20;
|
const radioTextGapFromLeft = fontSize + 5 || 20;
|
||||||
const radioSize = 18;
|
const radioSize = fontSize;
|
||||||
let y = yPos(position);
|
let y = yPos(position);
|
||||||
if (position?.options?.values.length > 0) {
|
if (position?.options?.values.length > 0) {
|
||||||
position?.options?.values.forEach((item, ind) => {
|
position?.options?.values.forEach((item, ind) => {
|
||||||
if (ind > 0) {
|
if (ind > 0) {
|
||||||
y = y + radioOptionGapFromTop;
|
y = y + radioOptionGapFromTop;
|
||||||
} else {
|
} else {
|
||||||
radioOptionGapFromTop = 25;
|
radioOptionGapFromTop = fontSize + 10 || 25;
|
||||||
}
|
}
|
||||||
if (!position?.options?.isHideLabel) {
|
if (!position?.options?.isHideLabel) {
|
||||||
// below line of code is used to embed label with radio button in pdf
|
// below line of code is used to embed label with radio button in pdf
|
||||||
@@ -1563,7 +1627,7 @@ export const multiSignEmbed = async (
|
|||||||
1,
|
1,
|
||||||
page.getSize(),
|
page.getSize(),
|
||||||
optionsFontSize,
|
optionsFontSize,
|
||||||
rgb(0, 0, 0),
|
updateColorInRgb,
|
||||||
font,
|
font,
|
||||||
page
|
page
|
||||||
);
|
);
|
||||||
@@ -1679,9 +1743,7 @@ export const contactBook = async (objectId) => {
|
|||||||
|
|
||||||
//function for getting document details from contract_Documents class
|
//function for getting document details from contract_Documents class
|
||||||
export const contractDocument = async (documentId) => {
|
export const contractDocument = async (documentId) => {
|
||||||
const data = {
|
const data = { docId: documentId };
|
||||||
docId: documentId
|
|
||||||
};
|
|
||||||
const documentDeatils = await axios
|
const documentDeatils = await axios
|
||||||
.post(`${localStorage.getItem("baseUrl")}functions/getDocument`, data, {
|
.post(`${localStorage.getItem("baseUrl")}functions/getDocument`, data, {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -1799,29 +1861,26 @@ export const handleCopyNextToWidget = (
|
|||||||
setXyPostion,
|
setXyPostion,
|
||||||
userId
|
userId
|
||||||
) => {
|
) => {
|
||||||
const isSigners = xyPostion.some((data) => data.signerPtr);
|
|
||||||
let filterSignerPos;
|
let filterSignerPos;
|
||||||
//get position of previous widget and create new widget next to that widget on same data except
|
//get position of previous widget and create new widget next to that widget on same data except
|
||||||
// xPosition and key
|
// xPosition and key
|
||||||
let newpos = position;
|
let newposition = position;
|
||||||
const calculateXPosition =
|
const calculateXPosition =
|
||||||
parseInt(position.xPosition) +
|
parseInt(position.xPosition) +
|
||||||
defaultWidthHeight(widgetType).width +
|
defaultWidthHeight(widgetType).width +
|
||||||
resizeBorderExtraWidth();
|
resizeBorderExtraWidth();
|
||||||
const newId = randomId();
|
const newId = randomId();
|
||||||
newpos = { ...newpos, xPosition: calculateXPosition, key: newId };
|
newposition = { ...newposition, xPosition: calculateXPosition, key: newId };
|
||||||
//if condition to create widget in request-sign flow
|
//if condition to create widget in request-sign flow
|
||||||
if (isSigners) {
|
if (userId) {
|
||||||
if (userId) {
|
filterSignerPos = xyPostion.filter((data) => data.Id === userId);
|
||||||
filterSignerPos = xyPostion.filter((data) => data.Id === userId);
|
const getPlaceHolder = filterSignerPos && filterSignerPos[0]?.placeHolder;
|
||||||
}
|
const getPageNumer = getPlaceHolder?.filter(
|
||||||
const getPlaceHolder = filterSignerPos[0]?.placeHolder;
|
|
||||||
const getPageNumer = getPlaceHolder.filter(
|
|
||||||
(data) => data.pageNumber === index
|
(data) => data.pageNumber === index
|
||||||
);
|
);
|
||||||
const getXYdata = getPageNumer[0].pos;
|
const getXYdata = getPageNumer && getPageNumer[0]?.pos;
|
||||||
getXYdata.push(newpos);
|
getXYdata.push(newposition);
|
||||||
if (getPageNumer.length > 0) {
|
if (getPageNumer && getPageNumer.length > 0) {
|
||||||
const newUpdateSignPos = getPlaceHolder.map((obj) => {
|
const newUpdateSignPos = getPlaceHolder.map((obj) => {
|
||||||
if (obj.pageNumber === index) {
|
if (obj.pageNumber === index) {
|
||||||
return { ...obj, pos: getXYdata };
|
return { ...obj, pos: getXYdata };
|
||||||
@@ -1839,9 +1898,8 @@ export const handleCopyNextToWidget = (
|
|||||||
setXyPostion(newUpdateSigner);
|
setXyPostion(newUpdateSigner);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// else condition to create widget in sign-yourself flow
|
let getXYdata = xyPostion[index]?.pos || [];
|
||||||
let getXYdata = xyPostion[index].pos;
|
getXYdata.push(newposition);
|
||||||
getXYdata.push(newpos);
|
|
||||||
const updatePlaceholder = xyPostion.map((obj, ind) => {
|
const updatePlaceholder = xyPostion.map((obj, ind) => {
|
||||||
if (ind === index) {
|
if (ind === index) {
|
||||||
return { ...obj, pos: getXYdata };
|
return { ...obj, pos: getXYdata };
|
||||||
@@ -1981,30 +2039,32 @@ export const fetchUrl = async (url, pdfName) => {
|
|||||||
console.error("Error downloading the file:", error);
|
console.error("Error downloading the file:", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//handle download signed pdf
|
export const getSignedUrl = async (pdfUrl, docId) => {
|
||||||
export const handleDownloadPdf = async (
|
//use only axios here due to public template sign
|
||||||
pdfDetails,
|
const axiosRes = await axios.post(
|
||||||
pdfUrl,
|
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
||||||
setIsDownloading
|
{ url: pdfUrl, docId: docId || "" },
|
||||||
) => {
|
{
|
||||||
const pdfName = pdfDetails[0] && pdfDetails[0].Name;
|
headers: {
|
||||||
setIsDownloading("pdf");
|
"content-type": "Application/json",
|
||||||
try {
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
|
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||||
const axiosRes = await axios.post(
|
|
||||||
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
|
||||||
{ url: pdfUrl },
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"content-type": "Application/json",
|
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
const url = axiosRes.data.result;
|
);
|
||||||
|
const url = axiosRes.data.result;
|
||||||
|
return url;
|
||||||
|
};
|
||||||
|
//handle download signed pdf
|
||||||
|
export const handleDownloadPdf = async (pdfDetails, setIsDownloading) => {
|
||||||
|
const pdfName = pdfDetails[0] && pdfDetails[0]?.Name;
|
||||||
|
const pdfUrl = pdfDetails?.[0]?.SignedUrl || pdfDetails?.[0]?.URL;
|
||||||
|
setIsDownloading && setIsDownloading("pdf");
|
||||||
|
const docId = !pdfDetails?.[0]?.IsEnableOTP ? pdfDetails?.[0]?.objectId : "";
|
||||||
|
try {
|
||||||
|
const url = await getSignedUrl(pdfUrl, docId);
|
||||||
await fetchUrl(url, pdfName);
|
await fetchUrl(url, pdfName);
|
||||||
setIsDownloading("");
|
setIsDownloading && setIsDownloading("");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err in getsignedurl", err);
|
console.log("err in getsignedurl", err);
|
||||||
setIsDownloading("");
|
setIsDownloading("");
|
||||||
@@ -2017,16 +2077,22 @@ export const sanitizeFileName = (pdfName) => {
|
|||||||
return pdfName.replace(/ /g, "_");
|
return pdfName.replace(/ /g, "_");
|
||||||
};
|
};
|
||||||
//function for print digital sign pdf
|
//function for print digital sign pdf
|
||||||
export const handleToPrint = async (event, pdfUrl, setIsDownloading) => {
|
export const handleToPrint = async (
|
||||||
|
event,
|
||||||
|
pdfUrl,
|
||||||
|
setIsDownloading,
|
||||||
|
pdfDetails
|
||||||
|
) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setIsDownloading("pdf");
|
setIsDownloading("pdf");
|
||||||
|
const docId = !pdfDetails?.[0]?.IsEnableOTP ? pdfDetails?.[0]?.objectId : "";
|
||||||
try {
|
try {
|
||||||
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
|
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
|
||||||
//`localStorage.getItem("baseUrl")` is also use in public-profile flow for public-sign
|
//`localStorage.getItem("baseUrl")` is also use in public-profile flow for public-sign
|
||||||
//if we give this `appInfo.baseUrl` as a base url then in public-profile it will create base url of it's window.location.origin ex- opensign.me which is not base url
|
//if we give this `appInfo.baseUrl` as a base url then in public-profile it will create base url of it's window.location.origin ex- opensign.me which is not base url
|
||||||
const axiosRes = await axios.post(
|
const axiosRes = await axios.post(
|
||||||
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
||||||
{ url: pdfUrl },
|
{ url: pdfUrl, docId: docId },
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"content-type": "Application/json",
|
"content-type": "Application/json",
|
||||||
@@ -2066,13 +2132,18 @@ export const handleToPrint = async (event, pdfUrl, setIsDownloading) => {
|
|||||||
//handle download signed pdf
|
//handle download signed pdf
|
||||||
export const handleDownloadCertificate = async (
|
export const handleDownloadCertificate = async (
|
||||||
pdfDetails,
|
pdfDetails,
|
||||||
setIsDownloading
|
setIsDownloading,
|
||||||
|
isZip
|
||||||
) => {
|
) => {
|
||||||
if (pdfDetails?.length > 0 && pdfDetails[0]?.CertificateUrl) {
|
if (pdfDetails?.length > 0 && pdfDetails[0]?.CertificateUrl) {
|
||||||
try {
|
try {
|
||||||
await fetch(pdfDetails[0] && pdfDetails[0]?.CertificateUrl);
|
await fetch(pdfDetails[0] && pdfDetails[0]?.CertificateUrl);
|
||||||
const certificateUrl = pdfDetails[0] && pdfDetails[0]?.CertificateUrl;
|
const certificateUrl = pdfDetails[0] && pdfDetails[0]?.CertificateUrl;
|
||||||
saveAs(certificateUrl, `Certificate_signed_by_OpenSign™.pdf`);
|
if (isZip) {
|
||||||
|
return certificateUrl;
|
||||||
|
} else {
|
||||||
|
saveAs(certificateUrl, `Certificate_signed_by_OpenSign™.pdf`);
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err in download in certificate", err);
|
console.log("err in download in certificate", err);
|
||||||
}
|
}
|
||||||
@@ -2098,7 +2169,13 @@ export const handleDownloadCertificate = async (
|
|||||||
if (doc?.CertificateUrl) {
|
if (doc?.CertificateUrl) {
|
||||||
await fetch(doc?.CertificateUrl);
|
await fetch(doc?.CertificateUrl);
|
||||||
const certificateUrl = doc?.CertificateUrl;
|
const certificateUrl = doc?.CertificateUrl;
|
||||||
saveAs(certificateUrl, `Certificate_signed_by_OpenSign™.pdf`);
|
if (isZip) {
|
||||||
|
setIsDownloading("");
|
||||||
|
return certificateUrl;
|
||||||
|
} else {
|
||||||
|
saveAs(certificateUrl, `Certificate_signed_by_OpenSign™.pdf`);
|
||||||
|
}
|
||||||
|
|
||||||
setIsDownloading("");
|
setIsDownloading("");
|
||||||
} else {
|
} else {
|
||||||
setIsDownloading("certificate");
|
setIsDownloading("certificate");
|
||||||
@@ -2142,9 +2219,11 @@ function compensateRotation(
|
|||||||
font,
|
font,
|
||||||
page
|
page
|
||||||
) {
|
) {
|
||||||
|
// Ensure pageRotation is between 0 and 360 degrees
|
||||||
|
pageRotation = ((pageRotation % 360) + 360) % 360;
|
||||||
let rotationRads = (pageRotation * Math.PI) / 180;
|
let rotationRads = (pageRotation * Math.PI) / 180;
|
||||||
|
|
||||||
//These coords are now from bottom/left
|
// Coordinates are from bottom-left
|
||||||
let coordsFromBottomLeft = { x: x / scale };
|
let coordsFromBottomLeft = { x: x / scale };
|
||||||
if (pageRotation === 90 || pageRotation === 270) {
|
if (pageRotation === 90 || pageRotation === 270) {
|
||||||
coordsFromBottomLeft.y = dimensions.width - (y + fontSize) / scale;
|
coordsFromBottomLeft.y = dimensions.width - (y + fontSize) / scale;
|
||||||
@@ -2154,6 +2233,7 @@ function compensateRotation(
|
|||||||
|
|
||||||
let drawX = null;
|
let drawX = null;
|
||||||
let drawY = null;
|
let drawY = null;
|
||||||
|
|
||||||
if (pageRotation === 90) {
|
if (pageRotation === 90) {
|
||||||
drawX =
|
drawX =
|
||||||
coordsFromBottomLeft.x * Math.cos(rotationRads) -
|
coordsFromBottomLeft.x * Math.cos(rotationRads) -
|
||||||
@@ -2179,8 +2259,8 @@ function compensateRotation(
|
|||||||
coordsFromBottomLeft.x * Math.sin(rotationRads) +
|
coordsFromBottomLeft.x * Math.sin(rotationRads) +
|
||||||
coordsFromBottomLeft.y * Math.cos(rotationRads) +
|
coordsFromBottomLeft.y * Math.cos(rotationRads) +
|
||||||
dimensions.height;
|
dimensions.height;
|
||||||
} else {
|
} else if (pageRotation === 0 || pageRotation === 360) {
|
||||||
//no rotation
|
// No rotation or full rotation
|
||||||
drawX = coordsFromBottomLeft.x;
|
drawX = coordsFromBottomLeft.x;
|
||||||
drawY = coordsFromBottomLeft.y;
|
drawY = coordsFromBottomLeft.y;
|
||||||
}
|
}
|
||||||
@@ -2284,3 +2364,156 @@ export const getDefaultSignature = async (objectId) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//function to rotate pdf page
|
||||||
|
export async function rotatePdfPage(
|
||||||
|
url,
|
||||||
|
rotateDegree,
|
||||||
|
pageNumber,
|
||||||
|
pdfRotateBase64
|
||||||
|
) {
|
||||||
|
let file;
|
||||||
|
|
||||||
|
//condition to handle pdf base64 in arrayBuffer format
|
||||||
|
if (pdfRotateBase64) {
|
||||||
|
file = base64ToArrayBuffer(pdfRotateBase64);
|
||||||
|
} else {
|
||||||
|
//condition to handle pdf url in arrayBuffer format
|
||||||
|
file = await convertPdfArrayBuffer(url);
|
||||||
|
}
|
||||||
|
// Load the existing PDF
|
||||||
|
const pdfDoc = await PDFDocument.load(file);
|
||||||
|
// Get the page according to page number
|
||||||
|
const page = pdfDoc.getPage(pageNumber);
|
||||||
|
//get current page rotation angle
|
||||||
|
const currentRotation = page.getRotation().angle;
|
||||||
|
// Apply the rotation in the counterclockwise direction
|
||||||
|
let newRotation = (currentRotation + rotateDegree) % 360;
|
||||||
|
// Adjust for negative angles to keep within 0-359 range
|
||||||
|
if (newRotation < 0) {
|
||||||
|
newRotation += 360;
|
||||||
|
}
|
||||||
|
page.setRotation(degrees(newRotation));
|
||||||
|
const pdfbase64 = await pdfDoc.saveAsBase64({ useObjectStreams: false });
|
||||||
|
//convert base64 to arraybuffer is used in pdf-lib
|
||||||
|
//pdfbase64 is used to show pdf rotated format
|
||||||
|
const arrayBuffer = base64ToArrayBuffer(pdfbase64);
|
||||||
|
//`base64` is used to show pdf
|
||||||
|
return { arrayBuffer: arrayBuffer, base64: pdfbase64 };
|
||||||
|
}
|
||||||
|
function base64ToArrayBuffer(base64) {
|
||||||
|
// Decode the base64 string to a binary string
|
||||||
|
const binaryString = atob(base64);
|
||||||
|
// Create a new ArrayBuffer with the same length as the binary string
|
||||||
|
const len = binaryString.length;
|
||||||
|
const bytes = new Uint8Array(len);
|
||||||
|
// Convert the binary string to a byte array
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
bytes[i] = binaryString.charCodeAt(i);
|
||||||
|
}
|
||||||
|
// Return the ArrayBuffer
|
||||||
|
return bytes.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const convertBase64ToFile = async (pdfName, pdfBase64) => {
|
||||||
|
const fileName = sanitizeFileName(pdfName) + ".pdf";
|
||||||
|
const pdfFile = new Parse.File(fileName, { base64: pdfBase64 });
|
||||||
|
// Save the Parse File if needed
|
||||||
|
const pdfData = await pdfFile.save();
|
||||||
|
const pdfUrl = pdfData.url();
|
||||||
|
return pdfUrl;
|
||||||
|
};
|
||||||
|
export const onClickZoomIn = (scale, zoomPercent, setScale, setZoomPercent) => {
|
||||||
|
setScale(scale + 0.1 * scale);
|
||||||
|
setZoomPercent(zoomPercent + 10);
|
||||||
|
};
|
||||||
|
export const onClickZoomOut = (
|
||||||
|
zoomPercent,
|
||||||
|
scale,
|
||||||
|
setZoomPercent,
|
||||||
|
setScale
|
||||||
|
) => {
|
||||||
|
if (zoomPercent > 0) {
|
||||||
|
if (zoomPercent === 10) {
|
||||||
|
setScale(1);
|
||||||
|
} else {
|
||||||
|
setScale(scale - 0.1 * scale);
|
||||||
|
}
|
||||||
|
setZoomPercent(zoomPercent - 10);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//function to use remove widgets from current page when user want to rotate page
|
||||||
|
export const handleRemoveWidgets = (
|
||||||
|
setSignerPos,
|
||||||
|
signerPos,
|
||||||
|
pageNumber,
|
||||||
|
setIsRotate
|
||||||
|
) => {
|
||||||
|
const updatedSignerPos = signerPos.map((placeholderObj) => {
|
||||||
|
return {
|
||||||
|
...placeholderObj,
|
||||||
|
placeHolder: placeholderObj?.placeHolder?.filter(
|
||||||
|
(data) => data?.pageNumber !== pageNumber
|
||||||
|
)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
setSignerPos(updatedSignerPos);
|
||||||
|
setIsRotate({
|
||||||
|
status: false,
|
||||||
|
degree: 0
|
||||||
|
});
|
||||||
|
};
|
||||||
|
//function to show warning when user rotate page and there are some already widgets on that page
|
||||||
|
export const handleRotateWarning = (signerPos, pageNumber) => {
|
||||||
|
const placeholderExist = signerPos?.some((placeholderObj) =>
|
||||||
|
placeholderObj?.placeHolder?.some((data) => data?.pageNumber === pageNumber)
|
||||||
|
);
|
||||||
|
if (placeholderExist) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// `generateTitleFromFilename` to generate Title of document from file name
|
||||||
|
export function generateTitleFromFilename(filename) {
|
||||||
|
try {
|
||||||
|
// Step 1: Trim whitespace
|
||||||
|
let title = filename.trim();
|
||||||
|
|
||||||
|
// Step 2: Remove the file extension (everything after the last '.')
|
||||||
|
const lastDotIndex = title.lastIndexOf(".");
|
||||||
|
if (lastDotIndex > 0) {
|
||||||
|
title = title.substring(0, lastDotIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Replace special characters (except Unicode letters, digits, spaces, and hyphens)
|
||||||
|
title = title.replace(/[^\p{L}\p{N}\s-]/gu, " ");
|
||||||
|
|
||||||
|
// Step 4: Replace multiple spaces with a single space
|
||||||
|
title = title.replace(/\s+/g, " ");
|
||||||
|
|
||||||
|
// Step 5: Capitalize first letter of each word (Title Case), handling Unicode characters
|
||||||
|
title = title.replace(
|
||||||
|
/\p{L}\S*/gu,
|
||||||
|
(txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Step 6: Restrict length of title (optional, let's say 100 characters)
|
||||||
|
if (title.length > 100) {
|
||||||
|
title = title.substring(0, 100).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7: Handle empty or invalid title by falling back to "Untitled Document"
|
||||||
|
if (!title || title.length === 0) {
|
||||||
|
return "Untitled Document";
|
||||||
|
}
|
||||||
|
|
||||||
|
return title;
|
||||||
|
} catch (error) {
|
||||||
|
// Handle unexpected errors gracefully by returning a default title
|
||||||
|
console.error("Error generating title from filename:", error);
|
||||||
|
return "Untitled Document";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { serverUrl_fn } from "./appinfo";
|
|||||||
const parseAppId = process.env.REACT_APP_APPID
|
const parseAppId = process.env.REACT_APP_APPID
|
||||||
? process.env.REACT_APP_APPID
|
? process.env.REACT_APP_APPID
|
||||||
: "opensign";
|
: "opensign";
|
||||||
const serverUrl = serverUrl_fn()
|
const serverUrl = serverUrl_fn();
|
||||||
export const SaveFileSize = async (size, imageUrl, tenantId) => {
|
export const SaveFileSize = async (size, imageUrl, tenantId) => {
|
||||||
//checking server url and save file's size
|
//checking server url and save file's size
|
||||||
const tenantPtr = {
|
const tenantPtr = {
|
||||||
|
|||||||
@@ -12,23 +12,35 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hide-scrollbar {
|
.hide-scrollbar {
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
-ms-overflow-style: none;
|
||||||
scrollbar-width: none; /* Firefox */
|
/* IE and Edge */
|
||||||
|
scrollbar-width: none;
|
||||||
|
/* Firefox */
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 766px) {
|
||||||
|
.bBofGr {
|
||||||
|
width: 14px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* below css class replace bootstrap background color with daisy */
|
/* below css class replace bootstrap background color with daisy */
|
||||||
.op-bg-primary {
|
.op-bg-primary {
|
||||||
@apply bg-primary;
|
@apply bg-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
.op-bg-secondary {
|
.op-bg-secondary {
|
||||||
@apply bg-secondary;
|
@apply bg-secondary;
|
||||||
}
|
}
|
||||||
|
|
||||||
.op-bg-info {
|
.op-bg-info {
|
||||||
@apply bg-info;
|
@apply bg-info;
|
||||||
}
|
}
|
||||||
.op-bg-success{
|
|
||||||
|
.op-bg-success {
|
||||||
@apply bg-success;
|
@apply bg-success;
|
||||||
}
|
}
|
||||||
|
|
||||||
.op-bg-warning {
|
.op-bg-warning {
|
||||||
@apply bg-warning;
|
@apply bg-warning;
|
||||||
}
|
}
|
||||||
@@ -37,25 +49,37 @@ body {
|
|||||||
.op-text-primary {
|
.op-text-primary {
|
||||||
@apply text-primary;
|
@apply text-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
.op-text-secondary {
|
.op-text-secondary {
|
||||||
@apply text-secondary;
|
@apply text-secondary;
|
||||||
}
|
}
|
||||||
|
|
||||||
.op-text-info {
|
.op-text-info {
|
||||||
@apply text-info;
|
@apply text-info;
|
||||||
}
|
}
|
||||||
.op-text-success{
|
|
||||||
|
.op-text-accent {
|
||||||
|
@apply text-accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.op-text-success {
|
||||||
@apply text-success;
|
@apply text-success;
|
||||||
}
|
}
|
||||||
|
|
||||||
.op-text-warning {
|
.op-text-warning {
|
||||||
@apply text-warning;
|
@apply text-warning;
|
||||||
}
|
}
|
||||||
.op-border-primary{
|
|
||||||
@apply border-primary
|
.op-border-primary {
|
||||||
|
@apply border-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CSS for scrollbar customization */
|
/* CSS for scrollbar customization */
|
||||||
* {
|
* {
|
||||||
scrollbar-width: thin; /* For Firefox */
|
scrollbar-width: thin;
|
||||||
scrollbar-color: gray; /* For Firefox */
|
/* For Firefox */
|
||||||
|
scrollbar-color: gray;
|
||||||
|
/* For Firefox */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For webkit-based browsers like Chrome, Safari */
|
/* For webkit-based browsers like Chrome, Safari */
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
|
||||||
export default function reportJson(id) {
|
export default function reportJson(id) {
|
||||||
// console.log("json ", json);
|
// console.log("json ", json);
|
||||||
const head = ["Sr.No", "Title", "Note", "Folder", "File", "Owner", "Signers"];
|
const head = ["Sr.No", "Title", "Note", "Folder", "File", "Owner", "Signers"];
|
||||||
@@ -10,9 +12,36 @@ export default function reportJson(id) {
|
|||||||
"Owner",
|
"Owner",
|
||||||
"Signers"
|
"Signers"
|
||||||
];
|
];
|
||||||
|
const iphead = [
|
||||||
|
"Sr.No",
|
||||||
|
"Title",
|
||||||
|
"Note",
|
||||||
|
"Folder",
|
||||||
|
"File",
|
||||||
|
"Status",
|
||||||
|
"Signers"
|
||||||
|
];
|
||||||
const contactbook = ["Sr.No", "Name", "Email", "Phone"];
|
const contactbook = ["Sr.No", "Name", "Email", "Phone"];
|
||||||
const dashboardReportHead = ["Title", "File", "Owner", "Signers"];
|
const dashboardReportHead = ["Title", "File", "Owner", "Signers"];
|
||||||
const templateReport = ["Sr.No", "Title", "File", "Owner", "Signers"];
|
const templateReport = ["Sr.No", "Title", "File", "Owner", "Signers"];
|
||||||
|
const templateSubAction = isEnableSubscription
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
btnId: "2434",
|
||||||
|
btnLabel: "Embed",
|
||||||
|
hoverLabel: "Embed",
|
||||||
|
btnIcon: "fa-light fa-code",
|
||||||
|
action: "Embed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "2434",
|
||||||
|
btnLabel: "Copy TemplateId",
|
||||||
|
hoverLabel: "Copy TemplateId",
|
||||||
|
btnIcon: "fa-light fa-copy",
|
||||||
|
action: "CopyTemplateId"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: [];
|
||||||
switch (id) {
|
switch (id) {
|
||||||
// draft documents report
|
// draft documents report
|
||||||
case "ByHuevtCFY":
|
case "ByHuevtCFY":
|
||||||
@@ -63,7 +92,7 @@ export default function reportJson(id) {
|
|||||||
case "1MwEuxLEkF":
|
case "1MwEuxLEkF":
|
||||||
return {
|
return {
|
||||||
reportName: "In-progress documents",
|
reportName: "In-progress documents",
|
||||||
heading: head,
|
heading: iphead,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnId: "8901",
|
btnId: "8901",
|
||||||
@@ -354,6 +383,7 @@ export default function reportJson(id) {
|
|||||||
redirectUrl: "template",
|
redirectUrl: "template",
|
||||||
action: "redirect"
|
action: "redirect"
|
||||||
},
|
},
|
||||||
|
...templateSubAction,
|
||||||
{
|
{
|
||||||
btnId: "1834",
|
btnId: "1834",
|
||||||
btnLabel: "Delete",
|
btnLabel: "Delete",
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const dashboardJson = [
|
|||||||
queryType: "",
|
queryType: "",
|
||||||
class: "contracts_Document",
|
class: "contracts_Document",
|
||||||
query:
|
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',
|
'where={"Type":{"#*ne":"Folder"},"Signers":{"#*exists":true,"#*ne":[]},"Placeholders":{"#*ne":null},"SignedUrl":{"#*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",
|
key: "count",
|
||||||
Redirect_type: "Report",
|
Redirect_type: "Report",
|
||||||
Redirect_id: "1MwEuxLEkF",
|
Redirect_id: "1MwEuxLEkF",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { isStaging } from "../constant/const";
|
|||||||
const plans = [
|
const plans = [
|
||||||
{
|
{
|
||||||
planName: "OPENSIGN™ FREE",
|
planName: "OPENSIGN™ FREE",
|
||||||
|
code: { monthly: "freeplan", yearly: "freeplan" },
|
||||||
img: "free.png",
|
img: "free.png",
|
||||||
currency: "",
|
currency: "",
|
||||||
monthlyPrice: "Free",
|
monthlyPrice: "Free",
|
||||||
@@ -12,7 +13,7 @@ const plans = [
|
|||||||
url: "",
|
url: "",
|
||||||
target: "_blank",
|
target: "_blank",
|
||||||
benefits: [
|
benefits: [
|
||||||
"Unlimited envelopes",
|
"Unlimited digital signatures",
|
||||||
"Sign documents yourself",
|
"Sign documents yourself",
|
||||||
"Request signatures from others",
|
"Request signatures from others",
|
||||||
"14 field types",
|
"14 field types",
|
||||||
@@ -26,12 +27,11 @@ const plans = [
|
|||||||
"Decline document support",
|
"Decline document support",
|
||||||
"Email notifications",
|
"Email notifications",
|
||||||
"Recipient authentication using OTP",
|
"Recipient authentication using OTP",
|
||||||
"Bulk send (upto 5 docs)",
|
|
||||||
"Public profiles",
|
"Public profiles",
|
||||||
"And much more"
|
"And much more"
|
||||||
],
|
],
|
||||||
yearlyBenefits: [
|
yearlyBenefits: [
|
||||||
"Unlimited envelopes",
|
"Unlimited digital signatures",
|
||||||
"Sign documents yourself",
|
"Sign documents yourself",
|
||||||
"Request signatures from others",
|
"Request signatures from others",
|
||||||
"14 field types",
|
"14 field types",
|
||||||
@@ -45,13 +45,15 @@ const plans = [
|
|||||||
"Decline document support",
|
"Decline document support",
|
||||||
"Email notifications",
|
"Email notifications",
|
||||||
"Recipient authentication using OTP",
|
"Recipient authentication using OTP",
|
||||||
"Bulk send (upto 5 docs)",
|
|
||||||
"Public profiles",
|
"Public profiles",
|
||||||
"And much more"
|
"And much more"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
planName: "OPENSIGN™ PROFESSIONAL",
|
planName: "OPENSIGN™ PROFESSIONAL",
|
||||||
|
code: isStaging
|
||||||
|
? { monthly: "pro-weekly", yearly: "pro-yearly" }
|
||||||
|
: { monthly: "professional-monthly", yearly: "professional-yearly" },
|
||||||
img: "professional.png",
|
img: "professional.png",
|
||||||
currency: "$",
|
currency: "$",
|
||||||
monthlyPrice: "29.99",
|
monthlyPrice: "29.99",
|
||||||
@@ -73,10 +75,10 @@ const plans = [
|
|||||||
"Webhooks",
|
"Webhooks",
|
||||||
"Zapier integration",
|
"Zapier integration",
|
||||||
"API Access",
|
"API Access",
|
||||||
"100 API signatures included",
|
"upto 100 API signatures",
|
||||||
"Custom email templates",
|
"Custom email templates",
|
||||||
"Auto reminders",
|
"Auto reminders",
|
||||||
"Bulk send (upto 20 docs)",
|
"Bulk send (upto 100 docs)",
|
||||||
"Premium Public profile usernames",
|
"Premium Public profile usernames",
|
||||||
"Embedding (coming soon)"
|
"Embedding (coming soon)"
|
||||||
],
|
],
|
||||||
@@ -88,16 +90,17 @@ const plans = [
|
|||||||
"Webhooks",
|
"Webhooks",
|
||||||
"Zapier integration",
|
"Zapier integration",
|
||||||
"API Access",
|
"API Access",
|
||||||
"240 API signatures included",
|
"upto 240 API signatures",
|
||||||
"Custom email templates",
|
"Custom email templates",
|
||||||
"Auto reminders",
|
"Auto reminders",
|
||||||
"Bulk send (upto 20 docs)",
|
"Bulk send (upto 240 docs)",
|
||||||
"Premium Public profile usernames",
|
"Premium Public profile usernames",
|
||||||
"Embedding (coming soon)"
|
"Embedding (coming soon)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
planName: "OPENSIGN™ TEAMS",
|
planName: "OPENSIGN™ TEAMS",
|
||||||
|
code: { monthly: "teams-monthly", yearly: "teams-yearly" },
|
||||||
img: "teams.png",
|
img: "teams.png",
|
||||||
currency: "$",
|
currency: "$",
|
||||||
monthlyPrice: `39.99<sup style="font-size: 17px;">/user</sup>`,
|
monthlyPrice: `39.99<sup style="font-size: 17px;">/user</sup>`,
|
||||||
@@ -105,31 +108,31 @@ const plans = [
|
|||||||
subtitle: "Exclusive Access to advanced features.",
|
subtitle: "Exclusive Access to advanced features.",
|
||||||
btn: { text: "Subscribe", color: "op-btn-accent" },
|
btn: { text: "Subscribe", color: "op-btn-accent" },
|
||||||
url: isStaging
|
url: isStaging
|
||||||
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/team-weekly"
|
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/teams-monthly"
|
||||||
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901237d0702bfaa959406306635d80f138c/teams-monthly",
|
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901237d0702bfaa959406306635d80f138c/teams-monthly",
|
||||||
yearlyUrl: isStaging
|
yearlyUrl: isStaging
|
||||||
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/team-weekly"
|
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/teams-yearly"
|
||||||
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af9011a864994bbeeec71fcf106188630199d/teams-yearly",
|
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af9011a864994bbeeec71fcf106188630199d/teams-yearly",
|
||||||
target: "_self",
|
target: "_self",
|
||||||
benefits: [
|
benefits: [
|
||||||
"Everything in OpenSign™ professional",
|
"Everything in OpenSign™ professional",
|
||||||
"100 API signatures included",
|
"upto 100 API signatures",
|
||||||
"Teams and Organizations",
|
"Teams and Organizations",
|
||||||
"Share Templates with teams",
|
"Share Templates with teams",
|
||||||
"Share Templates with individuals",
|
"Share Templates with individuals",
|
||||||
"DocumentId removal from signed docs",
|
"DocumentId removal from signed docs",
|
||||||
"Bulk send (upto 50 docs)",
|
"Bulk send (upto 100 docs)",
|
||||||
"Request Payments (coming soon)",
|
"Request Payments (coming soon)",
|
||||||
"Mobile app (coming soon)"
|
"Mobile app (coming soon)"
|
||||||
],
|
],
|
||||||
yearlyBenefits: [
|
yearlyBenefits: [
|
||||||
"Everything in OpenSign™ professional",
|
"Everything in OpenSign™ professional",
|
||||||
"500 API signatures included",
|
"upto 500 API signatures",
|
||||||
"Teams and Organizations",
|
"Teams and Organizations",
|
||||||
"Share Templates with teams",
|
"Share Templates with teams",
|
||||||
"Share Templates with individuals",
|
"Share Templates with individuals",
|
||||||
"DocumentId removal from signed docs",
|
"DocumentId removal from signed docs",
|
||||||
"Bulk send (upto 50 docs)",
|
"Bulk send (upto 500 docs)",
|
||||||
"Request Payments (coming soon)",
|
"Request Payments (coming soon)",
|
||||||
"Mobile app (coming soon)"
|
"Mobile app (coming soon)"
|
||||||
]
|
]
|
||||||
@@ -171,4 +174,74 @@ export const validplan = {
|
|||||||
"enterprise-monthly": true,
|
"enterprise-monthly": true,
|
||||||
"enterprise-yearly": true
|
"enterprise-yearly": true
|
||||||
};
|
};
|
||||||
|
export const paidUrl = (plan) => {
|
||||||
|
const teamperiod = {
|
||||||
|
"team-weekly": "monthly",
|
||||||
|
"team-yearly": "yearly",
|
||||||
|
"teams-monthly": "monthly",
|
||||||
|
"teams-yearly": "yearly"
|
||||||
|
};
|
||||||
|
const period = teamperiod[plan] || "";
|
||||||
|
if (period) {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
// console.log("userDetails ", userDetails);
|
||||||
|
const fullname = user && user.name ? user.name.split(" ") : "";
|
||||||
|
const firstname = fullname?.[0]
|
||||||
|
? "first_name=" + encodeURIComponent(fullname?.[0])
|
||||||
|
: "";
|
||||||
|
const lastname = fullname?.[1]
|
||||||
|
? "&last_name=" + encodeURIComponent(fullname?.[1])
|
||||||
|
: "";
|
||||||
|
const name = firstname ? firstname + lastname : "";
|
||||||
|
const email =
|
||||||
|
user && user.email ? "&email=" + encodeURIComponent(user.email) : "";
|
||||||
|
const company =
|
||||||
|
user && user.company
|
||||||
|
? "&company_name=" + encodeURIComponent(user.company)
|
||||||
|
: "";
|
||||||
|
const phone =
|
||||||
|
user && user.phone ? "&mobile=" + encodeURIComponent(user.phone) : "";
|
||||||
|
const allowedUsers =
|
||||||
|
localStorage.getItem("allowedUsers") &&
|
||||||
|
localStorage.getItem("allowedUsers") > 0
|
||||||
|
? localStorage.getItem("allowedUsers") - 1
|
||||||
|
: "";
|
||||||
|
const quantity = allowedUsers
|
||||||
|
? `addon_code%5B0%5D=extra-teams-users-${period}&addon_quantity%5B0%5D=${allowedUsers}&`
|
||||||
|
: "";
|
||||||
|
|
||||||
|
const details =
|
||||||
|
"?shipping_country_code=US&billing_country_code=US&billing_state_code=CA&" +
|
||||||
|
quantity +
|
||||||
|
name +
|
||||||
|
email +
|
||||||
|
company +
|
||||||
|
phone;
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
localStorage.setItem("userDetails", JSON.stringify(user));
|
||||||
|
}
|
||||||
|
const url = {
|
||||||
|
monthly: isStaging
|
||||||
|
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/teams-monthly"
|
||||||
|
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901237d0702bfaa959406306635d80f138c/teams-monthly",
|
||||||
|
yearly: isStaging
|
||||||
|
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/teams-yearly"
|
||||||
|
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af9011a864994bbeeec71fcf106188630199d/teams-yearly"
|
||||||
|
};
|
||||||
|
|
||||||
|
const planurl = url[period] + details;
|
||||||
|
return planurl;
|
||||||
|
} else {
|
||||||
|
return "/subscription";
|
||||||
|
}
|
||||||
|
};
|
||||||
export default plans;
|
export default plans;
|
||||||
|
|||||||
@@ -95,7 +95,9 @@ const HomeLayout = () => {
|
|||||||
domain: updateDomain
|
domain: updateDomain
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const handleNavigation = () => {
|
||||||
|
navigate("/subscription");
|
||||||
|
};
|
||||||
async function checkIsSubscribed() {
|
async function checkIsSubscribed() {
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const res = await fetchSubscription();
|
const res = await fetchSubscription();
|
||||||
@@ -107,10 +109,10 @@ const HomeLayout = () => {
|
|||||||
setIsUserValid(true);
|
setIsUserValid(true);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`);
|
handleNavigation(res.plan);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`);
|
handleNavigation(res.plan);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setIsUserValid(true);
|
setIsUserValid(true);
|
||||||
@@ -250,9 +252,9 @@ const HomeLayout = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLoginBtn = () => {
|
const handleLoginBtn = async () => {
|
||||||
try {
|
try {
|
||||||
Parse?.User?.logOut();
|
await Parse?.User?.logOut();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err ", err);
|
console.log("err ", err);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -56,8 +56,10 @@ const AddAdmin = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const clearStorage = async () => {
|
const clearStorage = async () => {
|
||||||
if (Parse.User.current()) {
|
try {
|
||||||
await Parse.User.logOut();
|
await Parse.User.logOut();
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err while logging out", err);
|
||||||
}
|
}
|
||||||
const baseUrl = localStorage.getItem("baseUrl");
|
const baseUrl = localStorage.getItem("baseUrl");
|
||||||
const appid = localStorage.getItem("parseAppId");
|
const appid = localStorage.getItem("parseAppId");
|
||||||
@@ -459,13 +461,13 @@ const AddAdmin = () => {
|
|||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="op-checkbox op-checkbox-sm"
|
className="op-checkbox op-checkbox-sm"
|
||||||
id="termsandcondition"
|
id="subscribetoopensign"
|
||||||
checked={isSubscribeNews}
|
checked={isSubscribeNews}
|
||||||
onChange={(e) => setIsSubscribeNews(e.target.checked)}
|
onChange={(e) => setIsSubscribeNews(e.target.checked)}
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
className="text-xs cursor-pointer ml-1 mb-0"
|
className="text-xs cursor-pointer ml-1 mb-0"
|
||||||
htmlFor="termsandcondition"
|
htmlFor="subscribetoopensign"
|
||||||
>
|
>
|
||||||
{t("subscribe-to-opensign")}
|
{t("subscribe-to-opensign")}
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ const DebugPdf = () => {
|
|||||||
|
|
||||||
const inferPdfType = async (pdf) => {
|
const inferPdfType = async (pdf) => {
|
||||||
try {
|
try {
|
||||||
const firstPage = await pdf.getPage(2);
|
const firstPage = await pdf.getPage(pdf?.numPages > 1 ? 2 : 1);
|
||||||
const scale = 1;
|
const scale = 1;
|
||||||
const { width, height } = firstPage.getViewport({ scale });
|
const { width, height } = firstPage.getViewport({ scale });
|
||||||
setPdfDimension({ width: width, height: height });
|
setPdfDimension({ width: width, height: height });
|
||||||
@@ -215,11 +215,7 @@ const DebugPdf = () => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{copied && (
|
{copied && <Alert type="success">Copied</Alert>}
|
||||||
<Alert type="success">
|
|
||||||
<span className="ml-3">Copied</span>
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
<Title title={"Debug Pdf"} />
|
<Title title={"Debug Pdf"} />
|
||||||
{width < 800 ? (
|
{width < 800 ? (
|
||||||
<HandleError handleError={"Debug PDF only availble for PC"} />
|
<HandleError handleError={"Debug PDF only availble for PC"} />
|
||||||
|
|||||||
@@ -15,11 +15,7 @@ function ForgotPassword() {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({ email: "", password: "", hideNav: "" });
|
||||||
email: "",
|
|
||||||
password: "",
|
|
||||||
hideNav: ""
|
|
||||||
});
|
|
||||||
const [sentStatus, setSentStatus] = useState("");
|
const [sentStatus, setSentStatus] = useState("");
|
||||||
const [image, setImage] = useState();
|
const [image, setImage] = useState();
|
||||||
|
|
||||||
@@ -65,6 +61,11 @@ function ForgotPassword() {
|
|||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
const saveLogo = async () => {
|
const saveLogo = async () => {
|
||||||
|
try {
|
||||||
|
await Parse.User.logOut();
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err while logging out ", err);
|
||||||
|
}
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const app = await getAppLogo();
|
const app = await getAppLogo();
|
||||||
if (app?.logo) {
|
if (app?.logo) {
|
||||||
|
|||||||
+238
-122
@@ -1,7 +1,6 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import { formJson } from "../json/FormJson";
|
import { formJson } from "../json/FormJson";
|
||||||
import AddUser from "../components/AddUser";
|
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import DropboxChooser from "../components/shared/fields/DropboxChoose";
|
import DropboxChooser from "../components/shared/fields/DropboxChoose";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
@@ -10,7 +9,12 @@ import SignersInput from "../components/shared/fields/SignersInput";
|
|||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import PageNotFound from "./PageNotFound";
|
import PageNotFound from "./PageNotFound";
|
||||||
import { SaveFileSize } from "../constant/saveFileSize";
|
import { SaveFileSize } from "../constant/saveFileSize";
|
||||||
import { checkIsSubscribed, getFileName, toDataUrl } from "../constant/Utils";
|
import {
|
||||||
|
checkIsSubscribed,
|
||||||
|
generateTitleFromFilename,
|
||||||
|
getFileName,
|
||||||
|
toDataUrl
|
||||||
|
} from "../constant/Utils";
|
||||||
import { PDFDocument } from "pdf-lib";
|
import { PDFDocument } from "pdf-lib";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { isEnableSubscription } from "../constant/const";
|
import { isEnableSubscription } from "../constant/const";
|
||||||
@@ -37,15 +41,11 @@ function generatePdfName(length) {
|
|||||||
function Form() {
|
function Form() {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
|
||||||
if (id === "lM0xRnM3iE") {
|
const config = formJson[id];
|
||||||
return <AddUser />;
|
if (config) {
|
||||||
|
return <Forms {...config} />;
|
||||||
} else {
|
} else {
|
||||||
const config = formJson[id];
|
return <PageNotFound prefix={"Form"} />;
|
||||||
if (config) {
|
|
||||||
return <Forms {...config} />;
|
|
||||||
} else {
|
|
||||||
return <PageNotFound prefix={"Form"} />;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +66,8 @@ const Forms = (props) => {
|
|||||||
password: "",
|
password: "",
|
||||||
file: "",
|
file: "",
|
||||||
remindOnceInEvery: 5,
|
remindOnceInEvery: 5,
|
||||||
autoreminder: false
|
autoreminder: false,
|
||||||
|
IsEnableOTP: "false"
|
||||||
});
|
});
|
||||||
const [fileupload, setFileUpload] = useState("");
|
const [fileupload, setFileUpload] = useState("");
|
||||||
const [fileload, setfileload] = useState(false);
|
const [fileload, setfileload] = useState(false);
|
||||||
@@ -79,6 +80,7 @@ const Forms = (props) => {
|
|||||||
const [isDecrypting, setIsDecrypting] = useState(false);
|
const [isDecrypting, setIsDecrypting] = useState(false);
|
||||||
const [isCorrectPass, setIsCorrectPass] = useState(true);
|
const [isCorrectPass, setIsCorrectPass] = useState(true);
|
||||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||||
|
const [isAdvanceOpt, setIsAdvanceOpt] = useState(false);
|
||||||
const handleStrInput = (e) => {
|
const handleStrInput = (e) => {
|
||||||
setIsCorrectPass(true);
|
setIsCorrectPass(true);
|
||||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||||
@@ -95,8 +97,8 @@ const Forms = (props) => {
|
|||||||
}, []);
|
}, []);
|
||||||
const fetchSubscription = async () => {
|
const fetchSubscription = async () => {
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const getIsSubscribe = await checkIsSubscribed();
|
const subscribe = await checkIsSubscribed();
|
||||||
setIsSubscribe(getIsSubscribe);
|
setIsSubscribe(subscribe.isValid);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -142,12 +144,11 @@ const Forms = (props) => {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err in sending posthog encryptedpdf", err);
|
console.log("err in sending posthog encryptedpdf", err);
|
||||||
}
|
}
|
||||||
// console.log("err ", err);
|
|
||||||
try {
|
try {
|
||||||
setIsDecrypting(true);
|
setIsDecrypting(true);
|
||||||
const size = files?.[0].size;
|
const size = files?.[0].size;
|
||||||
const name = generatePdfName(16);
|
const name = generatePdfName(16);
|
||||||
const url = "https://ai.nxglabs.in/decryptpdf"; //"https://ai.nxglabs.in/decryptpdf"; //
|
const url = "https://ai.nxglabs.in/decryptpdf"; //
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append("file", files[0]);
|
formData.append("file", files[0]);
|
||||||
formData.append("password", "");
|
formData.append("password", "");
|
||||||
@@ -190,6 +191,9 @@ const Forms = (props) => {
|
|||||||
if (parseFile.url()) {
|
if (parseFile.url()) {
|
||||||
setFileUpload(parseFile.url());
|
setFileUpload(parseFile.url());
|
||||||
setfileload(false);
|
setfileload(false);
|
||||||
|
const title = generateTitleFromFilename(files?.[0]?.name);
|
||||||
|
setFormData((obj) => ({ ...obj, Name: title }));
|
||||||
|
SaveFileSize(size, response.url(), tenantId);
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
SaveFileSize(size, parseFile.url(), tenantId);
|
SaveFileSize(size, parseFile.url(), tenantId);
|
||||||
return parseFile.url();
|
return parseFile.url();
|
||||||
@@ -263,6 +267,8 @@ const Forms = (props) => {
|
|||||||
setfileload(false);
|
setfileload(false);
|
||||||
if (response.url()) {
|
if (response.url()) {
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
const title = generateTitleFromFilename(files?.[0]?.name);
|
||||||
|
setFormData((obj) => ({ ...obj, Name: title }));
|
||||||
SaveFileSize(size, response.url(), tenantId);
|
SaveFileSize(size, response.url(), tenantId);
|
||||||
return response.url();
|
return response.url();
|
||||||
}
|
}
|
||||||
@@ -290,12 +296,17 @@ const Forms = (props) => {
|
|||||||
if (res.data) {
|
if (res.data) {
|
||||||
setFileUpload(res.data.url);
|
setFileUpload(res.data.url);
|
||||||
setfileload(false);
|
setfileload(false);
|
||||||
|
const title = generateTitleFromFilename(files?.[0]?.name);
|
||||||
|
setFormData((obj) => ({ ...obj, Name: title }));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
e.target.value = "";
|
e.target.value = "";
|
||||||
setfileload(false);
|
setfileload(false);
|
||||||
setpercentage(0);
|
setpercentage(0);
|
||||||
console.log("err in libreconverter ", err);
|
console.log("err in libreconverter ", err);
|
||||||
|
alert(
|
||||||
|
"We are currently experiencing some issues with processing DOCX files. Please upload the PDF version or contact us on support@opensignlabs.com"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,6 +345,8 @@ const Forms = (props) => {
|
|||||||
setfileload(false);
|
setfileload(false);
|
||||||
if (response.url()) {
|
if (response.url()) {
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
const title = generateTitleFromFilename(file.name);
|
||||||
|
setFormData((obj) => ({ ...obj, Name: title }));
|
||||||
SaveFileSize(size, response.url(), tenantId);
|
SaveFileSize(size, response.url(), tenantId);
|
||||||
return response.url();
|
return response.url();
|
||||||
}
|
}
|
||||||
@@ -371,9 +384,10 @@ const Forms = (props) => {
|
|||||||
});
|
});
|
||||||
setFileUpload(response.url());
|
setFileUpload(response.url());
|
||||||
setfileload(false);
|
setfileload(false);
|
||||||
|
|
||||||
if (response.url()) {
|
if (response.url()) {
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
const title = generateTitleFromFilename(file.name);
|
||||||
|
setFormData((obj) => ({ ...obj, Name: title }));
|
||||||
SaveFileSize(size, response.url(), tenantId);
|
SaveFileSize(size, response.url(), tenantId);
|
||||||
return response.url();
|
return response.url();
|
||||||
}
|
}
|
||||||
@@ -407,6 +421,13 @@ const Forms = (props) => {
|
|||||||
object.set("SendinOrder", isChecked);
|
object.set("SendinOrder", isChecked);
|
||||||
object.set("AutomaticReminders", formData.autoreminder);
|
object.set("AutomaticReminders", formData.autoreminder);
|
||||||
object.set("RemindOnceInEvery", parseInt(formData.remindOnceInEvery));
|
object.set("RemindOnceInEvery", parseInt(formData.remindOnceInEvery));
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const IsEnableOTP =
|
||||||
|
formData?.IsEnableOTP === "false" ? false : true;
|
||||||
|
object.set("IsEnableOTP", IsEnableOTP);
|
||||||
|
} else {
|
||||||
|
object.set("IsEnableOTP", false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
object.set("URL", fileupload);
|
object.set("URL", fileupload);
|
||||||
object.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
|
object.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
|
||||||
@@ -433,7 +454,17 @@ const Forms = (props) => {
|
|||||||
setFormData({
|
setFormData({
|
||||||
Name: "",
|
Name: "",
|
||||||
Description: "",
|
Description: "",
|
||||||
Note: ""
|
Note:
|
||||||
|
props.title === "Sign Yourself"
|
||||||
|
? "Note to myself"
|
||||||
|
: "Please review and sign this document",
|
||||||
|
TimeToCompleteDays: 15,
|
||||||
|
SendinOrder: "true",
|
||||||
|
password: "",
|
||||||
|
file: "",
|
||||||
|
remindOnceInEvery: 5,
|
||||||
|
autoreminder: false,
|
||||||
|
IsEnableOTP: "false"
|
||||||
});
|
});
|
||||||
setFileUpload("");
|
setFileUpload("");
|
||||||
setpercentage(0);
|
setpercentage(0);
|
||||||
@@ -482,7 +513,8 @@ const Forms = (props) => {
|
|||||||
password: "",
|
password: "",
|
||||||
file: "",
|
file: "",
|
||||||
remindOnceInEvery: 5,
|
remindOnceInEvery: 5,
|
||||||
autoreminder: false
|
autoreminder: false,
|
||||||
|
IsEnableOTP: "false"
|
||||||
});
|
});
|
||||||
setFileUpload("");
|
setFileUpload("");
|
||||||
setpercentage(0);
|
setpercentage(0);
|
||||||
@@ -534,6 +566,8 @@ const Forms = (props) => {
|
|||||||
setFormData((prev) => ({ ...prev, password: "" }));
|
setFormData((prev) => ({ ...prev, password: "" }));
|
||||||
setFileUpload(parseFile.url());
|
setFileUpload(parseFile.url());
|
||||||
setfileload(false);
|
setfileload(false);
|
||||||
|
const title = generateTitleFromFilename(formData?.file?.name);
|
||||||
|
setFormData((obj) => ({ ...obj, Name: title }));
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
SaveFileSize(size, parseFile.url(), tenantId);
|
SaveFileSize(size, parseFile.url(), tenantId);
|
||||||
return parseFile.url();
|
return parseFile.url();
|
||||||
@@ -646,7 +680,7 @@ const Forms = (props) => {
|
|||||||
)}
|
)}
|
||||||
<div className="text-xs">
|
<div className="text-xs">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
{`${t("report-heading.File")} (${t("file-type")} ${
|
{`${t("report-heading.File")} (${t("file-type")}${
|
||||||
isEnableSubscription ? ", docx)" : ")"
|
isEnableSubscription ? ", docx)" : ")"
|
||||||
}`}
|
}`}
|
||||||
<span className="text-red-500 text-[13px]">*</span>
|
<span className="text-red-500 text-[13px]">*</span>
|
||||||
@@ -759,120 +793,73 @@ const Forms = (props) => {
|
|||||||
isReset={isReset}
|
isReset={isReset}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{props.title === "Request Signatures" && (
|
{props.title !== "Sign Yourself" && (
|
||||||
<div className="text-xs mt-2">
|
<div className="text-xs mt-2">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
{t("time-to-complete")}
|
{t("send-in-order")}
|
||||||
<span className="text-red-500 text-[13px]">*</span>
|
<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">{t("send-in-order")}</p>
|
||||||
|
<p>{t("send-in-order-help.p1")}</p>
|
||||||
|
<p className="p-[5px]">
|
||||||
|
<ol className="list-disc">
|
||||||
|
<li>
|
||||||
|
<span className="font-bold">{t("yes")}: </span>
|
||||||
|
<span>{t("send-in-order-help.p2")}</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span className="font-bold">{t("no")}: </span>
|
||||||
|
<span>{t("send-in-order-help.p3")}</span>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</p>
|
||||||
|
<p>{t("send-in-order-help.p4")}</p>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||||
type="number"
|
<input
|
||||||
name="TimeToCompleteDays"
|
type="radio"
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
value={"true"}
|
||||||
value={formData.TimeToCompleteDays}
|
className="op-radio op-radio-xs"
|
||||||
onChange={(e) => handleStrInput(e)}
|
name="SendinOrder"
|
||||||
onInvalid={(e) =>
|
checked={formData.SendinOrder === "true"}
|
||||||
e.target.setCustomValidity(t("input-required"))
|
onChange={handleStrInput}
|
||||||
}
|
/>
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
<div className="text-center">{t("yes")}</div>
|
||||||
required
|
</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">{t("no")}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{props.title !== "Sign Yourself" && (
|
{isAdvanceOpt && (
|
||||||
<>
|
<div className="overflow-y-auto z-[500] transition-all">
|
||||||
<div className="text-xs mt-2">
|
{props.title === "Request Signatures" && (
|
||||||
<label className="block">
|
|
||||||
{t("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">{t("send-in-order")}</p>
|
|
||||||
<p>{t("send-in-order-help.p1")}</p>
|
|
||||||
<p className="p-[5px]">
|
|
||||||
<ol className="list-disc">
|
|
||||||
<li>
|
|
||||||
<span className="font-bold">{t("yes")}:</span>
|
|
||||||
<span>{t("send-in-order-help.p2")}</span>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<span className="font-bold">{t("no")}: </span>
|
|
||||||
<span>{t("send-in-order-help.p3")}</span>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</p>
|
|
||||||
<p>{t("send-in-order-help.p4")}</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">{t("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">{t("no")}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{isEnableSubscription && (
|
|
||||||
<div className="text-xs mt-2">
|
|
||||||
<span
|
|
||||||
className={
|
|
||||||
isSubscribe
|
|
||||||
? "font-semibold"
|
|
||||||
: "font-semibold text-gray-300"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{t("auto-reminder")}
|
|
||||||
{" "}
|
|
||||||
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
|
||||||
</span>
|
|
||||||
<label
|
|
||||||
className={`${
|
|
||||||
isSubscribe
|
|
||||||
? "cursor-pointer "
|
|
||||||
: "pointer-events-none opacity-50"
|
|
||||||
} relative block items-center mb-0`}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
|
|
||||||
checked={formData.autoreminder}
|
|
||||||
onChange={handleAutoReminder}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{formData?.autoreminder === true && (
|
|
||||||
<div className="text-xs mt-2">
|
<div className="text-xs mt-2">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
{t("remind-once")}
|
{t("time-to-complete")}
|
||||||
<span className="text-red-500 text-[13px]">*</span>
|
<span className="text-red-500 text-[13px]">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
value={formData.remindOnceInEvery}
|
name="TimeToCompleteDays"
|
||||||
name="remindOnceInEvery"
|
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
onChange={handleStrInput}
|
value={formData.TimeToCompleteDays}
|
||||||
|
onChange={(e) => handleStrInput(e)}
|
||||||
onInvalid={(e) =>
|
onInvalid={(e) =>
|
||||||
e.target.setCustomValidity(t("input-required"))
|
e.target.setCustomValidity(t("input-required"))
|
||||||
}
|
}
|
||||||
@@ -881,7 +868,136 @@ const Forms = (props) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
{props.title !== "Sign Yourself" && (
|
||||||
|
<>
|
||||||
|
{isEnableSubscription && (
|
||||||
|
<div className="text-xs mt-2">
|
||||||
|
<span className={isSubscribe ? "" : " text-gray-300"}>
|
||||||
|
{t("auto-reminder")}{" "}
|
||||||
|
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||||
|
</span>
|
||||||
|
<label
|
||||||
|
className={`${
|
||||||
|
isSubscribe
|
||||||
|
? "cursor-pointer "
|
||||||
|
: "pointer-events-none opacity-50"
|
||||||
|
} relative block items-center mb-0 mt-1.5`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
|
||||||
|
checked={formData.autoreminder}
|
||||||
|
onChange={handleAutoReminder}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{formData?.autoreminder === true && (
|
||||||
|
<div className="text-xs mt-2">
|
||||||
|
<label className="block">
|
||||||
|
{t("remind-once")}
|
||||||
|
<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}
|
||||||
|
onInvalid={(e) =>
|
||||||
|
e.target.setCustomValidity(t("input-required"))
|
||||||
|
}
|
||||||
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isEnableSubscription && (
|
||||||
|
<div className="text-xs mt-2">
|
||||||
|
<label className="block">
|
||||||
|
<span className={isSubscribe ? "" : " text-gray-300"}>
|
||||||
|
{t("isenable-otp")}{" "}
|
||||||
|
<a
|
||||||
|
data-tooltip-id="isenableotp-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>{" "}
|
||||||
|
{!isSubscribe && isEnableSubscription && (
|
||||||
|
<Upgrade />
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<Tooltip id="isenableotp-tooltip" className="z-50">
|
||||||
|
<div className="max-w-[200px] md:max-w-[450px]">
|
||||||
|
<p className="font-bold">{t("isenable-otp")}</p>
|
||||||
|
<p>{t("isenable-otp-help.p1")}</p>
|
||||||
|
<p className="p-[5px]">
|
||||||
|
<ol className="list-disc">
|
||||||
|
<li>
|
||||||
|
<span className="font-bold">
|
||||||
|
{t("yes")}:{" "}
|
||||||
|
</span>
|
||||||
|
<span>{t("isenable-otp-help.p2")}</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span className="font-bold">
|
||||||
|
{t("no")}:{" "}
|
||||||
|
</span>
|
||||||
|
<span>{t("isenable-otp-help.p3")}</span>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</p>
|
||||||
|
<p>{t("isenable-otp-help.p4")}</p>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
className={`${
|
||||||
|
isSubscribe ? "" : "pointer-events-none opacity-50"
|
||||||
|
} flex items-center gap-2 ml-2 mb-1 `}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={"true"}
|
||||||
|
className="op-radio op-radio-xs"
|
||||||
|
name="IsEnableOTP"
|
||||||
|
checked={formData.IsEnableOTP === "true"}
|
||||||
|
onChange={handleStrInput}
|
||||||
|
/>
|
||||||
|
<div className="text-center">{t("yes")}</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`${
|
||||||
|
isSubscribe ? "" : "pointer-events-none opacity-50"
|
||||||
|
} flex items-center gap-2 ml-2 mb-1 `}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={"false"}
|
||||||
|
name="IsEnableOTP"
|
||||||
|
className="op-radio op-radio-xs"
|
||||||
|
checked={formData.IsEnableOTP === "false"}
|
||||||
|
onChange={handleStrInput}
|
||||||
|
/>
|
||||||
|
<div className="text-center">{t("no")}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{props.title !== "Sign Yourself" && (
|
||||||
|
<div
|
||||||
|
onClick={() => setIsAdvanceOpt(!isAdvanceOpt)}
|
||||||
|
className={`mt-2.5 op-link op-link-primary text-sm`}
|
||||||
|
>
|
||||||
|
{isAdvanceOpt
|
||||||
|
? t("hide-advanced-options")
|
||||||
|
: t("advanced-options")}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex items-center mt-3 gap-2">
|
<div className="flex items-center mt-3 gap-2">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -10,17 +10,39 @@ import Loader from "../primitives/Loader";
|
|||||||
import SubscribeCard from "../primitives/SubscribeCard";
|
import SubscribeCard from "../primitives/SubscribeCard";
|
||||||
import Tour from "reactour";
|
import Tour from "reactour";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import Parse from "parse";
|
||||||
|
|
||||||
function GenerateToken() {
|
function GenerateToken() {
|
||||||
|
const origin = window.location.origin;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
|
const parseBaseUrl = localStorage.getItem("baseUrl");
|
||||||
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
|
const parseAppId = localStorage.getItem("parseAppId");
|
||||||
const [apiToken, SetApiToken] = useState("");
|
const [apiToken, SetApiToken] = useState("");
|
||||||
const [isLoader, setIsLoader] = useState(true);
|
const [isLoader, setIsLoader] = useState(true);
|
||||||
const [isModal, setIsModal] = useState(false);
|
const [isModal, setIsModal] = useState({
|
||||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
generateapi: false,
|
||||||
|
buyapis: false,
|
||||||
|
unauthorized: false
|
||||||
|
});
|
||||||
|
const [isSubscribe, setIsSubscribe] = useState({
|
||||||
|
plan: "",
|
||||||
|
isValid: false,
|
||||||
|
adminId: "",
|
||||||
|
adminEmail: ""
|
||||||
|
});
|
||||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||||
const [isTour, setIsTour] = useState(false);
|
const [isTour, setIsTour] = useState(false);
|
||||||
|
const [amount, setAmount] = useState({
|
||||||
|
quantity: 500,
|
||||||
|
priceperapi: 0.15,
|
||||||
|
allowedcredits: 0,
|
||||||
|
addoncredits: 0,
|
||||||
|
totalcredits: 0,
|
||||||
|
price: (75.0).toFixed(2)
|
||||||
|
});
|
||||||
|
const [isFormLoader, setIsFormLoader] = useState(false);
|
||||||
|
const [apitestToken, setApiTestToken] = useState("");
|
||||||
|
const quantityList = [500, 1000, 5000, 50000];
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchToken();
|
fetchToken();
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
@@ -34,8 +56,8 @@ function GenerateToken() {
|
|||||||
const fetchToken = async () => {
|
const fetchToken = async () => {
|
||||||
try {
|
try {
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const getIsSubscribe = await checkIsSubscribed();
|
const subscribe = await checkIsSubscribed();
|
||||||
setIsSubscribe(getIsSubscribe);
|
setIsSubscribe(subscribe);
|
||||||
}
|
}
|
||||||
const url = parseBaseUrl + "functions/getapitoken";
|
const url = parseBaseUrl + "functions/getapitoken";
|
||||||
const headers = {
|
const headers = {
|
||||||
@@ -45,22 +67,40 @@ function GenerateToken() {
|
|||||||
};
|
};
|
||||||
const res = await axios.post(url, {}, { headers: headers });
|
const res = await axios.post(url, {}, { headers: headers });
|
||||||
if (res) {
|
if (res) {
|
||||||
SetApiToken(res.data?.result?.result);
|
const resCredits = await Parse.Cloud.run("allowedcredits");
|
||||||
|
const allowedcredits = resCredits?.allowedcredits || 0;
|
||||||
|
const addoncredits = resCredits?.addoncredits || 0;
|
||||||
|
const totalcredits = allowedcredits + addoncredits;
|
||||||
|
setAmount((obj) => ({
|
||||||
|
...obj,
|
||||||
|
allowedcredits: allowedcredits,
|
||||||
|
addoncredits: addoncredits,
|
||||||
|
totalcredits: totalcredits
|
||||||
|
}));
|
||||||
|
SetApiToken(res?.data?.result?.result);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const body = { email: Parse?.User?.current()?.getEmail() || "" };
|
||||||
|
const testurl = "https://sandbox.opensignlabs.com/api/gettesttoken";
|
||||||
|
const testRes = await axios.post(testurl, body);
|
||||||
|
setApiTestToken(testRes.data?.token);
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in fetch test token", err);
|
||||||
}
|
}
|
||||||
setIsLoader(false);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
SetApiToken();
|
SetApiToken();
|
||||||
setIsLoader(false);
|
|
||||||
console.log("Err", err);
|
console.log("Err", err);
|
||||||
|
} finally {
|
||||||
|
setIsLoader(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!isSubscribe && isEnableSubscription) {
|
if (isSubscribe?.plan === "freeplan" && isEnableSubscription) {
|
||||||
setIsTour(true);
|
setIsTour(true);
|
||||||
} else {
|
} else {
|
||||||
setIsLoader(true);
|
setIsLoader(true);
|
||||||
setIsModal(false);
|
setIsModal((obj) => ({ ...obj, generateapi: false }));
|
||||||
try {
|
try {
|
||||||
const url = parseBaseUrl + "functions/generateapitoken";
|
const url = parseBaseUrl + "functions/generateapitoken";
|
||||||
const headers = {
|
const headers = {
|
||||||
@@ -91,20 +131,114 @@ function GenerateToken() {
|
|||||||
const copytoclipboard = (text) => {
|
const copytoclipboard = (text) => {
|
||||||
copytoData(text);
|
copytoData(text);
|
||||||
setIsAlert({ type: "success", msg: t("copied") });
|
setIsAlert({ type: "success", msg: t("copied") });
|
||||||
setTimeout(() => {
|
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500); // Reset copied state after 1.5 seconds
|
||||||
setIsAlert({ type: "success", msg: "" });
|
};
|
||||||
}, 1500); // Reset copied state after 1.5 seconds
|
const handleModal = () => {
|
||||||
|
if (isSubscribe?.plan === "freeplan" && isEnableSubscription) {
|
||||||
|
setIsTour(true);
|
||||||
|
} else {
|
||||||
|
setIsModal((obj) => ({ ...obj, generateapi: !obj.generateapi }));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const handleModal = () => setIsModal(!isModal);
|
|
||||||
|
|
||||||
|
const handleBuyAPIsModal = () => {
|
||||||
|
if (isSubscribe?.plan === "freeplan" && isEnableSubscription) {
|
||||||
|
setIsTour(true);
|
||||||
|
} else {
|
||||||
|
const extUser =
|
||||||
|
localStorage.getItem("Extand_Class") &&
|
||||||
|
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
|
if (isSubscribe?.adminId && extUser?.objectId === isSubscribe?.adminId) {
|
||||||
|
setIsModal((obj) => ({ ...obj, buyapis: !obj.buyapis }));
|
||||||
|
} else {
|
||||||
|
setIsSubscribe((obj) => ({
|
||||||
|
...obj,
|
||||||
|
adminEmail: extUser?.TenantId?.EmailAddress
|
||||||
|
}));
|
||||||
|
setIsModal((obj) => ({ ...obj, unauthorized: !obj.unauthorized }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleCloseModal = () => {
|
||||||
|
setIsModal({ generateapi: false, buyapis: false, unauthorized: false });
|
||||||
|
};
|
||||||
|
const handlePricePerAPIs = (e) => {
|
||||||
|
const quantity = e.target?.value;
|
||||||
|
const price =
|
||||||
|
quantity > 0
|
||||||
|
? (Math.round(quantity * amount.priceperapi * 100) / 100).toFixed(2)
|
||||||
|
: (Math.round(500 * amount.priceperapi * 100) / 100).toFixed(2);
|
||||||
|
setAmount((prev) => ({ ...prev, quantity: quantity, price: price }));
|
||||||
|
};
|
||||||
|
const handleAddOnApiSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setIsFormLoader(true);
|
||||||
|
try {
|
||||||
|
const resAddon = await Parse.Cloud.run("buycredits", {
|
||||||
|
credits: amount.quantity
|
||||||
|
});
|
||||||
|
if (resAddon) {
|
||||||
|
const _resAddon = JSON.parse(JSON.stringify(resAddon));
|
||||||
|
if (_resAddon.status === "success") {
|
||||||
|
setAmount((obj) => ({
|
||||||
|
...obj,
|
||||||
|
quantity: 500,
|
||||||
|
priceperapi: 0.15,
|
||||||
|
price: (75.0).toFixed(2),
|
||||||
|
totalcredits: obj?.totalcredits + _resAddon.addon,
|
||||||
|
addoncredits: obj?.addoncredits + _resAddon.addon
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setIsModal((obj) => ({ ...obj, buyapis: false }));
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err in buy addon", err);
|
||||||
|
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 2000);
|
||||||
|
setIsFormLoader(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleGenerateTestToken = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setIsLoader(true);
|
||||||
|
// setIsModal((obj) => ({ ...obj, generateapi: false }));
|
||||||
|
try {
|
||||||
|
const url = "https://sandbox.opensignlabs.com/api/generatetesttoken";
|
||||||
|
const headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
token: apitestToken || "1"
|
||||||
|
};
|
||||||
|
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
|
const body = {
|
||||||
|
name: extUser?.Name,
|
||||||
|
email: extUser?.Email,
|
||||||
|
phone: extUser?.Phone,
|
||||||
|
company: extUser?.Company,
|
||||||
|
jobTitle: extUser?.JobTitle
|
||||||
|
};
|
||||||
|
const res = await axios.post(url, body, { headers: headers });
|
||||||
|
if (res) {
|
||||||
|
setApiTestToken(res.data?.token);
|
||||||
|
setIsAlert({ type: "success", msg: t("token-generated") });
|
||||||
|
} else {
|
||||||
|
console.error("Error while generating Token");
|
||||||
|
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
|
||||||
|
console.log("while generating Token", error);
|
||||||
|
} finally {
|
||||||
|
setIsLoader(false);
|
||||||
|
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Title title={"API Token"} />
|
<Title title={"API Token"} />
|
||||||
{isAlert.msg && (
|
{isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
|
||||||
<Alert type={isAlert.type}>
|
|
||||||
<div className="ml-3">{isAlert.msg}</div>
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
{isLoader ? (
|
{isLoader ? (
|
||||||
<div className="flex justify-center items-center h-screen">
|
<div className="flex justify-center items-center h-screen">
|
||||||
<Loader />
|
<Loader />
|
||||||
@@ -115,29 +249,66 @@ function GenerateToken() {
|
|||||||
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||||
OpenSign™ {t("API")}{" "}
|
OpenSign™ {t("API")}{" "}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
url={
|
url="https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
||||||
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
|
||||||
}
|
|
||||||
isSubscribe={true}
|
isSubscribe={true}
|
||||||
/>
|
/>
|
||||||
</h1>
|
</h1>
|
||||||
<ul className="w-full flex flex-col p-2 text-sm">
|
<ul className="w-full flex flex-col p-2 text-sm">
|
||||||
|
<li className="flex flex-col md:flex-row justify-between items-center border-t-[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">
|
||||||
|
<span className="font-medium">API Test Token : </span>
|
||||||
|
<span className="text-xs">
|
||||||
|
<Tooltip message={t("help-test-token")} />
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span id="token" className="md:text-end py-2 md:py-0">
|
||||||
|
<span
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => copytoclipboard(apitestToken)}
|
||||||
|
>
|
||||||
|
{apitestToken ? apitestToken : "_____"}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
className="op-btn op-btn-accent op-btn-outline op-btn-sm ml-2 cursor-pointer"
|
||||||
|
onClick={() => copytoclipboard(apitestToken)}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-copy"></i>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={handleGenerateTestToken}
|
||||||
|
className="op-btn op-btn-primary w-[210px] md:w-auto"
|
||||||
|
>
|
||||||
|
{apitestToken
|
||||||
|
? t("regenerate-test-token")
|
||||||
|
: t("generate-test-token")}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
<li className="flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2">
|
<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">
|
<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">{t("api-token")}:</span>{" "}
|
<span className="ml-1">
|
||||||
|
<span className="font-medium">{t("api-token")} : </span>
|
||||||
|
<span className="text-xs">
|
||||||
|
<Tooltip message={t("help-api-token", { origin })} />
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
<span
|
<span
|
||||||
id="token"
|
id="token"
|
||||||
className={`${
|
className={`${
|
||||||
isSubscribe
|
isSubscribe?.plan === "freeplan"
|
||||||
? ""
|
? "bg-white/20 pointer-events-none select-none"
|
||||||
: "bg-white/20 pointer-events-none select-none"
|
: ""
|
||||||
} md:text-end py-2 md:py-0`}
|
} md:text-end py-2 md:py-0`}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
onClick={() => copytoclipboard(apiToken)}
|
onClick={() => copytoclipboard(apiToken)}
|
||||||
>
|
>
|
||||||
{apiToken ? apiToken : "_____"}
|
{isSubscribe?.plan !== "freeplan" && apiToken
|
||||||
|
? apiToken
|
||||||
|
: "_____"}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
className="op-btn op-btn-accent op-btn-outline op-btn-sm ml-2 cursor-pointer"
|
className="op-btn op-btn-accent op-btn-outline op-btn-sm ml-2 cursor-pointer"
|
||||||
@@ -149,13 +320,30 @@ function GenerateToken() {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={apiToken ? handleModal : handleSubmit}
|
onClick={apiToken ? handleModal : handleSubmit}
|
||||||
className="op-btn op-btn-primary"
|
className="op-btn op-btn-primary w-[210px] md:w-auto"
|
||||||
>
|
>
|
||||||
{apiToken ? t("regenerate-token") : t("generate-token")}
|
{apiToken ? t("regenerate-token") : t("generate-token")}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
<div className="text-xs md:text-[15px] my-3 w-full md:w-[70%] flex-col md:flex-row flex items-center gap-x-5">
|
||||||
|
<span className="font-medium">
|
||||||
|
{t("remaining-credits")}{" "}
|
||||||
|
<span className="text-xs">
|
||||||
|
<Tooltip
|
||||||
|
message={t("remaining-credits-help", {
|
||||||
|
allowedcredits: amount?.allowedcredits || 0,
|
||||||
|
addoncredits: amount?.addoncredits || 0
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span className="md:text-end py-2 md:py-0">
|
||||||
|
{amount.totalcredits}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
</ul>
|
</ul>
|
||||||
<div className="flex items-center justify-center">
|
<div className="flex flex-col md:flex-row items-center justify-center gap-0 md:gap-1">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -163,13 +351,20 @@ function GenerateToken() {
|
|||||||
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
className="op-btn op-btn-secondary mt-2 mb-3 px-8"
|
className="op-btn op-btn-secondary mt-2 md:mb-3 px-8 w-[210px] md:w-auto"
|
||||||
>
|
>
|
||||||
{t("view-docs")}
|
{t("view-docs")}
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleBuyAPIsModal()}
|
||||||
|
className="op-btn op-btn-accent mt-2 mb-3 px-8 w-[210px] md:w-auto"
|
||||||
|
>
|
||||||
|
{t("buy-credits")}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen={isModal}
|
isOpen={isModal.generateapi}
|
||||||
title={apiToken ? t("regenerate-token") : t("generate-token")}
|
title={apiToken ? t("regenerate-token") : t("generate-token")}
|
||||||
handleClose={handleModal}
|
handleClose={handleModal}
|
||||||
>
|
>
|
||||||
@@ -194,8 +389,68 @@ function GenerateToken() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
|
{/* buy APIs */}
|
||||||
|
<ModalUi
|
||||||
|
isOpen={isModal.buyapis}
|
||||||
|
title={"Buy Credits"}
|
||||||
|
handleClose={handleCloseModal}
|
||||||
|
>
|
||||||
|
{isFormLoader && (
|
||||||
|
<div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<form onSubmit={handleAddOnApiSubmit} className="p-3">
|
||||||
|
<div className="mb-3 flex justify-between">
|
||||||
|
<label
|
||||||
|
htmlFor="quantity"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("quantity-of-credits")}
|
||||||
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={amount.quantity}
|
||||||
|
onChange={(e) => handlePricePerAPIs(e)}
|
||||||
|
name="quantity"
|
||||||
|
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-1/4 text-xs"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
{quantityList.length > 0 &&
|
||||||
|
quantityList.map((x) => (
|
||||||
|
<option key={x} value={x}>
|
||||||
|
{x}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3 flex justify-between">
|
||||||
|
<label className="block text-xs text-gray-700 font-semibold">
|
||||||
|
{t("Price")} (1 * {amount.priceperapi})
|
||||||
|
</label>
|
||||||
|
<div className="w-1/4 flex justify-center items-center text-sm">
|
||||||
|
USD {amount.price}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr className="text-base-content mb-3" />
|
||||||
|
<button className="op-btn op-btn-primary w-full mt-2">
|
||||||
|
{t("Proceed")}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</ModalUi>
|
||||||
|
<ModalUi
|
||||||
|
isOpen={isModal.unauthorized}
|
||||||
|
title={"Unauthorized"}
|
||||||
|
handleClose={handleCloseModal}
|
||||||
|
>
|
||||||
|
<div className="m-8 flex justify-center text-center items-center font-medium break-all">
|
||||||
|
{t("unauthorized-modal", {
|
||||||
|
adminEmail: isSubscribe?.adminEmail
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
</div>
|
</div>
|
||||||
{!isSubscribe && isEnableSubscription && (
|
{isEnableSubscription && isSubscribe?.plan === "freeplan" && (
|
||||||
<div data-tut="apisubscribe">
|
<div data-tut="apisubscribe">
|
||||||
<SubscribeCard />
|
<SubscribeCard />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -28,6 +28,28 @@ function GuestLogin() {
|
|||||||
const [contactId, setContactId] = useState(contactBookId);
|
const [contactId, setContactId] = useState(contactBookId);
|
||||||
const [sendmail, setSendmail] = useState();
|
const [sendmail, setSendmail] = useState();
|
||||||
const [contact, setContact] = useState({ name: "", phone: "", email: "" });
|
const [contact, setContact] = useState({ name: "", phone: "", email: "" });
|
||||||
|
const navigateToDoc = async (docId, contactId) => {
|
||||||
|
try {
|
||||||
|
const docDetails = await Parse.Cloud.run("getDocument", {
|
||||||
|
docId: docId
|
||||||
|
});
|
||||||
|
if (!docDetails.error) {
|
||||||
|
if (sendmail === "false") {
|
||||||
|
navigate(
|
||||||
|
`/load/recipientSignPdf/${docId}/${contactId}?sendmail=${sendmail}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
navigate(`/load/recipientSignPdf/${docId}/${contactId}`);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err while getting doc", err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleServerUrl();
|
handleServerUrl();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
@@ -70,13 +92,14 @@ function GuestLogin() {
|
|||||||
"linkcontacttodoc",
|
"linkcontacttodoc",
|
||||||
params
|
params
|
||||||
);
|
);
|
||||||
// console.log("linkContactRes ", linkContactRes);
|
|
||||||
setContactId(linkContactRes?.contactId);
|
setContactId(linkContactRes?.contactId);
|
||||||
|
await navigateToDoc(checkSplit[0], linkContactRes?.contactId);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Err in link ext contact", err);
|
console.log("Err in link ext contact", err);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setContactId(checkSplit[2]);
|
setContactId(checkSplit[2]);
|
||||||
|
await navigateToDoc(checkSplit[0], checkSplit[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,15 +137,12 @@ function GuestLogin() {
|
|||||||
if (OTP) {
|
if (OTP) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
let url = `${serverUrl}functions/AuthLoginAsMail/`;
|
let url = `${serverUrl}functions/AuthLoginAsMail`;
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": parseId
|
"X-Parse-Application-Id": parseId
|
||||||
};
|
};
|
||||||
let body = {
|
let body = { email: email, otp: OTP };
|
||||||
email: email,
|
|
||||||
otp: OTP
|
|
||||||
};
|
|
||||||
let user = await axios.post(url, body, { headers: headers });
|
let user = await axios.post(url, body, { headers: headers });
|
||||||
if (user.data.result === "Invalid Otp") {
|
if (user.data.result === "Invalid Otp") {
|
||||||
alert(t("invalid-otp"));
|
alert(t("invalid-otp"));
|
||||||
@@ -140,7 +160,6 @@ function GuestLogin() {
|
|||||||
`Parse/${parseId}/currentUser`,
|
`Parse/${parseId}/currentUser`,
|
||||||
JSON.stringify(_user)
|
JSON.stringify(_user)
|
||||||
);
|
);
|
||||||
// console.log("contractUserDetails ", contractUserDetails);
|
|
||||||
if (contractUserDetails && contractUserDetails.length > 0) {
|
if (contractUserDetails && contractUserDetails.length > 0) {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"Extand_Class",
|
"Extand_Class",
|
||||||
@@ -174,10 +193,15 @@ function GuestLogin() {
|
|||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const linkContactRes = await Parse.Cloud.run("linkcontacttodoc", params);
|
const linkContactRes = await Parse.Cloud.run("linkcontacttodoc", params);
|
||||||
// console.log("linkContactRes ", linkContactRes);
|
|
||||||
setContactId(linkContactRes.contactId);
|
setContactId(linkContactRes.contactId);
|
||||||
setEnterOtp(true);
|
const IsEnableOTP = await navigateToDoc(
|
||||||
await SendOtp();
|
documentId,
|
||||||
|
linkContactRes.contactId
|
||||||
|
);
|
||||||
|
if (!IsEnableOTP) {
|
||||||
|
setEnterOtp(true);
|
||||||
|
await SendOtp();
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
alert(t("something-went-wrong-mssg"));
|
alert(t("something-went-wrong-mssg"));
|
||||||
@@ -208,7 +232,7 @@ function GuestLogin() {
|
|||||||
<div className="w-full md:w-[50%] text-base-content">
|
<div className="w-full md:w-[50%] text-base-content">
|
||||||
<h1 className="text-2xl md:text-[30px]">{t("welcome")}</h1>
|
<h1 className="text-2xl md:text-[30px]">{t("welcome")}</h1>
|
||||||
<legend className="text-[12px] text-[#878787] mt-2 mb-1">
|
<legend className="text-[12px] text-[#878787] mt-2 mb-1">
|
||||||
{t("guest-email-alert")}
|
{t("get-otp-alert")}
|
||||||
</legend>
|
</legend>
|
||||||
<div className="p-[20px] outline outline-1 outline-slate-300/50 my-2 op-card shadow-md">
|
<div className="p-[20px] outline outline-1 outline-slate-300/50 my-2 op-card shadow-md">
|
||||||
<input
|
<input
|
||||||
@@ -236,7 +260,7 @@ function GuestLogin() {
|
|||||||
>
|
>
|
||||||
<h1 className="text-2xl md:text-[30px]">{t("welcome")}</h1>
|
<h1 className="text-2xl md:text-[30px]">{t("welcome")}</h1>
|
||||||
<legend className="text-[12px] text-[#878787] mt-2">
|
<legend className="text-[12px] text-[#878787] mt-2">
|
||||||
{t("get-verification-code-2")}
|
{t("guest-email-alert")}
|
||||||
</legend>
|
</legend>
|
||||||
<div className="p-[20px] pt-[15px] outline outline-1 outline-slate-300/50 op-card my-2 shadow-md">
|
<div className="p-[20px] pt-[15px] outline outline-1 outline-slate-300/50 op-card my-2 shadow-md">
|
||||||
<p className="text-sm">{t("enter-verification-code")}</p>
|
<p className="text-sm">{t("enter-verification-code")}</p>
|
||||||
|
|||||||
@@ -80,7 +80,9 @@ function Login() {
|
|||||||
}
|
}
|
||||||
setState({ ...state, [name]: value });
|
setState({ ...state, [name]: value });
|
||||||
};
|
};
|
||||||
|
const handlePaidRoute = () => {
|
||||||
|
navigate("/subscription");
|
||||||
|
};
|
||||||
const handleSubmit = async (event) => {
|
const handleSubmit = async (event) => {
|
||||||
localStorage.removeItem("accesstoken");
|
localStorage.removeItem("accesstoken");
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -158,9 +160,9 @@ function Login() {
|
|||||||
JSON.stringify(LocalUserDetails)
|
JSON.stringify(LocalUserDetails)
|
||||||
);
|
);
|
||||||
const res = await fetchSubscription();
|
const res = await fetchSubscription();
|
||||||
const freeplan = res.plan;
|
const plan = res.plan;
|
||||||
const billingDate = res.billingDate;
|
const billingDate = res.billingDate;
|
||||||
if (freeplan === "freeplan") {
|
if (plan === "freeplan") {
|
||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
} else if (billingDate) {
|
} else if (billingDate) {
|
||||||
@@ -171,11 +173,11 @@ function Login() {
|
|||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
} else {
|
} else {
|
||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
navigate(`/subscription`, { replace: true });
|
handlePaidRoute(plan);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
navigate(`/subscription`, { replace: true });
|
handlePaidRoute(plan);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
@@ -330,9 +332,9 @@ function Login() {
|
|||||||
localStorage.setItem("pageType", menu.pageType);
|
localStorage.setItem("pageType", menu.pageType);
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const res = await fetchSubscription();
|
const res = await fetchSubscription();
|
||||||
const freeplan = res.plan;
|
const plan = res.plan;
|
||||||
const billingDate = res.billingDate;
|
const billingDate = res.billingDate;
|
||||||
if (freeplan === "freeplan") {
|
if (plan === "freeplan") {
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
} else if (billingDate) {
|
} else if (billingDate) {
|
||||||
if (new Date(billingDate) > new Date()) {
|
if (new Date(billingDate) > new Date()) {
|
||||||
@@ -342,14 +344,14 @@ function Login() {
|
|||||||
if (isFreeplan) {
|
if (isFreeplan) {
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`, { replace: true });
|
handlePaidRoute(plan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isFreeplan) {
|
if (isFreeplan) {
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`, { replace: true });
|
handlePaidRoute(plan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -462,8 +464,8 @@ function Login() {
|
|||||||
localStorage.setItem("userDetails", JSON.stringify(userInfo));
|
localStorage.setItem("userDetails", JSON.stringify(userInfo));
|
||||||
const res = await fetchSubscription();
|
const res = await fetchSubscription();
|
||||||
const billingDate = res.billingDate;
|
const billingDate = res.billingDate;
|
||||||
const freeplan = res.plan;
|
const plan = res.plan;
|
||||||
if (freeplan === "freeplan") {
|
if (plan === "freeplan") {
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
} else if (billingDate) {
|
} else if (billingDate) {
|
||||||
if (new Date(billingDate) > new Date()) {
|
if (new Date(billingDate) > new Date()) {
|
||||||
@@ -471,10 +473,10 @@ function Login() {
|
|||||||
// Redirect to the appropriate URL after successful login
|
// Redirect to the appropriate URL after successful login
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`);
|
handlePaidRoute(plan);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`);
|
handlePaidRoute(plan);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Redirect to the appropriate URL after successful login
|
// Redirect to the appropriate URL after successful login
|
||||||
@@ -573,10 +575,12 @@ function Login() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const logOutUser = () => {
|
const logOutUser = async () => {
|
||||||
setIsModal(false);
|
setIsModal(false);
|
||||||
if (Parse?.User?.current()) {
|
try {
|
||||||
Parse.User.logOut();
|
await Parse.User.logOut();
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err while logging out", err);
|
||||||
}
|
}
|
||||||
let appdata = localStorage.getItem("userSettings");
|
let appdata = localStorage.getItem("userSettings");
|
||||||
let applogo = localStorage.getItem("appLogo");
|
let applogo = localStorage.getItem("appLogo");
|
||||||
@@ -789,9 +793,7 @@ function Login() {
|
|||||||
</div>
|
</div>
|
||||||
<SelectLanguage />
|
<SelectLanguage />
|
||||||
{state.alertMsg && (
|
{state.alertMsg && (
|
||||||
<Alert type={state.alertType}>
|
<Alert type={state.alertType}>{state.alertMsg}</Alert>
|
||||||
<div className="ml-3">{state.alertMsg}</div>
|
|
||||||
</Alert>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<ModalUi
|
<ModalUi
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ import checkmark from "../assets/images/checkmark.png";
|
|||||||
import plansArr from "../json/plansArr";
|
import plansArr from "../json/plansArr";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import { openInNewTab } from "../constant/Utils";
|
import { openInNewTab, saveLanguageInLocal } from "../constant/Utils";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
const listItemStyle = {
|
const listItemStyle = {
|
||||||
@@ -53,12 +53,6 @@ const PlanSubscriptions = () => {
|
|||||||
? "&mobile=" + encodeURIComponent(userDetails.phone)
|
? "&mobile=" + encodeURIComponent(userDetails.phone)
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
const details =
|
|
||||||
"?shipping_country_code=US&billing_country_code=US&billing_state_code=CA&" +
|
|
||||||
name +
|
|
||||||
email +
|
|
||||||
company +
|
|
||||||
phone;
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
detectLanguage();
|
detectLanguage();
|
||||||
@@ -72,6 +66,32 @@ const PlanSubscriptions = () => {
|
|||||||
|
|
||||||
const handleFreePlan = async (item) => {
|
const handleFreePlan = async (item) => {
|
||||||
if (item.url) {
|
if (item.url) {
|
||||||
|
const code = yearlyVisible ? item.code.yearly : item.code.monthly;
|
||||||
|
const allowedUsers =
|
||||||
|
localStorage.getItem("allowedUsers") &&
|
||||||
|
localStorage.getItem("allowedUsers") > 0
|
||||||
|
? localStorage.getItem("allowedUsers") - 1
|
||||||
|
: "";
|
||||||
|
const teamperiod = {
|
||||||
|
"team-weekly": "monthly",
|
||||||
|
"team-yearly": "yearly",
|
||||||
|
"teams-monthly": "monthly",
|
||||||
|
"teams-yearly": "yearly"
|
||||||
|
};
|
||||||
|
const period = teamperiod[code] || "";
|
||||||
|
|
||||||
|
const quantity =
|
||||||
|
allowedUsers && period
|
||||||
|
? `addon_code%5B0%5D=extra-teams-users-${period}&addon_quantity%5B0%5D=${allowedUsers}&`
|
||||||
|
: "";
|
||||||
|
|
||||||
|
const details =
|
||||||
|
"?shipping_country_code=US&billing_country_code=US&billing_state_code=CA&" +
|
||||||
|
quantity +
|
||||||
|
name +
|
||||||
|
email +
|
||||||
|
company +
|
||||||
|
phone;
|
||||||
const url = yearlyVisible ? item.yearlyUrl + details : item.url + details;
|
const url = yearlyVisible ? item.yearlyUrl + details : item.url + details;
|
||||||
if (user) {
|
if (user) {
|
||||||
localStorage.setItem("userDetails", JSON.stringify(user));
|
localStorage.setItem("userDetails", JSON.stringify(user));
|
||||||
@@ -99,6 +119,30 @@ const PlanSubscriptions = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const handleLogout = async () => {
|
||||||
|
try {
|
||||||
|
await Parse?.User?.logOut();
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err while logging out", err);
|
||||||
|
}
|
||||||
|
let appdata = localStorage.getItem("userSettings");
|
||||||
|
let applogo = localStorage.getItem("appLogo");
|
||||||
|
let defaultmenuid = localStorage.getItem("defaultmenuid");
|
||||||
|
let PageLanding = localStorage.getItem("PageLanding");
|
||||||
|
let baseUrl = localStorage.getItem("baseUrl");
|
||||||
|
let appid = localStorage.getItem("parseAppId");
|
||||||
|
|
||||||
|
localStorage.clear();
|
||||||
|
saveLanguageInLocal(i18n);
|
||||||
|
localStorage.setItem("appLogo", applogo);
|
||||||
|
localStorage.setItem("defaultmenuid", defaultmenuid);
|
||||||
|
localStorage.setItem("PageLanding", PageLanding);
|
||||||
|
localStorage.setItem("userSettings", appdata);
|
||||||
|
localStorage.setItem("baseUrl", baseUrl);
|
||||||
|
localStorage.setItem("parseAppId", appid);
|
||||||
|
|
||||||
|
navigate("/");
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title title={"Subscriptions"} />
|
<Title title={"Subscriptions"} />
|
||||||
@@ -109,7 +153,13 @@ const PlanSubscriptions = () => {
|
|||||||
) : (
|
) : (
|
||||||
<div className="overflow-y-auto max-h-full">
|
<div className="overflow-y-auto max-h-full">
|
||||||
<div className="block my-2">
|
<div className="block my-2">
|
||||||
<div className="flex flex-col justify-center items-center w-full">
|
<div className="flex flex-col justify-center items-center w-full relative">
|
||||||
|
<button
|
||||||
|
className="md:hidden op-btn op-btn-primary op-btn-sm h-[40px] w-[250px] shadow-lg"
|
||||||
|
onClick={() => handleLogout()}
|
||||||
|
>
|
||||||
|
Log out
|
||||||
|
</button>
|
||||||
<div
|
<div
|
||||||
role="tablist"
|
role="tablist"
|
||||||
className="op-tabs op-tabs-boxed bg-base-100 my-2 shadow-lg transition-all"
|
className="op-tabs op-tabs-boxed bg-base-100 my-2 shadow-lg transition-all"
|
||||||
@@ -130,6 +180,12 @@ const PlanSubscriptions = () => {
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<ul className="op-card flex flex-col md:flex-row h-full bg-base-100 justify-center shadow-lg">
|
<ul className="op-card flex flex-col md:flex-row h-full bg-base-100 justify-center shadow-lg">
|
||||||
|
<button
|
||||||
|
className="hidden md:block -top-12 right-1 absolute w-[150px] h-[40px] op-btn op-btn-primary op-btn-sm shadow-lg"
|
||||||
|
onClick={() => handleLogout()}
|
||||||
|
>
|
||||||
|
{t("log-out")}
|
||||||
|
</button>
|
||||||
{plansArr.map((item) => (
|
{plansArr.map((item) => (
|
||||||
<li
|
<li
|
||||||
className="flex flex-col text-center border-collapse border-[1px] border-gray-300 max-w-[250px]"
|
className="flex flex-col text-center border-collapse border-[1px] border-gray-300 max-w-[250px]"
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ const SSOVerify = () => {
|
|||||||
console.log("err", err.message);
|
console.log("err", err.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const handlePaidRoute = () => {
|
||||||
|
navigate("/subscription");
|
||||||
|
};
|
||||||
const checkExtUser = async (ssosign) => {
|
const checkExtUser = async (ssosign) => {
|
||||||
const params = { email: ssosign?.email };
|
const params = { email: ssosign?.email };
|
||||||
try {
|
try {
|
||||||
@@ -196,10 +199,10 @@ const SSOVerify = () => {
|
|||||||
localStorage.removeItem("userDetails");
|
localStorage.removeItem("userDetails");
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`, { replace: true });
|
handlePaidRoute(plan);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`, { replace: true });
|
handlePaidRoute(plan);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
@@ -225,10 +228,12 @@ const SSOVerify = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// `handleCloseModal` is triggered when the user wants to close the new user flow modal
|
// `handleCloseModal` is triggered when the user wants to close the new user flow modal
|
||||||
const handleCloseModal = () => {
|
const handleCloseModal = async () => {
|
||||||
setIsModal(false);
|
setIsModal(false);
|
||||||
if (Parse?.User?.current()) {
|
try {
|
||||||
Parse.User.logOut();
|
await Parse.User.logOut();
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err while logging out", err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,10 @@ const Signup = () => {
|
|||||||
const togglePasswordVisibility = () => setShowPassword(!showPassword);
|
const togglePasswordVisibility = () => setShowPassword(!showPassword);
|
||||||
|
|
||||||
const clearStorage = async () => {
|
const clearStorage = async () => {
|
||||||
if (Parse.User.current()) {
|
try {
|
||||||
await Parse.User.logOut();
|
await Parse.User.logOut();
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err while logging out", err);
|
||||||
}
|
}
|
||||||
let baseUrl = localStorage.getItem("baseUrl");
|
let baseUrl = localStorage.getItem("baseUrl");
|
||||||
let appid = localStorage.getItem("parseAppId");
|
let appid = localStorage.getItem("parseAppId");
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import "../styles/signature.css";
|
|||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import Confetti from "react-confetti";
|
import Confetti from "react-confetti";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import LoaderWithMsg from "../primitives/LoaderWithMsg";
|
|
||||||
import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage";
|
import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage";
|
||||||
import { DndProvider } from "react-dnd";
|
import { DndProvider } from "react-dnd";
|
||||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||||
@@ -34,25 +33,31 @@ import {
|
|||||||
changeImageWH,
|
changeImageWH,
|
||||||
handleSendOTP,
|
handleSendOTP,
|
||||||
getContainerScale,
|
getContainerScale,
|
||||||
getDefaultSignature
|
getDefaultSignature,
|
||||||
|
onClickZoomIn,
|
||||||
|
onClickZoomOut,
|
||||||
|
rotatePdfPage
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import Tour from "reactour";
|
import Tour from "reactour";
|
||||||
import Signedby from "../components/pdf/Signedby";
|
import Signedby from "../components/pdf/Signedby";
|
||||||
import HandleError from "../primitives/HandleError";
|
|
||||||
import Header from "../components/pdf/PdfHeader";
|
import Header from "../components/pdf/PdfHeader";
|
||||||
import RenderPdf from "../components/pdf/RenderPdf";
|
import RenderPdf from "../components/pdf/RenderPdf";
|
||||||
import PlaceholderCopy from "../components/pdf/PlaceholderCopy";
|
import PlaceholderCopy from "../components/pdf/PlaceholderCopy";
|
||||||
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
|
||||||
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import TextFontSetting from "../components/pdf/TextFontSetting";
|
import TextFontSetting from "../components/pdf/TextFontSetting";
|
||||||
import VerifyEmail from "../components/pdf/VerifyEmail";
|
import VerifyEmail from "../components/pdf/VerifyEmail";
|
||||||
import PdfZoom from "../components/pdf/PdfZoom";
|
import PdfZoom from "../components/pdf/PdfZoom";
|
||||||
import Loader from "../primitives/Loader";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import RotateAlert from "../components/RotateAlert";
|
||||||
|
import DownloadPdfZip from "../primitives/DownloadPdfZip";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
import ModalUi from "../primitives/ModalUi";
|
||||||
|
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
||||||
|
import HandleError from "../primitives/HandleError";
|
||||||
|
import LoaderWithMsg from "../primitives/LoaderWithMsg";
|
||||||
//For signYourself inProgress section signer can add sign and complete doc sign.
|
//For signYourself inProgress section signer can add sign and complete doc sign.
|
||||||
function SignYourSelf() {
|
function SignYourSelf() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -123,52 +128,39 @@ function SignYourSelf() {
|
|||||||
const [zoomPercent, setZoomPercent] = useState(0);
|
const [zoomPercent, setZoomPercent] = useState(0);
|
||||||
const isHeader = useSelector((state) => state.showHeader);
|
const isHeader = useSelector((state) => state.showHeader);
|
||||||
const [scale, setScale] = useState(1);
|
const [scale, setScale] = useState(1);
|
||||||
|
const [pdfRotateBase64, setPdfRotatese64] = useState("");
|
||||||
|
const [isRotate, setIsRotate] = useState({ status: false, degree: 0 });
|
||||||
|
const [isSubscribe, setIsSubscribe] = useState({ plan: "", isValid: true });
|
||||||
|
const [isDownloadModal, setIsDownloadModal] = useState(false);
|
||||||
const divRef = useRef(null);
|
const divRef = useRef(null);
|
||||||
const nodeRef = useRef(null);
|
const nodeRef = useRef(null);
|
||||||
const [, drop] = useDrop({
|
const [, drop] = useDrop({
|
||||||
accept: "BOX",
|
accept: "BOX",
|
||||||
drop: (item, monitor) => addPositionOfSignature(item, monitor),
|
drop: (item, monitor) => addPositionOfSignature(item, monitor),
|
||||||
collect: (monitor) => ({
|
collect: (monitor) => ({ isOver: !!monitor.isOver() })
|
||||||
isOver: !!monitor.isOver()
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
const pdfRef = useRef();
|
const pdfRef = useRef();
|
||||||
const [{ isDragSign }, dragSignature] = useDrag({
|
const [{ isDragSign }, dragSignature] = useDrag({
|
||||||
type: "BOX",
|
type: "BOX",
|
||||||
item: {
|
item: { id: 1, text: "signature" },
|
||||||
id: 1,
|
collect: (monitor) => ({ isDragSign: !!monitor.isDragging() })
|
||||||
text: "signature"
|
|
||||||
},
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragSign: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const [{ isDragStamp }, dragStamp] = useDrag({
|
const [{ isDragStamp }, dragStamp] = useDrag({
|
||||||
type: "BOX",
|
type: "BOX",
|
||||||
item: {
|
item: { id: 2, text: "stamp" },
|
||||||
id: 2,
|
collect: (monitor) => ({ isDragStamp: !!monitor.isDragging() })
|
||||||
text: "stamp"
|
|
||||||
},
|
|
||||||
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragStamp: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const index = xyPostion.findIndex((object) => {
|
const index = xyPostion?.findIndex((object) => {
|
||||||
return object.pageNumber === pageNumber;
|
return object.pageNumber === pageNumber;
|
||||||
});
|
});
|
||||||
// rowlevel={JSON.parse(localStorage.getItem("rowlevel"))}
|
|
||||||
const rowLevel =
|
const rowLevel =
|
||||||
localStorage.getItem("rowlevel") &&
|
localStorage.getItem("rowlevel") &&
|
||||||
JSON.parse(localStorage.getItem("rowlevel"));
|
JSON.parse(localStorage.getItem("rowlevel"));
|
||||||
|
|
||||||
const signObjId =
|
const signObjId =
|
||||||
rowLevel && rowLevel?.id
|
rowLevel && rowLevel?.id
|
||||||
? rowLevel.id
|
? rowLevel.id
|
||||||
: rowLevel?.objectId && rowLevel.objectId;
|
: rowLevel?.objectId && rowLevel.objectId;
|
||||||
|
|
||||||
const documentId = docId ? docId : signObjId && signObjId;
|
const documentId = docId ? docId : signObjId && signObjId;
|
||||||
const senderUser =
|
const senderUser =
|
||||||
localStorage.getItem(
|
localStorage.getItem(
|
||||||
@@ -202,12 +194,18 @@ function SignYourSelf() {
|
|||||||
|
|
||||||
// Use setTimeout to wait for the transition to complete
|
// Use setTimeout to wait for the transition to complete
|
||||||
const timer = setTimeout(updateSize, 100); // match the transition duration
|
const timer = setTimeout(updateSize, 100); // match the transition duration
|
||||||
|
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [divRef.current, isHeader]);
|
}, [divRef.current, isHeader]);
|
||||||
|
|
||||||
//function for get document details for perticular signer with signer'object id
|
//function for get document details for perticular signer with signer'object id
|
||||||
const getDocumentDetails = async (showComplete) => {
|
const getDocumentDetails = async (showComplete) => {
|
||||||
|
try {
|
||||||
|
const subscribe = await checkIsSubscribed();
|
||||||
|
setIsSubscribe(subscribe);
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in fetch sub", err);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
let isCompleted;
|
let isCompleted;
|
||||||
//getting document details
|
//getting document details
|
||||||
@@ -216,6 +214,11 @@ function SignYourSelf() {
|
|||||||
if (documentData && documentData.length > 0) {
|
if (documentData && documentData.length > 0) {
|
||||||
setPdfDetails(documentData);
|
setPdfDetails(documentData);
|
||||||
setExtUserId(documentData[0]?.ExtUserPtr?.objectId);
|
setExtUserId(documentData[0]?.ExtUserPtr?.objectId);
|
||||||
|
const placeholders =
|
||||||
|
documentData[0]?.Placeholders?.length > 0
|
||||||
|
? documentData[0]?.Placeholders
|
||||||
|
: [];
|
||||||
|
setXyPostion(placeholders);
|
||||||
const url = documentData[0] && documentData[0]?.URL;
|
const url = documentData[0] && documentData[0]?.URL;
|
||||||
if (url) {
|
if (url) {
|
||||||
//convert document url in array buffer format to use embed widgets in pdf using pdf-lib
|
//convert document url in array buffer format to use embed widgets in pdf using pdf-lib
|
||||||
@@ -228,21 +231,17 @@ function SignYourSelf() {
|
|||||||
} else {
|
} else {
|
||||||
setHandleError(t("something-went-wrong-mssg"));
|
setHandleError(t("something-went-wrong-mssg"));
|
||||||
}
|
}
|
||||||
isCompleted =
|
isCompleted = documentData?.[0]?.IsCompleted;
|
||||||
documentData[0].IsCompleted && documentData[0].IsCompleted;
|
|
||||||
if (isCompleted) {
|
if (isCompleted) {
|
||||||
setIsCelebration(true);
|
setIsCelebration(true);
|
||||||
setTimeout(() => {
|
setTimeout(() => setIsCelebration(false), 5000);
|
||||||
setIsCelebration(false);
|
|
||||||
}, 5000);
|
|
||||||
setIsCompleted(true);
|
setIsCompleted(true);
|
||||||
setPdfUrl(documentData[0].SignedUrl);
|
setPdfUrl(documentData[0].SignedUrl);
|
||||||
const alreadySign = {
|
|
||||||
status: true,
|
|
||||||
mssg: t("document-signed-alert")
|
|
||||||
};
|
|
||||||
if (showComplete) {
|
if (showComplete) {
|
||||||
setShowAlreadySignDoc(alreadySign);
|
setShowAlreadySignDoc({
|
||||||
|
status: true,
|
||||||
|
mssg: t("document-signed-alert")
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
setIsUiLoading(false);
|
setIsUiLoading(false);
|
||||||
setIsSignPad(false);
|
setIsSignPad(false);
|
||||||
@@ -255,17 +254,11 @@ function SignYourSelf() {
|
|||||||
documentData === "Error: Something went wrong!" ||
|
documentData === "Error: Something went wrong!" ||
|
||||||
(documentData.result && documentData.result.error)
|
(documentData.result && documentData.result.error)
|
||||||
) {
|
) {
|
||||||
const loadObj = {
|
|
||||||
isLoad: false
|
|
||||||
};
|
|
||||||
setHandleError(t("something-went-wrong-mssg"));
|
setHandleError(t("something-went-wrong-mssg"));
|
||||||
setIsLoading(loadObj);
|
setIsLoading({ isLoad: false });
|
||||||
} else {
|
} else {
|
||||||
setHandleError(t("no-data-avaliable"));
|
setHandleError(t("no-data-avaliable"));
|
||||||
const loadObj = {
|
setIsLoading({ isLoad: false });
|
||||||
isLoad: false
|
|
||||||
};
|
|
||||||
setIsLoading(loadObj);
|
|
||||||
}
|
}
|
||||||
//function to get default signatur eof current user from `contracts_Signature` class
|
//function to get default signatur eof current user from `contracts_Signature` class
|
||||||
const defaultSignRes = await getDefaultSignature(jsonSender.objectId);
|
const defaultSignRes = await getDefaultSignature(jsonSender.objectId);
|
||||||
@@ -274,17 +267,12 @@ function SignYourSelf() {
|
|||||||
setMyInitial(defaultSignRes?.res?.defaultInitial);
|
setMyInitial(defaultSignRes?.res?.defaultInitial);
|
||||||
} else if (defaultSignRes?.status === "error") {
|
} else if (defaultSignRes?.status === "error") {
|
||||||
setHandleError("Error: Something went wrong!");
|
setHandleError("Error: Something went wrong!");
|
||||||
setIsLoading({
|
setIsLoading({ isLoad: false });
|
||||||
isLoad: false
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
const contractUsersRes = await contractUsers();
|
const contractUsersRes = await contractUsers();
|
||||||
if (contractUsersRes === "Error: Something went wrong!") {
|
if (contractUsersRes === "Error: Something went wrong!") {
|
||||||
const loadObj = {
|
|
||||||
isLoad: false
|
|
||||||
};
|
|
||||||
setHandleError(t("something-went-wrong-mssg"));
|
setHandleError(t("something-went-wrong-mssg"));
|
||||||
setIsLoading(loadObj);
|
setIsLoading({ isLoad: false });
|
||||||
} else if (contractUsersRes[0] && contractUsersRes.length > 0) {
|
} else if (contractUsersRes[0] && contractUsersRes.length > 0) {
|
||||||
setActiveMailAdapter(contractUsersRes[0]?.active_mail_adapter);
|
setActiveMailAdapter(contractUsersRes[0]?.active_mail_adapter);
|
||||||
setContractName("_Users");
|
setContractName("_Users");
|
||||||
@@ -364,51 +352,32 @@ function SignYourSelf() {
|
|||||||
const addWidgetOptions = (type) => {
|
const addWidgetOptions = (type) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "signature":
|
case "signature":
|
||||||
return {
|
return { name: "signature" };
|
||||||
name: "signature"
|
|
||||||
};
|
|
||||||
case "stamp":
|
case "stamp":
|
||||||
return {
|
return { name: "stamp" };
|
||||||
name: "stamp"
|
|
||||||
};
|
|
||||||
case "checkbox":
|
case "checkbox":
|
||||||
return {
|
return { name: "checkbox" };
|
||||||
name: "checkbox"
|
|
||||||
};
|
|
||||||
case textWidget:
|
case textWidget:
|
||||||
return {
|
return { name: "text" };
|
||||||
name: "text"
|
|
||||||
};
|
|
||||||
case "initials":
|
case "initials":
|
||||||
return {
|
return { name: "initials" };
|
||||||
name: "initials"
|
|
||||||
};
|
|
||||||
case "name":
|
case "name":
|
||||||
return {
|
return {
|
||||||
name: "name",
|
name: "name",
|
||||||
defaultValue: getWidgetValue(type),
|
defaultValue: getWidgetValue(type),
|
||||||
validation: {
|
validation: { type: "text", pattern: "" }
|
||||||
type: "text",
|
|
||||||
pattern: ""
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
case "company":
|
case "company":
|
||||||
return {
|
return {
|
||||||
name: "company",
|
name: "company",
|
||||||
defaultValue: getWidgetValue(type),
|
defaultValue: getWidgetValue(type),
|
||||||
validation: {
|
validation: { type: "text", pattern: "" }
|
||||||
type: "text",
|
|
||||||
pattern: ""
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
case "job title":
|
case "job title":
|
||||||
return {
|
return {
|
||||||
name: "job title",
|
name: "job title",
|
||||||
defaultValue: getWidgetValue(type),
|
defaultValue: getWidgetValue(type),
|
||||||
validation: {
|
validation: { type: "text", pattern: "" }
|
||||||
type: "text",
|
|
||||||
pattern: ""
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
case "date":
|
case "date":
|
||||||
return {
|
return {
|
||||||
@@ -417,17 +386,12 @@ function SignYourSelf() {
|
|||||||
validation: { format: "MM/dd/yyyy", type: "date-format" }
|
validation: { format: "MM/dd/yyyy", type: "date-format" }
|
||||||
};
|
};
|
||||||
case "image":
|
case "image":
|
||||||
return {
|
return { name: "image" };
|
||||||
name: "image"
|
|
||||||
};
|
|
||||||
case "email":
|
case "email":
|
||||||
return {
|
return {
|
||||||
name: "email",
|
name: "email",
|
||||||
defaultValue: getWidgetValue(type),
|
defaultValue: getWidgetValue(type),
|
||||||
validation: {
|
validation: { type: "email", pattern: "" }
|
||||||
type: "email",
|
|
||||||
pattern: ""
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
@@ -439,7 +403,7 @@ function SignYourSelf() {
|
|||||||
const key = randomId();
|
const key = randomId();
|
||||||
let dropData = [];
|
let dropData = [];
|
||||||
let dropObj = {};
|
let dropObj = {};
|
||||||
let filterDropPos = xyPostion.filter(
|
let filterDropPos = xyPostion?.filter(
|
||||||
(data) => data.pageNumber === pageNumber
|
(data) => data.pageNumber === pageNumber
|
||||||
);
|
);
|
||||||
const dragTypeValue = item?.text ? item.text : monitor.type;
|
const dragTypeValue = item?.text ? item.text : monitor.type;
|
||||||
@@ -454,29 +418,27 @@ function SignYourSelf() {
|
|||||||
);
|
);
|
||||||
//adding and updating drop position in array when user drop signature button in div
|
//adding and updating drop position in array when user drop signature button in div
|
||||||
if (item === "onclick") {
|
if (item === "onclick") {
|
||||||
|
// `getBoundingClientRect()` is used to get accurate measurement height of the div
|
||||||
|
const divHeight = divRef.current.getBoundingClientRect().height;
|
||||||
const getWidth = widgetTypeExist
|
const getWidth = widgetTypeExist
|
||||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
|
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
|
||||||
: dragTypeValue === "initials"
|
: defaultWidthHeight(dragTypeValue).width;
|
||||||
? defaultWidthHeight(dragTypeValue).width
|
|
||||||
: "";
|
|
||||||
const getHeight = widgetTypeExist
|
const getHeight = widgetTypeExist
|
||||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getHeight
|
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getHeight
|
||||||
: dragTypeValue === "initials"
|
: defaultWidthHeight(dragTypeValue).height;
|
||||||
? defaultWidthHeight(dragTypeValue).height
|
|
||||||
: "";
|
|
||||||
dropObj = {
|
dropObj = {
|
||||||
xPosition: containerWH.width / 2,
|
xPosition: getWidth / 2 + containerWH.width / 2,
|
||||||
yPosition: containerWH.height / 2,
|
yPosition: getHeight + divHeight / 2,
|
||||||
isStamp:
|
isStamp:
|
||||||
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
|
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
|
||||||
key: key,
|
key: key,
|
||||||
type: dragTypeValue,
|
type: dragTypeValue,
|
||||||
scale: containerScale,
|
scale: containerScale,
|
||||||
Width: getWidth / (containerScale * scale),
|
Width: getWidth,
|
||||||
Height: getHeight / (containerScale * scale),
|
Height: getHeight,
|
||||||
options: addWidgetOptions(dragTypeValue)
|
options: addWidgetOptions(dragTypeValue)
|
||||||
};
|
};
|
||||||
|
|
||||||
dropData.push(dropObj);
|
dropData.push(dropObj);
|
||||||
} else {
|
} else {
|
||||||
//This method returns the offset of the current pointer (mouse) position relative to the client viewport.
|
//This method returns the offset of the current pointer (mouse) position relative to the client viewport.
|
||||||
@@ -509,25 +471,18 @@ function SignYourSelf() {
|
|||||||
options: addWidgetOptions(dragTypeValue),
|
options: addWidgetOptions(dragTypeValue),
|
||||||
scale: containerScale
|
scale: containerScale
|
||||||
};
|
};
|
||||||
|
|
||||||
dropData.push(dropObj);
|
dropData.push(dropObj);
|
||||||
}
|
}
|
||||||
if (filterDropPos.length > 0) {
|
if (filterDropPos?.length > 0) {
|
||||||
const index = xyPostion.findIndex((object) => {
|
const index = xyPostion?.findIndex((object) => {
|
||||||
return object.pageNumber === pageNumber;
|
return object.pageNumber === pageNumber;
|
||||||
});
|
});
|
||||||
const updateData = filterDropPos[0].pos;
|
const updateData = filterDropPos?.[0].pos;
|
||||||
const newSignPos = updateData.concat(dropData);
|
const newSignPos = updateData.concat(dropData);
|
||||||
let xyPos = {
|
let xyPos = { pageNumber: pageNumber, pos: newSignPos };
|
||||||
pageNumber: pageNumber,
|
xyPostion?.splice(index, 1, xyPos);
|
||||||
pos: newSignPos
|
|
||||||
};
|
|
||||||
xyPostion.splice(index, 1, xyPos);
|
|
||||||
} else {
|
} else {
|
||||||
const xyPos = {
|
const xyPos = { pageNumber: pageNumber, pos: dropData };
|
||||||
pageNumber: pageNumber,
|
|
||||||
pos: dropData
|
|
||||||
};
|
|
||||||
setXyPostion((prev) => [...prev, xyPos]);
|
setXyPostion((prev) => [...prev, xyPos]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,7 +494,6 @@ function SignYourSelf() {
|
|||||||
) {
|
) {
|
||||||
setIsSignPad(true);
|
setIsSignPad(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dragTypeValue === "stamp" || dragTypeValue === "image") {
|
if (dragTypeValue === "stamp" || dragTypeValue === "image") {
|
||||||
setIsStamp(true);
|
setIsStamp(true);
|
||||||
} else if (dragTypeValue === "initials") {
|
} else if (dragTypeValue === "initials") {
|
||||||
@@ -602,6 +556,29 @@ function SignYourSelf() {
|
|||||||
setIsVerifyModal(true);
|
setIsVerifyModal(true);
|
||||||
await handleSendOTP(Parse.User.current().getEmail());
|
await handleSendOTP(Parse.User.current().getEmail());
|
||||||
};
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
if (xyPostion?.length > 0) {
|
||||||
|
autosavedetails();
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [xyPostion]);
|
||||||
|
|
||||||
|
// `autosavedetails` is used to save doc details after every 2 sec when changes are happern in placeholder like drag-drop widgets, remove signers
|
||||||
|
const autosavedetails = async () => {
|
||||||
|
try {
|
||||||
|
const docCls = new Parse.Object("contracts_Document");
|
||||||
|
docCls.id = documentId;
|
||||||
|
docCls.set("Placeholders", xyPostion);
|
||||||
|
docCls.set("IsSignyourself", true);
|
||||||
|
await docCls.save();
|
||||||
|
} catch (e) {
|
||||||
|
console.log("error", e);
|
||||||
|
alert(t("something-went-wrong-mssg"));
|
||||||
|
}
|
||||||
|
};
|
||||||
//function for send placeholder's co-ordinate(x,y) position embed signature url or stamp url
|
//function for send placeholder's co-ordinate(x,y) position embed signature url or stamp url
|
||||||
async function embedWidgetsData() {
|
async function embedWidgetsData() {
|
||||||
//check current user email is verified or not
|
//check current user email is verified or not
|
||||||
@@ -740,7 +717,7 @@ function SignYourSelf() {
|
|||||||
//function for get digital signature
|
//function for get digital signature
|
||||||
const signPdfFun = async (base64Url, documentId) => {
|
const signPdfFun = async (base64Url, documentId) => {
|
||||||
let isCustomCompletionMail = false;
|
let isCustomCompletionMail = false;
|
||||||
const getIsSubscribe = await checkIsSubscribed();
|
|
||||||
const tenantDetails = await getTenantDetails(jsonSender.objectId);
|
const tenantDetails = await getTenantDetails(jsonSender.objectId);
|
||||||
if (tenantDetails && tenantDetails === "user does not exist!") {
|
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||||
alert(t("user-not-exist"));
|
alert(t("user-not-exist"));
|
||||||
@@ -748,7 +725,7 @@ function SignYourSelf() {
|
|||||||
if (
|
if (
|
||||||
tenantDetails?.CompletionBody &&
|
tenantDetails?.CompletionBody &&
|
||||||
tenantDetails?.CompletionSubject &&
|
tenantDetails?.CompletionSubject &&
|
||||||
getIsSubscribe
|
isSubscribe?.isValid
|
||||||
) {
|
) {
|
||||||
isCustomCompletionMail = true;
|
isCustomCompletionMail = true;
|
||||||
}
|
}
|
||||||
@@ -781,7 +758,6 @@ function SignYourSelf() {
|
|||||||
const getNewse64 = await changeImageWH(base64Sign);
|
const getNewse64 = await changeImageWH(base64Sign);
|
||||||
//remove suffiix of base64
|
//remove suffiix of base64
|
||||||
const suffixbase64 = getNewse64 && getNewse64.split(",").pop();
|
const suffixbase64 = getNewse64 && getNewse64.split(",").pop();
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
pdfFile: base64Url,
|
pdfFile: base64Url,
|
||||||
docId: documentId,
|
docId: documentId,
|
||||||
@@ -794,6 +770,7 @@ function SignYourSelf() {
|
|||||||
const signedpdf = JSON.parse(JSON.stringify(resSignPdf));
|
const signedpdf = JSON.parse(JSON.stringify(resSignPdf));
|
||||||
setPdfUrl(signedpdf);
|
setPdfUrl(signedpdf);
|
||||||
getDocumentDetails(false);
|
getDocumentDetails(false);
|
||||||
|
setPdfRotatese64("");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -814,10 +791,10 @@ function SignYourSelf() {
|
|||||||
containerWH
|
containerWH
|
||||||
);
|
);
|
||||||
if (dragKey >= 0) {
|
if (dragKey >= 0) {
|
||||||
const filterDropPos = xyPostion.filter(
|
const filterDropPos = xyPostion?.filter(
|
||||||
(data) => data.pageNumber === pageNumber
|
(data) => data.pageNumber === pageNumber
|
||||||
);
|
);
|
||||||
if (filterDropPos.length > 0) {
|
if (filterDropPos?.length > 0) {
|
||||||
const getXYdata = xyPostion[index].pos;
|
const getXYdata = xyPostion[index].pos;
|
||||||
const getPosData = getXYdata;
|
const getPosData = getXYdata;
|
||||||
const addSign = getPosData.map((url) => {
|
const addSign = getPosData.map((url) => {
|
||||||
@@ -888,15 +865,11 @@ function SignYourSelf() {
|
|||||||
setIsSignPad(false);
|
setIsSignPad(false);
|
||||||
setIsImageSelect(false);
|
setIsImageSelect(false);
|
||||||
setImage();
|
setImage();
|
||||||
|
|
||||||
if (isDefaultSign) {
|
if (isDefaultSign) {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.src = defaultSignImg;
|
img.src = defaultSignImg;
|
||||||
if (img.complete) {
|
if (img.complete) {
|
||||||
imgWH = {
|
imgWH = { width: img.width, height: img.height };
|
||||||
width: img.width,
|
|
||||||
height: img.height
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const getUpdatePosition = onSaveSign(
|
const getUpdatePosition = onSaveSign(
|
||||||
@@ -921,19 +894,11 @@ function SignYourSelf() {
|
|||||||
const touch = e.touches[0]; // Get the first touch point
|
const touch = e.touches[0]; // Get the first touch point
|
||||||
mouseX = touch.clientX - divRect.left;
|
mouseX = touch.clientX - divRect.left;
|
||||||
mouseY = touch.clientY - divRect.top;
|
mouseY = touch.clientY - divRect.top;
|
||||||
setSignBtnPosition([
|
setSignBtnPosition([{ xPos: mouseX, yPos: mouseY }]);
|
||||||
{
|
|
||||||
xPos: mouseX,
|
|
||||||
yPos: mouseY
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
} else {
|
} else {
|
||||||
mouseX = e.clientX - divRect.left;
|
mouseX = e.clientX - divRect.left;
|
||||||
mouseY = e.clientY - divRect.top;
|
mouseY = e.clientY - divRect.top;
|
||||||
const xyPosition = {
|
const xyPosition = { xPos: mouseX, yPos: mouseY };
|
||||||
xPos: mouseX,
|
|
||||||
yPos: mouseY
|
|
||||||
};
|
|
||||||
setXYSignature(xyPosition);
|
setXYSignature(xyPosition);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -951,9 +916,7 @@ function SignYourSelf() {
|
|||||||
const handleDeleteSign = (key) => {
|
const handleDeleteSign = (key) => {
|
||||||
setCurrWidgetsDetails({});
|
setCurrWidgetsDetails({});
|
||||||
const updateResizeData = [];
|
const updateResizeData = [];
|
||||||
|
|
||||||
let filterData = xyPostion[index].pos.filter((data) => data.key !== key);
|
let filterData = xyPostion[index].pos.filter((data) => data.key !== key);
|
||||||
|
|
||||||
//delete and update block position
|
//delete and update block position
|
||||||
if (filterData.length > 0) {
|
if (filterData.length > 0) {
|
||||||
updateResizeData.push(filterData);
|
updateResizeData.push(filterData);
|
||||||
@@ -1093,7 +1056,11 @@ function SignYourSelf() {
|
|||||||
name: dropdownName,
|
name: dropdownName,
|
||||||
values: dropdownOptions,
|
values: dropdownOptions,
|
||||||
isReadOnly: isReadOnly,
|
isReadOnly: isReadOnly,
|
||||||
isHideLabel: isHideLabel || false
|
isHideLabel: isHideLabel || false,
|
||||||
|
fontSize:
|
||||||
|
fontSize || currWidgetsDetails?.options?.fontSize || "12",
|
||||||
|
fontColor:
|
||||||
|
fontColor || currWidgetsDetails?.options?.fontColor || "black"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1111,6 +1078,8 @@ function SignYourSelf() {
|
|||||||
handleCloseModal();
|
handleCloseModal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setFontSize();
|
||||||
|
setFontColor();
|
||||||
};
|
};
|
||||||
const handleCloseModal = () => {
|
const handleCloseModal = () => {
|
||||||
setCurrWidgetsDetails({});
|
setCurrWidgetsDetails({});
|
||||||
@@ -1154,6 +1123,56 @@ function SignYourSelf() {
|
|||||||
handleTextSettingModal(false);
|
handleTextSettingModal(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const clickOnZoomIn = () => {
|
||||||
|
onClickZoomIn(scale, zoomPercent, setScale, setZoomPercent);
|
||||||
|
};
|
||||||
|
const clickOnZoomOut = () => {
|
||||||
|
onClickZoomOut(zoomPercent, scale, setZoomPercent, setScale);
|
||||||
|
};
|
||||||
|
//`handleRotationFun` function is used to roatate pdf particular page
|
||||||
|
const handleRotationFun = async (rotateDegree) => {
|
||||||
|
const isPlaceholder = handleRotateWarning();
|
||||||
|
if (isPlaceholder) {
|
||||||
|
setIsRotate({ status: true, degree: rotateDegree });
|
||||||
|
} else {
|
||||||
|
const urlDetails = await rotatePdfPage(
|
||||||
|
pdfUrl || pdfDetails[0].URL,
|
||||||
|
rotateDegree,
|
||||||
|
pageNumber - 1,
|
||||||
|
pdfRotateBase64
|
||||||
|
);
|
||||||
|
setPdfArrayBuffer && setPdfArrayBuffer(urlDetails.arrayBuffer);
|
||||||
|
setPdfRotatese64(urlDetails.base64);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//function to show warning when user rotate page and there are some already widgets on that page
|
||||||
|
const handleRotateWarning = () => {
|
||||||
|
const placeholderData = xyPostion?.filter(
|
||||||
|
(data) => data.pageNumber === pageNumber
|
||||||
|
);
|
||||||
|
if (placeholderData && placeholderData.length > 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//function to use remove widgets from current page when user want to rotate page
|
||||||
|
const handleRemoveWidgets = async () => {
|
||||||
|
const updatePlaceholder = xyPostion.filter(
|
||||||
|
(data) => data.pageNumber !== pageNumber
|
||||||
|
);
|
||||||
|
const urlDetails = await rotatePdfPage(
|
||||||
|
pdfUrl || pdfDetails[0].URL,
|
||||||
|
isRotate.degree,
|
||||||
|
pageNumber - 1,
|
||||||
|
pdfRotateBase64
|
||||||
|
);
|
||||||
|
setPdfArrayBuffer && setPdfArrayBuffer(urlDetails.arrayBuffer);
|
||||||
|
setPdfRotatese64(urlDetails.base64);
|
||||||
|
setXyPostion(updatePlaceholder);
|
||||||
|
setIsRotate({ status: false, degree: 0 });
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<DndProvider backend={HTML5Backend}>
|
<DndProvider backend={HTML5Backend}>
|
||||||
<Title title={"Self Sign"} />
|
<Title title={"Self Sign"} />
|
||||||
@@ -1173,10 +1192,14 @@ function SignYourSelf() {
|
|||||||
)}
|
)}
|
||||||
{isCelebration && (
|
{isCelebration && (
|
||||||
<div className="relative z-[1000]">
|
<div className="relative z-[1000]">
|
||||||
<Confetti width={window.innerWidth} height={window.innerHeight} />
|
<Confetti
|
||||||
|
width={window.innerWidth}
|
||||||
|
height={window.innerHeight}
|
||||||
|
recycle={false} // Prevents confetti from repeating
|
||||||
|
gravity={0.1} // Adjust the gravity to control the speed
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="relative op-card overflow-hidden flex flex-col md:flex-row justify-between bg-base-300">
|
<div className="relative op-card overflow-hidden flex flex-col md:flex-row justify-between bg-base-300">
|
||||||
{!isEmailVerified && (
|
{!isEmailVerified && (
|
||||||
<VerifyEmail
|
<VerifyEmail
|
||||||
@@ -1213,14 +1236,13 @@ function SignYourSelf() {
|
|||||||
setSignBtnPosition={setSignBtnPosition}
|
setSignBtnPosition={setSignBtnPosition}
|
||||||
pageNumber={pageNumber}
|
pageNumber={pageNumber}
|
||||||
containerWH={containerWH}
|
containerWH={containerWH}
|
||||||
|
pdfRotateBase64={pdfRotateBase64}
|
||||||
/>
|
/>
|
||||||
<div className=" w-full md:w-[57%] flex mr-4">
|
<div className=" w-full md:w-[57%] flex mr-4">
|
||||||
<PdfZoom
|
<PdfZoom
|
||||||
setScale={setScale}
|
clickOnZoomIn={clickOnZoomIn}
|
||||||
scale={scale}
|
clickOnZoomOut={clickOnZoomOut}
|
||||||
containerWH={containerWH}
|
handleRotationFun={handleRotationFun}
|
||||||
setZoomPercent={setZoomPercent}
|
|
||||||
zoomPercent={zoomPercent}
|
|
||||||
/>
|
/>
|
||||||
<div className="w-full md:w-[95%]">
|
<div className="w-full md:w-[95%]">
|
||||||
<ModalUi
|
<ModalUi
|
||||||
@@ -1239,9 +1261,7 @@ function SignYourSelf() {
|
|||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen={showAlreadySignDoc.status}
|
isOpen={showAlreadySignDoc.status}
|
||||||
title={t("document-signed")}
|
title={t("document-signed")}
|
||||||
handleClose={() => {
|
handleClose={() => setShowAlreadySignDoc({ status: false })}
|
||||||
setShowAlreadySignDoc({ status: false });
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className="p-[20px] h-full">
|
<div className="p-[20px] h-full">
|
||||||
<p>{showAlreadySignDoc.mssg}</p>
|
<p>{showAlreadySignDoc.mssg}</p>
|
||||||
@@ -1265,6 +1285,10 @@ function SignYourSelf() {
|
|||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
isSignYourself={true}
|
isSignYourself={true}
|
||||||
handleClose={handleCloseModal}
|
handleClose={handleCloseModal}
|
||||||
|
fontSize={fontSize}
|
||||||
|
setFontSize={setFontSize}
|
||||||
|
fontColor={fontColor}
|
||||||
|
setFontColor={setFontColor}
|
||||||
/>
|
/>
|
||||||
<PlaceholderCopy
|
<PlaceholderCopy
|
||||||
isPageCopy={isPageCopy}
|
isPageCopy={isPageCopy}
|
||||||
@@ -1274,6 +1298,7 @@ function SignYourSelf() {
|
|||||||
allPages={allPages}
|
allPages={allPages}
|
||||||
pageNumber={pageNumber}
|
pageNumber={pageNumber}
|
||||||
signKey={signKey}
|
signKey={signKey}
|
||||||
|
widgetType={widgetType}
|
||||||
/>
|
/>
|
||||||
{/* this is modal of signature pad */}
|
{/* this is modal of signature pad */}
|
||||||
<SignPad
|
<SignPad
|
||||||
@@ -1309,6 +1334,7 @@ function SignYourSelf() {
|
|||||||
setIsAlert={setIsAlert}
|
setIsAlert={setIsAlert}
|
||||||
extUserId={extUserId}
|
extUserId={extUserId}
|
||||||
activeMailAdapter={activeMailAdapter}
|
activeMailAdapter={activeMailAdapter}
|
||||||
|
setIsDownloadModal={setIsDownloadModal}
|
||||||
/>
|
/>
|
||||||
{/* pdf header which contain funish back button */}
|
{/* pdf header which contain funish back button */}
|
||||||
<Header
|
<Header
|
||||||
@@ -1324,12 +1350,13 @@ function SignYourSelf() {
|
|||||||
isSignYourself={true}
|
isSignYourself={true}
|
||||||
setIsEmail={setIsEmail}
|
setIsEmail={setIsEmail}
|
||||||
isCompleted={isCompleted}
|
isCompleted={isCompleted}
|
||||||
|
handleRotationFun={handleRotationFun}
|
||||||
|
clickOnZoomIn={clickOnZoomIn}
|
||||||
|
clickOnZoomOut={clickOnZoomOut}
|
||||||
|
widgetsDetails={xyPostion}
|
||||||
|
setIsDownloadModal={setIsDownloadModal}
|
||||||
/>
|
/>
|
||||||
<div
|
<div ref={divRef} data-tut="reactourSecond" className="h-full">
|
||||||
ref={divRef}
|
|
||||||
data-tut="reactourSecond"
|
|
||||||
className="h-full md:h-[95%]"
|
|
||||||
>
|
|
||||||
{containerWH?.width && containerWH?.height && (
|
{containerWH?.width && containerWH?.height && (
|
||||||
<RenderPdf
|
<RenderPdf
|
||||||
pageNumber={pageNumber}
|
pageNumber={pageNumber}
|
||||||
@@ -1368,6 +1395,11 @@ function SignYourSelf() {
|
|||||||
handleTextSettingModal={handleTextSettingModal}
|
handleTextSettingModal={handleTextSettingModal}
|
||||||
setScale={setScale}
|
setScale={setScale}
|
||||||
scale={scale}
|
scale={scale}
|
||||||
|
pdfRotateBase64={pdfRotateBase64}
|
||||||
|
fontSize={fontSize}
|
||||||
|
setFontSize={setFontSize}
|
||||||
|
fontColor={fontColor}
|
||||||
|
setFontColor={setFontColor}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -1407,9 +1439,7 @@ function SignYourSelf() {
|
|||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen={validateAlert}
|
isOpen={validateAlert}
|
||||||
title={t("validation-alert")}
|
title={t("validation-alert")}
|
||||||
handleClose={() => {
|
handleClose={() => setValidateAlert(false)}
|
||||||
setValidateAlert(false);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className="p-[20px] h-full">
|
<div className="p-[20px] h-full">
|
||||||
<p>{t("validate-alert-mssg")}</p>
|
<p>{t("validate-alert-mssg")}</p>
|
||||||
@@ -1424,6 +1454,17 @@ function SignYourSelf() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
|
<RotateAlert
|
||||||
|
isRotate={isRotate.status}
|
||||||
|
setIsRotate={setIsRotate}
|
||||||
|
handleRemoveWidgets={handleRemoveWidgets}
|
||||||
|
/>
|
||||||
|
<DownloadPdfZip
|
||||||
|
setIsDownloadModal={setIsDownloadModal}
|
||||||
|
isDownloadModal={isDownloadModal}
|
||||||
|
pdfDetails={pdfDetails}
|
||||||
|
isDocId={true}
|
||||||
|
/>
|
||||||
<TextFontSetting
|
<TextFontSetting
|
||||||
isTextSetting={isTextSetting}
|
isTextSetting={isTextSetting}
|
||||||
setIsTextSetting={setIsTextSetting}
|
setIsTextSetting={setIsTextSetting}
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import ModalUi from "../primitives/ModalUi";
|
|||||||
import pad from "../assets/images/pad.svg";
|
import pad from "../assets/images/pad.svg";
|
||||||
import AddTeam from "../components/AddTeam";
|
import AddTeam from "../components/AddTeam";
|
||||||
import { isEnableSubscription } from "../constant/const";
|
import { isEnableSubscription } from "../constant/const";
|
||||||
import { checkIsSubscribedTeam } from "../constant/Utils";
|
import { checkIsSubscribed } from "../constant/Utils";
|
||||||
import SubscribeCard from "../primitives/SubscribeCard";
|
import SubscribeCard from "../primitives/SubscribeCard";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
|
import { validplan } from "../json/plansArr";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
const heading = ["Sr.No", "Name", "Parent Team", "Active"];
|
const heading = ["Sr.No", "Name", "Parent Team", "Active"];
|
||||||
@@ -38,7 +39,7 @@ const TeamList = () => {
|
|||||||
const [isActiveModal, setIsActiveModal] = useState({});
|
const [isActiveModal, setIsActiveModal] = useState({});
|
||||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||||
const [isActLoader, setIsActLoader] = useState({});
|
const [isActLoader, setIsActLoader] = useState({});
|
||||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
const [isSubscribe, setIsSubscribe] = useState({ plan: "", isValid: false });
|
||||||
const [isEditModal, setIsEditModal] = useState({});
|
const [isEditModal, setIsEditModal] = useState({});
|
||||||
const [isAdmin, setIsAdmin] = useState(false);
|
const [isAdmin, setIsAdmin] = useState(false);
|
||||||
const startIndex = (currentPage - 1) * recordperPage; // user per page
|
const startIndex = (currentPage - 1) * recordperPage; // user per page
|
||||||
@@ -103,8 +104,8 @@ const TeamList = () => {
|
|||||||
try {
|
try {
|
||||||
setIsLoader(true);
|
setIsLoader(true);
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const getIsSubscribe = await checkIsSubscribedTeam();
|
const subscribe = await checkIsSubscribed();
|
||||||
setIsSubscribe(getIsSubscribe);
|
setIsSubscribe(subscribe);
|
||||||
}
|
}
|
||||||
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
if (extUser) {
|
if (extUser) {
|
||||||
@@ -134,7 +135,7 @@ const TeamList = () => {
|
|||||||
const handleFormModal = () => {
|
const handleFormModal = () => {
|
||||||
setIsModal(!isModal);
|
setIsModal(!isModal);
|
||||||
};
|
};
|
||||||
// Get current list
|
// to slice out 10 objects from array for current page
|
||||||
const indexOfLastDoc = currentPage * recordperPage;
|
const indexOfLastDoc = currentPage * recordperPage;
|
||||||
const indexOfFirstDoc = indexOfLastDoc - recordperPage;
|
const indexOfFirstDoc = indexOfLastDoc - recordperPage;
|
||||||
const currentList = teamList?.slice(indexOfFirstDoc, indexOfLastDoc);
|
const currentList = teamList?.slice(indexOfFirstDoc, indexOfLastDoc);
|
||||||
@@ -145,8 +146,19 @@ const TeamList = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Change page
|
// Change page
|
||||||
const paginateFront = () => setCurrentPage(currentPage + 1);
|
const paginateFront = () => {
|
||||||
const paginateBack = () => setCurrentPage(currentPage - 1);
|
const lastValue = pageNumbers?.[pageNumbers?.length - 1];
|
||||||
|
if (currentPage < lastValue) {
|
||||||
|
setCurrentPage(currentPage + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const paginateBack = () => {
|
||||||
|
if (startIndex > 0) {
|
||||||
|
setCurrentPage(currentPage - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleActionBtn = (act, item) => {
|
const handleActionBtn = (act, item) => {
|
||||||
if (act.action === "edit") {
|
if (act.action === "edit") {
|
||||||
setIsEditModal({ [item.objectId]: true });
|
setIsEditModal({ [item.objectId]: true });
|
||||||
@@ -225,15 +237,11 @@ const TeamList = () => {
|
|||||||
<Loader />
|
<Loader />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isSubscribe && isEnableSubscription && !isLoader && (
|
{validplan[isSubscribe.plan] && isEnableSubscription && !isLoader && (
|
||||||
<>
|
<>
|
||||||
{isAdmin ? (
|
{isAdmin ? (
|
||||||
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
|
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
|
||||||
{isAlert.msg && (
|
{isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
|
||||||
<Alert type={isAlert.type}>
|
|
||||||
<div className="ml-3">{isAlert.msg}</div>
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
||||||
<div className="font-light">
|
<div className="font-light">
|
||||||
{t("report-name.Teams")}
|
{t("report-name.Teams")}
|
||||||
@@ -470,9 +478,9 @@ const TeamList = () => {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!isSubscribe && isEnableSubscription && !isLoader && (
|
{isEnableSubscription && !validplan[isSubscribe.plan] && !isLoader && (
|
||||||
<div data-tut="apisubscribe">
|
<div data-tut="apisubscribe">
|
||||||
<SubscribeCard plan={"TEAMS"} price={"20"} />
|
<SubscribeCard plan="TEAMS" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import { HTML5Backend } from "react-dnd-html5-backend";
|
|||||||
import { useDrag, useDrop } from "react-dnd";
|
import { useDrag, useDrop } from "react-dnd";
|
||||||
import WidgetComponent from "../components/pdf/WidgetComponent";
|
import WidgetComponent from "../components/pdf/WidgetComponent";
|
||||||
import Tour from "reactour";
|
import Tour from "reactour";
|
||||||
import LoaderWithMsg from "../primitives/LoaderWithMsg";
|
|
||||||
import HandleError from "../primitives/HandleError";
|
|
||||||
import SignerListPlace from "../components/pdf/SignerListPlace";
|
import SignerListPlace from "../components/pdf/SignerListPlace";
|
||||||
import Header from "../components/pdf/PdfHeader";
|
import Header from "../components/pdf/PdfHeader";
|
||||||
import WidgetNameModal from "../components/pdf/WidgetNameModal";
|
import WidgetNameModal from "../components/pdf/WidgetNameModal";
|
||||||
@@ -25,22 +23,32 @@ import {
|
|||||||
textInputWidget,
|
textInputWidget,
|
||||||
radioButtonWidget,
|
radioButtonWidget,
|
||||||
fetchSubscription,
|
fetchSubscription,
|
||||||
getContainerScale
|
getContainerScale,
|
||||||
|
convertBase64ToFile,
|
||||||
|
rotatePdfPage,
|
||||||
|
onClickZoomOut,
|
||||||
|
onClickZoomIn,
|
||||||
|
handleRemoveWidgets,
|
||||||
|
handleRotateWarning
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import RenderPdf from "../components/pdf/RenderPdf";
|
import RenderPdf from "../components/pdf/RenderPdf";
|
||||||
import "../styles/AddUser.css";
|
import "../styles/AddUser.css";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import LinkUserModal from "../primitives/LinkUserModal";
|
|
||||||
import EditTemplate from "../components/pdf/EditTemplate";
|
import EditTemplate from "../components/pdf/EditTemplate";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
|
||||||
import AddRoleModal from "../components/pdf/AddRoleModal";
|
import AddRoleModal from "../components/pdf/AddRoleModal";
|
||||||
import PlaceholderCopy from "../components/pdf/PlaceholderCopy";
|
import PlaceholderCopy from "../components/pdf/PlaceholderCopy";
|
||||||
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
|
||||||
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import PdfZoom from "../components/pdf/PdfZoom";
|
import PdfZoom from "../components/pdf/PdfZoom";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import RotateAlert from "../components/RotateAlert";
|
||||||
|
import ModalUi from "../primitives/ModalUi";
|
||||||
|
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
||||||
|
import HandleError from "../primitives/HandleError";
|
||||||
|
import LoaderWithMsg from "../primitives/LoaderWithMsg";
|
||||||
|
import LinkUserModal from "../primitives/LinkUserModal";
|
||||||
|
|
||||||
const TemplatePlaceholder = () => {
|
const TemplatePlaceholder = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -55,12 +63,15 @@ const TemplatePlaceholder = () => {
|
|||||||
const [xySignature, setXYSignature] = useState({});
|
const [xySignature, setXYSignature] = useState({});
|
||||||
const [dragKey, setDragKey] = useState();
|
const [dragKey, setDragKey] = useState();
|
||||||
const [signersdata, setSignersData] = useState([]);
|
const [signersdata, setSignersData] = useState([]);
|
||||||
const [signerObjId, setSignerObjId] = useState();
|
|
||||||
const [signerPos, setSignerPos] = useState([]);
|
const [signerPos, setSignerPos] = useState([]);
|
||||||
const [isSelectListId, setIsSelectId] = useState();
|
const [isSelectListId, setIsSelectId] = useState();
|
||||||
const [isSendAlert, setIsSendAlert] = useState(false);
|
const [isSendAlert, setIsSendAlert] = useState(false);
|
||||||
const [isCreateDocModal, setIsCreateDocModal] = useState(false);
|
const [isCreateDocModal, setIsCreateDocModal] = useState(false);
|
||||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||||
|
const [isRotate, setIsRotate] = useState({
|
||||||
|
status: false,
|
||||||
|
degree: 0
|
||||||
|
});
|
||||||
const [isLoading, setIsLoading] = useState({
|
const [isLoading, setIsLoading] = useState({
|
||||||
isLoad: true,
|
isLoad: true,
|
||||||
message: t("loading-mssg")
|
message: t("loading-mssg")
|
||||||
@@ -73,7 +84,6 @@ const TemplatePlaceholder = () => {
|
|||||||
const [tourStatus, setTourStatus] = useState([]);
|
const [tourStatus, setTourStatus] = useState([]);
|
||||||
const [signerUserId, setSignerUserId] = useState();
|
const [signerUserId, setSignerUserId] = useState();
|
||||||
const [pdfOriginalWH, setPdfOriginalWH] = useState([]);
|
const [pdfOriginalWH, setPdfOriginalWH] = useState([]);
|
||||||
const [contractName, setContractName] = useState("");
|
|
||||||
const [containerWH, setContainerWH] = useState();
|
const [containerWH, setContainerWH] = useState();
|
||||||
const signRef = useRef(null);
|
const signRef = useRef(null);
|
||||||
const dragRef = useRef(null);
|
const dragRef = useRef(null);
|
||||||
@@ -91,6 +101,7 @@ const TemplatePlaceholder = () => {
|
|||||||
const [isNameModal, setIsNameModal] = useState(false);
|
const [isNameModal, setIsNameModal] = useState(false);
|
||||||
const [isTextSetting, setIsTextSetting] = useState(false);
|
const [isTextSetting, setIsTextSetting] = useState(false);
|
||||||
const [pdfLoad, setPdfLoad] = useState(false);
|
const [pdfLoad, setPdfLoad] = useState(false);
|
||||||
|
const [pdfRotateBase64, setPdfRotatese64] = useState("");
|
||||||
const color = [
|
const color = [
|
||||||
"#93a3db",
|
"#93a3db",
|
||||||
"#e6c3db",
|
"#e6c3db",
|
||||||
@@ -181,21 +192,25 @@ const TemplatePlaceholder = () => {
|
|||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [divRef.current, isHeader]);
|
}, [divRef.current, isHeader]);
|
||||||
|
|
||||||
|
const handleNavigation = () => {
|
||||||
|
navigate("/subscription");
|
||||||
|
};
|
||||||
async function checkIsSubscribed() {
|
async function checkIsSubscribed() {
|
||||||
const res = await fetchSubscription();
|
const res = await fetchSubscription();
|
||||||
const freeplan = res.plan;
|
const plan = res.plan;
|
||||||
const billingDate = res.billingDate;
|
const billingDate = res.billingDate;
|
||||||
if (freeplan === "freeplan") {
|
if (plan === "freeplan") {
|
||||||
return true;
|
return true;
|
||||||
} else if (billingDate) {
|
} else if (billingDate) {
|
||||||
if (new Date(billingDate) > new Date()) {
|
if (new Date(billingDate) > new Date()) {
|
||||||
setIsSubscribe(true);
|
setIsSubscribe(true);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`);
|
handleNavigation(plan);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`);
|
handleNavigation(plan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// `fetchTemplate` function in used to get Template from server and setPlaceholder ,setSigner if present
|
// `fetchTemplate` function in used to get Template from server and setPlaceholder ,setSigner if present
|
||||||
@@ -225,8 +240,6 @@ const TemplatePlaceholder = () => {
|
|||||||
setPdfDetails(documentData);
|
setPdfDetails(documentData);
|
||||||
setIsSigners(true);
|
setIsSigners(true);
|
||||||
if (documentData[0].Signers && documentData[0].Signers.length > 0) {
|
if (documentData[0].Signers && documentData[0].Signers.length > 0) {
|
||||||
setSignerObjId(documentData[0].Signers[0].objectId);
|
|
||||||
setContractName(documentData[0].Signers[0].className);
|
|
||||||
setIsSelectId(0);
|
setIsSelectId(0);
|
||||||
if (
|
if (
|
||||||
documentData[0].Placeholders &&
|
documentData[0].Placeholders &&
|
||||||
@@ -365,21 +378,19 @@ const TemplatePlaceholder = () => {
|
|||||||
containerWH
|
containerWH
|
||||||
);
|
);
|
||||||
const key = randomId();
|
const key = randomId();
|
||||||
let filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
|
|
||||||
const dragTypeValue = item?.text ? item.text : monitor.type;
|
const dragTypeValue = item?.text ? item.text : monitor.type;
|
||||||
const widgetWidth = defaultWidthHeight(dragTypeValue).width;
|
const widgetWidth = defaultWidthHeight(dragTypeValue).width;
|
||||||
const widgetHeight = defaultWidthHeight(dragTypeValue).height;
|
const widgetHeight = defaultWidthHeight(dragTypeValue).height;
|
||||||
let dropData = [];
|
let dropData = [],
|
||||||
|
currentPagePosition;
|
||||||
let placeHolder;
|
let placeHolder;
|
||||||
if (item === "onclick") {
|
if (item === "onclick") {
|
||||||
|
// `getBoundingClientRect()` is used to get accurate measurement height of the div
|
||||||
|
const divHeight = divRef.current.getBoundingClientRect().height;
|
||||||
const dropObj = {
|
const dropObj = {
|
||||||
//onclick put placeholder center on pdf
|
//onclick put placeholder center on pdf
|
||||||
xPosition:
|
xPosition: widgetWidth / 4 + containerWH.width / 2,
|
||||||
(containerWH.width / 2 - widgetWidth / 2) /
|
yPosition: widgetHeight + divHeight / 2,
|
||||||
(containerScale * scale),
|
|
||||||
yPosition:
|
|
||||||
(containerWH.height / 2 - widgetHeight / 2) /
|
|
||||||
(containerScale * scale),
|
|
||||||
isStamp:
|
isStamp:
|
||||||
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
|
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
|
||||||
key: key,
|
key: key,
|
||||||
@@ -430,65 +441,40 @@ const TemplatePlaceholder = () => {
|
|||||||
pos: dropData
|
pos: dropData
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const { blockColor, Role } = signer;
|
let filterSignerPos = signerPos.find((data) => data.Id === uniqueId);
|
||||||
//adding placholder in existing signer pos array (placaholder)
|
const getPlaceHolder = filterSignerPos?.placeHolder;
|
||||||
if (filterSignerPos.length > 0) {
|
if (getPlaceHolder) {
|
||||||
const getPlaceHolder = filterSignerPos[0].placeHolder;
|
//checking exist placeholder on same page
|
||||||
|
currentPagePosition = getPlaceHolder.find(
|
||||||
|
(data) => data.pageNumber === pageNumber
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//checking current page has already some placeholders then update that placeholder and add upcoming placehoder position
|
||||||
|
if (getPlaceHolder && currentPagePosition) {
|
||||||
const updatePlace = getPlaceHolder.filter(
|
const updatePlace = getPlaceHolder.filter(
|
||||||
(data) => data.pageNumber !== pageNumber
|
(data) => data.pageNumber !== pageNumber
|
||||||
);
|
);
|
||||||
const getPageNumer = getPlaceHolder.filter(
|
const getPos = currentPagePosition?.pos;
|
||||||
(data) => data.pageNumber === pageNumber
|
const newSignPos = getPos.concat(dropData);
|
||||||
|
let xyPos = {
|
||||||
|
pageNumber: pageNumber,
|
||||||
|
pos: newSignPos
|
||||||
|
};
|
||||||
|
updatePlace.push(xyPos);
|
||||||
|
const updatesignerPos = signerPos.map((x) =>
|
||||||
|
x.Id === uniqueId ? { ...x, placeHolder: updatePlace } : x
|
||||||
);
|
);
|
||||||
|
setSignerPos(updatesignerPos);
|
||||||
//add entry of position for same signer on multiple page
|
|
||||||
if (getPageNumer.length > 0) {
|
|
||||||
const getPos = getPageNumer[0].pos;
|
|
||||||
const newSignPos = getPos.concat(dropData);
|
|
||||||
let xyPos = {
|
|
||||||
pageNumber: pageNumber,
|
|
||||||
pos: newSignPos
|
|
||||||
};
|
|
||||||
updatePlace.push(xyPos);
|
|
||||||
const updatesignerPos = signerPos.map((x) =>
|
|
||||||
x.Id === uniqueId ? { ...x, placeHolder: updatePlace } : x
|
|
||||||
);
|
|
||||||
setSignerPos(updatesignerPos);
|
|
||||||
} else {
|
|
||||||
const updatesignerPos = signerPos.map((x) =>
|
|
||||||
x.Id === uniqueId
|
|
||||||
? { ...x, placeHolder: [...x.placeHolder, placeHolder] }
|
|
||||||
: x
|
|
||||||
);
|
|
||||||
setSignerPos(updatesignerPos);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
//adding new placeholder for selected signer in pos array (placeholder)
|
//else condition to add placeholder widgets on multiple page first time
|
||||||
let placeHolderPos;
|
const updatesignerPos = signerPos.map((x) =>
|
||||||
if (contractName) {
|
x.Id === uniqueId && x?.placeHolder
|
||||||
placeHolderPos = {
|
? { ...x, placeHolder: [...x.placeHolder, placeHolder] }
|
||||||
signerPtr: {
|
: x.Id === uniqueId
|
||||||
__type: "Pointer",
|
? { ...x, placeHolder: [placeHolder] }
|
||||||
className: `${contractName}`,
|
: x
|
||||||
objectId: signerObjId
|
);
|
||||||
},
|
setSignerPos(updatesignerPos);
|
||||||
signerObjId: signerObjId,
|
|
||||||
blockColor: blockColor ? blockColor : color[isSelectListId],
|
|
||||||
placeHolder: [placeHolder],
|
|
||||||
Role: Role ? Role : roleName,
|
|
||||||
Id: uniqueId
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
placeHolderPos = {
|
|
||||||
signerPtr: {},
|
|
||||||
signerObjId: "",
|
|
||||||
blockColor: blockColor ? blockColor : color[isSelectListId],
|
|
||||||
placeHolder: [placeHolder],
|
|
||||||
Role: Role ? Role : roleName,
|
|
||||||
Id: uniqueId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
setSignerPos((prev) => [...prev, placeHolderPos]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dragTypeValue === "dropdown") {
|
if (dragTypeValue === "dropdown") {
|
||||||
@@ -615,10 +601,6 @@ const TemplatePlaceholder = () => {
|
|||||||
//function for delete signature block
|
//function for delete signature block
|
||||||
const handleDeleteSign = (key, Id) => {
|
const handleDeleteSign = (key, Id) => {
|
||||||
const updateData = [];
|
const updateData = [];
|
||||||
// const filterSignerPos = signerPos.filter(
|
|
||||||
// (data) => data.signerObjId === signerId
|
|
||||||
// );
|
|
||||||
|
|
||||||
const filterSignerPos = signerPos.filter((data) => data.Id === Id);
|
const filterSignerPos = signerPos.filter((data) => data.Id === Id);
|
||||||
|
|
||||||
if (filterSignerPos.length > 0) {
|
if (filterSignerPos.length > 0) {
|
||||||
@@ -651,11 +633,11 @@ const TemplatePlaceholder = () => {
|
|||||||
|
|
||||||
setSignerPos(newUpdateSigner);
|
setSignerPos(newUpdateSigner);
|
||||||
} else {
|
} else {
|
||||||
const updateFilter = signerPos.filter((data) => data.Id !== Id);
|
|
||||||
const getRemainPage = filterSignerPos[0].placeHolder.filter(
|
const getRemainPage = filterSignerPos[0].placeHolder.filter(
|
||||||
(data) => data.pageNumber !== pageNumber
|
(data) => data.pageNumber !== pageNumber
|
||||||
);
|
);
|
||||||
|
//condition to check placeholder length is greater than 1 do not need to remove whole placeholder
|
||||||
|
//array only resove particular widgets
|
||||||
if (getRemainPage && getRemainPage.length > 0) {
|
if (getRemainPage && getRemainPage.length > 0) {
|
||||||
const newUpdatePos = filterSignerPos.map((obj) => {
|
const newUpdatePos = filterSignerPos.map((obj) => {
|
||||||
if (obj.Id === Id) {
|
if (obj.Id === Id) {
|
||||||
@@ -669,7 +651,16 @@ const TemplatePlaceholder = () => {
|
|||||||
|
|
||||||
setSignerPos(signerupdate);
|
setSignerPos(signerupdate);
|
||||||
} else {
|
} else {
|
||||||
setSignerPos(updateFilter);
|
const updatedData = signerPos.map((item) => {
|
||||||
|
if (item.Id === Id) {
|
||||||
|
// Create a copy of the item object and delete the placeHolder field
|
||||||
|
const updatedItem = { ...item };
|
||||||
|
delete updatedItem.placeHolder;
|
||||||
|
return updatedItem;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
setSignerPos(updatedData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -691,19 +682,11 @@ const TemplatePlaceholder = () => {
|
|||||||
const touch = e.touches[0]; // Get the first touch point
|
const touch = e.touches[0]; // Get the first touch point
|
||||||
mouseX = touch.clientX - divRect.left;
|
mouseX = touch.clientX - divRect.left;
|
||||||
mouseY = touch.clientY - divRect.top;
|
mouseY = touch.clientY - divRect.top;
|
||||||
setSignBtnPosition([
|
setSignBtnPosition([{ xPos: mouseX, yPos: mouseY }]);
|
||||||
{
|
|
||||||
xPos: mouseX,
|
|
||||||
yPos: mouseY
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
} else {
|
} else {
|
||||||
mouseX = e.clientX - divRect.left;
|
mouseX = e.clientX - divRect.left;
|
||||||
mouseY = e.clientY - divRect.top;
|
mouseY = e.clientY - divRect.top;
|
||||||
const xyPosition = {
|
const xyPosition = { xPos: mouseX, yPos: mouseY };
|
||||||
xPos: mouseX,
|
|
||||||
yPos: mouseY
|
|
||||||
};
|
|
||||||
setXYSignature(xyPosition);
|
setXYSignature(xyPosition);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -712,20 +695,54 @@ const TemplatePlaceholder = () => {
|
|||||||
const handleMouseLeave = () => {
|
const handleMouseLeave = () => {
|
||||||
setSignBtnPosition([xySignature]);
|
setSignBtnPosition([xySignature]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const alertSendEmail = async () => {
|
const alertSendEmail = async () => {
|
||||||
if (signerPos.length !== signersdata.length) {
|
const isPlaceholderExist = signerPos.every((data) => data.placeHolder);
|
||||||
setIsSendAlert(true);
|
if (isPlaceholderExist) {
|
||||||
} else {
|
|
||||||
handleSaveTemplate();
|
handleSaveTemplate();
|
||||||
|
} else {
|
||||||
|
setIsSendAlert(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
if (signerPos?.length > 0) {
|
||||||
|
autosavedetails();
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [signerPos]);
|
||||||
|
|
||||||
|
// `autosavedetails` is used to save template details after every 2 sec when changes are happern in placeholder like drag-drop widgets, remove signers
|
||||||
|
const autosavedetails = async () => {
|
||||||
|
let signers = [];
|
||||||
|
if (signersdata?.length > 0) {
|
||||||
|
signersdata.forEach((x) => {
|
||||||
|
if (x.objectId) {
|
||||||
|
const obj = {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: "contracts_Contactbook",
|
||||||
|
objectId: x.objectId
|
||||||
|
};
|
||||||
|
signers.push(obj);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const templateCls = new Parse.Object("contracts_Template");
|
||||||
|
templateCls.id = templateId;
|
||||||
|
templateCls.set("Placeholders", signerPos);
|
||||||
|
templateCls.set("Signers", signers);
|
||||||
|
await templateCls.save();
|
||||||
|
} catch (err) {
|
||||||
|
console.log("error in autosave template", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleSaveTemplate = async () => {
|
const handleSaveTemplate = async () => {
|
||||||
if (signersdata?.length) {
|
if (signersdata?.length) {
|
||||||
const loadObj = {
|
const loadObj = { isLoad: true, message: t("loading-mssg") };
|
||||||
isLoad: true,
|
|
||||||
message: t("loading-mssg")
|
|
||||||
};
|
|
||||||
setIsLoading(loadObj);
|
setIsLoading(loadObj);
|
||||||
setIsSendAlert(false);
|
setIsSendAlert(false);
|
||||||
let signers = [];
|
let signers = [];
|
||||||
@@ -741,6 +758,17 @@ const TemplatePlaceholder = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
let pdfUrl = pdfDetails[0]?.URL;
|
||||||
|
if (pdfRotateBase64) {
|
||||||
|
try {
|
||||||
|
pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfDetails[0].Name,
|
||||||
|
pdfRotateBase64
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("error to convertBase64ToFile in placeholder flow", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const data = {
|
const data = {
|
||||||
Placeholders: signerPos,
|
Placeholders: signerPos,
|
||||||
@@ -751,23 +779,19 @@ const TemplatePlaceholder = () => {
|
|||||||
SendinOrder: pdfDetails[0]?.SendinOrder || false,
|
SendinOrder: pdfDetails[0]?.SendinOrder || false,
|
||||||
AutomaticReminders: pdfDetails[0]?.AutomaticReminders,
|
AutomaticReminders: pdfDetails[0]?.AutomaticReminders,
|
||||||
RemindOnceInEvery: parseInt(pdfDetails[0]?.RemindOnceInEvery),
|
RemindOnceInEvery: parseInt(pdfDetails[0]?.RemindOnceInEvery),
|
||||||
NextReminderDate: pdfDetails[0]?.NextReminderDate
|
NextReminderDate: pdfDetails[0]?.NextReminderDate,
|
||||||
|
IsEnableOTP: pdfDetails[0]?.IsEnableOTP === true ? true : false,
|
||||||
|
URL: pdfUrl
|
||||||
};
|
};
|
||||||
const updateTemplate = new Parse.Object("contracts_Template");
|
const updateTemplate = new Parse.Object("contracts_Template");
|
||||||
updateTemplate.id = templateId;
|
updateTemplate.id = templateId;
|
||||||
for (const key in data) {
|
for (const key in data) {
|
||||||
updateTemplate.set(key, data[key]);
|
updateTemplate.set(key, data[key]);
|
||||||
}
|
}
|
||||||
await updateTemplate.save(null, {
|
await updateTemplate.save();
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
|
||||||
});
|
|
||||||
|
|
||||||
setIsCreateDocModal(true);
|
setIsCreateDocModal(true);
|
||||||
setIsMailSend(true);
|
setIsMailSend(true);
|
||||||
const loadObj = {
|
setIsLoading({ isLoad: false });
|
||||||
isLoad: false
|
|
||||||
};
|
|
||||||
setIsLoading(loadObj);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
alert(t("something-went-wrong-mssg"));
|
alert(t("something-went-wrong-mssg"));
|
||||||
@@ -891,8 +915,21 @@ const TemplatePlaceholder = () => {
|
|||||||
const handleCreateDocModal = async () => {
|
const handleCreateDocModal = async () => {
|
||||||
setIsCreateDocModal(false);
|
setIsCreateDocModal(false);
|
||||||
setIsCreateDoc(true);
|
setIsCreateDoc(true);
|
||||||
|
let pdfUrl = pdfDetails[0]?.URL;
|
||||||
|
if (pdfRotateBase64) {
|
||||||
|
try {
|
||||||
|
pdfUrl = await convertBase64ToFile(pdfDetails[0].Name, pdfRotateBase64);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("error to convertBase64ToFile in placeholder flow", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
// handle create document
|
// handle create document
|
||||||
const res = await createDocument(pdfDetails, signerPos, signersdata);
|
const res = await createDocument(
|
||||||
|
pdfDetails,
|
||||||
|
signerPos,
|
||||||
|
signersdata,
|
||||||
|
pdfUrl
|
||||||
|
);
|
||||||
if (res.status === "success") {
|
if (res.status === "success") {
|
||||||
navigate(`/placeHolderSign/${res.id}`, {
|
navigate(`/placeHolderSign/${res.id}`, {
|
||||||
state: { title: "Use Template" }
|
state: { title: "Use Template" }
|
||||||
@@ -903,7 +940,6 @@ const TemplatePlaceholder = () => {
|
|||||||
setIsCreateDoc(false);
|
setIsCreateDoc(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// `handleAddSigner` is used to open Add Role Modal
|
// `handleAddSigner` is used to open Add Role Modal
|
||||||
const handleAddSigner = () => {
|
const handleAddSigner = () => {
|
||||||
setIsModalRole(true);
|
setIsModalRole(true);
|
||||||
@@ -914,8 +950,6 @@ const TemplatePlaceholder = () => {
|
|||||||
// save Role in entry in signerList and user
|
// save Role in entry in signerList and user
|
||||||
const handleAddRole = (e) => {
|
const handleAddRole = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setSignerObjId("");
|
|
||||||
setContractName("");
|
|
||||||
const count = signersdata.length > 0 ? signersdata.length + 1 : 1;
|
const count = signersdata.length > 0 ? signersdata.length + 1 : 1;
|
||||||
const Id = randomId();
|
const Id = randomId();
|
||||||
const index = signersdata.length;
|
const index = signersdata.length;
|
||||||
@@ -925,6 +959,15 @@ const TemplatePlaceholder = () => {
|
|||||||
blockColor: color[index]
|
blockColor: color[index]
|
||||||
};
|
};
|
||||||
setSignersData((prevArr) => [...prevArr, obj]);
|
setSignersData((prevArr) => [...prevArr, obj]);
|
||||||
|
const signerPosObj = {
|
||||||
|
signerPtr: {},
|
||||||
|
signerObjId: "",
|
||||||
|
blockColor: color[index],
|
||||||
|
Role: roleName || "User " + count,
|
||||||
|
Id: Id
|
||||||
|
};
|
||||||
|
|
||||||
|
setSignerPos((prev) => [...prev, signerPosObj]);
|
||||||
setIsModalRole(false);
|
setIsModalRole(false);
|
||||||
setRoleName("");
|
setRoleName("");
|
||||||
setUniqueId(Id);
|
setUniqueId(Id);
|
||||||
@@ -956,11 +999,12 @@ const TemplatePlaceholder = () => {
|
|||||||
setIsMailSend(false);
|
setIsMailSend(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
// `handleLinkUser` is used to open Add/Choose Signer Modal when user can link existing or new User with placeholder
|
// `handleLinkUser` is used to open Add/Choose Signer Modal when user can link existing or new User with placeholder
|
||||||
// and update entry in signersList
|
// and update entry in signersList
|
||||||
const handleLinkUser = (id) => {
|
const handleLinkUser = (id) => {
|
||||||
setIsAddUser({ [id]: true });
|
setIsAddUser({ [id]: true });
|
||||||
};
|
};
|
||||||
|
// `handleAddUser` is used to adduser
|
||||||
const handleAddUser = (data) => {
|
const handleAddUser = (data) => {
|
||||||
const signerPtr = {
|
const signerPtr = {
|
||||||
__type: "Pointer",
|
__type: "Pointer",
|
||||||
@@ -1089,7 +1133,13 @@ const TemplatePlaceholder = () => {
|
|||||||
status: status,
|
status: status,
|
||||||
defaultValue: defaultValue,
|
defaultValue: defaultValue,
|
||||||
isReadOnly: isReadOnly || false,
|
isReadOnly: isReadOnly || false,
|
||||||
isHideLabel: isHideLabel || false
|
isHideLabel: isHideLabel || false,
|
||||||
|
fontSize:
|
||||||
|
fontSize || currWidgetsDetails?.options?.fontSize || "12",
|
||||||
|
fontColor:
|
||||||
|
fontColor ||
|
||||||
|
currWidgetsDetails?.options?.fontColor ||
|
||||||
|
"black"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1121,7 +1171,13 @@ const TemplatePlaceholder = () => {
|
|||||||
},
|
},
|
||||||
isReadOnly: isReadOnly || false,
|
isReadOnly: isReadOnly || false,
|
||||||
defaultValue: defaultValue,
|
defaultValue: defaultValue,
|
||||||
isHideLabel: isHideLabel || false
|
isHideLabel: isHideLabel || false,
|
||||||
|
fontSize:
|
||||||
|
fontSize || currWidgetsDetails?.options?.fontSize || "12",
|
||||||
|
fontColor:
|
||||||
|
fontColor ||
|
||||||
|
currWidgetsDetails?.options?.fontColor ||
|
||||||
|
"black"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1133,7 +1189,13 @@ const TemplatePlaceholder = () => {
|
|||||||
name: dropdownName,
|
name: dropdownName,
|
||||||
status: status,
|
status: status,
|
||||||
values: dropdownOptions,
|
values: dropdownOptions,
|
||||||
defaultValue: defaultValue
|
defaultValue: defaultValue,
|
||||||
|
fontSize:
|
||||||
|
fontSize || currWidgetsDetails?.options?.fontSize || "12",
|
||||||
|
fontColor:
|
||||||
|
fontColor ||
|
||||||
|
currWidgetsDetails?.options?.fontColor ||
|
||||||
|
"black"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1160,6 +1222,8 @@ const TemplatePlaceholder = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setFontSize();
|
||||||
|
setFontColor();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleWidgetdefaultdata = (defaultdata) => {
|
const handleWidgetdefaultdata = (defaultdata) => {
|
||||||
@@ -1250,6 +1314,7 @@ const TemplatePlaceholder = () => {
|
|||||||
setCurrWidgetsDetails({});
|
setCurrWidgetsDetails({});
|
||||||
handleNameModal();
|
handleNameModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleNameModal = () => {
|
const handleNameModal = () => {
|
||||||
setIsNameModal(false);
|
setIsNameModal(false);
|
||||||
setCurrWidgetsDetails({});
|
setCurrWidgetsDetails({});
|
||||||
@@ -1258,6 +1323,38 @@ const TemplatePlaceholder = () => {
|
|||||||
setIsCheckbox(false);
|
setIsCheckbox(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const clickOnZoomIn = () => {
|
||||||
|
onClickZoomIn(scale, zoomPercent, setScale, setZoomPercent);
|
||||||
|
};
|
||||||
|
const clickOnZoomOut = () => {
|
||||||
|
onClickZoomOut(zoomPercent, scale, setZoomPercent, setScale);
|
||||||
|
};
|
||||||
|
//`handleRotationFun` function is used to roatate pdf particular page
|
||||||
|
const handleRotationFun = async (rotateDegree) => {
|
||||||
|
const isRotate = handleRotateWarning(signerPos, pageNumber);
|
||||||
|
if (isRotate) {
|
||||||
|
setIsRotate({ status: true, degree: rotateDegree });
|
||||||
|
} else {
|
||||||
|
const urlDetails = await rotatePdfPage(
|
||||||
|
pdfDetails[0].URL,
|
||||||
|
rotateDegree,
|
||||||
|
pageNumber - 1,
|
||||||
|
pdfRotateBase64
|
||||||
|
);
|
||||||
|
setPdfRotatese64(urlDetails.base64);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleRemovePlaceholder = async () => {
|
||||||
|
handleRemoveWidgets(setSignerPos, signerPos, pageNumber, setIsRotate);
|
||||||
|
const urlDetails = await rotatePdfPage(
|
||||||
|
pdfDetails[0].URL,
|
||||||
|
isRotate.degree,
|
||||||
|
pageNumber - 1,
|
||||||
|
pdfRotateBase64
|
||||||
|
);
|
||||||
|
setPdfRotatese64(urlDetails.base64);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title title={"Template"} />
|
<Title title={"Template"} />
|
||||||
@@ -1305,11 +1402,9 @@ const TemplatePlaceholder = () => {
|
|||||||
{/* pdf render view */}
|
{/* pdf render view */}
|
||||||
<div className=" w-full md:w-[57%] flex mr-4">
|
<div className=" w-full md:w-[57%] flex mr-4">
|
||||||
<PdfZoom
|
<PdfZoom
|
||||||
setScale={setScale}
|
clickOnZoomIn={clickOnZoomIn}
|
||||||
scale={scale}
|
clickOnZoomOut={clickOnZoomOut}
|
||||||
containerWH={containerWH}
|
handleRotationFun={handleRotationFun}
|
||||||
setZoomPercent={setZoomPercent}
|
|
||||||
zoomPercent={zoomPercent}
|
|
||||||
/>
|
/>
|
||||||
<div className="w-full md:w-[95%]">
|
<div className="w-full md:w-[95%]">
|
||||||
{/* this modal is used show alert set placeholder for all signers before send mail */}
|
{/* this modal is used show alert set placeholder for all signers before send mail */}
|
||||||
@@ -1391,6 +1486,10 @@ const TemplatePlaceholder = () => {
|
|||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
handleClose={handleNameModal}
|
handleClose={handleNameModal}
|
||||||
isSubscribe={isSubscribe}
|
isSubscribe={isSubscribe}
|
||||||
|
fontSize={fontSize}
|
||||||
|
setFontSize={setFontSize}
|
||||||
|
fontColor={fontColor}
|
||||||
|
setFontColor={setFontColor}
|
||||||
/>
|
/>
|
||||||
<DropdownWidgetOption
|
<DropdownWidgetOption
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -1402,6 +1501,10 @@ const TemplatePlaceholder = () => {
|
|||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
handleClose={handleNameModal}
|
handleClose={handleNameModal}
|
||||||
isSubscribe={isSubscribe}
|
isSubscribe={isSubscribe}
|
||||||
|
fontSize={fontSize}
|
||||||
|
setFontSize={setFontSize}
|
||||||
|
fontColor={fontColor}
|
||||||
|
setFontColor={setFontColor}
|
||||||
/>
|
/>
|
||||||
<DropdownWidgetOption
|
<DropdownWidgetOption
|
||||||
type="dropdown"
|
type="dropdown"
|
||||||
@@ -1413,6 +1516,10 @@ const TemplatePlaceholder = () => {
|
|||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
handleClose={handleNameModal}
|
handleClose={handleNameModal}
|
||||||
isSubscribe={isSubscribe}
|
isSubscribe={isSubscribe}
|
||||||
|
fontSize={fontSize}
|
||||||
|
setFontSize={setFontSize}
|
||||||
|
fontColor={fontColor}
|
||||||
|
setFontColor={setFontColor}
|
||||||
/>
|
/>
|
||||||
<PlaceholderCopy
|
<PlaceholderCopy
|
||||||
isPageCopy={isPageCopy}
|
isPageCopy={isPageCopy}
|
||||||
@@ -1440,6 +1547,9 @@ const TemplatePlaceholder = () => {
|
|||||||
currentSigner={true}
|
currentSigner={true}
|
||||||
setIsEditTemplate={handleEditTemplateModal}
|
setIsEditTemplate={handleEditTemplateModal}
|
||||||
dataTut4="reactourFour"
|
dataTut4="reactourFour"
|
||||||
|
handleRotationFun={handleRotationFun}
|
||||||
|
clickOnZoomIn={clickOnZoomIn}
|
||||||
|
clickOnZoomOut={clickOnZoomOut}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
ref={divRef}
|
ref={divRef}
|
||||||
@@ -1471,7 +1581,6 @@ const TemplatePlaceholder = () => {
|
|||||||
signersdata={signersdata}
|
signersdata={signersdata}
|
||||||
setIsPageCopy={setIsPageCopy}
|
setIsPageCopy={setIsPageCopy}
|
||||||
setSignKey={setSignKey}
|
setSignKey={setSignKey}
|
||||||
setSignerObjId={setSignerObjId}
|
|
||||||
isDragging={isDragging}
|
isDragging={isDragging}
|
||||||
setShowDropdown={setShowDropdown}
|
setShowDropdown={setShowDropdown}
|
||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
@@ -1485,6 +1594,11 @@ const TemplatePlaceholder = () => {
|
|||||||
setScale={setScale}
|
setScale={setScale}
|
||||||
scale={scale}
|
scale={scale}
|
||||||
setIsSelectId={setIsSelectId}
|
setIsSelectId={setIsSelectId}
|
||||||
|
pdfRotateBase64={pdfRotateBase64}
|
||||||
|
fontSize={fontSize}
|
||||||
|
setFontSize={setFontSize}
|
||||||
|
fontColor={fontColor}
|
||||||
|
setFontColor={setFontColor}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -1509,9 +1623,7 @@ const TemplatePlaceholder = () => {
|
|||||||
signerPos={signerPos}
|
signerPos={signerPos}
|
||||||
signersdata={signersdata}
|
signersdata={signersdata}
|
||||||
isSelectListId={isSelectListId}
|
isSelectListId={isSelectListId}
|
||||||
setSignerObjId={setSignerObjId}
|
|
||||||
setIsSelectId={setIsSelectId}
|
setIsSelectId={setIsSelectId}
|
||||||
setContractName={setContractName}
|
|
||||||
isSigners={isSigners}
|
isSigners={isSigners}
|
||||||
setIsShowEmail={setIsShowEmail}
|
setIsShowEmail={setIsShowEmail}
|
||||||
isMailSend={isMailSend}
|
isMailSend={isMailSend}
|
||||||
@@ -1541,10 +1653,8 @@ const TemplatePlaceholder = () => {
|
|||||||
setSignerPos={setSignerPos}
|
setSignerPos={setSignerPos}
|
||||||
signersdata={signersdata}
|
signersdata={signersdata}
|
||||||
isSelectListId={isSelectListId}
|
isSelectListId={isSelectListId}
|
||||||
setSignerObjId={setSignerObjId}
|
|
||||||
setRoleName={setRoleName}
|
setRoleName={setRoleName}
|
||||||
setIsSelectId={setIsSelectId}
|
setIsSelectId={setIsSelectId}
|
||||||
setContractName={setContractName}
|
|
||||||
handleAddSigner={handleAddSigner}
|
handleAddSigner={handleAddSigner}
|
||||||
setUniqueId={setUniqueId}
|
setUniqueId={setUniqueId}
|
||||||
handleDeleteUser={handleDeleteUser}
|
handleDeleteUser={handleDeleteUser}
|
||||||
@@ -1624,6 +1734,11 @@ const TemplatePlaceholder = () => {
|
|||||||
fontColor={fontColor}
|
fontColor={fontColor}
|
||||||
setFontColor={setFontColor}
|
setFontColor={setFontColor}
|
||||||
/>
|
/>
|
||||||
|
<RotateAlert
|
||||||
|
isRotate={isRotate.status}
|
||||||
|
setIsRotate={setIsRotate}
|
||||||
|
handleRemoveWidgets={handleRemovePlaceholder}
|
||||||
|
/>
|
||||||
</DndProvider>
|
</DndProvider>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const UpdateExistUserAdmin = () => {
|
|||||||
try {
|
try {
|
||||||
const isAdminExist = await Parse.Cloud.run("checkadminexist");
|
const isAdminExist = await Parse.Cloud.run("checkadminexist");
|
||||||
if (isAdminExist !== "not_exist") {
|
if (isAdminExist !== "not_exist") {
|
||||||
console.log("isAdminExist ", isAdminExist);
|
// console.log("isAdminExist ", isAdminExist);
|
||||||
setErrMsg("Admin already exists.");
|
setErrMsg("Admin already exists.");
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -65,12 +65,8 @@ const UpdateExistUserAdmin = () => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="h-screen flex justify-center">
|
<div className="h-screen flex justify-center">
|
||||||
<Title title="Add admin" />
|
<Title title={"Add Admin"} />
|
||||||
{isAlert.msg && (
|
{isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
|
||||||
<Alert type={isAlert.type}>
|
|
||||||
<div className="ml-3">{isAlert.msg}</div>
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
{loader ? (
|
{loader ? (
|
||||||
<div className="text-[grey] flex justify-center items-center text-lg md:text-2xl">
|
<div className="text-[grey] flex justify-center items-center text-lg md:text-2xl">
|
||||||
<Loader />
|
<Loader />
|
||||||
|
|||||||
+246
-116
@@ -9,8 +9,9 @@ import Tooltip from "../primitives/Tooltip";
|
|||||||
import AddUser from "../components/AddUser";
|
import AddUser from "../components/AddUser";
|
||||||
import SubscribeCard from "../primitives/SubscribeCard";
|
import SubscribeCard from "../primitives/SubscribeCard";
|
||||||
import { isEnableSubscription } from "../constant/const";
|
import { isEnableSubscription } from "../constant/const";
|
||||||
import { checkIsSubscribedTeam } from "../constant/Utils";
|
import { fetchSubscriptionInfo } from "../constant/Utils";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
|
import { validplan } from "../json/plansArr";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"];
|
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"];
|
||||||
// const actions = [];
|
// const actions = [];
|
||||||
@@ -18,7 +19,11 @@ const UserList = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [userList, setUserList] = useState([]);
|
const [userList, setUserList] = useState([]);
|
||||||
const [isLoader, setIsLoader] = useState(false);
|
const [isLoader, setIsLoader] = useState(false);
|
||||||
const [isModal, setIsModal] = useState(false);
|
const [isModal, setIsModal] = useState({
|
||||||
|
form: false,
|
||||||
|
addseats: false,
|
||||||
|
options: false
|
||||||
|
});
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const isDashboard =
|
const isDashboard =
|
||||||
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
|
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
|
||||||
@@ -26,8 +31,16 @@ const UserList = () => {
|
|||||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||||
const [isActiveModal, setIsActiveModal] = useState({});
|
const [isActiveModal, setIsActiveModal] = useState({});
|
||||||
const [isActLoader, setIsActLoader] = useState({});
|
const [isActLoader, setIsActLoader] = useState({});
|
||||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
const [isSubscribe, setIsSubscribe] = useState({
|
||||||
|
plan: "",
|
||||||
|
isValid: false,
|
||||||
|
priceperUser: 0
|
||||||
|
});
|
||||||
const [isAdmin, setIsAdmin] = useState(false);
|
const [isAdmin, setIsAdmin] = useState(false);
|
||||||
|
const [formHeader, setFormHeader] = useState(t("add-user"));
|
||||||
|
const [usersCount, setUserCounts] = useState({ allowed: 0, totalAllowed: 0 });
|
||||||
|
const [amount, setAmount] = useState({ quantity: 1, price: 0 });
|
||||||
|
const [isBuyLoader, setIsBuyLoader] = useState(false);
|
||||||
const recordperPage = 10;
|
const recordperPage = 10;
|
||||||
const startIndex = (currentPage - 1) * recordperPage; // user per page
|
const startIndex = (currentPage - 1) * recordperPage; // user per page
|
||||||
|
|
||||||
@@ -79,10 +92,13 @@ const UserList = () => {
|
|||||||
pages.push(lastPageIndex);
|
pages.push(lastPageIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pages;
|
return pages;
|
||||||
};
|
};
|
||||||
const pageNumbers = getPaginationRange();
|
const pageNumbers = getPaginationRange();
|
||||||
|
// to slice out 10 objects from array for current page
|
||||||
|
const indexOfLastDoc = currentPage * recordperPage;
|
||||||
|
const indexOfFirstDoc = indexOfLastDoc - recordperPage;
|
||||||
|
const currentList = userList?.slice(indexOfFirstDoc, indexOfLastDoc);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchUserList();
|
fetchUserList();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
@@ -90,13 +106,43 @@ const UserList = () => {
|
|||||||
async function fetchUserList() {
|
async function fetchUserList() {
|
||||||
try {
|
try {
|
||||||
setIsLoader(true);
|
setIsLoader(true);
|
||||||
|
const extUser =
|
||||||
|
localStorage.getItem("Extand_Class") &&
|
||||||
|
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const getIsSubscribe = await checkIsSubscribedTeam();
|
const subscribe = await fetchSubscriptionInfo();
|
||||||
setIsSubscribe(getIsSubscribe);
|
if (subscribe?.plan_code?.includes("team")) {
|
||||||
|
const isSupAdmin =
|
||||||
|
subscribe?.adminId && extUser?.objectId === subscribe?.adminId;
|
||||||
|
setIsSubscribe({
|
||||||
|
plan: subscribe.plan_code,
|
||||||
|
isValid: true,
|
||||||
|
adminId: subscribe.adminId,
|
||||||
|
priceperUser: subscribe.price,
|
||||||
|
isSuperAdmin: isSupAdmin
|
||||||
|
});
|
||||||
|
setAmount((prev) => ({ ...prev, price: subscribe.price }));
|
||||||
|
try {
|
||||||
|
const res = await Parse.Cloud.run("allowedusers");
|
||||||
|
setUserCounts((obj) => ({
|
||||||
|
...obj,
|
||||||
|
allowed: parseInt(res),
|
||||||
|
totalAllowed: parseInt(subscribe?.totalAllowedUser) || 0
|
||||||
|
}));
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err while get users", err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsSubscribe({
|
||||||
|
plan: subscribe.plan_code,
|
||||||
|
isValid: false,
|
||||||
|
adminId: subscribe.adminId
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setIsSubscribe(true);
|
setIsSubscribe({ plan: "teams-yearly", isValid: true });
|
||||||
}
|
}
|
||||||
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
|
||||||
if (extUser) {
|
if (extUser) {
|
||||||
const admin =
|
const admin =
|
||||||
extUser?.UserRole &&
|
extUser?.UserRole &&
|
||||||
@@ -115,26 +161,36 @@ const UserList = () => {
|
|||||||
console.log("Err in fetch userlist", err);
|
console.log("Err in fetch userlist", err);
|
||||||
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
|
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
|
||||||
} finally {
|
} finally {
|
||||||
setTimeout(() => {
|
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
|
||||||
setIsAlert({ type: "success", msg: "" });
|
|
||||||
}, 1500);
|
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleFormModal = () => {
|
const handleModal = (modalName) => {
|
||||||
setIsModal(!isModal);
|
setIsModal((obj) => ({ ...obj, [modalName]: !obj[modalName] }));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Change page
|
// Change page
|
||||||
const paginateFront = () => setCurrentPage(currentPage + 1);
|
const paginateFront = () => {
|
||||||
const paginateBack = () => setCurrentPage(currentPage - 1);
|
const lastValue = pageNumbers?.[pageNumbers?.length - 1];
|
||||||
// const handleActionBtn = (act, item) => {
|
if (currentPage < lastValue) {
|
||||||
// if (act.action === "delete") {
|
setCurrentPage(currentPage + 1);
|
||||||
// setIsDeleteModal({ [item.objectId]: true });
|
}
|
||||||
// }
|
};
|
||||||
// };
|
|
||||||
|
const paginateBack = () => {
|
||||||
|
if (startIndex > 0) {
|
||||||
|
setCurrentPage(currentPage - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleUserData = (userData) => {
|
const handleUserData = (userData) => {
|
||||||
setUserList((prev) => [userData, ...prev]);
|
if (userData) {
|
||||||
|
setUserCounts((obj) => ({
|
||||||
|
...obj,
|
||||||
|
allowed: obj?.allowed > 0 ? obj.allowed - 1 : 1
|
||||||
|
}));
|
||||||
|
setUserList((prev) => [userData, ...prev]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// `formatRow` is used to show data in poper manner like
|
// `formatRow` is used to show data in poper manner like
|
||||||
// if data is of array type then it will join array items with ","
|
// if data is of array type then it will join array items with ","
|
||||||
@@ -150,9 +206,8 @@ const UserList = () => {
|
|||||||
return "-";
|
return "-";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleClose = () => {
|
const handleClose = () => setIsActiveModal({});
|
||||||
setIsActiveModal({});
|
|
||||||
};
|
|
||||||
const handleToggleSubmit = async (user) => {
|
const handleToggleSubmit = async (user) => {
|
||||||
const index = userList.findIndex((obj) => obj.objectId === user.objectId);
|
const index = userList.findIndex((obj) => obj.objectId === user.objectId);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
@@ -184,6 +239,49 @@ const UserList = () => {
|
|||||||
const handleToggleBtn = (user) => {
|
const handleToggleBtn = (user) => {
|
||||||
setIsActiveModal({ [user.objectId]: true });
|
setIsActiveModal({ [user.objectId]: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAddOnSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setIsBuyLoader(true);
|
||||||
|
try {
|
||||||
|
const resAddon = await Parse.Cloud.run("buyaddonusers", {
|
||||||
|
users: parseInt(amount.quantity)
|
||||||
|
});
|
||||||
|
if (resAddon) {
|
||||||
|
const _resAddon = JSON.parse(JSON.stringify(resAddon));
|
||||||
|
if (_resAddon.status === "success") {
|
||||||
|
setUserCounts((obj) => ({
|
||||||
|
...obj,
|
||||||
|
allowed: parseInt(obj.allowed) + parseInt(amount.quantity),
|
||||||
|
totalAllowed: parseInt(_resAddon.addon)
|
||||||
|
}));
|
||||||
|
setAmount((obj) => ({ ...obj, quantity: 1 }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err in buy addon", err);
|
||||||
|
setIsAlert({ type: "danger", msg: t("something-went-wrong-mssg") });
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 2000);
|
||||||
|
setIsBuyLoader(false);
|
||||||
|
handleModal("addseats");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handlePricePerUser = (e) => {
|
||||||
|
const quantity = e.target.value;
|
||||||
|
const price = e.target?.value > 0 ? isSubscribe.priceperUser * quantity : 0;
|
||||||
|
setAmount((prev) => ({ ...prev, quantity: quantity, price: price }));
|
||||||
|
};
|
||||||
|
const handleBuyUsers = (allowed, totalAllowed) => {
|
||||||
|
if (allowed && totalAllowed) {
|
||||||
|
setUserCounts((obj) => ({
|
||||||
|
...obj,
|
||||||
|
allowed: parseInt(obj.allowed) + parseInt(allowed),
|
||||||
|
totalAllowed: parseInt(totalAllowed)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Title title={isAdmin ? "Users" : "Page not found"} />
|
<Title title={isAdmin ? "Users" : "Page not found"} />
|
||||||
@@ -193,34 +291,57 @@ const UserList = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{Object.keys(isActLoader)?.length > 0 && (
|
{Object.keys(isActLoader)?.length > 0 && (
|
||||||
<div className="absolute w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-30 rounded-box">
|
<div className="absolute w-full h-full flex justify-center items-center bg-black/30 z-30 rounded-box">
|
||||||
<Loader />
|
<Loader />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isSubscribe && !isLoader && (
|
{validplan[isSubscribe.plan] && !isLoader && (
|
||||||
<>
|
<>
|
||||||
{isAdmin ? (
|
{isAdmin ? (
|
||||||
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
|
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
|
||||||
{isAlert.msg && (
|
{isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
|
||||||
<Alert type={isAlert.type}>
|
|
||||||
<div className="ml-3">{isAlert.msg}</div>
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
||||||
<div className="font-light">
|
<div className="font-light">
|
||||||
{t("report-name.Users")}
|
{t("report-name.Users")}{" "}
|
||||||
<span className="text-xs md:text-[13px] font-normal">
|
<span className="text-xs md:text-[13px] font-normal">
|
||||||
<Tooltip message={t("users-from-teams")} />
|
<Tooltip message={t("users-from-teams")} />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="flex flex-row gap-2 items-center">
|
||||||
className="cursor-pointer"
|
{isEnableSubscription && isSubscribe?.isSuperAdmin && (
|
||||||
onClick={() => handleFormModal()}
|
<div
|
||||||
>
|
className="hidden md:flex op-btn op-btn-sm h-[35px] op-btn-primary op-btn-outline text-xs mb-0.5"
|
||||||
<i className="fa-light fa-square-plus text-accent text-[40px]"></i>
|
onClick={() => handleModal("addseats")}
|
||||||
|
>
|
||||||
|
{t("buy-users")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => handleModal("form")}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-square-plus text-accent text-[30px] md:text-[40px]"></i>
|
||||||
|
</div>
|
||||||
|
{isEnableSubscription && isSubscribe?.isSuperAdmin && (
|
||||||
|
<div
|
||||||
|
className="cursor-pointer relative md:hidden mb-0.5"
|
||||||
|
onClick={() => handleModal("options")}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-ellipsis-vertical fa-xl"></i>
|
||||||
|
{isModal?.options && (
|
||||||
|
<ul className="absolute -right-3 top-auto z-[70] w-max op-menu op-menu-xs shadow bg-base-100 text-base-content rounded-box border">
|
||||||
|
<li onClick={() => handleModal("addseats")}>
|
||||||
|
<span className="text-[13px] capitalize font-medium">
|
||||||
|
{t("buy-users")}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={` overflow-x-auto w-full`}>
|
<div className="overflow-x-auto w-full">
|
||||||
<table className="op-table border-collapse w-full">
|
<table className="op-table border-collapse w-full">
|
||||||
<thead className="text-[14px]">
|
<thead className="text-[14px]">
|
||||||
<tr className="border-y-[1px]">
|
<tr className="border-y-[1px]">
|
||||||
@@ -234,7 +355,7 @@ const UserList = () => {
|
|||||||
<tbody className="text-[12px]">
|
<tbody className="text-[12px]">
|
||||||
{userList?.length > 0 && (
|
{userList?.length > 0 && (
|
||||||
<>
|
<>
|
||||||
{userList.map((item, index) => (
|
{currentList.map((item, index) => (
|
||||||
<tr className="border-y-[1px]" key={index}>
|
<tr className="border-y-[1px]" key={index}>
|
||||||
{heading.includes("Sr.No") && (
|
{heading.includes("Sr.No") && (
|
||||||
<th className="px-4 py-2">
|
<th className="px-4 py-2">
|
||||||
@@ -298,49 +419,6 @@ const UserList = () => {
|
|||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
)}
|
)}
|
||||||
{/* <td className="px-3 py-2 text-white grid grid-cols-2">
|
|
||||||
{actions?.length > 0 &&
|
|
||||||
actions.map((act, index) => (
|
|
||||||
<button
|
|
||||||
key={index}
|
|
||||||
onClick={() => handleActionBtn(act, item)}
|
|
||||||
title={act.hoverLabel}
|
|
||||||
className={`${
|
|
||||||
act?.btnColor ? act.btnColor : ""
|
|
||||||
} op-btn op-btn-sm`}
|
|
||||||
>
|
|
||||||
<i className={act.btnIcon}></i>
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
{isDeleteModal[item.objectId] && (
|
|
||||||
<ModalUi
|
|
||||||
isOpen
|
|
||||||
title={t("delete-user")}
|
|
||||||
handleClose={handleClose}
|
|
||||||
>
|
|
||||||
<div className="m-[20px]">
|
|
||||||
<div className="text-lg font-normal text-black">
|
|
||||||
{t( "are-you-sure")} {t("delete")} {t("this-user")}?
|
|
||||||
</div>
|
|
||||||
<hr className="bg-[#ccc] mt-4 " />
|
|
||||||
<div className="flex items-center mt-3 gap-2 text-white">
|
|
||||||
<button
|
|
||||||
onClick={() => handleDelete(item)}
|
|
||||||
className="op-btn op-btn-primary"
|
|
||||||
>
|
|
||||||
{t("yes")}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={handleClose}
|
|
||||||
className="op-btn op-btn-secondary"
|
|
||||||
>
|
|
||||||
{('no)}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ModalUi>
|
|
||||||
)}
|
|
||||||
</td> */}
|
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
@@ -348,34 +426,42 @@ const UserList = () => {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div className="op-join flex flex-wrap items-center p-2">
|
<div className="flex flex-row justify-between items-center text-xs font-medium">
|
||||||
{userList.length > recordperPage && (
|
<div className="op-join flex flex-wrap items-center p-2">
|
||||||
<button
|
{userList.length > recordperPage && (
|
||||||
onClick={() => paginateBack()}
|
<button
|
||||||
className="op-join-item op-btn op-btn-sm"
|
onClick={() => paginateBack()}
|
||||||
>
|
className="op-join-item op-btn op-btn-sm"
|
||||||
{t("prev")}
|
>
|
||||||
</button>
|
{t("prev")}
|
||||||
)}
|
</button>
|
||||||
{pageNumbers.map((x, i) => (
|
)}
|
||||||
<button
|
{pageNumbers.map((x, i) => (
|
||||||
key={i}
|
<button
|
||||||
onClick={() => setCurrentPage(x)}
|
key={i}
|
||||||
disabled={x === "..."}
|
onClick={() => setCurrentPage(x)}
|
||||||
className={`${
|
disabled={x === "..."}
|
||||||
x === currentPage ? "op-btn-active" : ""
|
className={`${
|
||||||
} op-join-item op-btn op-btn-sm`}
|
x === currentPage ? "op-btn-active" : ""
|
||||||
>
|
} op-join-item op-btn op-btn-sm`}
|
||||||
{x}
|
>
|
||||||
</button>
|
{x}
|
||||||
))}
|
</button>
|
||||||
{userList.length > recordperPage && (
|
))}
|
||||||
<button
|
{userList.length > recordperPage && (
|
||||||
onClick={() => paginateFront()}
|
<button
|
||||||
className="op-join-item op-btn op-btn-sm"
|
onClick={() => paginateFront()}
|
||||||
>
|
className="op-join-item op-btn op-btn-sm"
|
||||||
{t("next")}
|
>
|
||||||
</button>
|
{t("next")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{isEnableSubscription && isSubscribe?.isSuperAdmin && (
|
||||||
|
<div>
|
||||||
|
{t("available-seats")}: {usersCount.allowed}/
|
||||||
|
{usersCount.totalAllowed}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{userList?.length <= 0 && (
|
{userList?.length <= 0 && (
|
||||||
@@ -397,16 +483,60 @@ const UserList = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<ModalUi
|
<ModalUi
|
||||||
title={t("add-user")}
|
isOpen={isModal.form}
|
||||||
isOpen={isModal}
|
title={formHeader}
|
||||||
handleClose={handleFormModal}
|
handleClose={() => handleModal("form")}
|
||||||
>
|
>
|
||||||
<AddUser
|
<AddUser
|
||||||
setIsAlert={setIsAlert}
|
setIsAlert={setIsAlert}
|
||||||
handleUserData={handleUserData}
|
handleUserData={handleUserData}
|
||||||
closePopup={handleFormModal}
|
handleBuyUsers={handleBuyUsers}
|
||||||
|
closePopup={() => handleModal("form")}
|
||||||
|
setFormHeader={setFormHeader}
|
||||||
/>
|
/>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
|
<ModalUi
|
||||||
|
isOpen={isModal.addseats}
|
||||||
|
title="Add Seats"
|
||||||
|
handleClose={() => handleModal("addseats")}
|
||||||
|
>
|
||||||
|
{isBuyLoader && (
|
||||||
|
<div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<form onSubmit={handleAddOnSubmit} className=" px-3 pb-6 pt-6">
|
||||||
|
<div className="mb-3 flex justify-between">
|
||||||
|
<label
|
||||||
|
htmlFor="quantity"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("Quantity-of-users")}
|
||||||
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
name="quantity"
|
||||||
|
value={amount.quantity}
|
||||||
|
onChange={(e) => handlePricePerUser(e)}
|
||||||
|
className="w-1/4 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3 flex justify-between">
|
||||||
|
<label className="block text-xs text-gray-700 font-semibold">
|
||||||
|
{t("Price")} (1 * {isSubscribe.priceperUser})
|
||||||
|
</label>
|
||||||
|
<div className="w-1/4 flex justify-center items-center text-sm">
|
||||||
|
USD {amount.price}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr className="text-base-content mb-3" />
|
||||||
|
<button className="op-btn op-btn-primary w-full">
|
||||||
|
{t("Proceed")}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</ModalUi>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
|
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
|
||||||
@@ -422,9 +552,9 @@ const UserList = () => {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!isSubscribe && isEnableSubscription && !isLoader && (
|
{isEnableSubscription && !validplan[isSubscribe.plan] && !isLoader && (
|
||||||
<div data-tut="apisubscribe">
|
<div data-tut="apisubscribe">
|
||||||
<SubscribeCard plan={"TEAMS"} price={"20"} />
|
<SubscribeCard plan="TEAMS" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import Tooltip from "../primitives/Tooltip";
|
|||||||
import { isEnableSubscription, isStaging } from "../constant/const";
|
import { isEnableSubscription, isStaging } from "../constant/const";
|
||||||
import {
|
import {
|
||||||
checkIsSubscribed,
|
checkIsSubscribed,
|
||||||
checkIsSubscribedTeam,
|
|
||||||
copytoData,
|
copytoData,
|
||||||
handleSendOTP,
|
handleSendOTP,
|
||||||
openInNewTab
|
openInNewTab
|
||||||
@@ -18,10 +17,13 @@ import {
|
|||||||
import Upgrade from "../primitives/Upgrade";
|
import Upgrade from "../primitives/Upgrade";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
|
import { validplan } from "../json/plansArr";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import SelectLanguage from "../components/pdf/SelectLanguage";
|
import SelectLanguage from "../components/pdf/SelectLanguage";
|
||||||
import { RWebShare } from "react-web-share";
|
import { RWebShare } from "react-web-share";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
|
import Tour from "reactour";
|
||||||
|
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
||||||
|
|
||||||
function UserProfile() {
|
function UserProfile() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -39,7 +41,7 @@ function UserProfile() {
|
|||||||
const [isDisableDocId, setIsDisableDocId] = useState(false);
|
const [isDisableDocId, setIsDisableDocId] = useState(false);
|
||||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||||
const [isUpgrade, setIsUpgrade] = useState(false);
|
const [isUpgrade, setIsUpgrade] = useState(false);
|
||||||
const [isAlert, setIsAlert] = useState({});
|
const [isAlert, setIsAlert] = useState({ type: "success", message: "" });
|
||||||
const [publicUserName, setPublicUserName] = useState(
|
const [publicUserName, setPublicUserName] = useState(
|
||||||
extendUser && extendUser?.[0]?.UserName
|
extendUser && extendUser?.[0]?.UserName
|
||||||
);
|
);
|
||||||
@@ -57,7 +59,10 @@ function UserProfile() {
|
|||||||
const [tagLine, setTagLine] = useState(
|
const [tagLine, setTagLine] = useState(
|
||||||
extendUser && extendUser?.[0]?.Tagline
|
extendUser && extendUser?.[0]?.Tagline
|
||||||
);
|
);
|
||||||
const [isTeam, setIsTeam] = useState(false);
|
const [isPlan, setIsPlan] = useState({ plan: "", isValid: false });
|
||||||
|
const [tourStatus, setTourStatus] = useState([]);
|
||||||
|
const [isProfileTour, setIsProfileTour] = useState(false);
|
||||||
|
const [isDontShow, setIsDontShow] = useState(false);
|
||||||
const getPublicUrl = isStaging
|
const getPublicUrl = isStaging
|
||||||
? `https://staging.opensign.me/${extendUser?.[0]?.UserName}`
|
? `https://staging.opensign.me/${extendUser?.[0]?.UserName}`
|
||||||
: `https://opensign.me/${extendUser?.[0]?.UserName}`;
|
: `https://opensign.me/${extendUser?.[0]?.UserName}`;
|
||||||
@@ -65,17 +70,27 @@ function UserProfile() {
|
|||||||
getUserDetail();
|
getUserDetail();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getUserDetail = async () => {
|
const getUserDetail = async () => {
|
||||||
setIsLoader(true);
|
setIsLoader(true);
|
||||||
const extClass = localStorage.getItem("Extand_Class");
|
const extClass = localStorage.getItem("Extand_Class");
|
||||||
const jsonSender = JSON.parse(extClass);
|
const jsonSender = JSON.parse(extClass);
|
||||||
|
const tourstatuss = jsonSender[0]?.TourStatus && jsonSender[0].TourStatus;
|
||||||
|
if (!isEnableSubscription) {
|
||||||
|
setIsProfileTour(true);
|
||||||
|
} else if (tourstatuss && tourstatuss.length > 0) {
|
||||||
|
setTourStatus(tourstatuss);
|
||||||
|
const checkTourRecipients = tourstatuss.filter(
|
||||||
|
(data) => data.profileTour
|
||||||
|
);
|
||||||
|
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
||||||
|
setIsProfileTour(checkTourRecipients[0]?.profileTour);
|
||||||
|
}
|
||||||
|
}
|
||||||
const HeaderDocId = jsonSender[0]?.HeaderDocId;
|
const HeaderDocId = jsonSender[0]?.HeaderDocId;
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const getIsSubscribe = await checkIsSubscribed();
|
const subscribe = await checkIsSubscribed();
|
||||||
const getIsTeam = await checkIsSubscribedTeam();
|
setIsSubscribe(subscribe.isValid);
|
||||||
setIsSubscribe(getIsSubscribe);
|
setIsPlan(subscribe);
|
||||||
setIsTeam(getIsTeam);
|
|
||||||
}
|
}
|
||||||
if (HeaderDocId) {
|
if (HeaderDocId) {
|
||||||
setIsDisableDocId(HeaderDocId);
|
setIsDisableDocId(HeaderDocId);
|
||||||
@@ -109,13 +124,8 @@ function UserProfile() {
|
|||||||
});
|
});
|
||||||
if (res) {
|
if (res) {
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
setIsAlert({
|
setIsAlert({ type: "danger", message: t("user-name-exist") });
|
||||||
type: "danger",
|
setTimeout(() => setIsAlert({}), 3000);
|
||||||
message: t("user-name-exist")
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsAlert({});
|
|
||||||
}, 3000);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -320,17 +330,80 @@ function UserProfile() {
|
|||||||
setJobTitle(extendUser?.[0]?.JobTitle);
|
setJobTitle(extendUser?.[0]?.JobTitle);
|
||||||
setIsDisableDocId(extendUser?.[0]?.HeaderDocId);
|
setIsDisableDocId(extendUser?.[0]?.HeaderDocId);
|
||||||
};
|
};
|
||||||
const copytoclipboard = () => {
|
const handlePaidRoute = () => {
|
||||||
copytoData(getPublicUrl);
|
navigate("/subscription");
|
||||||
setIsAlert({
|
|
||||||
type: "success",
|
|
||||||
message: t("copied")
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsAlert({});
|
|
||||||
}, 3000);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const copytoclipboard = () => {
|
||||||
|
copytoData(getPublicUrl);
|
||||||
|
setIsAlert({ type: "success", message: t("copied") });
|
||||||
|
setTimeout(() => setIsAlert({}), 3000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const tourConfig = [
|
||||||
|
{
|
||||||
|
content: () => (
|
||||||
|
<TourContentWithBtn
|
||||||
|
message={t("tour-mssg.public-template")}
|
||||||
|
isChecked={handleDontShow}
|
||||||
|
video="https://www.youtube.com/embed/_wB4UA7Jz5Q?si=I40CI3nVUWQzf42Y"
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
position: "top",
|
||||||
|
style: { fontSize: "13px" }
|
||||||
|
}
|
||||||
|
];
|
||||||
|
//function for update TourStatus
|
||||||
|
const closeTour = async () => {
|
||||||
|
try {
|
||||||
|
setIsProfileTour(true);
|
||||||
|
if (isDontShow) {
|
||||||
|
let updatedTourStatus = [];
|
||||||
|
if (tourStatus.length > 0) {
|
||||||
|
updatedTourStatus = [...tourStatus];
|
||||||
|
const profileIndex = tourStatus.findIndex(
|
||||||
|
(obj) => obj["profileTour"] === false || obj["profileTour"] === true
|
||||||
|
);
|
||||||
|
if (profileIndex !== -1) {
|
||||||
|
updatedTourStatus[profileIndex] = { profileTour: true };
|
||||||
|
} else {
|
||||||
|
updatedTourStatus.push({ profileTour: true });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updatedTourStatus = [{ profileTour: true }];
|
||||||
|
}
|
||||||
|
|
||||||
|
await axios.put(
|
||||||
|
`${localStorage.getItem("baseUrl")}classes/contracts_Users/${
|
||||||
|
extendUser?.[0]?.objectId
|
||||||
|
}`,
|
||||||
|
{
|
||||||
|
TourStatus: updatedTourStatus
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const res = await Parse.Cloud.run("getUserDetails");
|
||||||
|
const json = JSON.parse(JSON.stringify([res]));
|
||||||
|
const extRes = JSON.stringify(json);
|
||||||
|
localStorage.setItem("Extand_Class", extRes);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("axois err ", err);
|
||||||
|
alert(t("something-went-wrong-mssg"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleDontShow = (isChecked) => {
|
||||||
|
setIsDontShow(isChecked);
|
||||||
|
};
|
||||||
|
const handleOnlickHelp = () => {
|
||||||
|
setIsProfileTour(false);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Title title={"Profile"} />
|
<Title title={"Profile"} />
|
||||||
@@ -340,12 +413,19 @@ function UserProfile() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex justify-center items-center w-full relative">
|
<div className="flex justify-center items-center w-full relative">
|
||||||
{isAlert && (
|
{isAlert.message && (
|
||||||
<Alert className="z-[1000] fixed top-[10%]" type={isAlert.type}>
|
<Alert className="z-[1000] fixed top-[10%]" type={isAlert.type}>
|
||||||
{isAlert.message}
|
{isAlert.message}
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
<Tour
|
||||||
|
className="md:!min-w-[650px]"
|
||||||
|
onRequestClose={closeTour}
|
||||||
|
steps={tourConfig}
|
||||||
|
isOpen={!isProfileTour}
|
||||||
|
rounded={5}
|
||||||
|
closeWithMask={false}
|
||||||
|
/>
|
||||||
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box w-[450px]">
|
<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="flex flex-col justify-center items-center my-4">
|
||||||
<div className="w-[200px] h-[200px] overflow-hidden rounded-full">
|
<div className="w-[200px] h-[200px] overflow-hidden rounded-full">
|
||||||
@@ -382,17 +462,6 @@ function UserProfile() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul className="w-full flex flex-col p-2 text-sm">
|
<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.5" : "py-2"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<span className="font-semibold">{t("language")}:</span>{" "}
|
|
||||||
<SelectLanguage
|
|
||||||
isProfile={true}
|
|
||||||
updateExtUser={updateExtUser}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
<li
|
<li
|
||||||
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
|
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
|
||||||
editmode ? "py-1.5" : "py-2"
|
editmode ? "py-1.5" : "py-2"
|
||||||
@@ -403,7 +472,7 @@ function UserProfile() {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={name}
|
value={name}
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-sm"
|
className="op-input op-input-bordered op-input-sm w-[180px] focus:outline-none hover:border-base-content text-sm"
|
||||||
onChange={(e) => SetName(e.target.value)}
|
onChange={(e) => SetName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@@ -419,7 +488,7 @@ function UserProfile() {
|
|||||||
{editmode ? (
|
{editmode ? (
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-sm"
|
className="op-input op-input-bordered op-input-sm w-[180px] focus:outline-none hover:border-base-content text-sm"
|
||||||
onChange={(e) => SetPhone(e.target.value)}
|
onChange={(e) => SetPhone(e.target.value)}
|
||||||
value={Phone}
|
value={Phone}
|
||||||
/>
|
/>
|
||||||
@@ -441,7 +510,7 @@ function UserProfile() {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={company}
|
value={company}
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-sm"
|
className="op-input op-input-bordered op-input-sm w-[180px] focus:outline-none hover:border-base-content text-sm"
|
||||||
onChange={(e) => setCompany(e.target.value)}
|
onChange={(e) => setCompany(e.target.value)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@@ -458,7 +527,7 @@ function UserProfile() {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={jobTitle}
|
value={jobTitle}
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-sm"
|
className="op-input op-input-bordered op-input-sm w-[180px] focus:outline-none hover:border-base-content text-sm"
|
||||||
onChange={(e) => setJobTitle(e.target.value)}
|
onChange={(e) => setJobTitle(e.target.value)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@@ -486,40 +555,30 @@ function UserProfile() {
|
|||||||
</li>
|
</li>
|
||||||
{isEnableSubscription && (
|
{isEnableSubscription && (
|
||||||
<>
|
<>
|
||||||
<li className="flex md:flex-row flex-col md:justify-between md:items-center border-t-[1px] border-gray-300 py-2 break-all">
|
<li className="flex flex-row justify-between md:items-center border-t-[1px] border-gray-300 py-2 break-all">
|
||||||
<span className="font-semibold flex gap-1">
|
<span className="font-semibold flex gap-1">
|
||||||
{t("public-profile")} :{" "}
|
{t("public-profile")} :{" "}
|
||||||
<Tooltip
|
<Tooltip handleOnlickHelp={handleOnlickHelp} />
|
||||||
maxWidth="max-w-[250px]"
|
|
||||||
message={t("public-profile-help")}
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
<div className="flex md:flex-row flex-col md:items-center">
|
<div className="flex flex-row items-center gap-1">
|
||||||
{editmode || !extendUser?.[0]?.UserName ? (
|
{editmode || !extendUser?.[0]?.UserName ? (
|
||||||
<input
|
<>
|
||||||
maxLength={40}
|
<input
|
||||||
style={{
|
maxLength={40}
|
||||||
border:
|
onChange={handleOnchangeUserName}
|
||||||
!isSubscribe &&
|
value={publicUserName}
|
||||||
publicUserName?.length > 0 &&
|
disabled={!editmode}
|
||||||
publicUserName?.length < 9 &&
|
placeholder="enter user name"
|
||||||
"solid red"
|
className="op-input op-input-bordered op-input-sm w-[180px] focus:outline-none hover:border-base-content text-sm"
|
||||||
}}
|
/>
|
||||||
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"
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-row gap-1 items-center justify-between md:justify-start">
|
<div className="flex flex-row gap-1 items-center justify-between md:justify-start">
|
||||||
<span
|
<span
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
onClick={() => {
|
onClick={() => openInNewTab(getPublicUrl)}
|
||||||
openInNewTab(getPublicUrl);
|
className="cursor-pointer underline hover:text-blue-800 w-[110px] md:w-[150px] whitespace-nowrap overflow-hidden text-ellipsis"
|
||||||
}}
|
|
||||||
className="cursor-pointer underline hover:text-blue-800 w-[200px] md:w-[150px] whitespace-nowrap overflow-hidden text-ellipsis"
|
|
||||||
>
|
>
|
||||||
{isStaging
|
{isStaging
|
||||||
? `staging.opensign.me/${extendUser?.[0]?.UserName}`
|
? `staging.opensign.me/${extendUser?.[0]?.UserName}`
|
||||||
@@ -527,10 +586,7 @@ function UserProfile() {
|
|||||||
</span>
|
</span>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<RWebShare
|
<RWebShare
|
||||||
data={{
|
data={{ url: getPublicUrl, title: "Sign url" }}
|
||||||
url: getPublicUrl,
|
|
||||||
title: "Sign url"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<button className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm ">
|
<button className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm ">
|
||||||
<i className="fa-light fa-share-from-square"></i>{" "}
|
<i className="fa-light fa-share-from-square"></i>{" "}
|
||||||
@@ -540,37 +596,30 @@ function UserProfile() {
|
|||||||
className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm"
|
className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm"
|
||||||
onClick={() => copytoclipboard()}
|
onClick={() => copytoclipboard()}
|
||||||
>
|
>
|
||||||
<i className="fa-light fa-link"></i>{" "}
|
<i className="fa-light fa-copy" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex md:flex-row flex-col md:justify-between md:items-center border-t-[1px] border-gray-300 py-2 break-all">
|
<li className="flex flex-row justify-between items-center border-t-[1px] border-gray-300 py-2 break-all">
|
||||||
<span className="font-semibold flex gap-1">
|
<span className="font-semibold flex gap-1">
|
||||||
{t("tagline")} :{" "}
|
{t("tagline")} :{" "}
|
||||||
<Tooltip
|
<Tooltip handleOnlickHelp={handleOnlickHelp} />
|
||||||
maxWidth="max-w-[250px]"
|
|
||||||
message={t("tagline-help")}
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
<div className="flex md:flex-row flex-col md:items-center">
|
<div className="flex flex-row md:items-center gap-1">
|
||||||
{editmode ? (
|
{editmode || !extendUser?.[0]?.Tagline ? (
|
||||||
<input
|
<input
|
||||||
|
maxLength={40}
|
||||||
onChange={handleOnchangeTagLine}
|
onChange={handleOnchangeTagLine}
|
||||||
value={tagLine}
|
value={tagLine}
|
||||||
disabled={!editmode}
|
disabled={!editmode}
|
||||||
placeholder="enter tagline"
|
placeholder="enter tagline"
|
||||||
className="op-input op-input-bordered focus:outline-none hover:border-base-content op-input-xs"
|
className="op-input op-input-bordered op-input-sm w-[180px] focus:outline-none hover:border-base-content text-sm"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<input
|
<span>{extendUser?.[0]?.Tagline}</span>
|
||||||
value={extendUser?.[0]?.Tagline}
|
|
||||||
disabled
|
|
||||||
placeholder="enter tagline"
|
|
||||||
className="op-input op-input-bordered op-input-xs"
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@@ -581,7 +630,9 @@ function UserProfile() {
|
|||||||
<div className="flex justify-between items-center py-2">
|
<div className="flex justify-between items-center py-2">
|
||||||
<span
|
<span
|
||||||
className={
|
className={
|
||||||
isTeam ? "font-semibold" : "font-semibold text-gray-300"
|
validplan[isPlan.plan]
|
||||||
|
? "font-semibold"
|
||||||
|
: "font-semibold text-gray-300"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{t("disable-documentId")} :{" "}
|
{t("disable-documentId")} :{" "}
|
||||||
@@ -590,17 +641,21 @@ function UserProfile() {
|
|||||||
"https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid"
|
"https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{!isTeam && isEnableSubscription && <Upgrade />}
|
{!validplan[isPlan.plan] && isEnableSubscription && (
|
||||||
|
<Upgrade />
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
<label
|
<label
|
||||||
className={`${
|
className={`${
|
||||||
isTeam
|
validplan[isPlan.plan]
|
||||||
? `${editmode ? "cursor-pointer" : ""}`
|
? `${editmode ? "cursor-pointer" : ""}`
|
||||||
: "pointer-events-none opacity-50"
|
: "pointer-events-none opacity-50"
|
||||||
} relative block items-center mb-0`}
|
} relative block items-center mb-0`}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
disabled={isTeam ? false : true}
|
disabled={
|
||||||
|
validplan[isPlan.plan] && editmode ? false : true
|
||||||
|
}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
|
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
|
||||||
checked={isDisableDocId}
|
checked={isDisableDocId}
|
||||||
@@ -610,6 +665,17 @@ function UserProfile() {
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
|
<li
|
||||||
|
className={`flex justify-between items-center border-b-[1px] border-gray-300 break-all ${
|
||||||
|
editmode ? "py-1.5" : "py-2"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span className="font-semibold">{t("language")}:</span>{" "}
|
||||||
|
<SelectLanguage
|
||||||
|
isProfile={true}
|
||||||
|
updateExtUser={updateExtUser}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
@@ -620,6 +686,7 @@ function UserProfile() {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (
|
if (
|
||||||
|
editmode &&
|
||||||
!isSubscribe &&
|
!isSubscribe &&
|
||||||
publicUserName?.length > 0 &&
|
publicUserName?.length > 0 &&
|
||||||
publicUserName?.length < 9
|
publicUserName?.length < 9
|
||||||
@@ -689,6 +756,7 @@ function UserProfile() {
|
|||||||
)}
|
)}
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isUpgrade && (
|
{isUpgrade && (
|
||||||
<div className="op-modal op-modal-open">
|
<div className="op-modal op-modal-open">
|
||||||
<div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative">
|
<div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative">
|
||||||
@@ -708,7 +776,7 @@ function UserProfile() {
|
|||||||
<p>{t("user-name-limit-char")}</p>
|
<p>{t("user-name-limit-char")}</p>
|
||||||
<div className="op-card-actions justify-end">
|
<div className="op-card-actions justify-end">
|
||||||
<button
|
<button
|
||||||
onClick={() => navigate("/subscription")}
|
onClick={() => handlePaidRoute()}
|
||||||
className="op-btn op-btn-accent"
|
className="op-btn op-btn-accent"
|
||||||
>
|
>
|
||||||
{t("upgrade-now")}
|
{t("upgrade-now")}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ function Webhook() {
|
|||||||
const [webhook, setWebhook] = useState();
|
const [webhook, setWebhook] = useState();
|
||||||
const [isLoader, setIsLoader] = useState(true);
|
const [isLoader, setIsLoader] = useState(true);
|
||||||
const [isModal, setIsModal] = useState(false);
|
const [isModal, setIsModal] = useState(false);
|
||||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
const [isSubscribe, setIsSubscribe] = useState({ plan: "", isValid: true });
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||||
const [isTour, setIsTour] = useState(false);
|
const [isTour, setIsTour] = useState(false);
|
||||||
@@ -35,8 +35,8 @@ function Webhook() {
|
|||||||
];
|
];
|
||||||
const fetchWebhook = async () => {
|
const fetchWebhook = async () => {
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const getIsSubscribe = await checkIsSubscribed();
|
const subscribe = await checkIsSubscribed();
|
||||||
setIsSubscribe(getIsSubscribe);
|
setIsSubscribe(subscribe);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const extRes = await Parse.Cloud.run("getUserDetails");
|
const extRes = await Parse.Cloud.run("getUserDetails");
|
||||||
@@ -89,7 +89,7 @@ function Webhook() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleModal = () => {
|
const handleModal = () => {
|
||||||
if (!isSubscribe && isEnableSubscription) {
|
if (!isSubscribe?.isValid && isEnableSubscription) {
|
||||||
setIsTour(true);
|
setIsTour(true);
|
||||||
} else {
|
} else {
|
||||||
setIsModal(!isModal);
|
setIsModal(!isModal);
|
||||||
@@ -145,7 +145,7 @@ function Webhook() {
|
|||||||
</div>
|
</div>
|
||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen={isModal}
|
isOpen={isModal}
|
||||||
title={"Regenerate Token"}
|
title={t("add-webhook")}
|
||||||
handleClose={handleModal}
|
handleClose={handleModal}
|
||||||
>
|
>
|
||||||
{error && <Alert type="danger">{error}</Alert>}
|
{error && <Alert type="danger">{error}</Alert>}
|
||||||
@@ -177,7 +177,7 @@ function Webhook() {
|
|||||||
</div>
|
</div>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
</div>
|
</div>
|
||||||
{!isSubscribe && isEnableSubscription && (
|
{isEnableSubscription && !isSubscribe?.isValid && (
|
||||||
<div data-tut="webhooksubscribe">
|
<div data-tut="webhooksubscribe">
|
||||||
<SubscribeCard />
|
<SubscribeCard />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -46,109 +46,125 @@ const AddContact = (props) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIsLoader(true);
|
setIsLoader(true);
|
||||||
try {
|
if (localStorage.getItem("TenantId")) {
|
||||||
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");
|
|
||||||
|
|
||||||
if (localStorage.getItem("TenantId")) {
|
|
||||||
contactQuery.set("TenantId", {
|
|
||||||
__type: "Pointer",
|
|
||||||
className: "partners_Tenant",
|
|
||||||
objectId: localStorage.getItem("TenantId")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const _users = Parse.Object.extend("User");
|
const user = Parse.User.current();
|
||||||
const _user = new _users();
|
const query = new Parse.Query("contracts_Contactbook");
|
||||||
_user.set("name", name);
|
query.equalTo("CreatedBy", user);
|
||||||
_user.set("username", email);
|
query.notEqualTo("IsDeleted", true);
|
||||||
_user.set("email", email);
|
query.equalTo("Email", email);
|
||||||
_user.set("password", email);
|
const res = await query.first();
|
||||||
if (phone) {
|
if (!res) {
|
||||||
_user.set("phone", phone);
|
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");
|
||||||
|
|
||||||
const user = await _user.save();
|
if (localStorage.getItem("TenantId")) {
|
||||||
if (user) {
|
contactQuery.set("TenantId", {
|
||||||
const currentUser = Parse.User.current();
|
__type: "Pointer",
|
||||||
contactQuery.set(
|
className: "partners_Tenant",
|
||||||
"CreatedBy",
|
objectId: localStorage.getItem("TenantId")
|
||||||
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));
|
|
||||||
props.details(parseData);
|
|
||||||
if (props.closePopup) {
|
|
||||||
props.closePopup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 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));
|
||||||
|
props.details(parseData);
|
||||||
|
if (props.closePopup) {
|
||||||
|
props.closePopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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(parseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.closePopup) {
|
||||||
|
props.closePopup();
|
||||||
|
}
|
||||||
|
setIsLoader(false);
|
||||||
|
// Reset the form fields
|
||||||
|
setAddYourself(false);
|
||||||
|
setName("");
|
||||||
|
setPhone("");
|
||||||
|
setEmail("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(t("add-signer-alert"));
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
// Reset the form fields
|
|
||||||
setAddYourself(false);
|
|
||||||
setName("");
|
|
||||||
setPhone("");
|
|
||||||
setEmail("");
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err ", err);
|
// console.log("err", err);
|
||||||
if (err.code === 202) {
|
setIsLoader(false);
|
||||||
const params = { email: email };
|
alert(t("something-went-wrong-mssg"));
|
||||||
const userRes = await Parse.Cloud.run("getUserId", params);
|
|
||||||
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(parseData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.closePopup) {
|
|
||||||
props.closePopup();
|
|
||||||
}
|
|
||||||
setIsLoader(false);
|
|
||||||
// Reset the form fields
|
|
||||||
setAddYourself(false);
|
|
||||||
setName("");
|
|
||||||
setPhone("");
|
|
||||||
setEmail("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} else {
|
||||||
// console.log("err", err);
|
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
alert(t("something-went-wrong-mssg"));
|
alert(t("something-went-wrong-mssg"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
function Agreement(props) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [isChecked, setIsChecked] = useState(false);
|
||||||
|
return (
|
||||||
|
<div className="flex justify-between mx-2 mb-2 pt-1" data-tut="IsAgree">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<input
|
||||||
|
className="mr-3 op-checkbox op-checkbox-m"
|
||||||
|
type="checkbox"
|
||||||
|
value={isChecked}
|
||||||
|
onChange={(e) => {
|
||||||
|
setIsChecked(e.target.checked);
|
||||||
|
if (e.target.checked) {
|
||||||
|
props.setIsAgreeTour(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
I confirm that I have read and understood the 'Electronic Record
|
||||||
|
and Signature Disclosure' and consent to use electronic records and
|
||||||
|
signatures.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex">
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
if (isChecked) {
|
||||||
|
props.setIsAgreeTour(false);
|
||||||
|
props.setIsAgree(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="op-btn op-btn-primary op-btn-sm"
|
||||||
|
>
|
||||||
|
Agree & Continue
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Agreement;
|
||||||
@@ -25,8 +25,8 @@ const Alert = ({ children, type, className }) => {
|
|||||||
: "z-[1000] fixed top-20 left-1/2 transform -translate-x-1/2 text-sm"
|
: "z-[1000] fixed top-20 left-1/2 transform -translate-x-1/2 text-sm"
|
||||||
} `}
|
} `}
|
||||||
>
|
>
|
||||||
<div className={`op-alert ${textcolor} flex items-center`}>
|
<div className={`op-alert ${textcolor} flex justify-center`}>
|
||||||
<span>{children}</span>
|
<span className="px-1">{children}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import ModalUi from "./ModalUi";
|
||||||
|
import {
|
||||||
|
getSignedUrl,
|
||||||
|
handleDownloadCertificate,
|
||||||
|
handleDownloadPdf,
|
||||||
|
sanitizeFileName
|
||||||
|
} from "../constant/Utils";
|
||||||
|
import Loader from "./Loader";
|
||||||
|
import JSZip from "jszip";
|
||||||
|
import { saveAs } from "file-saver";
|
||||||
|
|
||||||
|
function DownloadPdfZip(props) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [selectType, setSelectType] = useState(1);
|
||||||
|
const [isDownloading, setIsDownloading] = useState(false);
|
||||||
|
const downloadType = [
|
||||||
|
{ id: 1, label: t("download-pdf") },
|
||||||
|
{ id: 2, label: t("pdf-certificate") }
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleDownload = async () => {
|
||||||
|
if (selectType === 1) {
|
||||||
|
await handleDownloadPdf(props.pdfDetails, setIsDownloading);
|
||||||
|
setSelectType(1);
|
||||||
|
props.setIsDownloadModal(false);
|
||||||
|
} else if (selectType === 2) {
|
||||||
|
setIsDownloading("pdf");
|
||||||
|
const zip = new JSZip();
|
||||||
|
const pdfDetails = props.pdfDetails;
|
||||||
|
const pdfName = pdfDetails?.[0]?.Name || "Document";
|
||||||
|
const pdfUrl = pdfDetails?.[0]?.SignedUrl || "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Fetch the first PDF (Signed Document)
|
||||||
|
const docId =
|
||||||
|
props.isDocId && !pdfDetails?.[0]?.IsEnableOTP
|
||||||
|
? pdfDetails?.[0]?.objectId
|
||||||
|
: "";
|
||||||
|
const signedUrl = await getSignedUrl(pdfUrl, docId);
|
||||||
|
const pdf1Response = await fetch(signedUrl);
|
||||||
|
if (!pdf1Response.ok) {
|
||||||
|
throw new Error(`Failed to fetch PDF: ${signedUrl}`);
|
||||||
|
}
|
||||||
|
const pdf1Blob = await pdf1Response.blob();
|
||||||
|
const isZip = true;
|
||||||
|
// Fetch the Certificate (or generate its URL dynamically)
|
||||||
|
const certificateUrl = await handleDownloadCertificate(
|
||||||
|
pdfDetails,
|
||||||
|
setIsDownloading,
|
||||||
|
isZip
|
||||||
|
);
|
||||||
|
const pdf2Response = await fetch(certificateUrl);
|
||||||
|
if (!pdf2Response.ok) {
|
||||||
|
throw new Error(`Failed to fetch certificate PDF: ${certificateUrl}`);
|
||||||
|
}
|
||||||
|
const pdf2Blob = await pdf2Response.blob();
|
||||||
|
// Add files to ZIP
|
||||||
|
zip.file(
|
||||||
|
`${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`,
|
||||||
|
pdf1Blob
|
||||||
|
);
|
||||||
|
zip.file("Certificate_signed_by_OpenSign™.pdf", pdf2Blob);
|
||||||
|
|
||||||
|
// Generate the ZIP and trigger download
|
||||||
|
const zipBlob = await zip.generateAsync({ type: "blob" });
|
||||||
|
saveAs(
|
||||||
|
zipBlob,
|
||||||
|
`${sanitizeFileName(pdfName)}_signed_by_OpenSign™.zip`
|
||||||
|
);
|
||||||
|
setSelectType(1);
|
||||||
|
props.setIsDownloadModal(false);
|
||||||
|
setIsDownloading("");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error creating ZIP file:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<ModalUi
|
||||||
|
isOpen={props.isDownloadModal}
|
||||||
|
title={t("download-files")}
|
||||||
|
handleClose={() => props.setIsDownloadModal(false)}
|
||||||
|
>
|
||||||
|
<div className="p-[20px] h-full">
|
||||||
|
{downloadType.map((data, ind) => {
|
||||||
|
return (
|
||||||
|
<label
|
||||||
|
key={ind}
|
||||||
|
className="flex items-center gap-1 mb-2 cursor-pointer"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
className="mr-[8px] op-radio op-radio-xs"
|
||||||
|
type="radio"
|
||||||
|
value={data.id}
|
||||||
|
onChange={() => setSelectType(data.id)}
|
||||||
|
checked={selectType === data.id}
|
||||||
|
/>
|
||||||
|
{data.label}
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
|
||||||
|
<button
|
||||||
|
onClick={() => handleDownload()}
|
||||||
|
type="submit"
|
||||||
|
className="op-btn op-btn-primary"
|
||||||
|
>
|
||||||
|
{t("download")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{isDownloading === "pdf" && (
|
||||||
|
<div className="fixed z-[200] inset-0 flex justify-center items-center bg-black bg-opacity-30">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<ModalUi
|
||||||
|
isOpen={isDownloading === "certificate"}
|
||||||
|
title={
|
||||||
|
isDownloading === "certificate"
|
||||||
|
? t("generating-certificate")
|
||||||
|
: t("pdf-download")
|
||||||
|
}
|
||||||
|
handleClose={() => setIsDownloading("")}
|
||||||
|
>
|
||||||
|
<div className="p-3 md:p-5 text-[13px] md:text-base text-center text-base-content">
|
||||||
|
{isDownloading === "certificate"}{" "}
|
||||||
|
<p>{t("generate-certificate-alert")}</p>
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
|
</ModalUi>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DownloadPdfZip;
|
||||||
@@ -11,9 +11,10 @@ import { RWebShare } from "react-web-share";
|
|||||||
import Tour from "reactour";
|
import Tour from "reactour";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import {
|
import {
|
||||||
checkIsSubscribedTeam,
|
checkIsSubscribed,
|
||||||
copytoData,
|
copytoData,
|
||||||
fetchUrl,
|
fetchUrl,
|
||||||
|
getSignedUrl,
|
||||||
replaceMailVaribles
|
replaceMailVaribles
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import Confetti from "react-confetti";
|
import Confetti from "react-confetti";
|
||||||
@@ -27,8 +28,11 @@ import BulkSendUi from "../components/BulkSendUi";
|
|||||||
import Loader from "./Loader";
|
import Loader from "./Loader";
|
||||||
import Select from "react-select";
|
import Select from "react-select";
|
||||||
import SubscribeCard from "./SubscribeCard";
|
import SubscribeCard from "./SubscribeCard";
|
||||||
|
import { validplan } from "../json/plansArr";
|
||||||
import { serverUrl_fn } from "../constant/appinfo";
|
import { serverUrl_fn } from "../constant/appinfo";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import DownloadPdfZip from "./DownloadPdfZip";
|
||||||
|
import EmbedTab from "../components/pdf/EmbedTab";
|
||||||
|
|
||||||
const ReportTable = (props) => {
|
const ReportTable = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -68,20 +72,15 @@ const ReportTable = (props) => {
|
|||||||
const [publicUserName, setIsPublicUserName] = useState("");
|
const [publicUserName, setIsPublicUserName] = useState("");
|
||||||
const [isViewShare, setIsViewShare] = useState({});
|
const [isViewShare, setIsViewShare] = useState({});
|
||||||
const [isSubscribe, setIsSubscribe] = useState(true);
|
const [isSubscribe, setIsSubscribe] = useState(true);
|
||||||
|
const [isModal, setIsModal] = useState({});
|
||||||
const [reason, setReason] = useState("");
|
const [reason, setReason] = useState("");
|
||||||
|
const [isDownloadModal, setIsDownloadModal] = useState(false);
|
||||||
|
const [isEmbed, setIsEmbed] = useState(false);
|
||||||
const Extand_Class = localStorage.getItem("Extand_Class");
|
const Extand_Class = localStorage.getItem("Extand_Class");
|
||||||
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
||||||
const startIndex = (currentPage - 1) * props.docPerPage;
|
const startIndex = (currentPage - 1) * props.docPerPage;
|
||||||
const { isMoreDocs, setIsNextRecord } = props;
|
const { isMoreDocs, setIsNextRecord } = props;
|
||||||
// For loop is used to calculate page numbers visible below table
|
|
||||||
// Initialize pageNumbers using useMemo to avoid unnecessary re-creation
|
|
||||||
// const pageNumbers = useMemo(() => {
|
|
||||||
// const calculatedPageNumbers = [];
|
|
||||||
// for (let i = 1; i <= Math.ceil(props.List.length / props.docPerPage); i++) {
|
|
||||||
// calculatedPageNumbers.push(i);
|
|
||||||
// }
|
|
||||||
// return calculatedPageNumbers;
|
|
||||||
// }, [props.List, props.docPerPage]);
|
|
||||||
const getPaginationRange = () => {
|
const getPaginationRange = () => {
|
||||||
const totalPageNumbers = 7; // Adjust this value to show more/less page numbers
|
const totalPageNumbers = 7; // Adjust this value to show more/less page numbers
|
||||||
const pages = [];
|
const pages = [];
|
||||||
@@ -273,7 +272,8 @@ const ReportTable = (props) => {
|
|||||||
Signers: signers,
|
Signers: signers,
|
||||||
SendinOrder: Doc?.SendinOrder || false,
|
SendinOrder: Doc?.SendinOrder || false,
|
||||||
AutomaticReminders: Doc?.AutomaticReminders || false,
|
AutomaticReminders: Doc?.AutomaticReminders || false,
|
||||||
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5
|
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5,
|
||||||
|
IsEnableOTP: Doc?.IsEnableOTP || false
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const res = await axios.post(
|
const res = await axios.post(
|
||||||
@@ -355,10 +355,10 @@ const ReportTable = (props) => {
|
|||||||
handleBulkSend(item);
|
handleBulkSend(item);
|
||||||
} else if (act.action === "sharewith") {
|
} else if (act.action === "sharewith") {
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const getIsSubscribe = await checkIsSubscribedTeam();
|
const subscribe = await checkIsSubscribed();
|
||||||
setIsSubscribe(getIsSubscribe);
|
setIsSubscribe(subscribe);
|
||||||
} else {
|
} else {
|
||||||
setIsSubscribe(true);
|
setIsSubscribe({ plan: "teams-yearly", isValid: true });
|
||||||
}
|
}
|
||||||
if (item?.SharedWith && item?.SharedWith.length > 0) {
|
if (item?.SharedWith && item?.SharedWith.length > 0) {
|
||||||
// below code is used to get existing sharewith teams and formated them as per react-select
|
// below code is used to get existing sharewith teams and formated them as per react-select
|
||||||
@@ -369,6 +369,10 @@ const ReportTable = (props) => {
|
|||||||
setSelectedTeam(formatedList);
|
setSelectedTeam(formatedList);
|
||||||
}
|
}
|
||||||
setIsShareWith({ [item.objectId]: true });
|
setIsShareWith({ [item.objectId]: true });
|
||||||
|
} else if (act.action === "Embed") {
|
||||||
|
handleEmbedFunction(item);
|
||||||
|
} else if (act.action === "CopyTemplateId") {
|
||||||
|
copyTemplateId(item.objectId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Get current list
|
// Get current list
|
||||||
@@ -377,8 +381,18 @@ const ReportTable = (props) => {
|
|||||||
const currentList = props.List?.slice(indexOfFirstDoc, indexOfLastDoc);
|
const currentList = props.List?.slice(indexOfFirstDoc, indexOfLastDoc);
|
||||||
|
|
||||||
// Change page
|
// Change page
|
||||||
const paginateFront = () => setCurrentPage(currentPage + 1);
|
const paginateFront = () => {
|
||||||
const paginateBack = () => setCurrentPage(currentPage - 1);
|
const lastValue = pageNumbers?.[pageNumbers?.length - 1];
|
||||||
|
if (currentPage < lastValue) {
|
||||||
|
setCurrentPage(currentPage + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const paginateBack = () => {
|
||||||
|
if (startIndex > 0) {
|
||||||
|
setCurrentPage(currentPage - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleContactFormModal = () => {
|
const handleContactFormModal = () => {
|
||||||
setIsContactform(!isContactform);
|
setIsContactform(!isContactform);
|
||||||
@@ -396,7 +410,7 @@ const ReportTable = (props) => {
|
|||||||
Templates: "contracts_Template"
|
Templates: "contracts_Template"
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const serverUrl = serverUrl_fn()
|
const serverUrl = serverUrl_fn();
|
||||||
const cls = clsObj[props.ReportName] || "contracts_Document";
|
const cls = clsObj[props.ReportName] || "contracts_Document";
|
||||||
const url = serverUrl + `/classes/${cls}/`;
|
const url = serverUrl + `/classes/${cls}/`;
|
||||||
const body =
|
const body =
|
||||||
@@ -448,7 +462,6 @@ const ReportTable = (props) => {
|
|||||||
}
|
}
|
||||||
setReason("");
|
setReason("");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleShare = (item) => {
|
const handleShare = (item) => {
|
||||||
setActLoader({ [item.objectId]: true });
|
setActLoader({ [item.objectId]: true });
|
||||||
const host = window.location.origin;
|
const host = window.location.origin;
|
||||||
@@ -479,9 +492,21 @@ const ReportTable = (props) => {
|
|||||||
};
|
};
|
||||||
//function to handle revoke/decline docment
|
//function to handle revoke/decline docment
|
||||||
const handleRevoke = async (item) => {
|
const handleRevoke = async (item) => {
|
||||||
|
const senderUser = localStorage.getItem(
|
||||||
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
|
);
|
||||||
|
const jsonSender = JSON.parse(senderUser);
|
||||||
setIsRevoke({});
|
setIsRevoke({});
|
||||||
setActLoader({ [`${item.objectId}`]: true });
|
setActLoader({ [`${item.objectId}`]: true });
|
||||||
const data = { IsDeclined: true, DeclineReason: reason };
|
const data = {
|
||||||
|
IsDeclined: true,
|
||||||
|
DeclineReason: reason,
|
||||||
|
DeclineBy: {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: "_User",
|
||||||
|
objectId: jsonSender?.objectId
|
||||||
|
}
|
||||||
|
};
|
||||||
await axios
|
await axios
|
||||||
.put(
|
.put(
|
||||||
`${localStorage.getItem("baseUrl")}classes/contracts_Document/${
|
`${localStorage.getItem("baseUrl")}classes/contracts_Document/${
|
||||||
@@ -499,7 +524,6 @@ const ReportTable = (props) => {
|
|||||||
.then(async (result) => {
|
.then(async (result) => {
|
||||||
const res = result.data;
|
const res = result.data;
|
||||||
if (res) {
|
if (res) {
|
||||||
setReason("");
|
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
setIsAlert(true);
|
setIsAlert(true);
|
||||||
setAlertMsg({
|
setAlertMsg({
|
||||||
@@ -511,7 +535,43 @@ const ReportTable = (props) => {
|
|||||||
(x) => x.objectId !== item.objectId
|
(x) => x.objectId !== item.objectId
|
||||||
);
|
);
|
||||||
props.setList(upldatedList);
|
props.setList(upldatedList);
|
||||||
|
const params = {
|
||||||
|
event: "declined",
|
||||||
|
body: {
|
||||||
|
objectId: item.objectId,
|
||||||
|
file: item?.SignedUrl || item?.URL,
|
||||||
|
name: item?.Name,
|
||||||
|
note: item?.Note || "",
|
||||||
|
description: item?.Description || "",
|
||||||
|
signers: item?.Signers?.map((x) => ({
|
||||||
|
name: x?.Name,
|
||||||
|
email: x?.Email,
|
||||||
|
phone: x?.Phone
|
||||||
|
})),
|
||||||
|
declinedBy: jsonSender?.email,
|
||||||
|
declinedReason: reason,
|
||||||
|
declinedAt: new Date(),
|
||||||
|
createdAt: item?.createdAt
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await axios.post(
|
||||||
|
`${localStorage.getItem("baseUrl")}functions/callwebhook`,
|
||||||
|
params,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
|
sessiontoken: localStorage.getItem("accesstoken")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err ", err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
setReason("");
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log("err", err);
|
console.log("err", err);
|
||||||
@@ -596,10 +656,15 @@ const ReportTable = (props) => {
|
|||||||
setActLoader({ [`${item.objectId}`]: true });
|
setActLoader({ [`${item.objectId}`]: true });
|
||||||
const url = item?.SignedUrl || item?.URL || "";
|
const url = item?.SignedUrl || item?.URL || "";
|
||||||
const pdfName = item?.Name || "exported_file";
|
const pdfName = item?.Name || "exported_file";
|
||||||
|
const isCompleted = item?.IsCompleted || false;
|
||||||
if (url) {
|
if (url) {
|
||||||
try {
|
try {
|
||||||
const signedUrl = await Parse.Cloud.run("getsignedurl", { url: url });
|
if (isCompleted) {
|
||||||
await fetchUrl(signedUrl, pdfName);
|
setIsDownloadModal({ [item.objectId]: true });
|
||||||
|
} else {
|
||||||
|
const signedUrl = await getSignedUrl(url);
|
||||||
|
await fetchUrl(signedUrl, pdfName);
|
||||||
|
}
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err in getsignedurl", err);
|
console.log("err in getsignedurl", err);
|
||||||
@@ -725,7 +790,7 @@ const ReportTable = (props) => {
|
|||||||
sessionToken: localStorage.getItem("accesstoken")
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
};
|
};
|
||||||
let params = {
|
let params = {
|
||||||
mailProvider: doc?.ExtUserPtr?.active_mail_adapter,
|
mailProvider: doc?.ExtUserPtr?.active_mail_adapter || "",
|
||||||
extUserId: doc?.ExtUserPtr?.objectId,
|
extUserId: doc?.ExtUserPtr?.objectId,
|
||||||
recipient: userDetails?.Email,
|
recipient: userDetails?.Email,
|
||||||
subject: mail.subject,
|
subject: mail.subject,
|
||||||
@@ -790,13 +855,13 @@ const ReportTable = (props) => {
|
|||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
setAlertMsg({
|
setAlertMsg({
|
||||||
type: "success",
|
type: "success",
|
||||||
message: count + t("document-sent-alert")
|
message: count + " " + t("document-sent-alert")
|
||||||
});
|
});
|
||||||
setTimeout(() => setIsAlert(false), 1500);
|
setTimeout(() => setIsAlert(false), 1500);
|
||||||
} else {
|
} else {
|
||||||
setAlertMsg({
|
setAlertMsg({
|
||||||
type: "success",
|
type: "success",
|
||||||
message: count + t("document-sent-alert")
|
message: count + " " + t("document-sent-alert")
|
||||||
});
|
});
|
||||||
setTimeout(() => setIsAlert(false), 1500);
|
setTimeout(() => setIsAlert(false), 1500);
|
||||||
}
|
}
|
||||||
@@ -838,14 +903,10 @@ const ReportTable = (props) => {
|
|||||||
console.log("err in fetch template in bulk modal", err);
|
console.log("err in fetch template in bulk modal", err);
|
||||||
setIsBulkSend({});
|
setIsBulkSend({});
|
||||||
setIsAlert(true);
|
setIsAlert(true);
|
||||||
setAlertMsg({
|
setAlertMsg({ type: "danger", message: t("something-went-wrong-mssg") });
|
||||||
type: "danger",
|
|
||||||
message: t("something-went-wrong-mssg")
|
|
||||||
});
|
|
||||||
setTimeout(() => setIsAlert(false), 1500);
|
setTimeout(() => setIsAlert(false), 1500);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//function to make template public and set public role
|
//function to make template public and set public role
|
||||||
const handlePublicTemplate = async (item) => {
|
const handlePublicTemplate = async (item) => {
|
||||||
if (selectedPublicRole || !props.isPublic[item.objectId]) {
|
if (selectedPublicRole || !props.isPublic[item.objectId]) {
|
||||||
@@ -1005,9 +1066,26 @@ const ReportTable = (props) => {
|
|||||||
type: "success",
|
type: "success",
|
||||||
message: t("copied")
|
message: t("copied")
|
||||||
});
|
});
|
||||||
setTimeout(() => setIsAlert(false), 1500);
|
setCopied({ ...copied, publicprofile: true });
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsAlert(false);
|
||||||
|
setCopied(false);
|
||||||
|
}, 1500);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const copyTemplateId = (templateid) => {
|
||||||
|
copytoData(templateid);
|
||||||
|
setIsAlert(true);
|
||||||
|
setAlertMsg({
|
||||||
|
type: "success",
|
||||||
|
message: t("copied")
|
||||||
|
});
|
||||||
|
setCopied({ ...copied, templateid: true });
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsAlert(false);
|
||||||
|
setCopied(false);
|
||||||
|
}, 1500);
|
||||||
|
};
|
||||||
const handleShowRole = (item) => {
|
const handleShowRole = (item) => {
|
||||||
const getRole = item.Placeholders.find((data) => !data.signerObjId);
|
const getRole = item.Placeholders.find((data) => !data.signerObjId);
|
||||||
return getRole?.Role;
|
return getRole?.Role;
|
||||||
@@ -1046,6 +1124,14 @@ const ReportTable = (props) => {
|
|||||||
setTimeout(() => setIsAlert(false), 1500);
|
setTimeout(() => setIsAlert(false), 1500);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const handleEmbedFunction = async (item) => {
|
||||||
|
setIsEmbed(true);
|
||||||
|
setIsPublicProfile({
|
||||||
|
[item.objectId]: true
|
||||||
|
});
|
||||||
|
let extendUser = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||||
|
setIsPublicUserName(extendUser[0]?.UserName || "");
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -1054,10 +1140,15 @@ const ReportTable = (props) => {
|
|||||||
<Loader />
|
<Loader />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="p-2 w-full overflow-auto bg-base-100 text-base-content op-card shadow-lg">
|
<div className="p-2 w-full overflow-hidden bg-base-100 text-base-content op-card shadow-lg">
|
||||||
{isCelebration && (
|
{isCelebration && (
|
||||||
<div className="relative z-[1000]">
|
<div className="relative z-[1000]">
|
||||||
<Confetti width={window.innerWidth} height={window.innerHeight} />
|
<Confetti
|
||||||
|
width={window.innerWidth}
|
||||||
|
height={window.innerHeight}
|
||||||
|
recycle={false} // Prevents confetti from repeating
|
||||||
|
gravity={0.1} // Adjust the gravity to control the speed
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isAlert && <Alert type={alertMsg.type}>{alertMsg.message}</Alert>}
|
{isAlert && <Alert type={alertMsg.type}>{alertMsg.message}</Alert>}
|
||||||
@@ -1097,8 +1188,8 @@ const ReportTable = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
isDashboard && props.List?.length > 0 ? "h-[317px]" : "h-full"
|
isDashboard && props.List?.length > 0 ? "min-h-[317px]" : "h-full"
|
||||||
} w-full`}
|
} overflow-auto w-full`}
|
||||||
>
|
>
|
||||||
<table className="op-table border-collapse w-full ">
|
<table className="op-table border-collapse w-full ">
|
||||||
<thead className="text-[14px]">
|
<thead className="text-[14px]">
|
||||||
@@ -1134,48 +1225,50 @@ const ReportTable = (props) => {
|
|||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-2 ">{item?.Email || "-"}</td>
|
<td className="px-4 py-2 ">{item?.Email || "-"}</td>
|
||||||
<td className="px-4 py-2">{item?.Phone || "-"}</td>
|
<td className="px-4 py-2">{item?.Phone || "-"}</td>
|
||||||
<td className="px-3 py-2 text-white grid grid-cols-2">
|
<td className="px-3 py-2">
|
||||||
{props.actions?.length > 0 &&
|
<div className="text-base-content min-w-max flex flex-row gap-x-2 gap-y-1 justify-start items-center">
|
||||||
props.actions.map((act, index) => (
|
{props.actions?.length > 0 &&
|
||||||
<button
|
props.actions.map((act, index) => (
|
||||||
key={index}
|
<button
|
||||||
onClick={() => handleActionBtn(act, item)}
|
key={index}
|
||||||
title={t(`btnLabel.${act.hoverLabel}`)}
|
onClick={() => handleActionBtn(act, item)}
|
||||||
className={`${
|
title={t(`btnLabel.${act.hoverLabel}`)}
|
||||||
act?.btnColor ? act.btnColor : ""
|
className={`${
|
||||||
} op-btn op-btn-sm`}
|
act?.btnColor ? act.btnColor : ""
|
||||||
|
} op-btn op-btn-sm`}
|
||||||
|
>
|
||||||
|
<i className={act.btnIcon}></i>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
{isDeleteModal[item.objectId] && (
|
||||||
|
<ModalUi
|
||||||
|
isOpen
|
||||||
|
title={"Delete Contact"}
|
||||||
|
handleClose={handleClose}
|
||||||
>
|
>
|
||||||
<i className={act.btnIcon}></i>
|
<div className="m-[20px]">
|
||||||
</button>
|
<div className="text-lg font-normal text-black">
|
||||||
))}
|
{t("contact-delete-alert")}
|
||||||
{isDeleteModal[item.objectId] && (
|
</div>
|
||||||
<ModalUi
|
<hr className="bg-[#ccc] mt-4 " />
|
||||||
isOpen
|
<div className="flex items-center mt-3 gap-2 text-white">
|
||||||
title={"Delete Contact"}
|
<button
|
||||||
handleClose={handleClose}
|
onClick={() => handleDelete(item)}
|
||||||
>
|
className="op-btn op-btn-primary"
|
||||||
<div className="m-[20px]">
|
>
|
||||||
<div className="text-lg font-normal text-black">
|
{t("yes")}
|
||||||
{t("contact-delete-alert")}
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleClose}
|
||||||
|
className="op-btn op-btn-secondary"
|
||||||
|
>
|
||||||
|
{t("no")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr className="bg-[#ccc] mt-4 " />
|
</ModalUi>
|
||||||
<div className="flex items-center mt-3 gap-2 text-white">
|
)}
|
||||||
<button
|
</div>
|
||||||
onClick={() => handleDelete(item)}
|
|
||||||
className="op-btn op-btn-primary"
|
|
||||||
>
|
|
||||||
{t("yes")}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={handleClose}
|
|
||||||
className="op-btn op-btn-secondary"
|
|
||||||
>
|
|
||||||
{t("no")}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ModalUi>
|
|
||||||
)}
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
) : (
|
) : (
|
||||||
@@ -1217,11 +1310,57 @@ const ReportTable = (props) => {
|
|||||||
{item?.URL ? t("download") : "-"}
|
{item?.URL ? t("download") : "-"}
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
{props.ReportName === "In-progress documents" ? (
|
||||||
|
<td className="px-4 py-2">
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
item?.AuditTrail?.length > 0 &&
|
||||||
|
setIsModal({ [item?.objectId]: true })
|
||||||
|
}
|
||||||
|
className={`${
|
||||||
|
item?.AuditTrail?.length
|
||||||
|
? "border-green-400"
|
||||||
|
: "cursor-default op-border-primary"
|
||||||
|
} focus:outline-none w-[60px] border-[2px] text-[12px] rounded-full md:self-center`}
|
||||||
|
>
|
||||||
|
{item?.AuditTrail?.length ? "VIEWED" : "SENT"}
|
||||||
|
</button>
|
||||||
|
{isModal[item.objectId] && (
|
||||||
|
<ModalUi
|
||||||
|
isOpen
|
||||||
|
title={t("document-logs")}
|
||||||
|
handleClose={() => setIsModal({})}
|
||||||
|
>
|
||||||
|
{item?.AuditTrail?.map((x, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="pl-3 first:mt-2 text-sm font-medium flex flex-col md:flex-row items-start md:gap-4 border-t-[1px] border-gray-600"
|
||||||
|
>
|
||||||
|
<div className="py-2 break-all font-bold md:text-[12px] md:col-span-2 w-full md:w-[210px]">
|
||||||
|
{x?.UserPtr?.Email || "-"}
|
||||||
|
</div>
|
||||||
|
<button className="px-2 cursor-default border-[2px] text-[12px] border-green-400 rounded-full md:self-center">
|
||||||
|
{x?.Activity?.toUpperCase() || "-"}
|
||||||
|
</button>
|
||||||
|
<div className=" text-[12px] py-2">
|
||||||
|
{x?.Activity === "Signed"
|
||||||
|
? new Date(x?.SignedOn)?.toUTCString()
|
||||||
|
: new Date(
|
||||||
|
x?.ViewedOn
|
||||||
|
)?.toUTCString() || "-"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</ModalUi>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
) : (
|
||||||
|
<td className="px-4 py-2">
|
||||||
|
{formatRow(item?.ExtUserPtr)}
|
||||||
|
</td>
|
||||||
|
)}
|
||||||
<td className="px-4 py-2">
|
<td className="px-4 py-2">
|
||||||
{formatRow(item?.ExtUserPtr)}
|
{!item?.IsSignyourself && item?.Placeholders ? (
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2">
|
|
||||||
{item?.Placeholders ? (
|
|
||||||
<button
|
<button
|
||||||
onClick={() => handleViewSigners(item)}
|
onClick={() => handleViewSigners(item)}
|
||||||
className="op-link op-link-primary"
|
className="op-link op-link-primary"
|
||||||
@@ -1237,11 +1376,7 @@ const ReportTable = (props) => {
|
|||||||
<td className=" pl-[20px] py-2">
|
<td className=" pl-[20px] py-2">
|
||||||
{props.ReportName === "Templates" && (
|
{props.ReportName === "Templates" && (
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
<label
|
<label className="cursor-pointer relative inline-flex items-center mb-0">
|
||||||
className={
|
|
||||||
"cursor-pointer relative inline-flex items-center mb-0"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
checked={props.isPublic?.[item.objectId]}
|
checked={props.isPublic?.[item.objectId]}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
@@ -1319,23 +1454,62 @@ const ReportTable = (props) => {
|
|||||||
title={t("public-url")}
|
title={t("public-url")}
|
||||||
handleClose={() => {
|
handleClose={() => {
|
||||||
setIsPublicProfile({});
|
setIsPublicProfile({});
|
||||||
|
setIsEmbed(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="m-[20px]">
|
<div className="m-[20px]">
|
||||||
{publicUserName ? (
|
{isEmbed && !item?.IsPublic ? (
|
||||||
|
<>
|
||||||
|
<p>{t("public-template-mssg-6")}</p>
|
||||||
|
<EmbedTab templateId={item.objectId} />
|
||||||
|
</>
|
||||||
|
) : publicUserName ? (
|
||||||
<div className="font-normal text-black">
|
<div className="font-normal text-black">
|
||||||
<p>{t("public-url-copy-mssg")}</p>
|
<span>{t("public-url-copy")}</span>
|
||||||
<div className=" flex items-center gap-3 mt-2 p-[2px] ">
|
<div className=" flex items-center justify-between gap-3 p-[2px] ">
|
||||||
<span className="font-bold">
|
<div className="w-[280px] whitespace-nowrap overflow-hidden text-ellipsis">
|
||||||
{t("public-url")}:
|
<span
|
||||||
</span>
|
onClick={() =>
|
||||||
<span
|
copytoProfileLink()
|
||||||
onClick={() => copytoProfileLink()}
|
}
|
||||||
className="underline underline-offset-2 w-[150px] md:w-[350px] whitespace-nowrap overflow-hidden text-ellipsis cursor-pointer"
|
className="ml-[2px] underline underline-offset-2 cursor-pointer text-blue-800"
|
||||||
>
|
>
|
||||||
{publicUrl()}
|
{publicUrl()}
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<RWebShare
|
||||||
|
data={{
|
||||||
|
url: publicUrl(),
|
||||||
|
title: "Public url"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm ">
|
||||||
|
<i className="fa-light fa-share-from-square"></i>{" "}
|
||||||
|
<span className="hidden md:inline-block">
|
||||||
|
{t("btnLabel.Share")}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</RWebShare>
|
||||||
|
<button
|
||||||
|
className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm"
|
||||||
|
onClick={() =>
|
||||||
|
copytoProfileLink()
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-copy" />
|
||||||
|
<span className="hidden md:inline-block">
|
||||||
|
{copied["publicprofile"]
|
||||||
|
? t("copied")
|
||||||
|
: t("copy")}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<p className="text-[13px] mt-[5px]">
|
||||||
|
{t("public-url-copy-mssg")}
|
||||||
|
</p>
|
||||||
|
<EmbedTab templateId={item.objectId} />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="font-normal text-black">
|
<div className="font-normal text-black">
|
||||||
@@ -1354,7 +1528,7 @@ const ReportTable = (props) => {
|
|||||||
</td>
|
</td>
|
||||||
)}
|
)}
|
||||||
<td className="px-2 py-2">
|
<td className="px-2 py-2">
|
||||||
<div className="text-base-content flex flex-row gap-x-2 gap-y-1 justify-start items-center">
|
<div className="text-base-content min-w-max flex flex-row gap-x-2 gap-y-1 justify-start items-center">
|
||||||
{props.actions?.length > 0 &&
|
{props.actions?.length > 0 &&
|
||||||
props.actions.map((act, index) =>
|
props.actions.map((act, index) =>
|
||||||
props.ReportName === "Templates" ? (
|
props.ReportName === "Templates" ? (
|
||||||
@@ -1383,7 +1557,13 @@ const ReportTable = (props) => {
|
|||||||
<i className={act.btnIcon}></i>
|
<i className={act.btnIcon}></i>
|
||||||
{act.btnLabel && (
|
{act.btnLabel && (
|
||||||
<span className="uppercase font-medium">
|
<span className="uppercase font-medium">
|
||||||
{t(`btnLabel.${act.btnLabel}`)}
|
{act.btnLabel.includes(
|
||||||
|
"Quick send"
|
||||||
|
) && isEnableSubscription
|
||||||
|
? "Bulk Send"
|
||||||
|
: `${t(
|
||||||
|
`btnLabel.${act.btnLabel}`
|
||||||
|
)}`}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{isOption[item.objectId] &&
|
{isOption[item.objectId] &&
|
||||||
@@ -1478,114 +1658,117 @@ const ReportTable = (props) => {
|
|||||||
{isShareWith[item.objectId] && (
|
{isShareWith[item.objectId] && (
|
||||||
<div className="op-modal op-modal-open">
|
<div className="op-modal op-modal-open">
|
||||||
<div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative">
|
<div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative">
|
||||||
{isSubscribe && isEnableSubscription && (
|
{validplan[isSubscribe.plan] &&
|
||||||
<>
|
isEnableSubscription && (
|
||||||
{item?.Signers?.length > 0 ? (
|
<>
|
||||||
<div className="h-[150px] flex justify-center items-center mx-2">
|
{item?.Signers?.length > 0 ? (
|
||||||
<div
|
<div className="h-[150px] flex justify-center items-center mx-2">
|
||||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
<div
|
||||||
onClick={() => setIsShareWith({})}
|
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
||||||
>
|
onClick={() => setIsShareWith({})}
|
||||||
✕
|
>
|
||||||
|
✕
|
||||||
|
</div>
|
||||||
|
<div className="text-base-content text-base text-center">
|
||||||
|
{t("share-with-alert")}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-base-content text-base text-center">
|
) : (
|
||||||
{t("share-with-alert")}
|
<>
|
||||||
</div>
|
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||||
</div>
|
{t("share-with")}
|
||||||
) : (
|
</h3>
|
||||||
<>
|
<div
|
||||||
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
||||||
{t("share-with")}
|
onClick={() => setIsShareWith({})}
|
||||||
</h3>
|
>
|
||||||
<div
|
✕
|
||||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
</div>
|
||||||
onClick={() => setIsShareWith({})}
|
<form
|
||||||
>
|
className="h-full w-full z-[1300] px-2 mt-3"
|
||||||
✕
|
onSubmit={(e) =>
|
||||||
</div>
|
handleShareWith(e, item)
|
||||||
<form
|
|
||||||
className="h-full w-full z-[1300] px-2 mt-3"
|
|
||||||
onSubmit={(e) =>
|
|
||||||
handleShareWith(e, item)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
// onSortEnd={onSortEnd}
|
|
||||||
distance={4}
|
|
||||||
isMulti
|
|
||||||
options={teamList}
|
|
||||||
value={selectedTeam}
|
|
||||||
onChange={onChange}
|
|
||||||
closeMenuOnSelect
|
|
||||||
required={true}
|
|
||||||
noOptionsMessage={() =>
|
|
||||||
t("team-not-found")
|
|
||||||
}
|
}
|
||||||
unstyled
|
>
|
||||||
classNames={{
|
<Select
|
||||||
control: () =>
|
// onSortEnd={onSortEnd}
|
||||||
"op-input op-input-bordered op-input-sm border-gray-400 focus:outline-none hover:border-base-content w-full h-full text-[11px]",
|
distance={4}
|
||||||
valueContainer: () =>
|
isMulti
|
||||||
"flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]",
|
options={teamList}
|
||||||
multiValue: () =>
|
value={selectedTeam}
|
||||||
"op-badge op-badge-primary h-full text-[11px]",
|
onChange={onChange}
|
||||||
multiValueLabel: () => "mb-[2px]",
|
closeMenuOnSelect
|
||||||
menu: () =>
|
required={true}
|
||||||
"mt-1 shadow-md rounded-lg bg-base-200 text-base-content",
|
noOptionsMessage={() =>
|
||||||
menuList: () =>
|
t("team-not-found")
|
||||||
"shadow-md rounded-lg overflow-hidden",
|
}
|
||||||
option: () =>
|
unstyled
|
||||||
"bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2",
|
classNames={{
|
||||||
noOptionsMessage: () =>
|
control: () =>
|
||||||
"p-2 bg-base-200 rounded-lg m-1 p-2"
|
"op-input op-input-bordered op-input-sm border-gray-400 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]",
|
||||||
<button className="op-btn op-btn-primary ml-[10px] my-3">
|
multiValue: () =>
|
||||||
{t("submit")}
|
"op-badge op-badge-primary h-full text-[11px]",
|
||||||
</button>
|
multiValueLabel: () =>
|
||||||
</form>
|
"mb-[2px]",
|
||||||
</>
|
menu: () =>
|
||||||
)}
|
"mt-1 shadow-md rounded-lg bg-base-200 text-base-content",
|
||||||
</>
|
menuList: () =>
|
||||||
)}
|
"shadow-md rounded-lg overflow-hidden",
|
||||||
{!isSubscribe && isEnableSubscription && (
|
option: () =>
|
||||||
<>
|
"bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2",
|
||||||
<div
|
noOptionsMessage: () =>
|
||||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-primary-content absolute right-2 top-2 z-40"
|
"p-2 bg-base-200 rounded-lg m-1 p-2"
|
||||||
onClick={() => setIsShareWith({})}
|
}}
|
||||||
>
|
/>
|
||||||
✕
|
<button className="op-btn op-btn-primary ml-[10px] my-3">
|
||||||
</div>
|
{t("submit")}
|
||||||
<SubscribeCard
|
</button>
|
||||||
plan={"TEAMS"}
|
</form>
|
||||||
price={"20"}
|
</>
|
||||||
/>
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{isSubscribe && !isEnableSubscription && (
|
{isEnableSubscription &&
|
||||||
<>
|
!validplan[isSubscribe.plan] && (
|
||||||
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
<>
|
||||||
{t("share-with")}
|
<div
|
||||||
</h3>
|
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-primary-content absolute right-2 top-2 z-40"
|
||||||
<div
|
onClick={() => setIsShareWith({})}
|
||||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
>
|
||||||
onClick={() => setIsShareWith({})}
|
✕
|
||||||
>
|
|
||||||
✕
|
|
||||||
</div>
|
|
||||||
<div className="px-2 mt-3 w-full h-full">
|
|
||||||
<div className="op-input op-input-bordered op-input-sm w-full h-full text-[13px] break-all">
|
|
||||||
{selectedTeam?.[0]?.label}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<SubscribeCard plan="TEAMS" />
|
||||||
<button
|
</>
|
||||||
onClick={(e) => handleShareWith(e, item)}
|
)}
|
||||||
className="op-btn op-btn-primary ml-[10px] my-3"
|
{!isEnableSubscription &&
|
||||||
>
|
validplan[isSubscribe.plan] && (
|
||||||
{t("submit")}
|
<>
|
||||||
</button>
|
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||||
</>
|
{t("share-with")}
|
||||||
)}
|
</h3>
|
||||||
|
<div
|
||||||
|
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
||||||
|
onClick={() => setIsShareWith({})}
|
||||||
|
>
|
||||||
|
✕
|
||||||
|
</div>
|
||||||
|
<div className="px-2 mt-3 w-full h-full">
|
||||||
|
<div className="op-input op-input-bordered op-input-sm w-full h-full text-[13px] break-all">
|
||||||
|
{selectedTeam?.[0]?.label}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={(e) =>
|
||||||
|
handleShareWith(e, item)
|
||||||
|
}
|
||||||
|
className="op-btn op-btn-primary ml-[10px] my-3"
|
||||||
|
>
|
||||||
|
{t("submit")}
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -1623,20 +1806,26 @@ const ReportTable = (props) => {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{item.Placeholders.map((x, i) => (
|
{item.Placeholders.map(
|
||||||
<tr key={i} className="text-sm font-medium">
|
(x, i) =>
|
||||||
{props.ReportName === "Templates" && (
|
x.Role !== "prefill" && (
|
||||||
<td className="text-[12px] p-2 pl-3 w-[30%]">
|
<tr
|
||||||
{x.Role && x.Role}
|
key={i}
|
||||||
</td>
|
className="text-sm font-medium"
|
||||||
)}
|
>
|
||||||
<td className="pl-3 text-[12px] py-2 break-all">
|
{props.ReportName === "Templates" && (
|
||||||
{x.email
|
<td className="text-[12px] p-2 pl-3 w-[30%]">
|
||||||
? x.email
|
{x.Role && x.Role}
|
||||||
: x?.signerPtr?.Email || "-"}
|
</td>
|
||||||
</td>
|
)}
|
||||||
</tr>
|
<td className="pl-3 text-[12px] py-2 break-all">
|
||||||
))}
|
{x.email
|
||||||
|
? x.email
|
||||||
|
: x?.signerPtr?.Email || "-"}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
@@ -1672,11 +1861,15 @@ const ReportTable = (props) => {
|
|||||||
{isBulkSend[item.objectId] && (
|
{isBulkSend[item.objectId] && (
|
||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen
|
isOpen
|
||||||
title={t("quick-send")}
|
title={
|
||||||
|
isEnableSubscription
|
||||||
|
? "Bulk send"
|
||||||
|
: t("quick-send")
|
||||||
|
}
|
||||||
handleClose={() => setIsBulkSend({})}
|
handleClose={() => setIsBulkSend({})}
|
||||||
>
|
>
|
||||||
{isLoader[item.objectId] ? (
|
{isLoader[item.objectId] ? (
|
||||||
<div className="w-full h-[100px] flex justify-center items-center bg-opacity-30 z-30">
|
<div className="w-full h-[100px] flex justify-center items-center z-30">
|
||||||
<Loader />
|
<Loader />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -1723,7 +1916,7 @@ const ReportTable = (props) => {
|
|||||||
className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm"
|
className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm"
|
||||||
onClick={() => copytoclipboard(share)}
|
onClick={() => copytoclipboard(share)}
|
||||||
>
|
>
|
||||||
<i className="fa-light fa-link"></i>{" "}
|
<i className="fa-light fa-copy" />
|
||||||
{copied[share.email]
|
{copied[share.email]
|
||||||
? t("copied")
|
? t("copied")
|
||||||
: t("copy")}
|
: t("copy")}
|
||||||
@@ -1877,6 +2070,14 @@ const ReportTable = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
)}
|
)}
|
||||||
|
{isDownloadModal[item.objectId] && (
|
||||||
|
<DownloadPdfZip
|
||||||
|
setIsDownloadModal={setIsDownloadModal}
|
||||||
|
isDownloadModal={isDownloadModal[item.objectId]}
|
||||||
|
pdfDetails={[item]}
|
||||||
|
isDocId={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -21,9 +21,11 @@ const ModalUi = ({
|
|||||||
>
|
>
|
||||||
{showHeader && (
|
{showHeader && (
|
||||||
<>
|
<>
|
||||||
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
{title && (
|
||||||
{title}
|
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||||
</h3>
|
{title}
|
||||||
|
</h3>
|
||||||
|
)}
|
||||||
{showClose && (
|
{showClose && (
|
||||||
<button
|
<button
|
||||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2"
|
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2"
|
||||||
|
|||||||
@@ -2,27 +2,30 @@ import React, { useState } from "react";
|
|||||||
import "../styles/signature.css";
|
import "../styles/signature.css";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
function CustomModal({
|
function CustomModal(props) {
|
||||||
show,
|
|
||||||
headMsg,
|
|
||||||
bodyMssg,
|
|
||||||
footerMessage,
|
|
||||||
declineDoc,
|
|
||||||
setIsDecline
|
|
||||||
}) {
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [reason, setReason] = useState("");
|
const [reason, setReason] = useState("");
|
||||||
return (
|
return (
|
||||||
show && (
|
props.show && (
|
||||||
<dialog className="op-modal op-modal-open absolute z-[448]">
|
<dialog className="op-modal op-modal-open absolute z-[448]">
|
||||||
<div className="w-[95%] md:w-[60%] lg:w-[40%] op-modal-box p-0 overflow-y-auto hide-scrollbar text-sm">
|
<div className="w-[95%] md:w-[60%] lg:w-[40%] op-modal-box p-0 overflow-y-auto hide-scrollbar text-sm">
|
||||||
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||||
{headMsg && headMsg}
|
{props?.headMsg && props?.headMsg}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="p-[10px] px-[20px]">
|
<div className="p-[10px] px-[20px]">
|
||||||
<p className="text-[15px]">{bodyMssg && bodyMssg}</p>
|
<p className="text-[15px]">{props.bodyMssg && props.bodyMssg}</p>
|
||||||
</div>
|
</div>
|
||||||
{footerMessage && (
|
{props.isDownloadBtn && (
|
||||||
|
<div className="flex justify-start w-full ml-[20px] mb-3 mt-1">
|
||||||
|
<button
|
||||||
|
className="op-btn op-btn-primary "
|
||||||
|
onClick={() => props.handleDownloadBtn()}
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{props.footerMessage && (
|
||||||
<>
|
<>
|
||||||
<div className="mx-3">
|
<div className="mx-3">
|
||||||
<textarea
|
<textarea
|
||||||
@@ -33,14 +36,13 @@ function CustomModal({
|
|||||||
onChange={(e) => setReason(e.target.value)}
|
onChange={(e) => setReason(e.target.value)}
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="h-[1px] bg-[#9f9f9f] w-full"></div> */}
|
|
||||||
<div className="m-[15px]">
|
<div className="m-[15px]">
|
||||||
<button
|
<button
|
||||||
className="op-btn op-btn-primary mr-2 px-6"
|
className="op-btn op-btn-primary mr-2 px-6"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
props.declineDoc(reason);
|
||||||
setReason("");
|
setReason("");
|
||||||
declineDoc(reason);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("yes")}
|
{t("yes")}
|
||||||
@@ -50,7 +52,7 @@ function CustomModal({
|
|||||||
className="op-btn op-btn-secondary"
|
className="op-btn op-btn-secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setReason("");
|
setReason("");
|
||||||
setIsDecline({ isDeclined: false });
|
props.setIsDecline({ isDeclined: false });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("close")}
|
{t("close")}
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
const QuotaCard = ({ isPaidInfo, handlClose }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
return isPaidInfo ? (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-primary-content absolute right-2 top-2 z-40"
|
||||||
|
onClick={() => handlClose && handlClose()}
|
||||||
|
>
|
||||||
|
✕
|
||||||
|
</div>
|
||||||
|
<div className="op-card op-bg-primary text-primary-content w-full shadow-lg">
|
||||||
|
<div className="op-card-body">
|
||||||
|
<h2 className="op-card-title">{t("quota-mail-info-head")}</h2>
|
||||||
|
<p>{t("quota-mail-info")}</p>
|
||||||
|
<p>
|
||||||
|
<Trans i18nKey={"quota-mail-tip"}>
|
||||||
|
Tip: You can still sign <strong>unlimited documents</strong> by
|
||||||
|
manually sharing the signing request links.
|
||||||
|
</Trans>
|
||||||
|
</p>
|
||||||
|
<div className="op-card-actions justify-end">
|
||||||
|
<button
|
||||||
|
onClick={() => navigate("/subscription")}
|
||||||
|
className="op-btn op-btn-accent"
|
||||||
|
>
|
||||||
|
{t("upgrade-now")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div className="op-card op-bg-primary text-primary-content w-full shadow-lg">
|
||||||
|
<div className="op-card-body">
|
||||||
|
<p>{t("quota-mail")}</p>
|
||||||
|
<p>{t("quota-mail-tip")}</p>
|
||||||
|
<div className="op-card-actions justify-end">
|
||||||
|
<button
|
||||||
|
onClick={() => navigate("/subscription")}
|
||||||
|
className="op-btn op-btn-accent"
|
||||||
|
>
|
||||||
|
{t("upgrade-now")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default QuotaCard;
|
||||||
@@ -5,18 +5,24 @@ import { useNavigate } from "react-router-dom";
|
|||||||
const SubscribeCard = ({ plan, price }) => {
|
const SubscribeCard = ({ plan, price }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const handlePaidRoute = () => navigate("/subscription");
|
||||||
|
const premiumPrice = price ? "$" + price : "$9.99";
|
||||||
|
const addonPrice = "$0.15";
|
||||||
|
const plandName = plan ? plan.toLowerCase() : "Paid";
|
||||||
return (
|
return (
|
||||||
<div className="op-card op-bg-primary text-primary-content w-full shadow-lg">
|
<div className="op-card op-bg-primary text-primary-content w-full shadow-lg">
|
||||||
<div className="op-card-body">
|
<div className="op-card-body">
|
||||||
<h2 className="op-card-title">
|
<h2 className="op-card-title">
|
||||||
{t("upgrade-to")} {plan ? plan : "PRO"} {t("plan")}
|
{t("upgrade-to")} {plan ? plan : "Paid"} {t("plan")}
|
||||||
</h2>
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
${price ? price : "29.99"}/month: {t("subscribe-card-plan")}
|
{plandName?.includes("team")
|
||||||
|
? t("subscribe-card-teamplan")
|
||||||
|
: t("subscribe-card-plan", { premiumPrice, addonPrice })}
|
||||||
</p>
|
</p>
|
||||||
<div className="op-card-actions justify-end">
|
<div className="op-card-actions justify-end">
|
||||||
<button
|
<button
|
||||||
onClick={() => navigate("/subscription")}
|
onClick={() => handlePaidRoute()}
|
||||||
className="op-btn op-btn-accent"
|
className="op-btn op-btn-accent"
|
||||||
>
|
>
|
||||||
{t("upgrade-now")}
|
{t("upgrade-now")}
|
||||||
|
|||||||
@@ -1,9 +1,21 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Tooltip as ReactTooltip } from "react-tooltip";
|
import { Tooltip as ReactTooltip } from "react-tooltip";
|
||||||
import { openInNewTab } from "../constant/Utils";
|
import { openInNewTab } from "../constant/Utils";
|
||||||
const Tooltip = ({ id, message, url, iconColor, maxWidth }) =>
|
const Tooltip = ({
|
||||||
url ? (
|
id,
|
||||||
<button onClick={() => openInNewTab(url)} className={"text-center"}>
|
message,
|
||||||
|
url,
|
||||||
|
iconColor,
|
||||||
|
maxWidth,
|
||||||
|
handleOnlickHelp
|
||||||
|
}) =>
|
||||||
|
url || handleOnlickHelp ? (
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
handleOnlickHelp ? handleOnlickHelp() : openInNewTab(url)
|
||||||
|
}
|
||||||
|
className={"text-center cursor-pointer"}
|
||||||
|
>
|
||||||
<sup>
|
<sup>
|
||||||
<i
|
<i
|
||||||
className="fa-light fa-question rounded-full border-[1px] py-[1.5px] px-[4px] text-[13px]"
|
className="fa-light fa-question rounded-full border-[1px] py-[1.5px] px-[4px] text-[13px]"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
export default function TourContentWithBtn({ message, isChecked }) {
|
export default function TourContentWithBtn({ message, isChecked, video }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [isCheck, setIsCheck] = useState(false);
|
const [isCheck, setIsCheck] = useState(false);
|
||||||
|
|
||||||
@@ -13,7 +13,18 @@ export default function TourContentWithBtn({ message, isChecked }) {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>{message}</p>
|
<p>{message}</p>
|
||||||
<label className="flex items-center justify-center mb-0">
|
{video && (
|
||||||
|
<div className="flex items-center justify-center w-full md:h-[300px] my-[10px] border-[1.3px] border-gray-400 rounded-sm">
|
||||||
|
<iframe
|
||||||
|
className="w-full h-full"
|
||||||
|
src={video}
|
||||||
|
title="YouTube video player"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||||
|
allowFullScreen
|
||||||
|
></iframe>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<label className="flex items-center justify-center mt-3 mb-0">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="op-checkbox op-checkbox-xs mr-1"
|
className="op-checkbox op-checkbox-xs mr-1"
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ const Validate = () => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleLoginBtn = () => {
|
const handleLoginBtn = async () => {
|
||||||
try {
|
try {
|
||||||
Parse.User.logOut();
|
await Parse.User.logOut();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err ", err);
|
console.log("err ", err);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
import { combineReducers } from "redux";
|
|
||||||
import infoReducer from "./infoReducer";
|
|
||||||
import ShowTenant from "./ShowTenant";
|
|
||||||
import TourStepsReducer from "./TourStepsReducer";
|
|
||||||
import showHeader from "./showHeader";
|
|
||||||
|
|
||||||
export default combineReducers({
|
|
||||||
appInfo: infoReducer,
|
|
||||||
TourSteps: TourStepsReducer,
|
|
||||||
ShowTenant,
|
|
||||||
showHeader
|
|
||||||
});
|
|
||||||
@@ -11,28 +11,37 @@ import { isPublicStaging } from "../constant/const";
|
|||||||
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.mjs`;
|
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.mjs`;
|
||||||
|
|
||||||
// Wrapper component to manage props
|
// Wrapper component to manage props
|
||||||
const PublicScriptFileWrapper = ({ initialProps }) => {
|
const PublicScriptFileWrapper = () => {
|
||||||
const [props, setProps] = useState(initialProps);
|
const [props, setProps] = useState("");
|
||||||
|
|
||||||
// Make the setProps function globally accessible
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// Assigns the function 'setProps' to the global 'window' object as 'updatePublicTemplateProps'.
|
||||||
|
// This allows 'setProps' to be accessed and called globally across different scripts or components,
|
||||||
|
// enabling dynamic updates to the public template's properties.
|
||||||
window.updatePublicTemplateProps = setProps;
|
window.updatePublicTemplateProps = setProps;
|
||||||
|
const publicScript = document.getElementById("opensign-script");
|
||||||
|
// condition for using plan js load opensign-script then get templateId
|
||||||
|
if (publicScript) {
|
||||||
|
// Get the custom templateId attribute
|
||||||
|
const templateId = publicScript.getAttribute("templateId");
|
||||||
|
if (templateId) {
|
||||||
|
setProps({ templateId: templateId });
|
||||||
|
} else {
|
||||||
|
const error = "error: TemplateId is missing";
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
return () => {
|
return () => {
|
||||||
window.updatePublicTemplateProps = undefined;
|
window.updatePublicTemplateProps = undefined;
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return <PdfRequestFiles {...props} />;
|
return <PdfRequestFiles {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const appId = isPublicStaging ? "opensign" : "legadranaxn";
|
const appId = isPublicStaging ? "opensign" : "legadranaxn";
|
||||||
//"opensign"
|
|
||||||
|
|
||||||
const serverUrl = isPublicStaging
|
const serverUrl = isPublicStaging
|
||||||
? "https://staging-app.opensignlabs.com/api/app"
|
? "https://staging-app.opensignlabs.com/api/app"
|
||||||
: "https://app.opensignlabs.com/api/app";
|
: "https://app.opensignlabs.com/api/app";
|
||||||
// "https://staging-app.opensignlabs.com/api/app"
|
|
||||||
|
|
||||||
localStorage.setItem("baseUrl", `${serverUrl}/`);
|
localStorage.setItem("baseUrl", `${serverUrl}/`);
|
||||||
localStorage.setItem("parseAppId", appId);
|
localStorage.setItem("parseAppId", appId);
|
||||||
@@ -56,9 +65,9 @@ document.head.appendChild(tailwindCssLink);
|
|||||||
// Create a root and render the wrapper component with initial props
|
// Create a root and render the wrapper component with initial props
|
||||||
const root = ReactDOM.createRoot(document.getElementById("script-component"));
|
const root = ReactDOM.createRoot(document.getElementById("script-component"));
|
||||||
root.render(
|
root.render(
|
||||||
<div>
|
<div data-theme="opensigncss">
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<PublicScriptFileWrapper initialProps={{ text: "templateId" }} />
|
<PublicScriptFileWrapper />
|
||||||
</Provider>
|
</Provider>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"header-news": "New feature: Public profiles are now live! Easily create and share public templates",
|
||||||
|
"header-news-btn": "Setup Now",
|
||||||
"create-account": "Create Account",
|
"create-account": "Create Account",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"phone": "Phone",
|
"phone": "Phone",
|
||||||
|
"phone-optional": "optional",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
"company": "Company",
|
"company": "Company",
|
||||||
"job-title": "Job title",
|
"job-title": "Job title",
|
||||||
@@ -38,7 +41,8 @@
|
|||||||
"upgrade-now": "Upgrade now",
|
"upgrade-now": "Upgrade now",
|
||||||
"upgrade-to": "Upgrade to",
|
"upgrade-to": "Upgrade to",
|
||||||
"plan": "Plan",
|
"plan": "Plan",
|
||||||
"subscribe-card-plan": "Sign 100 docs using API. Only $0.15/doc after that.",
|
"subscribe-card-teamplan":"Unlock the full power of collaboration! Create unlimited organizations, teams, and hierarchies. Share templates seamlessly across teams and assign custom user roles. Elevate your workflow today!",
|
||||||
|
"subscribe-card-plan": "Unlock premium features starting at just {{premiumPrice}}/month. Enjoy enhanced performance and only {{addonPrice}} per additional credit after your included premium credits.",
|
||||||
"user-name-limit-char": "To have a username less than 8 character please subscribe",
|
"user-name-limit-char": "To have a username less than 8 character please subscribe",
|
||||||
"tour-content": "Don't show this again",
|
"tour-content": "Don't show this again",
|
||||||
"pro": "PRO",
|
"pro": "PRO",
|
||||||
@@ -91,6 +95,7 @@
|
|||||||
"API Token": "API Token",
|
"API Token": "API Token",
|
||||||
"Webhook": "Webhook",
|
"Webhook": "Webhook",
|
||||||
"Teams": "Teams",
|
"Teams": "Teams",
|
||||||
|
"Team-update-successfully": "Team Updated successfully.",
|
||||||
"Users": "Users"
|
"Users": "Users"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -125,7 +130,9 @@
|
|||||||
"Share with team": "Share with team",
|
"Share with team": "Share with team",
|
||||||
"Share": "Share",
|
"Share": "Share",
|
||||||
"View": "View",
|
"View": "View",
|
||||||
"option": "Option"
|
"option": "Option",
|
||||||
|
"Embed": "Embed",
|
||||||
|
"Copy TemplateId":"Copy TemplateId"
|
||||||
},
|
},
|
||||||
"report-heading": {
|
"report-heading": {
|
||||||
"Sr.No": "Sr.No",
|
"Sr.No": "Sr.No",
|
||||||
@@ -145,7 +152,8 @@
|
|||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
"Status": "Status",
|
"Status": "Status",
|
||||||
"created-date": "Created Date",
|
"created-date": "Created Date",
|
||||||
"Type": "Type"
|
"Type": "Type",
|
||||||
|
"Logs": "Logs"
|
||||||
},
|
},
|
||||||
"report-help": {
|
"report-help": {
|
||||||
"Draft Documents": "These are documents you have started but have not finalized for sending.",
|
"Draft Documents": "These are documents you have started but have not finalized for sending.",
|
||||||
@@ -212,8 +220,8 @@
|
|||||||
"initials": "Initials",
|
"initials": "Initials",
|
||||||
"API": "API",
|
"API": "API",
|
||||||
"api-token": "API Token",
|
"api-token": "API Token",
|
||||||
"regenerate-token": "Regenerate Token",
|
"regenerate-token": "Regenerate Live Token",
|
||||||
"generate-token": "Generate Token",
|
"generate-token": "Generate Live Token",
|
||||||
"view-docs": "View Docs",
|
"view-docs": "View Docs",
|
||||||
"generate-token-alert": "Are you sure you want to regenerate token it will expire old token?",
|
"generate-token-alert": "Are you sure you want to regenerate token it will expire old token?",
|
||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
@@ -257,7 +265,8 @@
|
|||||||
"make-template-private-alert": "Are you sure you want to make this template private? This will remove it from your public profile.",
|
"make-template-private-alert": "Are you sure you want to make this template private? This will remove it from your public profile.",
|
||||||
"public-role": "Public role",
|
"public-role": "Public role",
|
||||||
"public-url": "Public URL",
|
"public-url": "Public URL",
|
||||||
"public-url-copy-mssg": " Here’s your public URL: Copy it or share it with the signer, and you will be able to see all your publicly set templates.",
|
"public-url-copy": "Here’s your public URL: ",
|
||||||
|
"public-url-copy-mssg":"Copy it or share it with the signer, and you will be able to see all your publicly set templates.",
|
||||||
"add-public-url-alert": "Please add your public URL, and you will be able to make a public template.",
|
"add-public-url-alert": "Please add your public URL, and you will be able to make a public template.",
|
||||||
"share-with-alert": "You cannot share a template if any roles already have contacts assigned. Please remove all contact assignments from the roles before sharing the template.",
|
"share-with-alert": "You cannot share a template if any roles already have contacts assigned. Please remove all contact assignments from the roles before sharing the template.",
|
||||||
"share-with": "Share with",
|
"share-with": "Share with",
|
||||||
@@ -308,7 +317,7 @@
|
|||||||
"contact-details": "Contact Details",
|
"contact-details": "Contact Details",
|
||||||
"verify-email": "Please verify your email !",
|
"verify-email": "Please verify your email !",
|
||||||
"send-otp": " Send OTP",
|
"send-otp": " Send OTP",
|
||||||
"otp-placeholder": "Enter OTP received over email",
|
"otp-placeholder": "Enter verification code received over email",
|
||||||
"loading-doc": "Loading Document..",
|
"loading-doc": "Loading Document..",
|
||||||
"widgets-name": {
|
"widgets-name": {
|
||||||
"signature": "signature",
|
"signature": "signature",
|
||||||
@@ -358,7 +367,7 @@
|
|||||||
"initial-teb": "Initials",
|
"initial-teb": "Initials",
|
||||||
"signature-tab": "Signature",
|
"signature-tab": "Signature",
|
||||||
"your-signature": "Your signature",
|
"your-signature": "Your signature",
|
||||||
"copy-to-all-pages": "Copy to all pages",
|
"copy-title": "Copy widget to",
|
||||||
"contact-delete-alert": "Are you sure you want to delete this contact?",
|
"contact-delete-alert": "Are you sure you want to delete this contact?",
|
||||||
"reset-password-alert-1": "Reset password link has been sent to your email id",
|
"reset-password-alert-1": "Reset password link has been sent to your email id",
|
||||||
"reset-password-alert-2": "Please setup email adapter ",
|
"reset-password-alert-2": "Please setup email adapter ",
|
||||||
@@ -368,7 +377,8 @@
|
|||||||
"copy-type": {
|
"copy-type": {
|
||||||
"All pages": "All pages",
|
"All pages": "All pages",
|
||||||
"All pages but last": "All pages but last",
|
"All pages but last": "All pages but last",
|
||||||
"All pages but first": "All pages but first"
|
"All pages but first": "All pages but first",
|
||||||
|
"Next to current widget": "Next to current widget"
|
||||||
},
|
},
|
||||||
"options": "Options",
|
"options": "Options",
|
||||||
"minimun-check": "Minimun check",
|
"minimun-check": "Minimun check",
|
||||||
@@ -445,7 +455,7 @@
|
|||||||
"decline-alert-3": "You can not sign this document as it has been declined/revoked.",
|
"decline-alert-3": "You can not sign this document as it has been declined/revoked.",
|
||||||
"sign here": "Sign here",
|
"sign here": "Sign here",
|
||||||
"guest-email-alert": "verification code is sent to your email",
|
"guest-email-alert": "verification code is sent to your email",
|
||||||
"get-otp-alert": "you will get a OTP via Email",
|
"get-otp-alert": "you will get a verification code via Email",
|
||||||
"user-already-exist": "User already exist.",
|
"user-already-exist": "User already exist.",
|
||||||
"server-error": "Internal server error !",
|
"server-error": "Internal server error !",
|
||||||
"fill-required-details!": "Please fill required details!",
|
"fill-required-details!": "Please fill required details!",
|
||||||
@@ -468,7 +478,7 @@
|
|||||||
"role-not-found": "Role not found.",
|
"role-not-found": "Role not found.",
|
||||||
"do-not-access": "You don't have access, please contact the admin.",
|
"do-not-access": "You don't have access, please contact the admin.",
|
||||||
"add-admin": "Add admin",
|
"add-admin": "Add admin",
|
||||||
"opensign-setup": "Opensign Setup",
|
"opensign-setup": "OpenSign Setup",
|
||||||
"join-discord": "Join our discord server",
|
"join-discord": "Join our discord server",
|
||||||
"admin-already-exist": "Admin already exist.",
|
"admin-already-exist": "Admin already exist.",
|
||||||
"password-update-alert-1": "Password updated successfully.",
|
"password-update-alert-1": "Password updated successfully.",
|
||||||
@@ -524,7 +534,7 @@
|
|||||||
"filed-required-correctly": "Please fill required details correctly.",
|
"filed-required-correctly": "Please fill required details correctly.",
|
||||||
"admin-created": "Admin created",
|
"admin-created": "Admin created",
|
||||||
"invalid-masterkey": "Invalid masterkey",
|
"invalid-masterkey": "Invalid masterkey",
|
||||||
"opensign-Setup": "Opensign Setup",
|
"opensign-Setup": "OpenSign Setup",
|
||||||
"master-key": " Master key",
|
"master-key": " Master key",
|
||||||
"profile-update-alert": "Profile updated successfully.",
|
"profile-update-alert": "Profile updated successfully.",
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
@@ -550,7 +560,7 @@
|
|||||||
"home-layout-1": "You have logged in successfully! Let's take a look.",
|
"home-layout-1": "You have logged in successfully! Let's take a look.",
|
||||||
"home-layout-2": "To upload documents for self-signing or to request others’ signatures, simply select the respective buttons.",
|
"home-layout-2": "To upload documents for self-signing or to request others’ signatures, simply select the respective buttons.",
|
||||||
"home-layout-3": "You are ready to start using OpenSign! If you need support feel free to contact us.",
|
"home-layout-3": "You are ready to start using OpenSign! If you need support feel free to contact us.",
|
||||||
"generate-token": "Upgrade now to generate API token",
|
"generate-token": "Upgrade now to generate production API token.",
|
||||||
"opensign-drive-1": "Click on the breadcrumb links to easily navigate through the folder hierarchy and view the documents within each folder.",
|
"opensign-drive-1": "Click on the breadcrumb links to easily navigate through the folder hierarchy and view the documents within each folder.",
|
||||||
"opensign-drive-2": "Click the add button to create a new folder or document.",
|
"opensign-drive-2": "Click the add button to create a new folder or document.",
|
||||||
"opensign-drive-3": "Sort your documents by Date or Name using this menu.",
|
"opensign-drive-3": "Sort your documents by Date or Name using this menu.",
|
||||||
@@ -565,9 +575,10 @@
|
|||||||
"pdf-request-file-5": "You can click 'Auto Sign All' to automatically sign at all the locations meant to be signed by you. Make sure that you review the document properly before you click this button .",
|
"pdf-request-file-5": "You can click 'Auto Sign All' to automatically sign at all the locations meant to be signed by you. Make sure that you review the document properly before you click this button .",
|
||||||
"placeholder-sign-1": "Select a recipient from this list to add a place-holder where he is supposed to sign.The placeholder will appear in the same colour as the recipient name once you drop it on the document.",
|
"placeholder-sign-1": "Select a recipient from this list to add a place-holder where he is supposed to sign.The placeholder will appear in the same colour as the recipient name once you drop it on the document.",
|
||||||
"placeholder-sign-2": "Clicking 'Add recipients' button will allow you to add more signers.",
|
"placeholder-sign-2": "Clicking 'Add recipients' button will allow you to add more signers.",
|
||||||
"placeholder-sign-3": "Drag or click on a field to add it to the document.",
|
"placeholder-sign-3": "Click this button to add more recipients/signers to the document.",
|
||||||
"placeholder-sign-4": "The PDF content area already displays the template's existing placeholders. For your convenience, these placeholders will match the color of the recipient's name, making them easily identifiable.",
|
"placeholder-sign-4": "Drag or click on a field to add it to the document.",
|
||||||
"placeholder-sign-5": "Clicking 'Send' will save the document. In the next step you can customize the emails to be sent out to the recipients or copy the signing links and share those with the recipients yourself.",
|
"placeholder-sign-5": "The PDF content area already displays the template's existing placeholders. For your convenience, these placeholders will match the color of the recipient's name, making them easily identifiable.",
|
||||||
|
"placeholder-sign-6": "Clicking 'Send' will save the document. In the next step you can customize the emails to be sent out to the recipients or copy the signing links and share those with the recipients yourself.",
|
||||||
"report-1": "Click the 'Add' button to create a new template. Templates are reusable documents designed to quickly generate new documents with the same structure and varying signers. For example, an HR template for onboarding could have predefined roles like ‘HR Manager’ and ‘New Employee’. Each time you use the template, you can assign the ‘New Employee’ role to different incoming staff members, while the ‘HR Manager’ role remains constant, facilitating a seamless onboarding process for each recruit. ",
|
"report-1": "Click the 'Add' button to create a new template. Templates are reusable documents designed to quickly generate new documents with the same structure and varying signers. For example, an HR template for onboarding could have predefined roles like ‘HR Manager’ and ‘New Employee’. Each time you use the template, you can assign the ‘New Employee’ role to different incoming staff members, while the ‘HR Manager’ role remains constant, facilitating a seamless onboarding process for each recruit. ",
|
||||||
"redirect": "Click the 'Use' button to create a new document from an existing template.",
|
"redirect": "Click the 'Use' button to create a new document from an existing template.",
|
||||||
"bulksend": "To quickly create and send multiple documents using an existing template, click the 'Quick Send' button.",
|
"bulksend": "To quickly create and send multiple documents using an existing template, click the 'Quick Send' button.",
|
||||||
@@ -584,13 +595,78 @@
|
|||||||
"Out for signatures": "Clicking on this card will take you to a list of documents awaiting signature.",
|
"Out for signatures": "Clicking on this card will take you to a list of documents awaiting signature.",
|
||||||
"Recent signature requests": "This is a list of documents that are waiting for your signature.",
|
"Recent signature requests": "This is a list of documents that are waiting for your signature.",
|
||||||
"Recently sent for signatures": "This is a list of documents you've sent to other parties for signature.",
|
"Recently sent for signatures": "This is a list of documents you've sent to other parties for signature.",
|
||||||
"Drafts": "This are documents you have started but have not finalized for sending."
|
"Drafts": "This are documents you have started but have not finalized for sending.",
|
||||||
},
|
"public-template": "This video demonstrates how to set up your personalized public profile, such as ‘https://opensign.me/your-username’. You’ll also learn how to customize your tagline and make your templates available for public signing."
|
||||||
|
},
|
||||||
"enter-email-plaholder": "Add an email address and hit enter",
|
"enter-email-plaholder": "Add an email address and hit enter",
|
||||||
"success-email-alert": "Email sent successfully!",
|
"success-email-alert": "Email sent successfully!",
|
||||||
"expired-doc-title": "Expired Document",
|
"expired-doc-title": "Expired Document",
|
||||||
"expired-on-mssg": "This document expired on {{expiredDate}} and is no longer available to sign.",
|
"expired-on-mssg": "This document expired on {{expiredDate}} and is no longer available to sign.",
|
||||||
"signature-validate-alert": "Please confirm that you have selected at least {{minRequiredCount}} checkboxes.",
|
"signature-validate-alert": "Please confirm that you have selected at least {{minRequiredCount}} checkboxes.",
|
||||||
"signature-validate-alert-2": "Ensure this field is accurately filled and meets all requirements.",
|
"signature-validate-alert-2": "Ensure this field is accurately filled and meets all requirements.",
|
||||||
"user-name-exist": "user name already exist"
|
"remaing-users": "Remaining users",
|
||||||
|
"Role": "Role",
|
||||||
|
"additional-users": "Please purchase add-on users.",
|
||||||
|
"Quantity-of-users": "Quantity of users",
|
||||||
|
"Price": "Price",
|
||||||
|
"Total-price-for-next-time": "Total price for next time",
|
||||||
|
"Proceed": "Proceed",
|
||||||
|
"Select": "Select",
|
||||||
|
"Add-seats": "Add Seats",
|
||||||
|
"user-name-exist": "user name already exist",
|
||||||
|
"format": "format",
|
||||||
|
"select-date-format": "Select a date format",
|
||||||
|
"quantity-of-credits": "Quantity of premium credits",
|
||||||
|
"remaining-credits": "Premium credits available:",
|
||||||
|
"remaining-credits-help":"Use premium credits for API document signing, bulk sending, or embedding OpenSign integration on your website. You have {{allowedcredits}} included credits and {{addoncredits}} additional purchased credits remaining.",
|
||||||
|
"additional-credits": "Please purchase premium credits",
|
||||||
|
"quota-err-quicksend": "Quota Reached, You don't have enough credits.",
|
||||||
|
"buy-credits": "Buy Premium Credits",
|
||||||
|
"rotate-right":"Rotate right",
|
||||||
|
"rotate-left":"Rotate left",
|
||||||
|
"rotate-alert-mssg":"All widgets on this page will be lost. Are you sure you want to proceed?",
|
||||||
|
"templateid":"Template-Id",
|
||||||
|
"bulk-send-subcription-alert":"Please upgrade to Professional or Team plan to use bulk send.",
|
||||||
|
"generate-test-token":"Generate Test Token",
|
||||||
|
"regenerate-test-token":"Regenerate Test Token",
|
||||||
|
"help-test-token":"This token can be used to test the APIs at the https://sandbox.opensignlabs.com/api/v1 endpoint, allowing you to conduct unlimited document signatures. Please note that the sandbox API will sign your documents with self-signed certificates, which may not be recognized as valid by Adobe. Once you’ve completed your testing, you can upgrade to one of our paid plans to generate a production token.",
|
||||||
|
"help-api-token":"This token can be used to access the production APIs at the {{origin}}/api/v1 endpoint. It can only be generated on one of our paid plans.",
|
||||||
|
"reason":"Reason",
|
||||||
|
"decline-by":"Declined/revoked by",
|
||||||
|
"document-declined": "Document declined",
|
||||||
|
"public-template-mssg-1":"To integrate OpenSign into your React or Next.js project, simply run the following command:",
|
||||||
|
"public-template-mssg-2" :"Ensure you have npm or yarn set up in your project. If you’re using Yarn, you can replace npm install with yarn add @opensign/react.",
|
||||||
|
"public-template-mssg-3" :"Need more details or examples?",
|
||||||
|
"public-template-mssg-4": "Visit the",
|
||||||
|
"public-template-mssg-5": " npm for the latest updates, detailed documentation, and version history.",
|
||||||
|
"public-template-mssg-6" :"You need to set this template as public before you can utilize this code snippet.",
|
||||||
|
"copy-code":"COPY",
|
||||||
|
"copied-code":"COPIED",
|
||||||
|
"Installation":"Installation",
|
||||||
|
"Usage" :"Usage",
|
||||||
|
"insufficient-credits":"Insufficient Signing Credits",
|
||||||
|
"insufficient-credits-mssg":"The owner of this document currently lacks the necessary OpenSign credits for you to sign. Please reach out to the owner if you require further details.",
|
||||||
|
"angular-npm-mssg-1": "To integrate OpenSign into your Angular project, simply run the following command:",
|
||||||
|
"quota-mail-info-head":"Monthly request signatures email limit",
|
||||||
|
"quota-mail-info": "You can send upto 15 signature request emails every month. Upgrade now to send unlimited signing requests directly.",
|
||||||
|
"quota-mail": "You've reached your limit of 15 signature request emails for this month. Upgrade now to continue sending emails directly.",
|
||||||
|
"quota-mail-tip":"Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.",
|
||||||
|
"quota-mail-head":"Quota Reached",
|
||||||
|
"unauthorized-modal":"You don't have permission to perform this action, please contact {{adminEmail}}.",
|
||||||
|
"sent-this-month":"Sent this month",
|
||||||
|
"available-seats":"Available seats",
|
||||||
|
"buy-users":"Buy more users",
|
||||||
|
"isenable-otp": "Enable OTP verification",
|
||||||
|
"isenable-otp-help": {
|
||||||
|
"p1": "Would you like to enable the verification process using a one-time password (OTP)?",
|
||||||
|
"p2": "Selecting this option will enable OTP verification. Users will receive a verification code via email, which they must enter to sign the document.",
|
||||||
|
"p3": "Selecting this option will disable OTP verification, allowing users to sign the document directly without additional steps.",
|
||||||
|
"p4": "Please choose the option that best suits your document signing requirements."
|
||||||
|
},
|
||||||
|
"advanced-options":"Advanced options",
|
||||||
|
"hide-advanced-options":"Hide Advanced options",
|
||||||
|
"download-files":"Download files",
|
||||||
|
"download-pdf":"Download Pdf",
|
||||||
|
"pdf-certificate":"Download Pdf + Certificate",
|
||||||
|
"document-logs":"Document logs"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"header-news": "Nouvelle fonctionnalité : les profils publics sont désormais en ligne ! Créez et partagez facilement des modèles publics",
|
||||||
|
"header-news-btn": "Configurer maintenant",
|
||||||
"create-account": "Créer un compte",
|
"create-account": "Créer un compte",
|
||||||
"login": "Se Connecter",
|
"login": "Se Connecter",
|
||||||
"language": "Langue",
|
"language": "Langue",
|
||||||
"name": "Nom et Prénom",
|
"name": "Nom et Prénom",
|
||||||
"phone": "Téléphone",
|
"phone": "Téléphone",
|
||||||
|
"phone-optional": "(facultatif)",
|
||||||
"email": "E-mail",
|
"email": "E-mail",
|
||||||
"company": "Organisation",
|
"company": "Organisation",
|
||||||
"job-title": "Votre Fonction",
|
"job-title": "Votre Fonction",
|
||||||
@@ -39,10 +42,11 @@
|
|||||||
"upgrade-to": "Mettre à niveau vers",
|
"upgrade-to": "Mettre à niveau vers",
|
||||||
"pro": "PRO",
|
"pro": "PRO",
|
||||||
"plan": "Offre",
|
"plan": "Offre",
|
||||||
"subscribe-card-plan": "Signez 100 documents à l'aide de l'API. Seulement 0,15 $/doc par la suite.",
|
"subscribe-card-teamplan":"Libérez toute la puissance de la collaboration ! Créez un nombre illimité d'organisations, d'équipes et de hiérarchies. Partagez des modèles de manière transparente entre les équipes et attribuez des rôles d'utilisateur personnalisés. Améliorez votre flux de travail dès aujourd'hui !",
|
||||||
|
"subscribe-card-plan": "Débloquez des fonctionnalités premium à partir de seulement {{premiumPrice}}/mois. Bénéficiez de performances améliorées et de seulement {{addonPrice}} par crédit supplémentaire après vos crédits premium inclus.",
|
||||||
"user-name-limit-char": "Pour avoir un nom d'utilisateur de moins de 8 caractères s'il vous plaît s'abonner",
|
"user-name-limit-char": "Pour avoir un nom d'utilisateur de moins de 8 caractères s'il vous plaît s'abonner",
|
||||||
"tour-content": "Ne plus afficher",
|
"tour-content": "Ne plus afficher",
|
||||||
"team": "ÉQUIPE",
|
"team": "Équipe",
|
||||||
"docs": "Documents",
|
"docs": "Documents",
|
||||||
"session-expired": "Votre session a expiré.",
|
"session-expired": "Votre session a expiré.",
|
||||||
"user": "Utilisateur",
|
"user": "Utilisateur",
|
||||||
@@ -91,6 +95,7 @@
|
|||||||
"API Token": "Jeton API",
|
"API Token": "Jeton API",
|
||||||
"Webhook": "Webhook",
|
"Webhook": "Webhook",
|
||||||
"Teams": "Équipe",
|
"Teams": "Équipe",
|
||||||
|
"Team-update-successfully": "Équipe mise à jour avec succès.",
|
||||||
"Users": "Utilisateurs"
|
"Users": "Utilisateurs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -131,7 +136,8 @@
|
|||||||
"Name": "Nom",
|
"Name": "Nom",
|
||||||
"Status": "Statut",
|
"Status": "Statut",
|
||||||
"created-date": "Date de création",
|
"created-date": "Date de création",
|
||||||
"Type": "Saisir"
|
"Type": "Saisir",
|
||||||
|
"Logs": "Journaux"
|
||||||
},
|
},
|
||||||
"btnLabel": {
|
"btnLabel": {
|
||||||
"sign": "Signer",
|
"sign": "Signer",
|
||||||
@@ -144,7 +150,9 @@
|
|||||||
"Share with team": "Partager avec l'équipe",
|
"Share with team": "Partager avec l'équipe",
|
||||||
"Share": "Partager",
|
"Share": "Partager",
|
||||||
"View": "Voir",
|
"View": "Voir",
|
||||||
"option": "Option"
|
"option": "Option",
|
||||||
|
"Embed": "Intégrer",
|
||||||
|
"Copy TemplateId": "Copier l'ID du modèle"
|
||||||
},
|
},
|
||||||
"report-help": {
|
"report-help": {
|
||||||
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
|
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
|
||||||
@@ -197,7 +205,7 @@
|
|||||||
"parent-folder": "Dossier Parent",
|
"parent-folder": "Dossier Parent",
|
||||||
"create": "Créer",
|
"create": "Créer",
|
||||||
"signers": "Signataires",
|
"signers": "Signataires",
|
||||||
"signers-help": "Commencez à saisir le nom d'un contact pour voir les signataires suggérés par vos contacts enregistrés ou en ajouter de nouveaux. Organisez l'ordre de signature en ajoutant des signataires dans l'ordre souhaité. Utilisez le bouton « + » pour inclure les signataires et le « x » pour les supprimer. Chaque signataire recevra un e-mail invité à signer le document dans l'ordre indiqué.",
|
"signers-help": "Commencez à saisir le nom d'un contact pour voir les signataires suggérés par vos contacts enregistrés ou en ajouter de nouveaux. Organisez l'ordre de signature en ajoutant des signataires dans l'ordre souhaité. Utilisez le bouton « + » pour inclure les signataires et le « x » pour les supprimer. Chaque signataire recevra un e-mail invité à signer le document dans l'ordre indiqué.",
|
||||||
"add-signer": "Ajouter un signataire",
|
"add-signer": "Ajouter un signataire",
|
||||||
"contact-not-found": "Contact introuvable",
|
"contact-not-found": "Contact introuvable",
|
||||||
"add-yourself": "Ajoutez-vous",
|
"add-yourself": "Ajoutez-vous",
|
||||||
@@ -211,8 +219,8 @@
|
|||||||
"initials": "Initiales",
|
"initials": "Initiales",
|
||||||
"API": "API",
|
"API": "API",
|
||||||
"api-token": "Jeton API",
|
"api-token": "Jeton API",
|
||||||
"regenerate-token": "Régénérer le jeton",
|
"regenerate-token": "Régénérer en direct jeton",
|
||||||
"generate-token": "Générer un jeton",
|
"generate-token": "Générer en direct jeton",
|
||||||
"view-docs": "Afficher les documents",
|
"view-docs": "Afficher les documents",
|
||||||
"generate-token-alert": "Êtes-vous sûr de vouloir régénérer le jeton, votre ancien jeton sera supprimer?",
|
"generate-token-alert": "Êtes-vous sûr de vouloir régénérer le jeton, votre ancien jeton sera supprimer?",
|
||||||
"yes": "Oui",
|
"yes": "Oui",
|
||||||
@@ -252,11 +260,12 @@
|
|||||||
"view": "voir",
|
"view": "voir",
|
||||||
"make-template-public": "Rendre le modèle public",
|
"make-template-public": "Rendre le modèle public",
|
||||||
"make-template-private": "Rendre le modèle privé",
|
"make-template-private": "Rendre le modèle privé",
|
||||||
"make-template-public-alert": "Êtes-vous sûr de vouloir rendre ce modèle public ?",
|
"make-template-public-alert": "Êtes-vous sûr de vouloir rendre ce modèle public ?",
|
||||||
"make-template-private-alert": "Êtes-vous sûr de vouloir rendre ce modèle privé ? Cela le supprimera de votre profil public.",
|
"make-template-private-alert": "Êtes-vous sûr de vouloir rendre ce modèle privé ? Cela le supprimera de votre profil public.",
|
||||||
"public-role": "Rôle public",
|
"public-role": "Rôle public",
|
||||||
"public-url": "URL publique",
|
"public-url": "URL publique",
|
||||||
"public-url-copy-mssg": "Voici votre URL publique : copiez-la ou partagez-le avec le signataire et vous pouvoir voir tous vos paramètres publics modèles.",
|
"public-url-copy": "Voici votre URL publique : ",
|
||||||
|
"public-url-copy-mssg": "copiez-la ou partagez-le avec le signataire et vous pouvoir voir tous vos paramètres publics modèles.",
|
||||||
"add-public-url-alert": "Veuillez ajouter votre URL publique et vous pourra rendre public modèle.",
|
"add-public-url-alert": "Veuillez ajouter votre URL publique et vous pourra rendre public modèle.",
|
||||||
"share-with-alert": "Vous ne pouvez pas partager un modèle si des contacts sont déjà attribués à des rôles. Veuillez supprimer toutes les attributions de contacts des rôles avant de partager le modèle.",
|
"share-with-alert": "Vous ne pouvez pas partager un modèle si des contacts sont déjà attribués à des rôles. Veuillez supprimer toutes les attributions de contacts des rôles avant de partager le modèle.",
|
||||||
"share-with": "Partager avec",
|
"share-with": "Partager avec",
|
||||||
@@ -274,14 +283,14 @@
|
|||||||
"copy-link": "Copier le lien",
|
"copy-link": "Copier le lien",
|
||||||
"copy": "Copier",
|
"copy": "Copier",
|
||||||
"revoke-document": "Révoquer le document",
|
"revoke-document": "Révoquer le document",
|
||||||
"revoke-document-alert": "Êtes-vous sûr de vouloir révoquer ce document ?",
|
"revoke-document-alert": "Êtes-vous sûr de vouloir révoquer ce document ?",
|
||||||
"resend-mail": "Renvoyer le courrier",
|
"resend-mail": "Renvoyer le courrier",
|
||||||
"resend-mail-help": "Vous pouvez utiliser les variables suivantes qui seront remplacées par leurs valeurs réelles : - {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email} }, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}.",
|
"resend-mail-help": "Vous pouvez utiliser les variables suivantes qui seront remplacées par leurs valeurs réelles : - {{document_title}}, {{sender_name}}, {{sender_mail}}, {{sender_phone}}, {{receiver_name}}, {{receiver_email} }, {{receiver_phone}}, {{expiry_date}}, {{company_name}}, {{signing_url}}.",
|
||||||
"subject": "Sujet",
|
"subject": "Sujet",
|
||||||
"body": "Corps",
|
"body": "Corps",
|
||||||
"add-contact": "Ajouter le contact",
|
"add-contact": "Ajouter le contact",
|
||||||
"add-signer-alert": "Le contact existe déjà !",
|
"add-signer-alert": "Le contact existe déjà !",
|
||||||
"record-delete-alert": "Enregistrement supprimé avec succès !",
|
"record-delete-alert": "Enregistrement supprimé avec succès !",
|
||||||
"record-revoke-alert": " Enregistrement révoqué avec succès ! ",
|
"record-revoke-alert": " Enregistrement révoqué avec succès ! ",
|
||||||
"mail-sent-alert": "Courriel envoyé avec succès.",
|
"mail-sent-alert": "Courriel envoyé avec succès.",
|
||||||
"document-sent-alert": "Document envoyé avec succès !",
|
"document-sent-alert": "Document envoyé avec succès !",
|
||||||
@@ -307,7 +316,7 @@
|
|||||||
"contact-details": "Coordonnées",
|
"contact-details": "Coordonnées",
|
||||||
"verify-email": "Veuillez vérifier votre email!",
|
"verify-email": "Veuillez vérifier votre email!",
|
||||||
"send-otp": "envoyer un code à usage unique",
|
"send-otp": "envoyer un code à usage unique",
|
||||||
"otp-placeholder": "Saisissez l'OTP reçu par e-mail",
|
"otp-placeholder": "Entrez le code de vérification reçu par e-mail",
|
||||||
"loading-doc": "Chargement du document..",
|
"loading-doc": "Chargement du document..",
|
||||||
"widgets-name": {
|
"widgets-name": {
|
||||||
"signature": "signature",
|
"signature": "signature",
|
||||||
@@ -337,7 +346,7 @@
|
|||||||
"finish": "terminé",
|
"finish": "terminé",
|
||||||
"mail": "Mail",
|
"mail": "Mail",
|
||||||
"sign-now": "Signez maintenant",
|
"sign-now": "Signez maintenant",
|
||||||
"successfully-signed": "Signé avec succès !",
|
"successfully-signed": "Signé avec succès !",
|
||||||
"email-mssg": "Les destinataires ajoutés ici recevront une copie du document signé.",
|
"email-mssg": "Les destinataires ajoutés ici recevront une copie du document signé.",
|
||||||
"email-error-1": "veuillez fournir une adresse e-mail correcte",
|
"email-error-1": "veuillez fournir une adresse e-mail correcte",
|
||||||
"email-error-2": "Vous ne pouvez envoyer qu'à dix destinataires à la fois.",
|
"email-error-2": "Vous ne pouvez envoyer qu'à dix destinataires à la fois.",
|
||||||
@@ -357,8 +366,8 @@
|
|||||||
"initial-teb": "Initiales",
|
"initial-teb": "Initiales",
|
||||||
"signature-tab": "Signature",
|
"signature-tab": "Signature",
|
||||||
"your-signature": "Votre signature",
|
"your-signature": "Votre signature",
|
||||||
"copy-to-all-pages": "Copier sur toutes les pages",
|
"copy-title": "Copier le widget vers",
|
||||||
"contact-delete-alert": "Êtes-vous sûr de vouloir supprimer ce contact ?",
|
"contact-delete-alert": "Êtes-vous sûr de vouloir supprimer ce contact ?",
|
||||||
"reset-password": "Le lien de réinitialisation du mot de passe a été envoyé à votre identifiant de messagerie",
|
"reset-password": "Le lien de réinitialisation du mot de passe a été envoyé à votre identifiant de messagerie",
|
||||||
"reset-password-alert-2": "Veuillez configurer l'adaptateur de messagerie",
|
"reset-password-alert-2": "Veuillez configurer l'adaptateur de messagerie",
|
||||||
"reset-password-alert-3": "Réinitialisez votre mot de passe",
|
"reset-password-alert-3": "Réinitialisez votre mot de passe",
|
||||||
@@ -367,7 +376,8 @@
|
|||||||
"copy-type": {
|
"copy-type": {
|
||||||
"All pages": "Toutes les pages",
|
"All pages": "Toutes les pages",
|
||||||
"All pages but last": "Toutes les pages sauf la dernière",
|
"All pages but last": "Toutes les pages sauf la dernière",
|
||||||
"All pages but first": "Toutes les pages sauf la première"
|
"All pages but first": "Toutes les pages sauf la première",
|
||||||
|
"Next to current widget": "À côté du widget actuel"
|
||||||
},
|
},
|
||||||
"options": "Possibilités",
|
"options": "Possibilités",
|
||||||
"minimun-check": "Vérification minimale",
|
"minimun-check": "Vérification minimale",
|
||||||
@@ -393,7 +403,7 @@
|
|||||||
"create-document": "Créer un document",
|
"create-document": "Créer un document",
|
||||||
"template-created-alert": "Voulez-vous créer un document en utilisant le modèle que vous vient de créer ?",
|
"template-created-alert": "Voulez-vous créer un document en utilisant le modèle que vous vient de créer ?",
|
||||||
"signers-alert": "alerte des signataires",
|
"signers-alert": "alerte des signataires",
|
||||||
"template-creation-alert-1": "Veuillez sélectionner le signataire pour ajouter un espace réservé !",
|
"template-creation-alert-1": "Veuillez sélectionner le signataire pour ajouter un espace réservé !",
|
||||||
"ok": "D'accord",
|
"ok": "D'accord",
|
||||||
"radio-group": "Groupe de radio",
|
"radio-group": "Groupe de radio",
|
||||||
"dropdown-options": "Options déroulantes",
|
"dropdown-options": "Options déroulantes",
|
||||||
@@ -409,9 +419,9 @@
|
|||||||
"hint": "Indice",
|
"hint": "Indice",
|
||||||
"color": "couleur",
|
"color": "couleur",
|
||||||
"role-help": {
|
"role-help": {
|
||||||
"p1": "Que sont les rôles modèles ?",
|
"p1": "Que sont les rôles modèles ?",
|
||||||
"p2": "Commencez par spécifier chaque rôle nécessaire à la finalisation du document. Pensez aux parties impliquées dans le processus de signature et à leurs responsabilités. Les rôles courants incluent les RH pour les documents internes, le Client pour les accords ou le Fournisseur pour les accords commerciaux.",
|
"p2": "Commencez par spécifier chaque rôle nécessaire à la finalisation du document. Pensez aux parties impliquées dans le processus de signature et à leurs responsabilités. Les rôles courants incluent les RH pour les documents internes, le Client pour les accords ou le Fournisseur pour les accords commerciaux.",
|
||||||
"p3": "Pourquoi pré-attacher les utilisateurs à certains rôles ?",
|
"p3": "Pourquoi pré-attacher les utilisateurs à certains rôles ?",
|
||||||
"p4": "Pour les rôles qui impliquent systématiquement la même personne (par exemple, la signature du PDG sur les lettres d'offre des employés), vous pouvez pré-attacher un utilisateur à un rôle dans le modèle. Cette étape est facultative mais recommandée pour des raisons d'efficacité et de cohérence entre les documents.",
|
"p4": "Pour les rôles qui impliquent systématiquement la même personne (par exemple, la signature du PDG sur les lettres d'offre des employés), vous pouvez pré-attacher un utilisateur à un rôle dans le modèle. Cette étape est facultative mais recommandée pour des raisons d'efficacité et de cohérence entre les documents.",
|
||||||
"p5": "Quand dois-je spécifier l'utilisateur attaché à chaque rôle ?",
|
"p5": "Quand dois-je spécifier l'utilisateur attaché à chaque rôle ?",
|
||||||
"p6": "Lorsque vous créez un document à partir de votre modèle, vous serez invité à attacher des utilisateurs à chaque rôle défini. Si un rôle est déjà associé à un utilisateur, celui-ci sera pré-rempli, mais vous pourrez le modifier si nécessaire avant d'envoyer le document."
|
"p6": "Lorsque vous créez un document à partir de votre modèle, vous serez invité à attacher des utilisateurs à chaque rôle défini. Si un rôle est déjà associé à un utilisateur, celui-ci sera pré-rempli, mais vous pourrez le modifier si nécessaire avant d'envoyer le document."
|
||||||
@@ -424,8 +434,8 @@
|
|||||||
"placeholder-alert-3": "Etes-vous sûr de vouloir envoyer ce document pour signature ? ",
|
"placeholder-alert-3": "Etes-vous sûr de vouloir envoyer ce document pour signature ? ",
|
||||||
"placeholder-alert-4": "Vous avez envoyé avec succès des mails à tous les",
|
"placeholder-alert-4": "Vous avez envoyé avec succès des mails à tous les",
|
||||||
"placeholder-alert-5": "Voulez-vous signer des documents maintenant ?",
|
"placeholder-alert-5": "Voulez-vous signer des documents maintenant ?",
|
||||||
"placeholder-alert-6": "Veuillez configurer l'adaptateur de messagerie pour envoyer du courrier !",
|
"placeholder-alert-6": "Veuillez configurer l'adaptateur de messagerie pour envoyer du courrier !",
|
||||||
"placeholder-alert-7": "Veuillez sélectionner le signataire pour ajouter un espace réservé !",
|
"placeholder-alert-7": "Veuillez sélectionner le signataire pour ajouter un espace réservé !",
|
||||||
"email-subject": "Sujet du courriel",
|
"email-subject": "Sujet du courriel",
|
||||||
"email-body": "corps de l'e-mail",
|
"email-body": "corps de l'e-mail",
|
||||||
"email-placeholder": "Ajouter le corps de l'e-mail",
|
"email-placeholder": "Ajouter le corps de l'e-mail",
|
||||||
@@ -444,14 +454,14 @@
|
|||||||
"decline-alert-3": "Vous ne pouvez pas signer ce document car il a été refusé/révoqué.",
|
"decline-alert-3": "Vous ne pouvez pas signer ce document car il a été refusé/révoqué.",
|
||||||
"sign here": "Signer ici",
|
"sign here": "Signer ici",
|
||||||
"guest-email-alert": "le code de vérification a été envoyé sur votre e-mail",
|
"guest-email-alert": "le code de vérification a été envoyé sur votre e-mail",
|
||||||
"get-otp-alert": "vous recevrez un mot de passe à usage unique par e-mail",
|
"get-otp-alert": "vous recevrez un code de vérification par e-mail",
|
||||||
"user-already-exist": "L'utilisateur existe déjà.",
|
"user-already-exist": "L'utilisateur existe déjà.",
|
||||||
"server-error": "Erreur interne du serveur !",
|
"server-error": "Erreur interne du serveur !",
|
||||||
"fill-required-details!": "Veuillez remplir les informations requises !",
|
"fill-required-details!": "Veuillez remplir les informations requises !",
|
||||||
"sign-up-form": "Formulaire d'inscription",
|
"sign-up-form": "Formulaire d'inscription",
|
||||||
"sign-up": "S'inscrire",
|
"sign-up": "S'inscrire",
|
||||||
"folder-already-exist!": "le dossier existe déjà !",
|
"folder-already-exist!": "le dossier existe déjà !",
|
||||||
"please-select-position!": "Veuillez sélectionner un poste !",
|
"please-select-position!": "Veuillez sélectionner un poste !",
|
||||||
"default-sign-alert": "Êtes-vous sûr de vouloir vous connecter automatiquement à tous les emplacements demandés ? ",
|
"default-sign-alert": "Êtes-vous sûr de vouloir vous connecter automatiquement à tous les emplacements demandés ? ",
|
||||||
"Your-Signature": "Votre signature",
|
"Your-Signature": "Votre signature",
|
||||||
"auto-sign-all": "Tout signer automatiquement",
|
"auto-sign-all": "Tout signer automatiquement",
|
||||||
@@ -459,15 +469,15 @@
|
|||||||
"pdf-download": "Téléchargement PDF",
|
"pdf-download": "Téléchargement PDF",
|
||||||
"generate-certificate-alert": " Votre certificat d'achèvement est en cours de génération. Veuillez patienter quelques instants. Si le téléchargement ne démarre pas sous peu, cliquez à nouveau sur le bouton. ",
|
"generate-certificate-alert": " Votre certificat d'achèvement est en cours de génération. Veuillez patienter quelques instants. Si le téléchargement ne démarre pas sous peu, cliquez à nouveau sur le bouton. ",
|
||||||
"folder-already-exist": "Le dossier existe déjà !",
|
"folder-already-exist": "Le dossier existe déjà !",
|
||||||
"folder-created-successfully": "Dossier créé avec succès !",
|
"folder-created-successfully": "Dossier créé avec succès !",
|
||||||
"fill-folder-name": "Veuillez indiquer le nom du dossier",
|
"fill-folder-name": "Veuillez indiquer le nom du dossier",
|
||||||
"already-exists-this-username": "Un utilisateur existe déjà avec ce nom d'utilisateur !",
|
"already-exists-this-username": "Un utilisateur existe déjà avec ce nom d'utilisateur !",
|
||||||
"verification-code-sent": "Un e-mail de vérification a été envoyé à votre adresse e-mail !",
|
"verification-code-sent": "Un e-mail de vérification a été envoyé à votre adresse e-mail !",
|
||||||
"registered-user-successfully": "Utilisateur enregistré avec succès.",
|
"registered-user-successfully": "Utilisateur enregistré avec succès.",
|
||||||
"role-not-found": "Rôle introuvable.",
|
"role-not-found": "Rôle introuvable.",
|
||||||
"do-not-access": "Vous n'y avez pas accès, veuillez contacter l'administrateur.",
|
"do-not-access": "Vous n'y avez pas accès, veuillez contacter l'administrateur.",
|
||||||
"add-admin": "Ajouter un administrateur",
|
"add-admin": "Ajouter un administrateur",
|
||||||
"opensign-setup": "Configuration d'Opensign",
|
"opensign-setup": "Configuration d'OpenSign",
|
||||||
"join-discord": "Rejoignez notre serveur Discord",
|
"join-discord": "Rejoignez notre serveur Discord",
|
||||||
"admin-already-exist": "L'administrateur existe déjà.",
|
"admin-already-exist": "L'administrateur existe déjà.",
|
||||||
"password-update-alert-1": "Mot de passe mis à jour avec succès.",
|
"password-update-alert-1": "Mot de passe mis à jour avec succès.",
|
||||||
@@ -511,19 +521,19 @@
|
|||||||
"choose-password": "Choisissez un mot de passe",
|
"choose-password": "Choisissez un mot de passe",
|
||||||
"enter-password": "Entrer le mot de passe",
|
"enter-password": "Entrer le mot de passe",
|
||||||
"sure": "bien sûr",
|
"sure": "bien sûr",
|
||||||
"subscribed-alert": "Vous êtes déjà abonné au forfait !",
|
"subscribed-alert": "Vous êtes déjà abonné au forfait !",
|
||||||
"monthly": "Mensuel",
|
"monthly": "Mensuel",
|
||||||
"yearly-upto": "Annuel (jusqu'à 66 % de réduction)",
|
"yearly-upto": "Annuel (jusqu'à 66 % de réduction)",
|
||||||
"billed-yearly": "Facturé annuellement",
|
"billed-yearly": "Facturé annuellement",
|
||||||
"billed-monthly": "Facturé mensuellement",
|
"billed-monthly": "Facturé mensuellement",
|
||||||
"plansubscription-1": "Hébergez-le vous-même gratuitement",
|
"plansubscription-1": "Hébergez-le vous-même gratuitement",
|
||||||
"visit-github": "Visitez Github",
|
"visit-github": "Visitez Github",
|
||||||
"user-already-exist-name": "Un utilisateur existe déjà avec ce nom d'utilisateur !",
|
"user-already-exist-name": "Un utilisateur existe déjà avec ce nom d'utilisateur !",
|
||||||
"do-not-access-contact-admin": "Vous n'y avez pas accès, veuillez contacter l'administrateur.",
|
"do-not-access-contact-admin": "Vous n'y avez pas accès, veuillez contacter l'administrateur.",
|
||||||
"filed-required-correctly": "Veuillez remplir correctement les informations requises.",
|
"filed-required-correctly": "Veuillez remplir correctement les informations requises.",
|
||||||
"admin-created": "Administrateur créé",
|
"admin-created": "Administrateur créé",
|
||||||
"invalid-masterkey": "Clé principale invalide",
|
"invalid-masterkey": "Clé principale invalide",
|
||||||
"opensign-Setup": "Configuration d'Opensign",
|
"opensign-Setup": "Configuration d'OpenSign",
|
||||||
"master-key": "La clef maitresse",
|
"master-key": "La clef maitresse",
|
||||||
"profile-update-alert": "Mise à jour du profil réussie.",
|
"profile-update-alert": "Mise à jour du profil réussie.",
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
@@ -546,10 +556,10 @@
|
|||||||
"discord": "Discorde"
|
"discord": "Discorde"
|
||||||
},
|
},
|
||||||
"tour-mssg": {
|
"tour-mssg": {
|
||||||
"home-layout-1": "Vous vous êtes connecté avec succès ! Jetons un coup d'oeil.",
|
"home-layout-1": "Vous vous êtes connecté avec succès ! Jetons un coup d'oeil.",
|
||||||
"home-layout-2": "Pour télécharger des documents à auto-signature ou pour demander la signature d'autres personnes, sélectionnez simplement les boutons correspondants.",
|
"home-layout-2": "Pour télécharger des documents à auto-signature ou pour demander la signature d'autres personnes, sélectionnez simplement les boutons correspondants.",
|
||||||
"home-layout-3": "Vous êtes prêt à commencer à utiliser OpenSign ! Si vous avez besoin d'aide, n'hésitez pas à nous contacter.",
|
"home-layout-3": "Vous êtes prêt à commencer à utiliser OpenSign ! Si vous avez besoin d'aide, n'hésitez pas à nous contacter.",
|
||||||
"generate-token": "Mettez à niveau maintenant pour générer un jeton API",
|
"generate-token": "Effectuez la mise à niveau maintenant pour générer un jeton API de production.",
|
||||||
"opensign-drive-1": "Cliquez sur les liens du fil d'Ariane pour naviguer facilement dans la hiérarchie des dossiers et afficher les documents dans chaque dossier.",
|
"opensign-drive-1": "Cliquez sur les liens du fil d'Ariane pour naviguer facilement dans la hiérarchie des dossiers et afficher les documents dans chaque dossier.",
|
||||||
"opensign-drive-2": "Cliquez sur le bouton Ajouter pour créer un nouveau dossier ou document.",
|
"opensign-drive-2": "Cliquez sur le bouton Ajouter pour créer un nouveau dossier ou document.",
|
||||||
"opensign-drive-3": "Triez vos documents par date ou par nom à l'aide de ce menu.",
|
"opensign-drive-3": "Triez vos documents par date ou par nom à l'aide de ce menu.",
|
||||||
@@ -564,9 +574,10 @@
|
|||||||
"pdf-request-file-5": "Vous pouvez cliquer sur 'Signer automatiquement tout' pour signer automatiquement à tous les emplacements que vous êtes censé signer. Assurez-vous de lire correctement le document avant de cliquer sur ce bouton.",
|
"pdf-request-file-5": "Vous pouvez cliquer sur 'Signer automatiquement tout' pour signer automatiquement à tous les emplacements que vous êtes censé signer. Assurez-vous de lire correctement le document avant de cliquer sur ce bouton.",
|
||||||
"placeholder-sign-1": "Sélectionnez un destinataire dans cette liste pour ajouter un espace réservé à l'endroit où il est censé signer. L'espace réservé apparaîtra de la même couleur que le nom du destinataire une fois que vous le déposerez sur le document.",
|
"placeholder-sign-1": "Sélectionnez un destinataire dans cette liste pour ajouter un espace réservé à l'endroit où il est censé signer. L'espace réservé apparaîtra de la même couleur que le nom du destinataire une fois que vous le déposerez sur le document.",
|
||||||
"placeholder-sign-2": "Cliquer sur le bouton 'Ajouter des destinataires' vous permettra d'ajouter plus de signataires.",
|
"placeholder-sign-2": "Cliquer sur le bouton 'Ajouter des destinataires' vous permettra d'ajouter plus de signataires.",
|
||||||
"placeholder-sign-3": "Faites glisser ou cliquez sur un champ pour l'ajouter au document.",
|
"placeholder-sign-3": "Cliquez sur ce bouton pour ajouter plus de destinataires/signataires au document",
|
||||||
"placeholder-sign-4": "La zone de contenu PDF affiche déjà les espaces réservés existants du modèle. Pour votre commodité, ces espaces réservés correspondront à la couleur du nom du destinataire, ce qui les rendra facilement identifiables.",
|
"placeholder-sign-4": "Faites glisser ou cliquez sur un champ pour l'ajouter au document.",
|
||||||
"placeholder-sign-5": "Cliquer sur 'Envoyer' enregistrera le document. À l'étape suivante, vous pourrez personnaliser les e-mails à envoyer aux destinataires ou copier les liens de signature et les partager vous-même avec les destinataires.",
|
"placeholder-sign-5": "La zone de contenu PDF affiche déjà les espaces réservés existants du modèle. Pour votre commodité, ces espaces réservés correspondront à la couleur du nom du destinataire, ce qui les rendra facilement identifiables.",
|
||||||
|
"placeholder-sign-6": "Cliquer sur 'Envoyer' enregistrera le document. À l'étape suivante, vous pourrez personnaliser les e-mails à envoyer aux destinataires ou copier les liens de signature et les partager vous-même avec les destinataires.",
|
||||||
"report-1": "Cliquez sur le bouton 'Ajouter' pour créer un nouveau modèle. Les modèles sont des documents réutilisables conçus pour générer rapidement de nouveaux documents avec la même structure et différents signataires. Par exemple, un modèle RH pour l'intégration peut avoir des rôles prédéfinis tels que 'Responsable RH' et ' Nouvel employé'. Chaque fois que vous utilisez le modèle, vous pouvez attribuer le rôle 'Nouvel employé' à différents membres du personnel entrants, tandis que le rôle 'Responsable RH' reste constant, facilitant ainsi un processus d'intégration fluide pour chaque recrue",
|
"report-1": "Cliquez sur le bouton 'Ajouter' pour créer un nouveau modèle. Les modèles sont des documents réutilisables conçus pour générer rapidement de nouveaux documents avec la même structure et différents signataires. Par exemple, un modèle RH pour l'intégration peut avoir des rôles prédéfinis tels que 'Responsable RH' et ' Nouvel employé'. Chaque fois que vous utilisez le modèle, vous pouvez attribuer le rôle 'Nouvel employé' à différents membres du personnel entrants, tandis que le rôle 'Responsable RH' reste constant, facilitant ainsi un processus d'intégration fluide pour chaque recrue",
|
||||||
"redirect": "Cliquez sur le bouton 'Utiliser' pour créer un nouveau document à partir d'un modèle existant.",
|
"redirect": "Cliquez sur le bouton 'Utiliser' pour créer un nouveau document à partir d'un modèle existant.",
|
||||||
"bulksend": "Pour créer et envoyer rapidement plusieurs documents à l'aide d'un modèle existant, cliquez sur le bouton 'Envoi rapide'.",
|
"bulksend": "Pour créer et envoyer rapidement plusieurs documents à l'aide d'un modèle existant, cliquez sur le bouton 'Envoi rapide'.",
|
||||||
@@ -583,7 +594,8 @@
|
|||||||
"Out for signatures": "En cliquant sur cette carte, vous accéderez à une liste de documents en attente de signature.",
|
"Out for signatures": "En cliquant sur cette carte, vous accéderez à une liste de documents en attente de signature.",
|
||||||
"Recent signature requests": "Voici une liste de documents qui attendent votre signature.",
|
"Recent signature requests": "Voici une liste de documents qui attendent votre signature.",
|
||||||
"Recently sent for signatures": "Il s'agit d'une liste de documents que vous avez envoyés à d'autres parties pour signature.",
|
"Recently sent for signatures": "Il s'agit d'une liste de documents que vous avez envoyés à d'autres parties pour signature.",
|
||||||
"Drafts": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi."
|
"Drafts": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
|
||||||
|
"public-template": "Cette vidéo montre comment configurer votre profil public personnalisé, tel que 'https://opensign.me/your-username'. Vous apprendrez également comment personnaliser votre slogan et rendre vos modèles disponibles pour la signature publique."
|
||||||
},
|
},
|
||||||
"enter-email-plaholder": "Ajoutez une adresse email et appuyez sur Entrée",
|
"enter-email-plaholder": "Ajoutez une adresse email et appuyez sur Entrée",
|
||||||
"success-email-alert": "E-mail envoyé avec succès!",
|
"success-email-alert": "E-mail envoyé avec succès!",
|
||||||
@@ -591,5 +603,70 @@
|
|||||||
"expired-on-mssg": "Ce document a expiré le {{expiredDate}} et n'est plus disponible pour signature.",
|
"expired-on-mssg": "Ce document a expiré le {{expiredDate}} et n'est plus disponible pour signature.",
|
||||||
"signature-validate-alert": "Veuillez confirmer que vous avez coché au moins {{minRequiredCount}} cases.",
|
"signature-validate-alert": "Veuillez confirmer que vous avez coché au moins {{minRequiredCount}} cases.",
|
||||||
"signature-validate-alert-2": "Assurez-vous que ce champ est rempli avec précision et répond à toutes les exigences.",
|
"signature-validate-alert-2": "Assurez-vous que ce champ est rempli avec précision et répond à toutes les exigences.",
|
||||||
"user-name-exist": "le nom d'utilisateur existe déjà"
|
"user-name-exist": "le nom d'utilisateur existe déjà",
|
||||||
|
"remaing-users": "Utilisateurs restants",
|
||||||
|
"Role": "Rôle",
|
||||||
|
"additional-users": "Veuillez acheter des utilisateurs supplémentaires.",
|
||||||
|
"Quantity-of-users": "Quantité d'utilisateurs",
|
||||||
|
"Price": "Prix",
|
||||||
|
"Total-price-for-next-time": "Prix total pour la prochaine fois",
|
||||||
|
"Proceed": "Procéder",
|
||||||
|
"Select": "sélectionner",
|
||||||
|
"Add-seats": "Ajouter des sièges",
|
||||||
|
"format": "format",
|
||||||
|
"select-date-format": "Sélectionnez un format de date",
|
||||||
|
"quantity-of-credits":"Quantité de crédits de prime",
|
||||||
|
"remaining-credits":"Crédits premium disponibles :",
|
||||||
|
"additional-credits":"Veuillez acheter des crédits premium",
|
||||||
|
"remaining-credits-help":"Utilisez des crédits premium pour la signature de documents API, l'envoi groupé ou l'intégration d'OpenSign sur votre site Web. Il vous reste {{allowedcredits}} crédits inclus et {{addoncredits}} crédits achetés supplémentaires.",
|
||||||
|
"quota-err-quicksend": "Quota atteint, vous n'avez pas assez de crédits.",
|
||||||
|
"buy-credits": "Acheter des crédits premium",
|
||||||
|
"rotate-right" :"Faire pivoter à droite",
|
||||||
|
"rotate-left" :"Faire pivoter à gauche",
|
||||||
|
"rotate-alert-mssg" :"Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?",
|
||||||
|
"templateid":"ID de modèle",
|
||||||
|
"bulk-send-subcription-alert":"Veuillez passer au forfait Professionnel ou Équipe pour utiliser Quicksend.",
|
||||||
|
"generate-test-token": "Générer jeton de test",
|
||||||
|
"regenerate-test-token":"Régénérer le jeton de test",
|
||||||
|
"help-test-token":"Ce jeton peut être utilisé pour tester les API au niveau du point de terminaison https://sandbox.opensignlabs.com/api/v1, vous permettant ainsi d'effectuer un nombre illimité de signatures de documents. Veuillez noter que l'API sandbox signera vos documents avec des certificats auto-signés, qui peuvent ne pas être reconnus comme valides par Adobe. Une fois vos tests terminés, vous pouvez passer à l’un de nos forfaits payants pour générer un jeton de production.",
|
||||||
|
"help-api-token":"Ce jeton peut être utilisé pour accéder aux API de production au point de terminaison {{origin}}/api/v1. Il ne peut être généré que sur l'un de nos forfaits payants.",
|
||||||
|
"reason" :"Raison",
|
||||||
|
"decline-by" :"Refusé/révoqué par",
|
||||||
|
"document-declined":"document refusé",
|
||||||
|
"public-template-mssg-1" :"Pour intégrer OpenSign dans votre projet React ou Next.js, exécutez simplement la commande suivante :",
|
||||||
|
"public-template-mssg-2" :"Assurez-vous que npm ou Yarn est configuré dans votre projet. Si vous utilisez Yarn, vous pouvez remplacer npm install par Yarn Add @opensign/react.",
|
||||||
|
"public-template-mssg-3" :"Besoin de plus de détails ou d'exemples ?",
|
||||||
|
"public-template-mssg-4": "Visitez le",
|
||||||
|
"public-template-mssg-5": "npm pour les dernières mises à jour, une documentation détaillée et l'historique des versions.",
|
||||||
|
"public-template-mssg-6":"Vous devez définir ce modèle comme public avant de pouvoir utiliser cet extrait de code.",
|
||||||
|
"copy-code":"COPIE",
|
||||||
|
"copied-code":"COPIÉ",
|
||||||
|
"Installation":"Installation",
|
||||||
|
"Usage" :"Usage",
|
||||||
|
"insufficient-credits":"Crédits de signature insuffisants",
|
||||||
|
"insufficient-credits-mssg" :"Le propriétaire de ce document ne dispose actuellement pas des crédits OpenSign nécessaires pour que vous puissiez le signer. Veuillez contacter le propriétaire si vous avez besoin de plus de détails.",
|
||||||
|
"angular-npm-mssg-1" :"Pour intégrer OpenSign dans votre projet Angular, exécutez simplement la commande suivante :",
|
||||||
|
"quota-mail-info-head":"Limite mensuelle d'e-mails de signatures de demandes",
|
||||||
|
"quota-mail-info": "Vous pouvez envoyer jusqu'à 15 e-mails de demande de signature chaque mois. Mettez à niveau maintenant pour envoyer directement des demandes de signature illimitées.",
|
||||||
|
"quota-mail": "Vous avez atteint votre limite de 15 e-mails de demande de signature pour ce mois. Mettez à niveau maintenant pour continuer à envoyer des e-mails directement.",
|
||||||
|
"quota-mail-tip-tip":"Astuce : Vous pouvez toujours signer un nombre <1>illimité de documents</1> en partageant manuellement les liens de demande de signature.",
|
||||||
|
"quota-mail-head":"Quota atteint",
|
||||||
|
"unauthorized-modal":"Vous n'êtes pas autorisé à effectuer cette action, veuillez contacter {{adminEmail}}.",
|
||||||
|
"sent-this-month":"envoyé ce mois-ci",
|
||||||
|
"available-seats":"Disponible sièges",
|
||||||
|
"buy-users":"Acheter plus d'utilisateurs",
|
||||||
|
"isenable-otp": "Activer la vérification OTP",
|
||||||
|
"isenable-otp-help": {
|
||||||
|
"p1": "Souhaitez-vous activer le processus de vérification à l'aide d'un mot de passe à usage unique (OTP)?",
|
||||||
|
"p2": "La sélection de cette option activera la vérification OTP. Les utilisateurs recevront un code de vérification par e-mail, qu'ils devront saisir pour signer le document.",
|
||||||
|
"p3": "La sélection de cette option désactivera la vérification OTP, permettant aux utilisateurs de signer le document directement sans étapes supplémentaires.",
|
||||||
|
"p4": "Veuillez choisir l'option qui correspond le mieux à vos exigences en matière de signature de documents."
|
||||||
|
},
|
||||||
|
"advanced-options":"Options avancées",
|
||||||
|
"hide-advanced-options": "Masquer les options avancées",
|
||||||
|
"download-files" :"Télécharger des fichiers",
|
||||||
|
"download-pdf" :"Télécharger le PDF",
|
||||||
|
"pdf-certificate" :"Télécharger Pdf + Certificat",
|
||||||
|
"document-logs":"Journaux de documents"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import dotenv from 'dotenv';
|
|||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
export const cloudServerUrl = 'http://localhost:8080/app';
|
export const cloudServerUrl = 'http://localhost:8080/app';
|
||||||
|
export const appName = process.env.APP_NAME || 'OpenSign™';
|
||||||
export function customAPIurl() {
|
export function customAPIurl() {
|
||||||
const url = new URL(cloudServerUrl);
|
const url = new URL(cloudServerUrl);
|
||||||
return url.pathname === '/api/app' ? url.origin + '/api' : url.origin;
|
return url.pathname === '/api/app' ? url.origin + '/api' : url.origin;
|
||||||
@@ -42,36 +43,38 @@ export function replaceMailVaribles(subject, body, variables) {
|
|||||||
export const saveFileUsage = async (size, fileUrl, userId) => {
|
export const saveFileUsage = async (size, fileUrl, userId) => {
|
||||||
//checking server url and save file's size
|
//checking server url and save file's size
|
||||||
try {
|
try {
|
||||||
const tenantQuery = new Parse.Query('partners_Tenant');
|
if (userId) {
|
||||||
tenantQuery.equalTo('UserId', {
|
const tenantQuery = new Parse.Query('partners_Tenant');
|
||||||
__type: 'Pointer',
|
tenantQuery.equalTo('UserId', {
|
||||||
className: '_User',
|
__type: 'Pointer',
|
||||||
objectId: userId,
|
className: '_User',
|
||||||
});
|
objectId: userId,
|
||||||
const tenant = await tenantQuery.first();
|
});
|
||||||
if (tenant) {
|
const tenant = await tenantQuery.first();
|
||||||
const tenantPtr = { __type: 'Pointer', className: 'partners_Tenant', objectId: tenant.id };
|
if (tenant) {
|
||||||
try {
|
const tenantPtr = { __type: 'Pointer', className: 'partners_Tenant', objectId: tenant.id };
|
||||||
const tenantCredits = new Parse.Query('partners_TenantCredits');
|
try {
|
||||||
tenantCredits.equalTo('PartnersTenant', tenantPtr);
|
const tenantCredits = new Parse.Query('partners_TenantCredits');
|
||||||
const res = await tenantCredits.first({ useMasterKey: true });
|
tenantCredits.equalTo('PartnersTenant', tenantPtr);
|
||||||
if (res) {
|
const res = await tenantCredits.first({ useMasterKey: true });
|
||||||
const response = JSON.parse(JSON.stringify(res));
|
if (res) {
|
||||||
const usedStorage = response?.usedStorage ? response.usedStorage + size : size;
|
const response = JSON.parse(JSON.stringify(res));
|
||||||
const updateCredit = new Parse.Object('partners_TenantCredits');
|
const usedStorage = response?.usedStorage ? response.usedStorage + size : size;
|
||||||
updateCredit.id = res.id;
|
const updateCredit = new Parse.Object('partners_TenantCredits');
|
||||||
updateCredit.set('usedStorage', usedStorage);
|
updateCredit.id = res.id;
|
||||||
await updateCredit.save(null, { useMasterKey: true });
|
updateCredit.set('usedStorage', usedStorage);
|
||||||
} else {
|
await updateCredit.save(null, { useMasterKey: true });
|
||||||
const newCredit = new Parse.Object('partners_TenantCredits');
|
} else {
|
||||||
newCredit.set('usedStorage', size);
|
const newCredit = new Parse.Object('partners_TenantCredits');
|
||||||
newCredit.set('PartnersTenant', tenantPtr);
|
newCredit.set('usedStorage', size);
|
||||||
await newCredit.save(null, { useMasterKey: true });
|
newCredit.set('PartnersTenant', tenantPtr);
|
||||||
|
await newCredit.save(null, { useMasterKey: true });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err in save usage', err);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
saveDataFile(size, fileUrl, tenantPtr);
|
||||||
console.log('err in save usage', err);
|
|
||||||
}
|
}
|
||||||
saveDataFile(size, fileUrl, tenantPtr);
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err in fetch tenant Id', err);
|
console.log('err in fetch tenant Id', err);
|
||||||
@@ -91,7 +94,7 @@ const saveDataFile = async (size, fileUrl, tenantPtr) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateMailCount = async extUserId => {
|
export const updateMailCount = async (extUserId, plan, monthchange) => {
|
||||||
// Update count in contracts_Users class
|
// Update count in contracts_Users class
|
||||||
const query = new Parse.Query('contracts_Users');
|
const query = new Parse.Query('contracts_Users');
|
||||||
query.equalTo('objectId', extUserId);
|
query.equalTo('objectId', extUserId);
|
||||||
@@ -100,13 +103,23 @@ export const updateMailCount = async extUserId => {
|
|||||||
const contractUser = await query.first({ useMasterKey: true });
|
const contractUser = await query.first({ useMasterKey: true });
|
||||||
if (contractUser) {
|
if (contractUser) {
|
||||||
contractUser.increment('EmailCount', 1);
|
contractUser.increment('EmailCount', 1);
|
||||||
|
if (plan === 'freeplan') {
|
||||||
|
if (monthchange) {
|
||||||
|
contractUser.set('LastEmailCountReset', new Date());
|
||||||
|
contractUser.set('MonthlyFreeEmails', 1);
|
||||||
|
} else {
|
||||||
|
if (contractUser?.get('MonthlyFreeEmails')) {
|
||||||
|
contractUser.increment('MonthlyFreeEmails', 1);
|
||||||
|
if (contractUser?.get('LastEmailCountReset')) {
|
||||||
|
contractUser.set('LastEmailCountReset', new Date());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
contractUser.set('MonthlyFreeEmails', 1);
|
||||||
|
contractUser.set('LastEmailCountReset', new Date());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
await contractUser.save(null, { useMasterKey: true });
|
await contractUser.save(null, { useMasterKey: true });
|
||||||
} else {
|
|
||||||
// Create new entry if not found
|
|
||||||
const ContractsUsers = Parse.Object.extend('contracts_Users');
|
|
||||||
const newContractUser = new ContractsUsers();
|
|
||||||
newContractUser.set('EmailCount', 1);
|
|
||||||
await newContractUser.save(null, { useMasterKey: true });
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('Error updating EmailCount in contracts_Users: ' + error.message);
|
console.log('Error updating EmailCount in contracts_Users: ' + error.message);
|
||||||
@@ -210,3 +223,14 @@ export const useLocal = process.env.USE_LOCAL ? process.env.USE_LOCAL.toLowerCas
|
|||||||
export const smtpsecure = process.env.SMTP_PORT && process.env.SMTP_PORT !== '465' ? false : true;
|
export const smtpsecure = process.env.SMTP_PORT && process.env.SMTP_PORT !== '465' ? false : true;
|
||||||
export const smtpenable =
|
export const smtpenable =
|
||||||
process.env.SMTP_ENABLE && process.env.SMTP_ENABLE.toLowerCase() === 'true' ? true : false;
|
process.env.SMTP_ENABLE && process.env.SMTP_ENABLE.toLowerCase() === 'true' ? true : false;
|
||||||
|
|
||||||
|
export const planCredits = {
|
||||||
|
'pro-weekly': 100,
|
||||||
|
'pro-yearly': 240,
|
||||||
|
'professional-monthly': 100,
|
||||||
|
'professional-yearly': 240,
|
||||||
|
'team-weekly': 100,
|
||||||
|
'team-yearly': 500,
|
||||||
|
'teams-monthly': 100,
|
||||||
|
'teams-yearly': 500,
|
||||||
|
};
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import saveInvoice from './saveInvoice.js';
|
|||||||
import savePayments from './savePayments.js';
|
import savePayments from './savePayments.js';
|
||||||
import gooogleauth from './googleauth.js';
|
import gooogleauth from './googleauth.js';
|
||||||
import autoReminder from './autoReminder.js';
|
import autoReminder from './autoReminder.js';
|
||||||
|
import validateSmtp from './validateSmtp.js';
|
||||||
export const app = express();
|
export const app = express();
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
@@ -22,3 +23,4 @@ app.post('/saveinvoice', saveInvoice);
|
|||||||
app.post('/savepayment', savePayments);
|
app.post('/savepayment', savePayments);
|
||||||
app.post('/googleauth', gooogleauth);
|
app.post('/googleauth', gooogleauth);
|
||||||
app.post('/sendreminder', autoReminder);
|
app.post('/sendreminder', autoReminder);
|
||||||
|
app.post('/validatesmtp', validateSmtp);
|
||||||
|
|||||||
@@ -1,10 +1,36 @@
|
|||||||
|
import { planCredits } from '../../Utils.js';
|
||||||
|
|
||||||
export default async function saveSubscription(request, response) {
|
export default async function saveSubscription(request, response) {
|
||||||
const SubscriptionId = request.body?.data?.subscription?.subscription_id;
|
const SubscriptionId = request.body?.data?.subscription?.subscription_id;
|
||||||
const body = request.body;
|
const body = request.body;
|
||||||
const Email = request.body.data?.subscription?.customer?.email;
|
const Email = request.body.data?.subscription?.customer?.email;
|
||||||
const Next_billing_date = request.body?.data?.subscription?.next_billing_at;
|
const Next_billing_date = request.body?.data?.subscription?.next_billing_at;
|
||||||
const planCode = request.body?.data?.subscription?.plan?.plan_code;
|
const planCode = request.body?.data?.subscription?.plan?.plan_code;
|
||||||
|
const addons = request.body?.data?.subscription?.addons || [];
|
||||||
|
const event = request.body?.data?.event_type || '';
|
||||||
|
const credits = planCredits?.[planCode] || 0;
|
||||||
|
const isTeamPlan = planCode?.includes('team');
|
||||||
|
let newAddons = 0;
|
||||||
|
if (addons?.length > 0) {
|
||||||
|
let allowedUsersMonthly = 0;
|
||||||
|
let allowedUsersYearly = 0;
|
||||||
|
addons?.forEach(item => {
|
||||||
|
if (item.addon_code === 'extra-teams-users-monthly') {
|
||||||
|
allowedUsersMonthly += item.quantity;
|
||||||
|
} else if (item.addon_code === 'extra-teams-users-yearly') {
|
||||||
|
allowedUsersYearly += item.quantity;
|
||||||
|
} else if (item.addon_code === 'extra-users') {
|
||||||
|
allowedUsersMonthly += item.quantity;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) {
|
||||||
|
newAddons = allowedUsersMonthly + allowedUsersYearly + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (planCode === 'teams-yearly' || planCode === 'teams-monthly' || planCode === 'team-weekly') {
|
||||||
|
newAddons = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const extUserCls = new Parse.Query('contracts_Users');
|
const extUserCls = new Parse.Query('contracts_Users');
|
||||||
extUserCls.equalTo('Email', Email);
|
extUserCls.equalTo('Email', Email);
|
||||||
@@ -18,6 +44,7 @@ export default async function saveSubscription(request, response) {
|
|||||||
});
|
});
|
||||||
const subscription = await subcriptionCls.first({ useMasterKey: true });
|
const subscription = await subcriptionCls.first({ useMasterKey: true });
|
||||||
if (subscription) {
|
if (subscription) {
|
||||||
|
const _resSub = JSON.parse(JSON.stringify(subscription));
|
||||||
const updateSubscription = new Parse.Object('contracts_Subscriptions');
|
const updateSubscription = new Parse.Object('contracts_Subscriptions');
|
||||||
updateSubscription.id = subscription.id;
|
updateSubscription.id = subscription.id;
|
||||||
updateSubscription.set('SubscriptionId', SubscriptionId);
|
updateSubscription.set('SubscriptionId', SubscriptionId);
|
||||||
@@ -28,6 +55,81 @@ export default async function saveSubscription(request, response) {
|
|||||||
updateSubscription.unset('Next_billing_date');
|
updateSubscription.unset('Next_billing_date');
|
||||||
}
|
}
|
||||||
updateSubscription.set('PlanCode', planCode);
|
updateSubscription.set('PlanCode', planCode);
|
||||||
|
if (newAddons > 0) {
|
||||||
|
updateSubscription.set('AllowedUsers', parseInt(newAddons));
|
||||||
|
}
|
||||||
|
let existAddon = 0;
|
||||||
|
let allowedUsersMonthly = 0;
|
||||||
|
let allowedUsersYearly = 0;
|
||||||
|
_resSub.SubscriptionDetails?.data?.subscription?.addons?.forEach(item => {
|
||||||
|
if (item.addon_code === 'extra-teams-users-monthly') {
|
||||||
|
allowedUsersMonthly += item.quantity;
|
||||||
|
} else if (item.addon_code === 'extra-teams-users-yearly') {
|
||||||
|
allowedUsersYearly += item.quantity;
|
||||||
|
} else if (item.addon_code === 'extra-users') {
|
||||||
|
allowedUsersMonthly += item.quantity;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) {
|
||||||
|
existAddon = allowedUsersMonthly + allowedUsersYearly + 1; // + 1 is Admin user
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
planCode === 'teams-yearly' ||
|
||||||
|
planCode === 'teams-monthly' ||
|
||||||
|
planCode === 'team-weekly'
|
||||||
|
) {
|
||||||
|
existAddon = 1; // 1 is Admin user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const isSameAsPrevPlan = subscription?.get('PlanCode') === planCode;
|
||||||
|
if (isSameAsPrevPlan) {
|
||||||
|
const planCredits = subscription?.get('PlanCredits');
|
||||||
|
const existAllowedCredits = subscription?.get('AllowedCredits') || 0;
|
||||||
|
if (planCredits) {
|
||||||
|
const oldAddons = existAddon;
|
||||||
|
const substractedAddon = newAddons - oldAddons;
|
||||||
|
if (isTeamPlan && substractedAddon > 0) {
|
||||||
|
const newCredits = existAllowedCredits + substractedAddon * planCredits;
|
||||||
|
updateSubscription.set('AllowedCredits', newCredits);
|
||||||
|
if (event === 'subscription_created') {
|
||||||
|
updateSubscription.set('PlanCredits', credits);
|
||||||
|
}
|
||||||
|
} else if (isTeamPlan) {
|
||||||
|
const existCredits = existAddon * planCredits;
|
||||||
|
updateSubscription.set('AllowedCredits', existCredits);
|
||||||
|
if (event === 'subscription_created') {
|
||||||
|
updateSubscription.set('PlanCredits', credits);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updateSubscription.set('AllowedCredits', planCredits);
|
||||||
|
if (event === 'subscription_created') {
|
||||||
|
updateSubscription.set('PlanCredits', credits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (credits > 0) {
|
||||||
|
if (isTeamPlan) {
|
||||||
|
const newCredits = newAddons * credits;
|
||||||
|
updateSubscription.set('AllowedCredits', newCredits);
|
||||||
|
updateSubscription.set('PlanCredits', credits);
|
||||||
|
} else {
|
||||||
|
updateSubscription.set('AllowedCredits', credits);
|
||||||
|
updateSubscription.set('PlanCredits', credits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (credits > 0) {
|
||||||
|
if (isTeamPlan) {
|
||||||
|
const newCredits = newAddons * credits;
|
||||||
|
updateSubscription.set('AllowedCredits', newCredits);
|
||||||
|
updateSubscription.set('PlanCredits', credits);
|
||||||
|
} else {
|
||||||
|
updateSubscription.set('AllowedCredits', credits);
|
||||||
|
updateSubscription.set('PlanCredits', credits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
await updateSubscription.save(null, { useMasterKey: true });
|
await updateSubscription.save(null, { useMasterKey: true });
|
||||||
return response.status(200).json({ status: 'update subscription!' });
|
return response.status(200).json({ status: 'update subscription!' });
|
||||||
} else {
|
} else {
|
||||||
@@ -55,6 +157,19 @@ export default async function saveSubscription(request, response) {
|
|||||||
createSubscription.unset('Next_billing_date');
|
createSubscription.unset('Next_billing_date');
|
||||||
}
|
}
|
||||||
createSubscription.set('PlanCode', planCode);
|
createSubscription.set('PlanCode', planCode);
|
||||||
|
if (newAddons > 0) {
|
||||||
|
createSubscription.set('AllowedUsers', parseInt(newAddons));
|
||||||
|
}
|
||||||
|
if (credits > 0) {
|
||||||
|
if (isTeamPlan) {
|
||||||
|
const totalCredits = parseInt(newAddons) * credits;
|
||||||
|
createSubscription.set('AllowedCredits', totalCredits);
|
||||||
|
createSubscription.set('PlanCredits', credits);
|
||||||
|
} else {
|
||||||
|
createSubscription.set('AllowedCredits', credits);
|
||||||
|
createSubscription.set('PlanCredits', credits);
|
||||||
|
}
|
||||||
|
}
|
||||||
await createSubscription.save(null, { useMasterKey: true });
|
await createSubscription.save(null, { useMasterKey: true });
|
||||||
return response.status(200).json({ status: 'create subscription!' });
|
return response.status(200).json({ status: 'create subscription!' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,9 @@ import { cloudServerUrl, customAPIurl, replaceMailVaribles } from '../../../../U
|
|||||||
// `sendDoctoWebhook` is used to send res data of document on webhook
|
// `sendDoctoWebhook` is used to send res data of document on webhook
|
||||||
async function sendDoctoWebhook(doc, WebhookUrl, userId) {
|
async function sendDoctoWebhook(doc, WebhookUrl, userId) {
|
||||||
if (WebhookUrl) {
|
if (WebhookUrl) {
|
||||||
const params = {
|
const params = { event: 'created', ...doc };
|
||||||
event: 'created',
|
|
||||||
...doc,
|
|
||||||
};
|
|
||||||
await axios
|
await axios
|
||||||
.post(WebhookUrl, params, {
|
.post(WebhookUrl, params, { headers: { 'Content-Type': 'application/json' } })
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
})
|
|
||||||
.then(res => {
|
.then(res => {
|
||||||
try {
|
try {
|
||||||
// console.log('res ', res);
|
// console.log('res ', res);
|
||||||
@@ -62,6 +57,7 @@ export default async function createDocumentWithTemplate(request, response) {
|
|||||||
if (!reqToken) {
|
if (!reqToken) {
|
||||||
return response.status(400).json({ error: 'Please Provide API Token' });
|
return response.status(400).json({ error: 'Please Provide API Token' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const tokenQuery = new Parse.Query('appToken');
|
const tokenQuery = new Parse.Query('appToken');
|
||||||
tokenQuery.equalTo('token', reqToken);
|
tokenQuery.equalTo('token', reqToken);
|
||||||
tokenQuery.include('userId');
|
tokenQuery.include('userId');
|
||||||
@@ -74,304 +70,348 @@ export default async function createDocumentWithTemplate(request, response) {
|
|||||||
className: '_User',
|
className: '_User',
|
||||||
objectId: parseUser.userId.objectId,
|
objectId: parseUser.userId.objectId,
|
||||||
};
|
};
|
||||||
const templateQuery = new Parse.Query('contracts_Template');
|
const extUsers = new Parse.Query('contracts_Users');
|
||||||
templateQuery.include('ExtUserPtr');
|
extUsers.equalTo('UserId', userPtr);
|
||||||
const templateRes = await templateQuery.get(templateId, { useMasterKey: true });
|
const extUser = await extUsers.first({ useMasterKey: true });
|
||||||
if (templateRes) {
|
|
||||||
const template = JSON.parse(JSON.stringify(templateRes));
|
|
||||||
if (template?.Placeholders?.length > 0) {
|
|
||||||
const emptyplaceholder = template?.Placeholders.filter(x => !x.signerObjId);
|
|
||||||
const isValid =
|
|
||||||
signers.length >= emptyplaceholder.length &&
|
|
||||||
signers.length <= template?.Placeholders?.length;
|
|
||||||
const placeholder =
|
|
||||||
signers.length > emptyplaceholder.length ? template.Placeholders : emptyplaceholder;
|
|
||||||
const updateSigners = placeholder.every(y => signers?.some(x => x.role === y.Role));
|
|
||||||
// console.log('isValid ', isValid);
|
|
||||||
if (isValid && updateSigners) {
|
|
||||||
//Check if every item's placeholders contain at least one placeholder with type 'signature'.
|
|
||||||
let isSignature = template?.Placeholders?.every(item =>
|
|
||||||
item?.placeHolder.some(x => x?.pos.some(data => data?.type === 'signature'))
|
|
||||||
);
|
|
||||||
if (!isSignature) {
|
|
||||||
return response
|
|
||||||
.status(400)
|
|
||||||
.json({ error: 'Please add at least one signature widget for all signers' });
|
|
||||||
}
|
|
||||||
const folderPtr = {
|
|
||||||
__type: 'Pointer',
|
|
||||||
className: 'contracts_Document',
|
|
||||||
objectId: folderId,
|
|
||||||
};
|
|
||||||
const object = new Parse.Object('contracts_Document');
|
|
||||||
object.set('Name', template.Name);
|
|
||||||
if (template?.Note) {
|
|
||||||
object.set('Note', template.Note);
|
|
||||||
}
|
|
||||||
if (template?.Description) {
|
|
||||||
object.set('Description', template.Description);
|
|
||||||
}
|
|
||||||
object.set('IsSendMail', send_email);
|
|
||||||
if (sendInOrder) {
|
|
||||||
object.set('SendinOrder', sendInOrder);
|
|
||||||
} else if (template?.SendinOrder && template?.SendinOrder) {
|
|
||||||
object.set('SendinOrder', template?.SendinOrder);
|
|
||||||
}
|
|
||||||
let templateSigner = template?.Signers ? template?.Signers : [];
|
|
||||||
let contact = [];
|
|
||||||
if (signers && signers.length > 0) {
|
|
||||||
let parseSigners = [...signers];
|
|
||||||
let createContactUrl = protocol + '/v1/createcontact';
|
|
||||||
|
|
||||||
for (const obj of parseSigners) {
|
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||||
const body = {
|
subscription.equalTo('TenantId', {
|
||||||
name: obj?.name || '',
|
__type: 'Pointer',
|
||||||
email: obj?.email || '',
|
className: 'partners_Tenant',
|
||||||
phone: obj?.phone || '',
|
objectId: extUser.get('TenantId').id,
|
||||||
|
});
|
||||||
|
subscription.include('ExtUserPtr');
|
||||||
|
subscription.greaterThanOrEqualTo('Next_billing_date', new Date());
|
||||||
|
const resSub = await subscription.first({ useMasterKey: true });
|
||||||
|
if (resSub) {
|
||||||
|
const _resSub = JSON.parse(JSON.stringify(resSub));
|
||||||
|
const allowedCredits = _resSub?.AllowedCredits || 0;
|
||||||
|
const addonCredits = _resSub?.AddonCredits || 0;
|
||||||
|
const totalcredits = allowedCredits + addonCredits;
|
||||||
|
if (totalcredits > 0) {
|
||||||
|
const templateQuery = new Parse.Query('contracts_Template');
|
||||||
|
templateQuery.include('ExtUserPtr');
|
||||||
|
const templateRes = await templateQuery.get(templateId, { useMasterKey: true });
|
||||||
|
if (templateRes) {
|
||||||
|
const template = JSON.parse(JSON.stringify(templateRes));
|
||||||
|
if (template?.Placeholders?.length > 0) {
|
||||||
|
const emptyplaceholder = template?.Placeholders.filter(x => !x.signerObjId);
|
||||||
|
const isValid =
|
||||||
|
signers.length >= emptyplaceholder.length &&
|
||||||
|
signers.length <= template?.Placeholders?.length;
|
||||||
|
const placeholder =
|
||||||
|
signers.length > emptyplaceholder.length ? template.Placeholders : emptyplaceholder;
|
||||||
|
const updateSigners = placeholder.every(y => signers?.some(x => x.role === y.Role));
|
||||||
|
// console.log('isValid ', isValid);
|
||||||
|
if (isValid && updateSigners) {
|
||||||
|
//Check if every item's placeholders contain at least one placeholder with type 'signature'.
|
||||||
|
let isSignature = template?.Placeholders?.every(item =>
|
||||||
|
item?.placeHolder.some(x => x?.pos.some(data => data?.type === 'signature'))
|
||||||
|
);
|
||||||
|
if (!isSignature) {
|
||||||
|
return response
|
||||||
|
.status(400)
|
||||||
|
.json({ error: 'Please add at least one signature widget for all signers' });
|
||||||
|
}
|
||||||
|
const folderPtr = {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Document',
|
||||||
|
objectId: folderId,
|
||||||
};
|
};
|
||||||
try {
|
const object = new Parse.Object('contracts_Document');
|
||||||
const res = await axios.post(createContactUrl, body, {
|
object.set('Name', template.Name);
|
||||||
headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
|
if (template?.Note) {
|
||||||
|
object.set('Note', template.Note);
|
||||||
|
}
|
||||||
|
if (template?.Description) {
|
||||||
|
object.set('Description', template.Description);
|
||||||
|
}
|
||||||
|
object.set('IsSendMail', send_email);
|
||||||
|
if (sendInOrder) {
|
||||||
|
object.set('SendinOrder', sendInOrder);
|
||||||
|
} else if (template?.SendinOrder && template?.SendinOrder) {
|
||||||
|
object.set('SendinOrder', template?.SendinOrder);
|
||||||
|
}
|
||||||
|
let templateSigner = template?.Signers ? template?.Signers : [];
|
||||||
|
let contact = [];
|
||||||
|
if (signers && signers.length > 0) {
|
||||||
|
let parseSigners = [...signers];
|
||||||
|
let createContactUrl = protocol + '/v1/createcontact';
|
||||||
|
|
||||||
|
for (const obj of parseSigners) {
|
||||||
|
const body = {
|
||||||
|
name: obj?.name || '',
|
||||||
|
email: obj?.email || '',
|
||||||
|
phone: obj?.phone || '',
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const res = await axios.post(createContactUrl, body, {
|
||||||
|
headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
|
||||||
|
});
|
||||||
|
const contactPtr = {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Contactbook',
|
||||||
|
objectId: res.data?.objectId,
|
||||||
|
};
|
||||||
|
const newObj = { ...obj, contactPtr: contactPtr };
|
||||||
|
contact.push(newObj);
|
||||||
|
} catch (err) {
|
||||||
|
// console.log('err ', err);
|
||||||
|
if (err?.response?.data?.objectId) {
|
||||||
|
const contactPtr = {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Contactbook',
|
||||||
|
objectId: err.response.data?.objectId,
|
||||||
|
};
|
||||||
|
const newObj = { ...obj, contactPtr: contactPtr };
|
||||||
|
contact.push(newObj);
|
||||||
|
} else {
|
||||||
|
console.log('err ', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const contactPtrs = contact.map(x => x.contactPtr);
|
||||||
|
object.set('Signers', [...templateSigner, ...contactPtrs]);
|
||||||
|
|
||||||
|
let updatedPlaceholder = template?.Placeholders?.map(x => {
|
||||||
|
let matchingSigner = contact.find(y => x.Role && x.Role === y.role);
|
||||||
|
|
||||||
|
if (matchingSigner) {
|
||||||
|
return {
|
||||||
|
...x,
|
||||||
|
signerObjId: matchingSigner?.contactPtr?.objectId,
|
||||||
|
signerPtr: matchingSigner?.contactPtr,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return { ...x };
|
||||||
|
}
|
||||||
});
|
});
|
||||||
const contactPtr = {
|
object.set('Placeholders', updatedPlaceholder);
|
||||||
__type: 'Pointer',
|
|
||||||
className: 'contracts_Contactbook',
|
|
||||||
objectId: res.data?.objectId,
|
|
||||||
};
|
|
||||||
const newObj = { ...obj, contactPtr: contactPtr };
|
|
||||||
contact.push(newObj);
|
|
||||||
} catch (err) {
|
|
||||||
// console.log('err ', err);
|
|
||||||
if (err?.response?.data?.objectId) {
|
|
||||||
const contactPtr = {
|
|
||||||
__type: 'Pointer',
|
|
||||||
className: 'contracts_Contactbook',
|
|
||||||
objectId: err.response.data?.objectId,
|
|
||||||
};
|
|
||||||
const newObj = { ...obj, contactPtr: contactPtr };
|
|
||||||
contact.push(newObj);
|
|
||||||
} else {
|
|
||||||
console.log('err ', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const contactPtrs = contact.map(x => x.contactPtr);
|
|
||||||
object.set('Signers', [...templateSigner, ...contactPtrs]);
|
|
||||||
|
|
||||||
let updatedPlaceholder = template?.Placeholders?.map(x => {
|
|
||||||
let matchingSigner = contact.find(y => x.Role && x.Role === y.role);
|
|
||||||
|
|
||||||
if (matchingSigner) {
|
|
||||||
return {
|
|
||||||
...x,
|
|
||||||
signerObjId: matchingSigner?.contactPtr?.objectId,
|
|
||||||
signerPtr: matchingSigner?.contactPtr,
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
return {
|
object.set('Signers', templateSigner);
|
||||||
...x,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
object.set('URL', template.URL);
|
||||||
object.set('Placeholders', updatedPlaceholder);
|
object.set('SignedUrl', template.URL);
|
||||||
} else {
|
object.set('SentToOthers', true);
|
||||||
object.set('Signers', templateSigner);
|
if (TimeToCompleteDays) {
|
||||||
}
|
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
||||||
object.set('URL', template.URL);
|
}
|
||||||
object.set('SignedUrl', template.URL);
|
const enableOTP = request.body?.enableOTP === true ? true : false;
|
||||||
object.set('SentToOthers', true);
|
const IsEnableOTP = enableOTP || template?.IsEnableOTP || false;
|
||||||
if (TimeToCompleteDays) {
|
object.set('IsEnableOTP', IsEnableOTP);
|
||||||
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
object.set('CreatedBy', template.CreatedBy);
|
||||||
}
|
object.set('ExtUserPtr', {
|
||||||
object.set('CreatedBy', template.CreatedBy);
|
__type: 'Pointer',
|
||||||
object.set('ExtUserPtr', {
|
className: 'contracts_Users',
|
||||||
__type: 'Pointer',
|
objectId: template.ExtUserPtr.objectId,
|
||||||
className: 'contracts_Users',
|
});
|
||||||
objectId: template.ExtUserPtr.objectId,
|
if (folderId) {
|
||||||
});
|
object.set('Folder', folderPtr);
|
||||||
if (folderId) {
|
}
|
||||||
object.set('Folder', folderPtr);
|
const newACL = new Parse.ACL();
|
||||||
}
|
newACL.setPublicReadAccess(false);
|
||||||
const newACL = new Parse.ACL();
|
newACL.setPublicWriteAccess(false);
|
||||||
newACL.setPublicReadAccess(false);
|
newACL.setReadAccess(userPtr.objectId, true);
|
||||||
newACL.setPublicWriteAccess(false);
|
newACL.setWriteAccess(userPtr.objectId, true);
|
||||||
newACL.setReadAccess(userPtr.objectId, true);
|
object.setACL(newACL);
|
||||||
newACL.setWriteAccess(userPtr.objectId, true);
|
const res = await object.save(null, { useMasterKey: true });
|
||||||
object.setACL(newACL);
|
|
||||||
const res = await object.save(null, { useMasterKey: true });
|
|
||||||
|
|
||||||
const newDate = new Date();
|
const newDate = new Date();
|
||||||
newDate.setDate(newDate.getDate() + 15);
|
newDate.setDate(newDate.getDate() + 15);
|
||||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
});
|
});
|
||||||
let sender = template.ExtUserPtr.Email;
|
let sender = template.ExtUserPtr.Email;
|
||||||
let sendMail;
|
let sendMail;
|
||||||
if (send_email === false) {
|
if (send_email === false) {
|
||||||
console.log("don't send mail");
|
console.log("don't send mail");
|
||||||
} else {
|
} else {
|
||||||
let contactMail = contact;
|
let contactMail = contact;
|
||||||
if (sendInOrder) {
|
if (sendInOrder) {
|
||||||
contactMail = contact.slice();
|
contactMail = contact.slice();
|
||||||
contactMail.splice(1);
|
contactMail.splice(1);
|
||||||
}
|
|
||||||
for (let i = 0; i < contactMail.length; i++) {
|
|
||||||
try {
|
|
||||||
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
|
||||||
let url = `${cloudServerUrl}/functions/sendmailv3/`;
|
|
||||||
const headers = {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-Parse-Application-Id': process.env.APP_ID,
|
|
||||||
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
|
||||||
};
|
|
||||||
|
|
||||||
const objectId = contactMail[i].contactPtr.objectId;
|
|
||||||
const hostUrl = baseUrl.origin;
|
|
||||||
//encode this url value `${res.id}/${contactMail[i].email}/${objectId}` to base64 using `btoa` function
|
|
||||||
const encodeBase64 = btoa(`${res.id}/${contactMail[i].email}/${objectId}`);
|
|
||||||
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
|
||||||
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
|
||||||
const orgName = template.ExtUserPtr.Company ? template.ExtUserPtr.Company : '';
|
|
||||||
const themeBGcolor = '#47a3ad';
|
|
||||||
const email_html =
|
|
||||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src='" +
|
|
||||||
imgPng +
|
|
||||||
"' height='50' style='padding:20px; width:170px; height:40px;' /></div><div style='padding: 2px;font-family: system-ui;background-color:" +
|
|
||||||
themeBGcolor +
|
|
||||||
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
|
||||||
template.ExtUserPtr.Name +
|
|
||||||
' has requested you to review and sign <strong> ' +
|
|
||||||
template.Name +
|
|
||||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
|
||||||
sender +
|
|
||||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
|
||||||
orgName +
|
|
||||||
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
|
||||||
localExpireDate +
|
|
||||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
|
||||||
signPdf +
|
|
||||||
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px;'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
|
||||||
sender +
|
|
||||||
' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' +
|
|
||||||
openSignUrl +
|
|
||||||
' target=_blank>here</a>.</p> </div></div></body> </html>';
|
|
||||||
|
|
||||||
let replaceVar;
|
|
||||||
const variables = {
|
|
||||||
document_title: template.Name,
|
|
||||||
sender_name: template.ExtUserPtr.Name,
|
|
||||||
sender_mail: template.ExtUserPtr.Email,
|
|
||||||
sender_phone: template.ExtUserPtr?.Phone || '',
|
|
||||||
receiver_name: contactMail[i].name,
|
|
||||||
receiver_email: contactMail[i].email,
|
|
||||||
receiver_phone: contactMail[i]?.phone || '',
|
|
||||||
expiry_date: localExpireDate,
|
|
||||||
company_name: orgName,
|
|
||||||
signing_url: signPdf,
|
|
||||||
};
|
|
||||||
if (email_subject && email_body) {
|
|
||||||
replaceVar = replaceMailVaribles(email_subject, email_body, variables);
|
|
||||||
} else if (email_subject) {
|
|
||||||
replaceVar = replaceMailVaribles(email_subject, '', variables);
|
|
||||||
replaceVar = { subject: replaceVar.subject, body: email_html };
|
|
||||||
} else if (email_body) {
|
|
||||||
replaceVar = replaceMailVaribles(
|
|
||||||
`${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`,
|
|
||||||
email_body,
|
|
||||||
variables
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
replaceVar = {
|
|
||||||
subject: `${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`,
|
|
||||||
body: email_html,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
for (let i = 0; i < contactMail.length; i++) {
|
||||||
|
try {
|
||||||
|
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
||||||
|
let url = `${cloudServerUrl}/functions/sendmailv3/`;
|
||||||
|
const headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Parse-Application-Id': process.env.APP_ID,
|
||||||
|
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
||||||
|
};
|
||||||
|
|
||||||
const subject = replaceVar.subject;
|
const objectId = contactMail[i].contactPtr.objectId;
|
||||||
const html = replaceVar.body;
|
const hostUrl = baseUrl.origin;
|
||||||
let params = {
|
//encode this url value `${res.id}/${contactMail[i].email}/${objectId}` to base64 using `btoa` function
|
||||||
recipient: contactMail[i].email,
|
const encodeBase64 = btoa(`${res.id}/${contactMail[i].email}/${objectId}`);
|
||||||
subject: subject,
|
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
||||||
from: sender,
|
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
||||||
html: html,
|
const orgName = template.ExtUserPtr.Company
|
||||||
extUserId: template.ExtUserPtr.objectId,
|
? template.ExtUserPtr.Company
|
||||||
};
|
: '';
|
||||||
sendMail = await axios.post(url, params, { headers: headers });
|
const themeBGcolor = '#47a3ad';
|
||||||
} catch (error) {
|
const email_html =
|
||||||
console.log('error', error);
|
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src='" +
|
||||||
|
imgPng +
|
||||||
|
"' height='50' style='padding:20px; width:170px; height:40px;' /></div><div style='padding: 2px;font-family: system-ui;background-color:" +
|
||||||
|
themeBGcolor +
|
||||||
|
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
||||||
|
template.ExtUserPtr.Name +
|
||||||
|
' has requested you to review and sign <strong> ' +
|
||||||
|
template.Name +
|
||||||
|
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||||
|
sender +
|
||||||
|
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
||||||
|
orgName +
|
||||||
|
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||||
|
localExpireDate +
|
||||||
|
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
||||||
|
signPdf +
|
||||||
|
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px;'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
||||||
|
sender +
|
||||||
|
' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' +
|
||||||
|
openSignUrl +
|
||||||
|
' target=_blank>here</a>.</p> </div></div></body> </html>';
|
||||||
|
|
||||||
|
let replaceVar;
|
||||||
|
const variables = {
|
||||||
|
document_title: template.Name,
|
||||||
|
sender_name: template.ExtUserPtr.Name,
|
||||||
|
sender_mail: template.ExtUserPtr.Email,
|
||||||
|
sender_phone: template.ExtUserPtr?.Phone || '',
|
||||||
|
receiver_name: contactMail[i].name,
|
||||||
|
receiver_email: contactMail[i].email,
|
||||||
|
receiver_phone: contactMail[i]?.phone || '',
|
||||||
|
expiry_date: localExpireDate,
|
||||||
|
company_name: orgName,
|
||||||
|
signing_url: signPdf,
|
||||||
|
};
|
||||||
|
if (email_subject && email_body) {
|
||||||
|
replaceVar = replaceMailVaribles(email_subject, email_body, variables);
|
||||||
|
} else if (email_subject) {
|
||||||
|
replaceVar = replaceMailVaribles(email_subject, '', variables);
|
||||||
|
replaceVar = { subject: replaceVar.subject, body: email_html };
|
||||||
|
} else if (email_body) {
|
||||||
|
replaceVar = replaceMailVaribles(
|
||||||
|
`${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`,
|
||||||
|
email_body,
|
||||||
|
variables
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
replaceVar = {
|
||||||
|
subject: `${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`,
|
||||||
|
body: email_html,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const subject = replaceVar.subject;
|
||||||
|
const html = replaceVar.body;
|
||||||
|
let params = {
|
||||||
|
recipient: contactMail[i].email,
|
||||||
|
subject: subject,
|
||||||
|
from: sender,
|
||||||
|
html: html,
|
||||||
|
extUserId: template.ExtUserPtr.objectId,
|
||||||
|
mailProvider: template?.ExtUserPtr?.active_mail_adapter || '',
|
||||||
|
};
|
||||||
|
sendMail = await axios.post(url, params, { headers: headers });
|
||||||
|
} catch (error) {
|
||||||
|
console.log('error', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// if (sendMail.data.result.status === 'success') {
|
||||||
|
try {
|
||||||
|
const doc = {
|
||||||
|
objectId: res.id,
|
||||||
|
file: template?.URL,
|
||||||
|
name: template?.Name,
|
||||||
|
note: template?.Note || '',
|
||||||
|
description: template?.Description || '',
|
||||||
|
signers: contact?.map(x => ({
|
||||||
|
name: x.name,
|
||||||
|
email: x.email,
|
||||||
|
phone: x?.phone || '',
|
||||||
|
})),
|
||||||
|
createdAt: res.createdAt,
|
||||||
|
};
|
||||||
|
if (template.ExtUserPtr && template.ExtUserPtr?.Webhook) {
|
||||||
|
sendDoctoWebhook(doc, template.ExtUserPtr?.Webhook, userPtr?.objectId);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Err', err);
|
||||||
|
}
|
||||||
|
if (request.posthog) {
|
||||||
|
request.posthog?.capture({
|
||||||
|
distinctId: parseUser.userId.email,
|
||||||
|
event: 'api_create_document_with_templateid',
|
||||||
|
properties: { response_code: 200 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const subscriptionCls = new Parse.Object('contracts_Subscriptions');
|
||||||
|
subscriptionCls.id = resSub.id;
|
||||||
|
if (allowedCredits > 0) {
|
||||||
|
const updateAllowedcredits = allowedCredits - 1 || 0;
|
||||||
|
subscriptionCls.set('AllowedCredits', updateAllowedcredits);
|
||||||
|
} else {
|
||||||
|
const updateAddonCredits = addonCredits > 0 ? addonCredits - 1 : 0;
|
||||||
|
subscriptionCls.set('AddonCredits', updateAddonCredits);
|
||||||
|
}
|
||||||
|
const resSubcription = await subscriptionCls.save(null, { useMasterKey: true });
|
||||||
|
// console.log("resSubcription ", resSubcription)
|
||||||
|
return response.json({
|
||||||
|
objectId: res.id,
|
||||||
|
signurl: contact.map(x => ({
|
||||||
|
email: x.email,
|
||||||
|
url: `${baseUrl.origin}/login/${btoa(
|
||||||
|
`${res.id}/${x.email}/${x.contactPtr.objectId}`
|
||||||
|
)}`,
|
||||||
|
})),
|
||||||
|
message: 'Document sent successfully!',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (request.posthog) {
|
||||||
|
request.posthog?.capture({
|
||||||
|
distinctId: parseUser.userId.email,
|
||||||
|
event: 'api_create_document_with_templateid',
|
||||||
|
properties: { response_code: 400 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return response.status(400).json({ error: 'Please provide signers properly!' });
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
// if (sendMail.data.result.status === 'success') {
|
if (request.posthog) {
|
||||||
try {
|
request.posthog?.capture({
|
||||||
const doc = {
|
distinctId: parseUser.userId.email,
|
||||||
objectId: res.id,
|
event: 'api_create_document_with_templateid',
|
||||||
file: template?.URL,
|
properties: { response_code: 400 },
|
||||||
name: template?.Name,
|
});
|
||||||
note: template?.Note || '',
|
|
||||||
description: template?.Description || '',
|
|
||||||
signers: contact?.map(x => ({
|
|
||||||
name: x.name,
|
|
||||||
email: x.email,
|
|
||||||
phone: x?.phone || '',
|
|
||||||
})),
|
|
||||||
createdAt: res.createdAt,
|
|
||||||
};
|
|
||||||
if (template.ExtUserPtr && template.ExtUserPtr?.Webhook) {
|
|
||||||
sendDoctoWebhook(doc, template.ExtUserPtr?.Webhook, userPtr?.objectId);
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
return response.status(400).json({ error: 'Please setup template properly!' });
|
||||||
console.log('Err', err);
|
|
||||||
}
|
}
|
||||||
if (request.posthog) {
|
|
||||||
request.posthog?.capture({
|
|
||||||
distinctId: parseUser.userId.email,
|
|
||||||
event: 'api_create_document_with_templateid',
|
|
||||||
properties: { response_code: 200 },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return response.json({
|
|
||||||
objectId: res.id,
|
|
||||||
signurl: contact.map(x => ({
|
|
||||||
email: x.email,
|
|
||||||
url: `${baseUrl.origin}/login/${btoa(
|
|
||||||
`${res.id}/${x.email}/${x.contactPtr.objectId}`
|
|
||||||
)}`,
|
|
||||||
})),
|
|
||||||
message: 'Document sent successfully!',
|
|
||||||
});
|
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
if (request.posthog) {
|
if (request.posthog) {
|
||||||
request.posthog?.capture({
|
request.posthog?.capture({
|
||||||
distinctId: parseUser.userId.email,
|
distinctId: parseUser.userId.email,
|
||||||
event: 'api_create_document_with_templateid',
|
event: 'api_create_document_with_templateid',
|
||||||
properties: { response_code: 400 },
|
properties: { response_code: 404 },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return response.status(400).json({ error: 'Please provide signers properly!' });
|
return response.status(404).json({ error: 'Invalid template id!' });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (request.posthog) {
|
return response
|
||||||
request.posthog?.capture({
|
.status(429)
|
||||||
distinctId: parseUser.userId.email,
|
.json({ error: 'Quota reached, Please buy credits and try again later.' });
|
||||||
event: 'api_create_document_with_templateid',
|
|
||||||
properties: { response_code: 400 },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return response.status(400).json({ error: 'Please setup template properly!' });
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (request.posthog) {
|
return response.status(400).json({
|
||||||
request.posthog?.capture({
|
error: 'Please purchase or renew your subscription.',
|
||||||
distinctId: parseUser.userId.email,
|
});
|
||||||
event: 'api_create_document_with_templateid',
|
|
||||||
properties: { response_code: 404 },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return response.status(404).json({ error: 'Invalid template id!' });
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return response.status(405).json({ error: 'Invalid API Token!' });
|
return response.status(405).json({ error: 'Invalid API Token!' });
|
||||||
|
|||||||
@@ -12,15 +12,10 @@ import {
|
|||||||
// `sendDoctoWebhook` is used to send res data of document on webhook
|
// `sendDoctoWebhook` is used to send res data of document on webhook
|
||||||
async function sendDoctoWebhook(doc, WebhookUrl, userId) {
|
async function sendDoctoWebhook(doc, WebhookUrl, userId) {
|
||||||
if (WebhookUrl) {
|
if (WebhookUrl) {
|
||||||
const params = {
|
const params = { event: 'created', ...doc };
|
||||||
event: 'created',
|
|
||||||
...doc,
|
|
||||||
};
|
|
||||||
|
|
||||||
await axios
|
await axios
|
||||||
.post(WebhookUrl, params, {
|
.post(WebhookUrl, params, { headers: { 'Content-Type': 'application/json' } })
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
})
|
|
||||||
.then(res => {
|
.then(res => {
|
||||||
try {
|
try {
|
||||||
// console.log('res ', res);
|
// console.log('res ', res);
|
||||||
@@ -68,6 +63,7 @@ export default async function createDocumentwithCoordinate(request, response) {
|
|||||||
const email_body = request.body.email_body;
|
const email_body = request.body.email_body;
|
||||||
const sendInOrder = request.body.sendInOrder || false;
|
const sendInOrder = request.body.sendInOrder || false;
|
||||||
const TimeToCompleteDays = request.body.timeToCompleteDays || 15;
|
const TimeToCompleteDays = request.body.timeToCompleteDays || 15;
|
||||||
|
const IsEnableOTP = request.body?.enableOTP === true ? true : false;
|
||||||
// console.log('fileData ', fileData);
|
// console.log('fileData ', fileData);
|
||||||
const protocol = customAPIurl();
|
const protocol = customAPIurl();
|
||||||
const baseUrl = new URL(process.env.PUBLIC_URL);
|
const baseUrl = new URL(process.env.PUBLIC_URL);
|
||||||
@@ -89,309 +85,350 @@ export default async function createDocumentwithCoordinate(request, response) {
|
|||||||
className: '_User',
|
className: '_User',
|
||||||
objectId: parseUser.userId.objectId,
|
objectId: parseUser.userId.objectId,
|
||||||
};
|
};
|
||||||
if (signers && signers.length > 0) {
|
const extUsers = new Parse.Query('contracts_Users');
|
||||||
// Check if at least one signature exists among all items in the signers array
|
extUsers.equalTo('UserId', userPtr);
|
||||||
let isSignExist = signers.every(item =>
|
const extUser = await extUsers.first({ useMasterKey: true });
|
||||||
item.widgets.some(data => data?.type === 'signature')
|
|
||||||
);
|
|
||||||
if (!isSignExist) {
|
|
||||||
return response
|
|
||||||
.status(400)
|
|
||||||
.json({ error: 'Please add at least one signature widget for all signers' });
|
|
||||||
}
|
|
||||||
let fileUrl;
|
|
||||||
if (request.files?.[0]) {
|
|
||||||
const base64 = fileData?.toString('base64');
|
|
||||||
const file = new Parse.File(request.files?.[0]?.originalname, {
|
|
||||||
base64: base64,
|
|
||||||
});
|
|
||||||
await file.save({ useMasterKey: true });
|
|
||||||
fileUrl = file.url();
|
|
||||||
const buffer = Buffer.from(base64, 'base64');
|
|
||||||
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
|
||||||
} else {
|
|
||||||
const filename = sanitizeFileName(`${name}.pdf`);
|
|
||||||
const file = new Parse.File(filename, { base64: base64File }, 'application/pdf');
|
|
||||||
await file.save({ useMasterKey: true });
|
|
||||||
fileUrl = file.url();
|
|
||||||
const buffer = Buffer.from(base64File, 'base64');
|
|
||||||
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
|
||||||
}
|
|
||||||
const contractsUser = new Parse.Query('contracts_Users');
|
|
||||||
contractsUser.equalTo('UserId', userPtr);
|
|
||||||
const extUser = await contractsUser.first({ useMasterKey: true });
|
|
||||||
const parseExtUser = JSON.parse(JSON.stringify(extUser));
|
|
||||||
|
|
||||||
const extUserPtr = {
|
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||||
__type: 'Pointer',
|
subscription.equalTo('TenantId', {
|
||||||
className: 'contracts_Users',
|
__type: 'Pointer',
|
||||||
objectId: extUser.id,
|
className: 'partners_Tenant',
|
||||||
};
|
objectId: extUser.get('TenantId').id,
|
||||||
|
});
|
||||||
const object = new Parse.Object('contracts_Document');
|
subscription.include('ExtUserPtr');
|
||||||
object.set('Name', name);
|
subscription.greaterThanOrEqualTo('Next_billing_date', new Date());
|
||||||
|
const resSub = await subscription.first({ useMasterKey: true });
|
||||||
if (note) {
|
if (resSub) {
|
||||||
object.set('Note', note);
|
const _resSub = JSON.parse(JSON.stringify(resSub));
|
||||||
}
|
const allowedCredits = _resSub?.AllowedCredits || 0;
|
||||||
if (description) {
|
const addonCredits = _resSub?.AddonCredits || 0;
|
||||||
object.set('Description', description);
|
const totalcredits = allowedCredits + addonCredits;
|
||||||
}
|
if (totalcredits > 0) {
|
||||||
if (sendInOrder) {
|
if (signers && signers.length > 0) {
|
||||||
object.set('SendinOrder', sendInOrder);
|
// Check if at least one signature exists among all items in the signers array
|
||||||
}
|
let isSignExist = signers.every(item =>
|
||||||
object.set('URL', fileUrl);
|
item.widgets.some(data => data?.type === 'signature')
|
||||||
object.set('SignedUrl', fileUrl);
|
);
|
||||||
object.set('SentToOthers', true);
|
if (!isSignExist) {
|
||||||
object.set('CreatedBy', userPtr);
|
return response
|
||||||
object.set('ExtUserPtr', extUserPtr);
|
.status(400)
|
||||||
if (TimeToCompleteDays) {
|
.json({ error: 'Please add at least one signature widget for all signers' });
|
||||||
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
}
|
||||||
}
|
let fileUrl;
|
||||||
object.set('IsSendMail', send_email);
|
if (request.files?.[0]) {
|
||||||
let contact = [];
|
const base64 = fileData?.toString('base64');
|
||||||
if (signers && signers.length > 0) {
|
const file = new Parse.File(request.files?.[0]?.originalname, {
|
||||||
let parseSigners;
|
base64: base64,
|
||||||
if (base64File) {
|
|
||||||
parseSigners = signers;
|
|
||||||
} else {
|
|
||||||
parseSigners = JSON.parse(signers);
|
|
||||||
}
|
|
||||||
let createContactUrl = protocol + '/v1/createcontact';
|
|
||||||
|
|
||||||
for (const [index, element] of parseSigners.entries()) {
|
|
||||||
const body = {
|
|
||||||
name: element?.name || '',
|
|
||||||
email: element?.email || '',
|
|
||||||
phone: element?.phone || '',
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
const res = await axios.post(createContactUrl, body, {
|
|
||||||
headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
|
|
||||||
});
|
});
|
||||||
// console.log('res ', res.data);
|
await file.save({ useMasterKey: true });
|
||||||
const contactPtr = {
|
fileUrl = file.url();
|
||||||
__type: 'Pointer',
|
const buffer = Buffer.from(base64, 'base64');
|
||||||
className: 'contracts_Contactbook',
|
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||||
objectId: res.data?.objectId,
|
} else {
|
||||||
};
|
const filename = sanitizeFileName(`${name}.pdf`);
|
||||||
const newObj = { ...element, contactPtr: contactPtr, index: index };
|
const file = new Parse.File(filename, { base64: base64File }, 'application/pdf');
|
||||||
contact.push(newObj);
|
await file.save({ useMasterKey: true });
|
||||||
} catch (err) {
|
fileUrl = file.url();
|
||||||
// console.log('err ', err.response);
|
const buffer = Buffer.from(base64File, 'base64');
|
||||||
if (err?.response?.data?.objectId) {
|
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||||
const contactPtr = {
|
|
||||||
__type: 'Pointer',
|
|
||||||
className: 'contracts_Contactbook',
|
|
||||||
objectId: err.response.data?.objectId,
|
|
||||||
};
|
|
||||||
const newObj = { ...element, contactPtr: contactPtr, index: index };
|
|
||||||
contact.push(newObj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
const contractsUser = new Parse.Query('contracts_Users');
|
||||||
object.set(
|
contractsUser.equalTo('UserId', userPtr);
|
||||||
'Signers',
|
const extUser = await contractsUser.first({ useMasterKey: true });
|
||||||
contact?.map(x => x.contactPtr)
|
const parseExtUser = JSON.parse(JSON.stringify(extUser));
|
||||||
);
|
|
||||||
let updatePlaceholders = contact.map(signer => {
|
|
||||||
const placeHolder = [];
|
|
||||||
|
|
||||||
for (const widget of signer.widgets) {
|
const extUserPtr = {
|
||||||
const pageNumber = widget.page;
|
__type: 'Pointer',
|
||||||
const options = formatWidgetOptions(widget.type, widget.options);
|
className: 'contracts_Users',
|
||||||
const page = placeHolder.find(page => page.pageNumber === pageNumber);
|
objectId: extUser.id,
|
||||||
const widgetData = {
|
|
||||||
isStamp: widget.type === 'stamp' || widget.type === 'image',
|
|
||||||
key: randomId(),
|
|
||||||
isDrag: false,
|
|
||||||
scale: 1,
|
|
||||||
isMobile: false,
|
|
||||||
zIndex: 1,
|
|
||||||
type: widget.type === 'textbox' ? 'text input' : widget.type,
|
|
||||||
options: options,
|
|
||||||
Width: widget.w,
|
|
||||||
Height: widget.h,
|
|
||||||
xPosition: widget.x,
|
|
||||||
yPosition: widget.y,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (page) {
|
|
||||||
page.pos.push(widgetData);
|
|
||||||
} else {
|
|
||||||
placeHolder.push({
|
|
||||||
pageNumber,
|
|
||||||
pos: [widgetData],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
signerObjId: signer?.contactPtr?.objectId,
|
|
||||||
signerPtr: signer?.contactPtr,
|
|
||||||
Role: signer.role,
|
|
||||||
Id: randomId(),
|
|
||||||
blockColor: color[signer?.index],
|
|
||||||
placeHolder,
|
|
||||||
};
|
};
|
||||||
});
|
|
||||||
object.set('Placeholders', updatePlaceholders);
|
|
||||||
}
|
|
||||||
if (folderId) {
|
|
||||||
object.set('Folder', {
|
|
||||||
__type: 'Pointer',
|
|
||||||
className: 'contracts_Document',
|
|
||||||
objectId: folderId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const newACL = new Parse.ACL();
|
|
||||||
newACL.setPublicReadAccess(false);
|
|
||||||
newACL.setPublicWriteAccess(false);
|
|
||||||
newACL.setReadAccess(userPtr.objectId, true);
|
|
||||||
newACL.setWriteAccess(userPtr.objectId, true);
|
|
||||||
object.setACL(newACL);
|
|
||||||
const res = await object.save(null, { useMasterKey: true });
|
|
||||||
const doc = {
|
|
||||||
objectId: res.id,
|
|
||||||
file: fileUrl,
|
|
||||||
name: name,
|
|
||||||
note: note || '',
|
|
||||||
description: description || '',
|
|
||||||
signers: contact?.map(x => ({ name: x.name, email: x.email, phone: x?.phone || '' })),
|
|
||||||
createdAt: res.createdAt,
|
|
||||||
};
|
|
||||||
if (parseExtUser && parseExtUser.Webhook) {
|
|
||||||
sendDoctoWebhook(doc, parseExtUser?.Webhook, userPtr?.objectId);
|
|
||||||
}
|
|
||||||
const newDate = new Date();
|
|
||||||
newDate.setDate(newDate.getDate() + 15);
|
|
||||||
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
|
||||||
day: 'numeric',
|
|
||||||
month: 'long',
|
|
||||||
year: 'numeric',
|
|
||||||
});
|
|
||||||
let sender = parseExtUser.Email;
|
|
||||||
if (send_email === false) {
|
|
||||||
console.log("don't send mail");
|
|
||||||
} else {
|
|
||||||
let contactMail = contact;
|
|
||||||
if (sendInOrder) {
|
|
||||||
contactMail = contact.slice();
|
|
||||||
contactMail.splice(1);
|
|
||||||
}
|
|
||||||
for (let i = 0; i < contactMail.length; i++) {
|
|
||||||
try {
|
|
||||||
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
|
||||||
let url = `${cloudServerUrl}/functions/sendmailv3/`;
|
|
||||||
const headers = {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-Parse-Application-Id': process.env.APP_ID,
|
|
||||||
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
|
||||||
};
|
|
||||||
|
|
||||||
const objectId = contactMail[i].contactPtr.objectId;
|
const object = new Parse.Object('contracts_Document');
|
||||||
const hostUrl = baseUrl.origin;
|
object.set('Name', name);
|
||||||
//encode this url value `${response.id}/${contactMail[i].email}/${objectId}` to base64 using `btoa` function
|
|
||||||
const encodeBase64 = btoa(`${res.id}/${contactMail[i].email}/${objectId}`);
|
|
||||||
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
|
||||||
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
|
||||||
const orgName = parseExtUser.Company ? parseExtUser.Company : '';
|
|
||||||
const themeBGcolor = '#47a3ad';
|
|
||||||
const email_html =
|
|
||||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" +
|
|
||||||
imgPng +
|
|
||||||
" height='50' style='padding:20px; width:170px; height:40px;' /></div> <div style='padding:2px; font-family: system-ui;background-color:" +
|
|
||||||
themeBGcolor +
|
|
||||||
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
|
||||||
parseExtUser.Name +
|
|
||||||
' has requested you to review and sign <strong> ' +
|
|
||||||
name +
|
|
||||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
|
||||||
sender +
|
|
||||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
|
||||||
orgName +
|
|
||||||
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
|
||||||
localExpireDate +
|
|
||||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
|
||||||
signPdf +
|
|
||||||
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
|
||||||
sender +
|
|
||||||
' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' +
|
|
||||||
openSignUrl +
|
|
||||||
' target=_blank>here</a>.</p> </div></div></body> </html>';
|
|
||||||
let replaceVar;
|
|
||||||
const variables = {
|
|
||||||
document_title: name,
|
|
||||||
sender_name: parseExtUser.Name,
|
|
||||||
sender_mail: parseExtUser.Email,
|
|
||||||
sender_phone: parseExtUser?.Phone || '',
|
|
||||||
receiver_name: contactMail[i].name,
|
|
||||||
receiver_email: contactMail[i].email,
|
|
||||||
receiver_phone: contactMail[i]?.phone || '',
|
|
||||||
expiry_date: localExpireDate,
|
|
||||||
company_name: orgName,
|
|
||||||
signing_url: signPdf,
|
|
||||||
};
|
|
||||||
if (email_subject && email_body) {
|
|
||||||
replaceVar = replaceMailVaribles(email_subject, email_body, variables);
|
|
||||||
} else if (email_subject) {
|
|
||||||
replaceVar = replaceMailVaribles(email_subject, '', variables);
|
|
||||||
replaceVar = { subject: replaceVar.subject, body: email_html };
|
|
||||||
} else if (email_body) {
|
|
||||||
replaceVar = replaceMailVaribles(
|
|
||||||
`${parseExtUser.Name} has requested you to sign "${name}"`,
|
|
||||||
email_body,
|
|
||||||
variables
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
replaceVar = {
|
|
||||||
subject: `${parseExtUser.Name} has requested you to sign "${name}"`,
|
|
||||||
body: email_html,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const subject = replaceVar.subject;
|
|
||||||
const html = replaceVar.body;
|
|
||||||
|
|
||||||
let params = {
|
if (note) {
|
||||||
recipient: contactMail[i].email,
|
object.set('Note', note);
|
||||||
subject: subject,
|
|
||||||
from: sender,
|
|
||||||
html: html,
|
|
||||||
extUserId: extUser.id,
|
|
||||||
};
|
|
||||||
|
|
||||||
await axios.post(url, params, { headers: headers });
|
|
||||||
} catch (error) {
|
|
||||||
console.log('error', error);
|
|
||||||
}
|
}
|
||||||
|
if (description) {
|
||||||
|
object.set('Description', description);
|
||||||
|
}
|
||||||
|
if (sendInOrder) {
|
||||||
|
object.set('SendinOrder', sendInOrder);
|
||||||
|
}
|
||||||
|
object.set('URL', fileUrl);
|
||||||
|
object.set('SignedUrl', fileUrl);
|
||||||
|
object.set('SentToOthers', true);
|
||||||
|
object.set('CreatedBy', userPtr);
|
||||||
|
object.set('ExtUserPtr', extUserPtr);
|
||||||
|
if (TimeToCompleteDays) {
|
||||||
|
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
||||||
|
}
|
||||||
|
object.set('IsEnableOTP', IsEnableOTP);
|
||||||
|
object.set('IsSendMail', send_email);
|
||||||
|
let contact = [];
|
||||||
|
if (signers && signers.length > 0) {
|
||||||
|
let parseSigners;
|
||||||
|
if (base64File) {
|
||||||
|
parseSigners = signers;
|
||||||
|
} else {
|
||||||
|
parseSigners = JSON.parse(signers);
|
||||||
|
}
|
||||||
|
let createContactUrl = protocol + '/v1/createcontact';
|
||||||
|
|
||||||
|
for (const [index, element] of parseSigners.entries()) {
|
||||||
|
const body = {
|
||||||
|
name: element?.name || '',
|
||||||
|
email: element?.email || '',
|
||||||
|
phone: element?.phone || '',
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const res = await axios.post(createContactUrl, body, {
|
||||||
|
headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
|
||||||
|
});
|
||||||
|
// console.log('res ', res.data);
|
||||||
|
const contactPtr = {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Contactbook',
|
||||||
|
objectId: res.data?.objectId,
|
||||||
|
};
|
||||||
|
const newObj = { ...element, contactPtr: contactPtr, index: index };
|
||||||
|
contact.push(newObj);
|
||||||
|
} catch (err) {
|
||||||
|
// console.log('err ', err.response);
|
||||||
|
if (err?.response?.data?.objectId) {
|
||||||
|
const contactPtr = {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Contactbook',
|
||||||
|
objectId: err.response.data?.objectId,
|
||||||
|
};
|
||||||
|
const newObj = { ...element, contactPtr: contactPtr, index: index };
|
||||||
|
contact.push(newObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
object.set(
|
||||||
|
'Signers',
|
||||||
|
contact?.map(x => x.contactPtr)
|
||||||
|
);
|
||||||
|
let updatePlaceholders = contact.map(signer => {
|
||||||
|
const placeHolder = [];
|
||||||
|
|
||||||
|
for (const widget of signer.widgets) {
|
||||||
|
const pageNumber = widget.page;
|
||||||
|
const options = formatWidgetOptions(widget.type, widget.options);
|
||||||
|
const page = placeHolder.find(page => page.pageNumber === pageNumber);
|
||||||
|
const widgetData = {
|
||||||
|
isStamp: widget.type === 'stamp' || widget.type === 'image',
|
||||||
|
key: randomId(),
|
||||||
|
isDrag: false,
|
||||||
|
scale: 1,
|
||||||
|
isMobile: false,
|
||||||
|
zIndex: 1,
|
||||||
|
type: widget.type === 'textbox' ? 'text input' : widget.type,
|
||||||
|
options: options,
|
||||||
|
Width: widget.w,
|
||||||
|
Height: widget.h,
|
||||||
|
xPosition: widget.x,
|
||||||
|
yPosition: widget.y,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (page) {
|
||||||
|
page.pos.push(widgetData);
|
||||||
|
} else {
|
||||||
|
placeHolder.push({ pageNumber, pos: [widgetData] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
signerObjId: signer?.contactPtr?.objectId,
|
||||||
|
signerPtr: signer?.contactPtr,
|
||||||
|
Role: signer.role,
|
||||||
|
Id: randomId(),
|
||||||
|
blockColor: color[signer?.index],
|
||||||
|
placeHolder,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
object.set('Placeholders', updatePlaceholders);
|
||||||
|
}
|
||||||
|
if (folderId) {
|
||||||
|
object.set('Folder', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Document',
|
||||||
|
objectId: folderId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const newACL = new Parse.ACL();
|
||||||
|
newACL.setPublicReadAccess(false);
|
||||||
|
newACL.setPublicWriteAccess(false);
|
||||||
|
newACL.setReadAccess(userPtr.objectId, true);
|
||||||
|
newACL.setWriteAccess(userPtr.objectId, true);
|
||||||
|
object.setACL(newACL);
|
||||||
|
const res = await object.save(null, { useMasterKey: true });
|
||||||
|
const doc = {
|
||||||
|
objectId: res.id,
|
||||||
|
file: fileUrl,
|
||||||
|
name: name,
|
||||||
|
note: note || '',
|
||||||
|
description: description || '',
|
||||||
|
signers: contact?.map(x => ({ name: x.name, email: x.email, phone: x?.phone || '' })),
|
||||||
|
createdAt: res.createdAt,
|
||||||
|
};
|
||||||
|
if (parseExtUser && parseExtUser.Webhook) {
|
||||||
|
sendDoctoWebhook(doc, parseExtUser?.Webhook, userPtr?.objectId);
|
||||||
|
}
|
||||||
|
const newDate = new Date();
|
||||||
|
newDate.setDate(newDate.getDate() + 15);
|
||||||
|
const localExpireDate = newDate.toLocaleDateString('en-US', {
|
||||||
|
day: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
year: 'numeric',
|
||||||
|
});
|
||||||
|
let sender = parseExtUser.Email;
|
||||||
|
if (send_email === false) {
|
||||||
|
console.log("don't send mail");
|
||||||
|
} else {
|
||||||
|
let contactMail = contact;
|
||||||
|
if (sendInOrder) {
|
||||||
|
contactMail = contact.slice();
|
||||||
|
contactMail.splice(1);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < contactMail.length; i++) {
|
||||||
|
try {
|
||||||
|
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
||||||
|
let url = `${cloudServerUrl}/functions/sendmailv3/`;
|
||||||
|
const headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Parse-Application-Id': process.env.APP_ID,
|
||||||
|
'X-Parse-Master-Key': process.env.MASTER_KEY,
|
||||||
|
};
|
||||||
|
|
||||||
|
const objectId = contactMail[i].contactPtr.objectId;
|
||||||
|
const hostUrl = baseUrl.origin;
|
||||||
|
//encode this url value `${response.id}/${contactMail[i].email}/${objectId}` to base64 using `btoa` function
|
||||||
|
const encodeBase64 = btoa(`${res.id}/${contactMail[i].email}/${objectId}`);
|
||||||
|
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
||||||
|
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
||||||
|
const orgName = parseExtUser.Company ? parseExtUser.Company : '';
|
||||||
|
const themeBGcolor = '#47a3ad';
|
||||||
|
const email_html =
|
||||||
|
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" +
|
||||||
|
imgPng +
|
||||||
|
" height='50' style='padding:20px; width:170px; height:40px;' /></div> <div style='padding:2px; font-family: system-ui;background-color:" +
|
||||||
|
themeBGcolor +
|
||||||
|
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
||||||
|
parseExtUser.Name +
|
||||||
|
' has requested you to review and sign <strong> ' +
|
||||||
|
name +
|
||||||
|
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||||
|
sender +
|
||||||
|
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
||||||
|
orgName +
|
||||||
|
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||||
|
localExpireDate +
|
||||||
|
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
||||||
|
signPdf +
|
||||||
|
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
||||||
|
sender +
|
||||||
|
' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' +
|
||||||
|
openSignUrl +
|
||||||
|
' target=_blank>here</a>.</p> </div></div></body> </html>';
|
||||||
|
let replaceVar;
|
||||||
|
const variables = {
|
||||||
|
document_title: name,
|
||||||
|
sender_name: parseExtUser.Name,
|
||||||
|
sender_mail: parseExtUser.Email,
|
||||||
|
sender_phone: parseExtUser?.Phone || '',
|
||||||
|
receiver_name: contactMail[i].name,
|
||||||
|
receiver_email: contactMail[i].email,
|
||||||
|
receiver_phone: contactMail[i]?.phone || '',
|
||||||
|
expiry_date: localExpireDate,
|
||||||
|
company_name: orgName,
|
||||||
|
signing_url: signPdf,
|
||||||
|
};
|
||||||
|
if (email_subject && email_body) {
|
||||||
|
replaceVar = replaceMailVaribles(email_subject, email_body, variables);
|
||||||
|
} else if (email_subject) {
|
||||||
|
replaceVar = replaceMailVaribles(email_subject, '', variables);
|
||||||
|
replaceVar = { subject: replaceVar.subject, body: email_html };
|
||||||
|
} else if (email_body) {
|
||||||
|
replaceVar = replaceMailVaribles(
|
||||||
|
`${parseExtUser.Name} has requested you to sign "${name}"`,
|
||||||
|
email_body,
|
||||||
|
variables
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
replaceVar = {
|
||||||
|
subject: `${parseExtUser.Name} has requested you to sign "${name}"`,
|
||||||
|
body: email_html,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const subject = replaceVar.subject;
|
||||||
|
const html = replaceVar.body;
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
recipient: contactMail[i].email,
|
||||||
|
subject: subject,
|
||||||
|
from: sender,
|
||||||
|
html: html,
|
||||||
|
extUserId: extUser.id,
|
||||||
|
mailProvider: parseExtUser?.active_mail_adapter || '',
|
||||||
|
};
|
||||||
|
|
||||||
|
await axios.post(url, params, { headers: headers });
|
||||||
|
} catch (error) {
|
||||||
|
console.log('error', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if (sendMail.data.result.status === 'success') {
|
||||||
|
if (request.posthog) {
|
||||||
|
request.posthog?.capture({
|
||||||
|
distinctId: parseUser.userId.email,
|
||||||
|
event: 'api_create_document',
|
||||||
|
properties: { response_code: 200 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const subscriptionCls = new Parse.Object('contracts_Subscriptions');
|
||||||
|
subscriptionCls.id = resSub.id;
|
||||||
|
if (allowedCredits > 0) {
|
||||||
|
const updateAllowedcredits = allowedCredits - 1 || 0;
|
||||||
|
subscriptionCls.set('AllowedCredits', updateAllowedcredits);
|
||||||
|
} else {
|
||||||
|
const updateAddonCredits = addonCredits > 0 ? addonCredits - 1 : 0;
|
||||||
|
subscriptionCls.set('AddonCredits', updateAddonCredits);
|
||||||
|
}
|
||||||
|
const resSubcription = await subscriptionCls.save(null, { useMasterKey: true });
|
||||||
|
// console.log('resSubcription ', resSubcription);
|
||||||
|
return response.json({
|
||||||
|
objectId: res.id,
|
||||||
|
signurl: contact.map(x => ({
|
||||||
|
email: x.email,
|
||||||
|
url: `${baseUrl.origin}/login/${btoa(
|
||||||
|
`${res.id}/${x.email}/${x.contactPtr.objectId}`
|
||||||
|
)}`,
|
||||||
|
})),
|
||||||
|
message: 'Document sent successfully!',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (request.posthog) {
|
||||||
|
request.posthog?.capture({
|
||||||
|
distinctId: parseUser.userId.email,
|
||||||
|
event: 'api_create_document',
|
||||||
|
properties: { response_code: 400 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return response.status(400).json({ error: 'Please provide signers!' });
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return response
|
||||||
|
.status(429)
|
||||||
|
.json({ error: 'Quota reached, Please buy credits and try again later.' });
|
||||||
}
|
}
|
||||||
// if (sendMail.data.result.status === 'success') {
|
|
||||||
if (request.posthog) {
|
|
||||||
request.posthog?.capture({
|
|
||||||
distinctId: parseUser.userId.email,
|
|
||||||
event: 'api_create_document',
|
|
||||||
properties: { response_code: 200 },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return response.json({
|
|
||||||
objectId: res.id,
|
|
||||||
signurl: contact.map(x => ({
|
|
||||||
email: x.email,
|
|
||||||
url: `${baseUrl.origin}/login/${btoa(`${res.id}/${x.email}/${x.contactPtr.objectId}`)}`,
|
|
||||||
})),
|
|
||||||
message: 'Document sent successfully!',
|
|
||||||
});
|
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
if (request.posthog) {
|
return response.status(400).json({
|
||||||
request.posthog?.capture({
|
error: 'Please purchase or renew your subscription.',
|
||||||
distinctId: parseUser.userId.email,
|
});
|
||||||
event: 'api_create_document',
|
|
||||||
properties: { response_code: 400 },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return response.status(400).json({ error: 'Please provide signers!' });
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return response.status(405).json({ error: 'Invalid API Token!' });
|
return response.status(405).json({ error: 'Invalid API Token!' });
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export default async function createTemplate(request, response) {
|
|||||||
const SendinOrder = request.body.sendInOrder || false;
|
const SendinOrder = request.body.sendInOrder || false;
|
||||||
const fileData = request.files?.[0] ? request.files[0].buffer : null;
|
const fileData = request.files?.[0] ? request.files[0].buffer : null;
|
||||||
const baseUrl = new URL(process.env.PUBLIC_URL);
|
const baseUrl = new URL(process.env.PUBLIC_URL);
|
||||||
|
const isEnableOTP = request.body?.enableOTP === true ? true : false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const reqToken = request.headers['x-api-token'];
|
const reqToken = request.headers['x-api-token'];
|
||||||
@@ -65,6 +66,7 @@ export default async function createTemplate(request, response) {
|
|||||||
object.set('URL', fileUrl);
|
object.set('URL', fileUrl);
|
||||||
object.set('CreatedBy', userPtr);
|
object.set('CreatedBy', userPtr);
|
||||||
object.set('ExtUserPtr', extUserPtr);
|
object.set('ExtUserPtr', extUserPtr);
|
||||||
|
object.set('IsEnableOTP', isEnableOTP);
|
||||||
if (SendinOrder) {
|
if (SendinOrder) {
|
||||||
object.set('SendinOrder', SendinOrder);
|
object.set('SendinOrder', SendinOrder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ export default async function createTemplatewithCoordinate(request, response) {
|
|||||||
const base64File = request.body.file;
|
const base64File = request.body.file;
|
||||||
const fileData = request.files?.[0] ? request.files[0].buffer : null;
|
const fileData = request.files?.[0] ? request.files[0].buffer : null;
|
||||||
const SendinOrder = request.body.sendInOrder || false;
|
const SendinOrder = request.body.sendInOrder || false;
|
||||||
|
const isEnableOTP = request.body?.enableOTP === true ? true : false;
|
||||||
|
|
||||||
// console.log('fileData ', fileData);
|
// console.log('fileData ', fileData);
|
||||||
const protocol = customAPIurl();
|
const protocol = customAPIurl();
|
||||||
|
|
||||||
@@ -80,6 +82,7 @@ export default async function createTemplatewithCoordinate(request, response) {
|
|||||||
object.set('URL', fileUrl);
|
object.set('URL', fileUrl);
|
||||||
object.set('CreatedBy', userPtr);
|
object.set('CreatedBy', userPtr);
|
||||||
object.set('ExtUserPtr', extUserPtr);
|
object.set('ExtUserPtr', extUserPtr);
|
||||||
|
object.set('IsEnableOTP', isEnableOTP);
|
||||||
let contact = [];
|
let contact = [];
|
||||||
if (signers && signers.length > 0) {
|
if (signers && signers.length > 0) {
|
||||||
let parseSigners;
|
let parseSigners;
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ export default async function draftDocument(request, response) {
|
|||||||
const send_email = request.body.send_email || true;
|
const send_email = request.body.send_email || true;
|
||||||
const fileData = request.files?.[0] ? request.files[0].buffer : null;
|
const fileData = request.files?.[0] ? request.files[0].buffer : null;
|
||||||
const SendinOrder = request.body.sendInOrder || false;
|
const SendinOrder = request.body.sendInOrder || false;
|
||||||
|
const isEnableOTP = request.body?.enableOTP === true ? true : false;
|
||||||
|
|
||||||
// console.log('fileData ', fileData);
|
// console.log('fileData ', fileData);
|
||||||
const protocol = customAPIurl();
|
const protocol = customAPIurl();
|
||||||
const baseUrl = new URL(process.env.PUBLIC_URL);
|
const baseUrl = new URL(process.env.PUBLIC_URL);
|
||||||
@@ -83,6 +85,7 @@ export default async function draftDocument(request, response) {
|
|||||||
object.set('CreatedBy', userPtr);
|
object.set('CreatedBy', userPtr);
|
||||||
object.set('ExtUserPtr', extUserPtr);
|
object.set('ExtUserPtr', extUserPtr);
|
||||||
object.set('IsSendMail', send_email);
|
object.set('IsSendMail', send_email);
|
||||||
|
object.set('IsEnableOTP', isEnableOTP);
|
||||||
if (signers && signers.length > 0) {
|
if (signers && signers.length > 0) {
|
||||||
let parseSigners;
|
let parseSigners;
|
||||||
if (base64File) {
|
if (base64File) {
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export default async function getDocument(request, response) {
|
|||||||
document?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) ||
|
document?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) ||
|
||||||
[],
|
[],
|
||||||
sendInOrder: document?.SendinOrder || false,
|
sendInOrder: document?.SendinOrder || false,
|
||||||
|
enableOTP: document?.IsEnableOTP || false,
|
||||||
createdAt: document.createdAt,
|
createdAt: document.createdAt,
|
||||||
updatedAt: document.updatedAt,
|
updatedAt: document.updatedAt,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ export default async function getDocumentList(request, response) {
|
|||||||
x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) ||
|
x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) ||
|
||||||
[],
|
[],
|
||||||
sendInOrder: x?.SendinOrder || false,
|
sendInOrder: x?.SendinOrder || false,
|
||||||
|
enableOTP: x?.IsEnableOTP || false,
|
||||||
createdAt: x.createdAt,
|
createdAt: x.createdAt,
|
||||||
updatedAt: x.updatedAt,
|
updatedAt: x.updatedAt,
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ export default async function getTemplate(request, response) {
|
|||||||
),
|
),
|
||||||
})) || [],
|
})) || [],
|
||||||
sendInOrder: template?.SendinOrder || false,
|
sendInOrder: template?.SendinOrder || false,
|
||||||
|
enableOTP: template?.IsEnableOTP || false,
|
||||||
createdAt: template.createdAt,
|
createdAt: template.createdAt,
|
||||||
updatedAt: template.updatedAt,
|
updatedAt: template.updatedAt,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ export default async function getTemplatetList(request, response) {
|
|||||||
),
|
),
|
||||||
})) || [],
|
})) || [],
|
||||||
sendInOrder: template?.SendinOrder || false,
|
sendInOrder: template?.SendinOrder || false,
|
||||||
|
enableOTP: template?.IsEnableOTP || false,
|
||||||
createdAt: template.createdAt,
|
createdAt: template.createdAt,
|
||||||
updatedAt: template.updatedAt,
|
updatedAt: template.updatedAt,
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export default async function resendMail(request, response) {
|
|||||||
if (resDoc) {
|
if (resDoc) {
|
||||||
const _resDoc = resDoc.toJSON();
|
const _resDoc = resDoc.toJSON();
|
||||||
const contact = _resDoc.Signers.find(x => x.Email === userMail);
|
const contact = _resDoc.Signers.find(x => x.Email === userMail);
|
||||||
|
const activeMailAdapter = _resDoc?.ExtUserPtr?.active_mail_adapter || '';
|
||||||
if (contact) {
|
if (contact) {
|
||||||
try {
|
try {
|
||||||
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
|
||||||
@@ -131,6 +132,7 @@ export default async function resendMail(request, response) {
|
|||||||
from: sender,
|
from: sender,
|
||||||
html: html,
|
html: html,
|
||||||
extUserId: _resDoc.ExtUserPtr.objectId,
|
extUserId: _resDoc.ExtUserPtr.objectId,
|
||||||
|
mailProvider: activeMailAdapter,
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await axios.post(url, params, { headers: headers });
|
const res = await axios.post(url, params, { headers: headers });
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export default async function updateDocument(request, response) {
|
|||||||
const token = await tokenQuery.first({ useMasterKey: true });
|
const token = await tokenQuery.first({ useMasterKey: true });
|
||||||
if (token !== undefined) {
|
if (token !== undefined) {
|
||||||
// Valid Token then proceed request
|
// Valid Token then proceed request
|
||||||
const allowedKeys = ['name', 'note', 'description', 'folderId'];
|
const allowedKeys = ['name', 'note', 'description', 'folderId', 'enableOTP'];
|
||||||
const objectKeys = Object.keys(request.body);
|
const objectKeys = Object.keys(request.body);
|
||||||
const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0;
|
const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0;
|
||||||
const parseUser = JSON.parse(JSON.stringify(token));
|
const parseUser = JSON.parse(JSON.stringify(token));
|
||||||
@@ -48,6 +48,10 @@ export default async function updateDocument(request, response) {
|
|||||||
objectId: request?.body?.folderId,
|
objectId: request?.body?.folderId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.body?.enableOTP) {
|
||||||
|
updateQuery.set('IsEnableOTP', request.body?.enableOTP);
|
||||||
|
}
|
||||||
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
|
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
|
||||||
if (updatedRes) {
|
if (updatedRes) {
|
||||||
if (request.posthog) {
|
if (request.posthog) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export default async function updateTemplate(request, response) {
|
|||||||
const token = await tokenQuery.first({ useMasterKey: true });
|
const token = await tokenQuery.first({ useMasterKey: true });
|
||||||
if (token !== undefined) {
|
if (token !== undefined) {
|
||||||
// Valid Token then proceed request
|
// Valid Token then proceed request
|
||||||
const allowedKeys = ['name', 'note', 'description', 'folderId'];
|
const allowedKeys = ['name', 'note', 'description', 'folderId', 'enableOTP'];
|
||||||
const objectKeys = Object.keys(request.body);
|
const objectKeys = Object.keys(request.body);
|
||||||
const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0;
|
const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0;
|
||||||
const parseUser = JSON.parse(JSON.stringify(token));
|
const parseUser = JSON.parse(JSON.stringify(token));
|
||||||
@@ -48,6 +48,9 @@ export default async function updateTemplate(request, response) {
|
|||||||
objectId: request?.body?.folderId,
|
objectId: request?.body?.folderId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (request.body?.enableOTP) {
|
||||||
|
updateQuery.set('IsEnableOTP', request.body?.enableOTP);
|
||||||
|
}
|
||||||
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
|
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
|
||||||
if (updatedRes) {
|
if (updatedRes) {
|
||||||
if (request.posthog) {
|
if (request.posthog) {
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import { createTransport } from 'nodemailer';
|
||||||
|
import { appName } from '../../Utils.js';
|
||||||
|
// Online Javascript Editor for free
|
||||||
|
// Write, Edit and Run your Javascript code using JS Online Compiler
|
||||||
|
|
||||||
|
function generateOtpWithSum10() {
|
||||||
|
let otp = [];
|
||||||
|
let sum = 0;
|
||||||
|
|
||||||
|
// First, generate 3 random digits (0-9) and add them to the sum
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
let digit = Math.floor(Math.random() * 10);
|
||||||
|
otp.push(digit);
|
||||||
|
sum += digit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the last digit to ensure the sum equals 10
|
||||||
|
let lastDigit = 10 - sum;
|
||||||
|
|
||||||
|
// If the last digit is not valid (e.g., greater than 9), regenerate
|
||||||
|
if (lastDigit >= 0 && lastDigit <= 9) {
|
||||||
|
otp.push(lastDigit);
|
||||||
|
} else {
|
||||||
|
return generateOtpWithSum10(); // Recursively generate again
|
||||||
|
}
|
||||||
|
|
||||||
|
return otp.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function validateSmtp(request, response) {
|
||||||
|
const host = request.body.host;
|
||||||
|
const port = request.body?.port?.toString();
|
||||||
|
const username = request.body.username;
|
||||||
|
const password = request.body.password;
|
||||||
|
const secure = request.body?.secure;
|
||||||
|
const email = request.body?.email;
|
||||||
|
const otp = generateOtpWithSum10();
|
||||||
|
// console.log('Generated OTP:', otp);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const smtpsecure = secure || port !== '465' ? false : true;
|
||||||
|
const transporterSMTP = createTransport({
|
||||||
|
host: host,
|
||||||
|
port: port,
|
||||||
|
secure: smtpsecure,
|
||||||
|
auth: { user: username, pass: password },
|
||||||
|
});
|
||||||
|
const from = appName;
|
||||||
|
const mailsender = username;
|
||||||
|
const messageParams = {
|
||||||
|
from: from + ' <' + mailsender + '>',
|
||||||
|
to: email,
|
||||||
|
subject: `Your ${appName} SMTP credentials verification code`,
|
||||||
|
text: 'mail',
|
||||||
|
html:
|
||||||
|
`<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'><div style='background-color:red;padding:2px;font-family:system-ui; background-color:#47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',>SMTP Verification Code</p></div><div style='padding:20px'><p style='font-family:system-ui;font-size:14px'>Your verification code is:</p><p style=' text-decoration: none; font-weight: bolder; color:blue;font-size:45px;margin:20px'>` +
|
||||||
|
otp +
|
||||||
|
'</p></div> </div> </div></body></html>',
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await transporterSMTP.sendMail(messageParams);
|
||||||
|
console.log('custom smtp transporter res: ', res?.response);
|
||||||
|
if (!res.err) {
|
||||||
|
response.status(200).json({ message: 'success' });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err ', err);
|
||||||
|
const code = err?.responseCode || 400;
|
||||||
|
const message = err?.response || 'failed!';
|
||||||
|
response.status(code).json({ error: message });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,6 @@ import usersignup from './parsefunction/usersignup.js';
|
|||||||
import FacebookSign from './parsefunction/FacebookSign.js';
|
import FacebookSign from './parsefunction/FacebookSign.js';
|
||||||
import DocumentAftersave from './parsefunction/DocumentAftersave.js';
|
import DocumentAftersave from './parsefunction/DocumentAftersave.js';
|
||||||
import ContactbookAftersave from './parsefunction/ContactBookAftersave.js';
|
import ContactbookAftersave from './parsefunction/ContactBookAftersave.js';
|
||||||
// import ContractUsersAftersave from './parsefunction/ContractUsersAftersave.js';
|
|
||||||
import sendMailOTPv1 from './parsefunction/SendMailOTPv1.js';
|
import sendMailOTPv1 from './parsefunction/SendMailOTPv1.js';
|
||||||
import AuthLoginAsMail from './parsefunction/AuthLoginAsMail.js';
|
import AuthLoginAsMail from './parsefunction/AuthLoginAsMail.js';
|
||||||
import getUserId from './parsefunction/getUserId.js';
|
import getUserId from './parsefunction/getUserId.js';
|
||||||
@@ -60,14 +59,26 @@ import addTeam from './parsefunction/addTeam.js';
|
|||||||
import updateTeam from './parsefunction/updateTeam.js';
|
import updateTeam from './parsefunction/updateTeam.js';
|
||||||
import getOrgAdmins from './parsefunction/getOrgAdmins.js';
|
import getOrgAdmins from './parsefunction/getOrgAdmins.js';
|
||||||
import getAllUserTeamByOrg from './parsefunction/getAllUserTeamByOrg.js';
|
import getAllUserTeamByOrg from './parsefunction/getAllUserTeamByOrg.js';
|
||||||
|
import AllowedUsers from './parsefunction/AlllowedUsers.js';
|
||||||
|
import BuyAddonUsers from './parsefunction/BuyAddonUsers.js';
|
||||||
|
import ExtUserAftersave from './parsefunction/ExtUserAftersave.js';
|
||||||
|
import ExtUserAfterdelete from './parsefunction/ExtUserAfterdelete.js';
|
||||||
|
import AllowedCredits from './parsefunction/AllowedCredits.js';
|
||||||
|
import BuyCredits from './parsefunction/BuyCredits.js';
|
||||||
|
import getContact from './parsefunction/getContact.js';
|
||||||
|
import updateContactTour from './parsefunction/updateContactTour.js';
|
||||||
|
import declinedocument from './parsefunction/declinedocument.js';
|
||||||
|
import addcustomsmtp from './parsefunction/addcustomsmtp.js';
|
||||||
|
import deactivateMailAdapter from './parsefunction/deactivateMailAdapter.js';
|
||||||
|
|
||||||
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
|
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
|
||||||
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
|
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
|
||||||
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
|
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
|
||||||
// Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
|
|
||||||
Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave);
|
Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave);
|
||||||
Parse.Cloud.afterSave('contracts_Teams', TeamsAftersave);
|
Parse.Cloud.afterSave('contracts_Teams', TeamsAftersave);
|
||||||
Parse.Cloud.afterSave('contracts_Subscriptions', SubscriptionAftersave);
|
Parse.Cloud.afterSave('contracts_Subscriptions', SubscriptionAftersave);
|
||||||
|
Parse.Cloud.afterSave('contracts_Users', ExtUserAftersave);
|
||||||
|
|
||||||
// This beforeSave function triggers before an object is added or updated in the specified class, allowing for validation or modification.
|
// This beforeSave function triggers before an object is added or updated in the specified class, allowing for validation or modification.
|
||||||
Parse.Cloud.beforeSave('contracts_Document', DocumentBeforesave);
|
Parse.Cloud.beforeSave('contracts_Document', DocumentBeforesave);
|
||||||
Parse.Cloud.beforeSave('contracts_Template', TemplateBeforeSave);
|
Parse.Cloud.beforeSave('contracts_Template', TemplateBeforeSave);
|
||||||
@@ -79,6 +90,9 @@ Parse.Cloud.afterFind('contracts_Template', TemplateAfterFind);
|
|||||||
Parse.Cloud.afterFind('contracts_Signature', SignatureAfterFind);
|
Parse.Cloud.afterFind('contracts_Signature', SignatureAfterFind);
|
||||||
Parse.Cloud.afterFind('partners_Tenant', TenantAterFind);
|
Parse.Cloud.afterFind('partners_Tenant', TenantAterFind);
|
||||||
|
|
||||||
|
// This afterDelete function triggers after an object get deleted.
|
||||||
|
Parse.Cloud.afterDelete('contracts_Users', ExtUserAfterdelete);
|
||||||
|
|
||||||
// This define function creates a custom Cloud Function that can be called from the client-side, enabling custom business logic on the server.
|
// This define function creates a custom Cloud Function that can be called from the client-side, enabling custom business logic on the server.
|
||||||
Parse.Cloud.define('signPdf', PDF);
|
Parse.Cloud.define('signPdf', PDF);
|
||||||
Parse.Cloud.define('sendmailv3', sendmailv3);
|
Parse.Cloud.define('sendmailv3', sendmailv3);
|
||||||
@@ -129,3 +143,12 @@ Parse.Cloud.define('addteam', addTeam);
|
|||||||
Parse.Cloud.define('updateteam', updateTeam);
|
Parse.Cloud.define('updateteam', updateTeam);
|
||||||
Parse.Cloud.define('getorgadmins', getOrgAdmins);
|
Parse.Cloud.define('getorgadmins', getOrgAdmins);
|
||||||
Parse.Cloud.define('getalluserteambyorg', getAllUserTeamByOrg);
|
Parse.Cloud.define('getalluserteambyorg', getAllUserTeamByOrg);
|
||||||
|
Parse.Cloud.define('allowedusers', AllowedUsers);
|
||||||
|
Parse.Cloud.define('buyaddonusers', BuyAddonUsers);
|
||||||
|
Parse.Cloud.define('allowedcredits', AllowedCredits);
|
||||||
|
Parse.Cloud.define('buycredits', BuyCredits);
|
||||||
|
Parse.Cloud.define('getcontact', getContact);
|
||||||
|
Parse.Cloud.define('updatecontacttour', updateContactTour);
|
||||||
|
Parse.Cloud.define('declinedoc', declinedocument);
|
||||||
|
Parse.Cloud.define('addsmtp', addcustomsmtp);
|
||||||
|
Parse.Cloud.define('deactivatemailadapter', deactivateMailAdapter);
|
||||||
|
|||||||
@@ -189,34 +189,3 @@ export default async function AddAdmin(request) {
|
|||||||
console.log('Err ', err);
|
console.log('Err ', err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// async function saveSubscription(extUserId, UserId, tenantId, subscription) {
|
|
||||||
// const SubscriptionId = subscription?.data?.subscription?.subscription_id || '';
|
|
||||||
// const Next_billing_date = subscription?.data?.subscription?.next_billing_at || '';
|
|
||||||
// const planCode = subscription?.data?.subscription?.plan?.plan_code || '';
|
|
||||||
// try {
|
|
||||||
// const createSubscription = new Parse.Object('contracts_Subscriptions');
|
|
||||||
// createSubscription.set('SubscriptionId', SubscriptionId);
|
|
||||||
// createSubscription.set('SubscriptionDetails', subscription);
|
|
||||||
// createSubscription.set('ExtUserPtr', {
|
|
||||||
// __type: 'Pointer',
|
|
||||||
// className: 'contracts_Users',
|
|
||||||
// objectId: extUserId,
|
|
||||||
// });
|
|
||||||
// createSubscription.set('CreatedBy', {
|
|
||||||
// __type: 'Pointer',
|
|
||||||
// className: '_User',
|
|
||||||
// objectId: UserId,
|
|
||||||
// });
|
|
||||||
// createSubscription.set('TenantId', {
|
|
||||||
// __type: 'Pointer',
|
|
||||||
// className: 'partners_Tenant',
|
|
||||||
// objectId: tenantId,
|
|
||||||
// });
|
|
||||||
// createSubscription.set('Next_billing_date', new Date(Next_billing_date));
|
|
||||||
// createSubscription.set('PlanCode', planCode);
|
|
||||||
// await createSubscription.save(null, { useMasterKey: true });
|
|
||||||
// } catch (err) {
|
|
||||||
// console.log('err in save subscription pgsignup', err);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
export default async function AllowedUsers(request) {
|
||||||
|
if (!request?.user) {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const extUser = new Parse.Query('contracts_Users');
|
||||||
|
extUser.equalTo('UserId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: '_User',
|
||||||
|
objectId: request.user.id,
|
||||||
|
});
|
||||||
|
const resExtUser = await extUser.first({ useMasterKey: true });
|
||||||
|
if (resExtUser) {
|
||||||
|
const _resExtUser = JSON.parse(JSON.stringify(resExtUser));
|
||||||
|
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||||
|
subscription.equalTo('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: _resExtUser.TenantId.objectId,
|
||||||
|
});
|
||||||
|
subscription.include('ExtUserPtr');
|
||||||
|
const resSub = await subscription.first({ useMasterKey: true });
|
||||||
|
if (resSub) {
|
||||||
|
const _resSub = JSON.parse(JSON.stringify(resSub));
|
||||||
|
const count = _resSub?.UsersCount || 0;
|
||||||
|
if (count > 0) {
|
||||||
|
const allowedUser = resSub.get('AllowedUsers') || 0;
|
||||||
|
const remainUsers = allowedUser - count;
|
||||||
|
if (remainUsers > 0) {
|
||||||
|
return remainUsers;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const alloweduser = resSub.get('AllowedUsers') || 0;
|
||||||
|
return alloweduser;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err in allowedusers', err);
|
||||||
|
const code = err?.code || 400;
|
||||||
|
const msg = err?.message || 'Something went wrong.';
|
||||||
|
throw new Parse.Error(code, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
export default async function AllowedCredits(request) {
|
||||||
|
if (!request?.user) {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const extUser = new Parse.Query('contracts_Users');
|
||||||
|
extUser.equalTo('UserId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: '_User',
|
||||||
|
objectId: request.user.id,
|
||||||
|
});
|
||||||
|
const resExtUser = await extUser.first({ useMasterKey: true });
|
||||||
|
if (resExtUser) {
|
||||||
|
const _resExtUser = JSON.parse(JSON.stringify(resExtUser));
|
||||||
|
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||||
|
subscription.equalTo('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: _resExtUser.TenantId.objectId,
|
||||||
|
});
|
||||||
|
subscription.include('ExtUserPtr');
|
||||||
|
const resSub = await subscription.first({ useMasterKey: true });
|
||||||
|
if (resSub) {
|
||||||
|
const _resSub = JSON.parse(JSON.stringify(resSub));
|
||||||
|
const AllowedCredits = _resSub?.AllowedCredits || 0;
|
||||||
|
const AddonCredits = _resSub?.AddonCredits || 0;
|
||||||
|
return { allowedcredits: AllowedCredits, addoncredits: AddonCredits };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err in allowedCredits', err);
|
||||||
|
const code = err?.code || 400;
|
||||||
|
const msg = err?.message || 'Something went wrong.';
|
||||||
|
throw new Parse.Error(code, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import { planCredits } from '../../Utils.js';
|
||||||
|
export default async function BuyAddonUsers(request) {
|
||||||
|
const users = request.params.users;
|
||||||
|
if (!request?.user) {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||||
|
}
|
||||||
|
if (users) {
|
||||||
|
try {
|
||||||
|
const extUser = new Parse.Query('contracts_Users');
|
||||||
|
extUser.equalTo('UserId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: '_User',
|
||||||
|
objectId: request.user.id,
|
||||||
|
});
|
||||||
|
const resExtUser = await extUser.first({ useMasterKey: true });
|
||||||
|
if (resExtUser) {
|
||||||
|
const _resExtUser = JSON.parse(JSON.stringify(resExtUser));
|
||||||
|
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||||
|
subscription.equalTo('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: _resExtUser.TenantId.objectId,
|
||||||
|
});
|
||||||
|
subscription.include('ExtUserPtr');
|
||||||
|
const resSub = await subscription.first({ useMasterKey: true });
|
||||||
|
if (resSub) {
|
||||||
|
const _resSub = JSON.parse(JSON.stringify(resSub));
|
||||||
|
// Define the URL
|
||||||
|
const url = 'https://accounts.zoho.in/oauth/v2/token';
|
||||||
|
|
||||||
|
// Convert the data to x-www-form-urlencoded format
|
||||||
|
const formData = new URLSearchParams();
|
||||||
|
formData.append('refresh_token', process.env.ZOHO_REFRESH_TOKEN);
|
||||||
|
formData.append('client_id', process.env.ZOHO_CLIENT_ID);
|
||||||
|
formData.append('client_secret', process.env.ZOHO_CLIENT_SECRET);
|
||||||
|
formData.append('redirect_uri', process.env.ZOHO_REDIRECT_URI);
|
||||||
|
formData.append('grant_type', 'refresh_token');
|
||||||
|
|
||||||
|
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
|
||||||
|
// Make the POST request using Axios
|
||||||
|
const res = await axios.post(url, formData, { headers });
|
||||||
|
if (res.data.access_token) {
|
||||||
|
const subscriptionId = _resSub.SubscriptionId;
|
||||||
|
const price = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.price;
|
||||||
|
const plan_code = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.plan_code;
|
||||||
|
const addonsArr = _resSub?.SubscriptionDetails?.data?.subscription?.addons || [];
|
||||||
|
let addon = 0;
|
||||||
|
if (addonsArr?.length > 0) {
|
||||||
|
let allowedUsersMonthly = 0;
|
||||||
|
let allowedUsersYearly = 0;
|
||||||
|
addonsArr?.forEach(item => {
|
||||||
|
if (item.addon_code === 'extra-teams-users-monthly') {
|
||||||
|
allowedUsersMonthly += item.quantity;
|
||||||
|
} else if (item.addon_code === 'extra-teams-users-yearly') {
|
||||||
|
allowedUsersYearly += item.quantity;
|
||||||
|
} else if (item.addon_code === 'extra-users') {
|
||||||
|
allowedUsersMonthly += item.quantity;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (allowedUsersMonthly > 0 || allowedUsersYearly > 0) {
|
||||||
|
addon = allowedUsersMonthly + allowedUsersYearly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const quantity = parseInt(users) + parseInt(addon);
|
||||||
|
const addoncode = plan_code.includes('yearly')
|
||||||
|
? 'extra-teams-users-yearly'
|
||||||
|
: 'extra-teams-users-monthly';
|
||||||
|
const data = JSON.stringify({
|
||||||
|
plan: { plan_code: plan_code },
|
||||||
|
addons: [
|
||||||
|
{
|
||||||
|
addon_code: addoncode,
|
||||||
|
addon_description: 'Extra users',
|
||||||
|
price: price,
|
||||||
|
quantity: quantity,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const updatedSubscription = await axios.put(
|
||||||
|
'https://www.zohoapis.in/billing/v1/subscriptions/' + subscriptionId,
|
||||||
|
data,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
|
||||||
|
'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const subscriptionInfo = { data: updatedSubscription.data };
|
||||||
|
const allowedUsers = quantity + 1;
|
||||||
|
const existAllowedCredits = _resSub?.AllowedCredits || 0;
|
||||||
|
const credits = resSub?.PlanCredits || planCredits[plan_code];
|
||||||
|
const newAllowedCredits = users * credits;
|
||||||
|
const totalCredits = existAllowedCredits + newAllowedCredits;
|
||||||
|
const updateSub = new Parse.Object('contracts_Subscriptions');
|
||||||
|
updateSub.id = resSub.id;
|
||||||
|
updateSub.set('SubscriptionDetails', subscriptionInfo);
|
||||||
|
updateSub.set('AllowedUsers', allowedUsers);
|
||||||
|
updateSub.set('AllowedCredits', totalCredits);
|
||||||
|
const resupdateSub = await updateSub.save(null, { useMasterKey: true });
|
||||||
|
return { status: 'success', addon: allowedUsers };
|
||||||
|
} else {
|
||||||
|
throw new Parse.Error('400', 'Invalid access token.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
const code = err?.response?.data?.code || err?.response?.status || err?.code || 400;
|
||||||
|
const msg =
|
||||||
|
err?.response?.data?.error ||
|
||||||
|
err?.response?.data ||
|
||||||
|
err?.message ||
|
||||||
|
'Something went wrong.';
|
||||||
|
console.log('err in buyaddon', code, msg);
|
||||||
|
throw new Parse.Error(code, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
export default async function BuyCredits(request) {
|
||||||
|
const credits = request.params.credits;
|
||||||
|
if (!request?.user) {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||||
|
}
|
||||||
|
if (credits) {
|
||||||
|
try {
|
||||||
|
const extUser = new Parse.Query('contracts_Users');
|
||||||
|
extUser.equalTo('UserId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: '_User',
|
||||||
|
objectId: request.user.id,
|
||||||
|
});
|
||||||
|
const resExtUser = await extUser.first({ useMasterKey: true });
|
||||||
|
if (resExtUser) {
|
||||||
|
const _resExtUser = JSON.parse(JSON.stringify(resExtUser));
|
||||||
|
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||||
|
subscription.equalTo('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: _resExtUser.TenantId.objectId,
|
||||||
|
});
|
||||||
|
subscription.include('ExtUserPtr');
|
||||||
|
const resSub = await subscription.first({ useMasterKey: true });
|
||||||
|
if (resSub) {
|
||||||
|
const _resSub = JSON.parse(JSON.stringify(resSub));
|
||||||
|
// Define the URL
|
||||||
|
const url = 'https://accounts.zoho.in/oauth/v2/token';
|
||||||
|
|
||||||
|
// Convert the data to x-www-form-urlencoded format
|
||||||
|
const formData = new URLSearchParams();
|
||||||
|
formData.append('refresh_token', process.env.ZOHO_REFRESH_TOKEN);
|
||||||
|
formData.append('client_id', process.env.ZOHO_CLIENT_ID);
|
||||||
|
formData.append('client_secret', process.env.ZOHO_CLIENT_SECRET);
|
||||||
|
formData.append('redirect_uri', process.env.ZOHO_REDIRECT_URI);
|
||||||
|
formData.append('grant_type', 'refresh_token');
|
||||||
|
|
||||||
|
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
|
||||||
|
|
||||||
|
// Make the POST request using Axios
|
||||||
|
const res = await axios.post(url, formData, { headers });
|
||||||
|
if (res.data.access_token) {
|
||||||
|
const subscriptionId = _resSub.SubscriptionId;
|
||||||
|
const plan_code = _resSub?.SubscriptionDetails?.data?.subscription?.plan?.plan_code;
|
||||||
|
const quantity = parseInt(credits);
|
||||||
|
const addoncode = 'addon-credits';
|
||||||
|
const data = JSON.stringify({
|
||||||
|
plan: { plan_code: plan_code },
|
||||||
|
addons: [
|
||||||
|
{ addon_code: addoncode, addon_description: 'addon credits', quantity: quantity },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const creditsUrl = `https://www.zohoapis.in/billing/v1/subscriptions/${subscriptionId}/buyonetimeaddon`;
|
||||||
|
const resCredits = await axios.post(creditsUrl, data, {
|
||||||
|
headers: {
|
||||||
|
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
|
||||||
|
'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// console.log('resCredits ', resCredits.data);
|
||||||
|
if (resCredits.data) {
|
||||||
|
const existAddonCredits = _resSub?.AddonCredits ? _resSub.AddonCredits : 0;
|
||||||
|
const addonCredits = existAddonCredits + quantity;
|
||||||
|
const updateSub = new Parse.Object('contracts_Subscriptions');
|
||||||
|
updateSub.id = resSub.id;
|
||||||
|
updateSub.set('AddonCredits', addonCredits);
|
||||||
|
const resupdateSub = await updateSub.save(null, { useMasterKey: true });
|
||||||
|
// console.log('resupdateSub ', resupdateSub);
|
||||||
|
return { status: 'success', addon: quantity };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Parse.Error('400', 'Invalid access token.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
const code = err?.response?.data?.code || err?.response?.status || err?.code || 400;
|
||||||
|
const msg =
|
||||||
|
err?.response?.data?.error ||
|
||||||
|
err?.response?.data ||
|
||||||
|
err?.message ||
|
||||||
|
'Something went wrong.';
|
||||||
|
console.log('err in Buyaddonusers', code, msg);
|
||||||
|
throw new Parse.Error(code, msg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide parameters.');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
async function ContractUsersAftersave(request) {
|
|
||||||
console.log('In contracts_Users aftersave');
|
|
||||||
|
|
||||||
if (!request.original) {
|
|
||||||
const shareWithTeam = request.object.get('ShareWithTeam');
|
|
||||||
const newACL = new Parse.ACL();
|
|
||||||
const contactbook = new Parse.Object('contracts_Contactbook');
|
|
||||||
contactbook.set('Name', request.object.get('Name'));
|
|
||||||
contactbook.set('Email', request.object.get('Email'));
|
|
||||||
contactbook.set('ExtUserPtr', request.object.get('objectId'));
|
|
||||||
if (request.object?.get('Phone')) {
|
|
||||||
contactbook.set('Phone', request.object.get('Phone'));
|
|
||||||
}
|
|
||||||
contactbook.set('ExtUserPtr', {
|
|
||||||
__type: 'Pointer',
|
|
||||||
className: 'contracts_Users',
|
|
||||||
objectId: request.object.id,
|
|
||||||
});
|
|
||||||
contactbook.set('UserId', request.object.get('UserId'));
|
|
||||||
|
|
||||||
// newACL.setPublicReadAccess(false);
|
|
||||||
// newACL.setPublicWriteAccess(false);
|
|
||||||
const tenant_Id = request.object.get('TenantId');
|
|
||||||
if (shareWithTeam) {
|
|
||||||
if (tenant_Id) {
|
|
||||||
newACL.setReadAccess('tenant_' + tenant_Id.id, true);
|
|
||||||
newACL.setWriteAccess('tenant_' + tenant_Id.id, true);
|
|
||||||
}
|
|
||||||
newACL.setReadAccess(request.user, true);
|
|
||||||
newACL.setWriteAccess(request.user, true);
|
|
||||||
} else {
|
|
||||||
newACL.setReadAccess(request.user, true);
|
|
||||||
newACL.setWriteAccess(request.user, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
contactbook.setACL(newACL);
|
|
||||||
contactbook.save(null, { useMasterkey: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default ContractUsersAftersave;
|
|
||||||
@@ -5,7 +5,7 @@ async function DocumentBeforesave(request) {
|
|||||||
const oldDocument = request.original;
|
const oldDocument = request.original;
|
||||||
|
|
||||||
// Check if SignedUrl field has been added (transition from undefined to defined)
|
// Check if SignedUrl field has been added (transition from undefined to defined)
|
||||||
if (!oldDocument?.get('SignedUrl') && document?.get('SignedUrl')) {
|
if (oldDocument && !oldDocument?.get('SignedUrl') && document?.get('SignedUrl')) {
|
||||||
// Update count in contracts_Users class
|
// Update count in contracts_Users class
|
||||||
const query = new Parse.Query('contracts_Users');
|
const query = new Parse.Query('contracts_Users');
|
||||||
query.equalTo('objectId', oldDocument.get('ExtUserPtr').id);
|
query.equalTo('objectId', oldDocument.get('ExtUserPtr').id);
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
async function ExtUserAfterdelete(request) {
|
||||||
|
try {
|
||||||
|
const extUser = request.object;
|
||||||
|
const tenantId = extUser.get('TenantId')?.id;
|
||||||
|
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||||
|
subscription.equalTo('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: tenantId,
|
||||||
|
});
|
||||||
|
const resSub = await subscription.first({ useMasterKey: true });
|
||||||
|
if (resSub) {
|
||||||
|
const updateSub = new Parse.Object('contracts_Subscriptions');
|
||||||
|
updateSub.id = resSub.id;
|
||||||
|
if (resSub?.get('UsersCount') > 0) {
|
||||||
|
updateSub.decrement('UsersCount', 1);
|
||||||
|
} else {
|
||||||
|
updateSub.decrement('UsersCount', 0);
|
||||||
|
}
|
||||||
|
updateSub.save(null, { useMasterKey: true });
|
||||||
|
} else {
|
||||||
|
const addSub = new Parse.Object('contracts_Subscriptions');
|
||||||
|
addSub.set('UsersCount', 0);
|
||||||
|
addSub.save(null, { useMasterKey: true });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err in extuser afterdelete', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ExtUserAfterdelete;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
async function ExtUserAftersave(request) {
|
||||||
|
try {
|
||||||
|
if (!request.original) {
|
||||||
|
const extUser = request.object;
|
||||||
|
const tenantId = extUser.get('TenantId')?.id;
|
||||||
|
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||||
|
subscription.equalTo('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: tenantId,
|
||||||
|
});
|
||||||
|
const resSub = await subscription.first({ useMasterKey: true });
|
||||||
|
if (resSub) {
|
||||||
|
const updateSub = new Parse.Object('contracts_Subscriptions');
|
||||||
|
updateSub.id = resSub.id;
|
||||||
|
updateSub.increment('UsersCount', 1);
|
||||||
|
await updateSub.save(null, { useMasterKey: true });
|
||||||
|
} else {
|
||||||
|
const addSub = new Parse.Object('contracts_Subscriptions');
|
||||||
|
addSub.set('UsersCount', 1);
|
||||||
|
addSub.set('ExtUserPtr', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Users',
|
||||||
|
objectId: extUser.id,
|
||||||
|
});
|
||||||
|
addSub.set('CreatedBy', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: '_User',
|
||||||
|
objectId: extUser.get('UserId').id,
|
||||||
|
});
|
||||||
|
addSub.set('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: extUser.get('TenantId').id,
|
||||||
|
});
|
||||||
|
await addSub.save(null, { useMasterKey: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err in extuser aftersave', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ExtUserAftersave;
|
||||||
@@ -62,6 +62,7 @@ const createDocumentFromTemplate = async (template, existContact, index) => {
|
|||||||
object.set('CreatedBy', template?.CreatedBy);
|
object.set('CreatedBy', template?.CreatedBy);
|
||||||
object.set('ExtUserPtr', template?.ExtUserPtr);
|
object.set('ExtUserPtr', template?.ExtUserPtr);
|
||||||
object.set('OriginIp', template?.OriginIp || '');
|
object.set('OriginIp', template?.OriginIp || '');
|
||||||
|
object.set('IsEnableOTP', template?.IsEnableOTP || false);
|
||||||
let signers = template?.Signers || [];
|
let signers = template?.Signers || [];
|
||||||
const signerobj = {
|
const signerobj = {
|
||||||
__type: 'Pointer',
|
__type: 'Pointer',
|
||||||
@@ -221,6 +222,25 @@ const sendMailToAllSigners = async docId => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deductcount = async _resSub => {
|
||||||
|
try {
|
||||||
|
const subscriptionCls = new Parse.Object('contracts_Subscriptions');
|
||||||
|
subscriptionCls.id = _resSub.objectId;
|
||||||
|
const allowedCredits = _resSub?.AllowedCredits || 0;
|
||||||
|
const addonCredits = _resSub?.AddonCredits || 0;
|
||||||
|
if (allowedCredits > 0) {
|
||||||
|
const updateAllowedcredits = allowedCredits - 1 || 0;
|
||||||
|
subscriptionCls.set('AllowedCredits', updateAllowedcredits);
|
||||||
|
} else {
|
||||||
|
const updateAddonCredits = addonCredits > 0 ? addonCredits - 1 : 0;
|
||||||
|
subscriptionCls.set('AddonCredits', updateAddonCredits);
|
||||||
|
}
|
||||||
|
await subscriptionCls.save(null, { useMasterKey: true });
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Err in deductcount in PublicUserLinkContacttoDoc cloud function', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// `PublicUserLinkContactToDoc` cloud function is used to create contact, add this contact in contracts_Guest role and
|
// `PublicUserLinkContactToDoc` cloud function is used to create contact, add this contact in contracts_Guest role and
|
||||||
// create new document from template and save contact pointer in placeholder, signers and ACL of Document
|
// create new document from template and save contact pointer in placeholder, signers and ACL of Document
|
||||||
export default async function PublicUserLinkContactToDoc(req) {
|
export default async function PublicUserLinkContactToDoc(req) {
|
||||||
@@ -240,126 +260,163 @@ export default async function PublicUserLinkContactToDoc(req) {
|
|||||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found.');
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found.');
|
||||||
}
|
}
|
||||||
const _tempRes = JSON.parse(JSON.stringify(tempRes));
|
const _tempRes = JSON.parse(JSON.stringify(tempRes));
|
||||||
const Placeholders = _tempRes?.Placeholders || [];
|
const subscription = new Parse.Query('contracts_Subscriptions');
|
||||||
let index;
|
subscription.equalTo('TenantId', {
|
||||||
if (role) {
|
__type: 'Pointer',
|
||||||
index = Placeholders?.findIndex(x => x.Role && x.Role === role);
|
className: 'partners_Tenant',
|
||||||
} else {
|
objectId: _tempRes?.ExtUserPtr?.TenantId?.objectId,
|
||||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, '');
|
});
|
||||||
}
|
subscription.include('ExtUserPtr');
|
||||||
if (index !== -1) {
|
const date = new Date();
|
||||||
// Execute the query to check if a contact already exists in the 'contracts_Contactbook' class
|
subscription.greaterThanOrEqualTo('Next_billing_date', date);
|
||||||
const contactCls = new Parse.Query('contracts_Contactbook');
|
const resSub = await subscription.first({ useMasterKey: true });
|
||||||
contactCls.equalTo('Email', email);
|
if (resSub) {
|
||||||
contactCls.equalTo('CreatedBy', _tempRes.CreatedBy);
|
const _resSub = JSON.parse(JSON.stringify(resSub));
|
||||||
contactCls.notEqualTo('IsDeleted', true);
|
const allowedCredits = _resSub?.AllowedCredits || 0;
|
||||||
const existContact = await contactCls.first({ useMasterKey: true });
|
const addonCredits = _resSub?.AddonCredits || 0;
|
||||||
if (existContact) {
|
const totalcredits = allowedCredits + addonCredits;
|
||||||
const template_json = JSON.parse(JSON.stringify(tempRes));
|
if (totalcredits > 0) {
|
||||||
//update contact in placeholder, signers and update ACl in provide document
|
const Placeholders = _tempRes?.Placeholders || [];
|
||||||
const docRes = await createDocumentFromTemplate(template_json, existContact, index);
|
let index;
|
||||||
if (docRes) {
|
if (role) {
|
||||||
//condition will execute only if sendInOrder will be false for send email to all signers at a time.
|
index = Placeholders?.findIndex(x => x.Role && x.Role === role);
|
||||||
if (!template_json?.SendinOrder) {
|
} else {
|
||||||
await sendMailToAllSigners(docRes.id);
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, '');
|
||||||
}
|
|
||||||
return { contactId: existContact.id, docId: docRes.id };
|
|
||||||
}
|
}
|
||||||
} else {
|
if (index !== -1) {
|
||||||
// Execute the query to check if a user already exists in the 'contracts_Users' class
|
// Execute the query to check if a contact already exists in the 'contracts_Contactbook' class
|
||||||
const extUserQuery = new Parse.Query('contracts_Users');
|
const contactCls = new Parse.Query('contracts_Contactbook');
|
||||||
extUserQuery.equalTo('Email', email);
|
contactCls.equalTo('Email', email);
|
||||||
const extUser = await extUserQuery.first({ useMasterKey: true });
|
contactCls.equalTo('CreatedBy', _tempRes.CreatedBy);
|
||||||
if (extUser) {
|
contactCls.notEqualTo('IsDeleted', true);
|
||||||
const _extUser = JSON.parse(JSON.stringify(extUser));
|
const existContact = await contactCls.first({ useMasterKey: true });
|
||||||
const contact = {
|
if (existContact) {
|
||||||
UserId: _extUser.UserId,
|
const template_json = JSON.parse(JSON.stringify(tempRes));
|
||||||
Name: _extUser.Name,
|
//update contact in placeholder, signers and update ACl in provide document
|
||||||
Email: email,
|
const docRes = await createDocumentFromTemplate(template_json, existContact, index);
|
||||||
Phone: _extUser?.Phone ? _extUser.Phone : '',
|
if (docRes) {
|
||||||
CreatedBy: _tempRes.CreatedBy,
|
await deductcount(_resSub);
|
||||||
TenantId: _tempRes.ExtUserPtr.TenantId,
|
//condition will execute only if sendInOrder will be false for send email to all signers at a time.
|
||||||
};
|
if (!template_json?.SendinOrder) {
|
||||||
const template_json = JSON.parse(JSON.stringify(tempRes));
|
await sendMailToAllSigners(docRes.id);
|
||||||
// if user present on platform create contact on the basis of extended user details
|
}
|
||||||
const contactRes = await saveRoleContact(contact);
|
return { contactId: existContact.id, docId: docRes.id };
|
||||||
const docRes = await createDocumentFromTemplate(template_json, contactRes, index);
|
|
||||||
if (docRes) {
|
|
||||||
//condition will execute only if sendInOrder will be false for send email to all signers at a time.
|
|
||||||
if (!template_json?.SendinOrder) {
|
|
||||||
await sendMailToAllSigners(docRes.id);
|
|
||||||
}
|
}
|
||||||
return { contactId: contactRes.id, docId: docRes.id };
|
} else {
|
||||||
}
|
// Execute the query to check if a user already exists in the 'contracts_Users' class
|
||||||
} else if (name) {
|
const extUserQuery = new Parse.Query('contracts_Users');
|
||||||
try {
|
extUserQuery.equalTo('Email', email);
|
||||||
// Execute the query to check if a user already exists in the '_User' class
|
const extUser = await extUserQuery.first({ useMasterKey: true });
|
||||||
const userQuery = new Parse.Query(Parse.User);
|
if (extUser) {
|
||||||
userQuery.equalTo('email', email);
|
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||||
const userRes = await userQuery.first({ useMasterKey: true });
|
|
||||||
if (userRes) {
|
|
||||||
const contact = {
|
const contact = {
|
||||||
UserId: { __type: 'Pointer', className: '_User', objectId: userRes.id },
|
UserId: _extUser.UserId,
|
||||||
Name: name,
|
Name: _extUser.Name,
|
||||||
Email: email,
|
Email: email,
|
||||||
Phone: phone,
|
Phone: _extUser?.Phone ? _extUser.Phone : '',
|
||||||
CreatedBy: _tempRes.CreatedBy,
|
CreatedBy: _tempRes.CreatedBy,
|
||||||
TenantId: _tempRes.ExtUserPtr.TenantId,
|
TenantId: _tempRes.ExtUserPtr.TenantId,
|
||||||
};
|
};
|
||||||
const template_json = JSON.parse(JSON.stringify(tempRes));
|
const template_json = JSON.parse(JSON.stringify(tempRes));
|
||||||
// Create new contract on the basis provided contact details by user and userId from _User class
|
// if user present on platform create contact on the basis of extended user details
|
||||||
const contactRes = await saveRoleContact(contact);
|
const contactRes = await saveRoleContact(contact);
|
||||||
//update contact in placeholder, signers and update ACl in provide document
|
|
||||||
const docRes = await createDocumentFromTemplate(template_json, contactRes, index);
|
const docRes = await createDocumentFromTemplate(template_json, contactRes, index);
|
||||||
if (docRes) {
|
if (docRes) {
|
||||||
|
await deductcount(_resSub);
|
||||||
//condition will execute only if sendInOrder will be false for send email to all signers at a time.
|
//condition will execute only if sendInOrder will be false for send email to all signers at a time.
|
||||||
if (!template_json?.SendinOrder) {
|
if (!template_json?.SendinOrder) {
|
||||||
await sendMailToAllSigners(docRes.id);
|
await sendMailToAllSigners(docRes.id);
|
||||||
}
|
}
|
||||||
return { contactId: contactRes.id, docId: docRes.id };
|
return { contactId: contactRes.id, docId: docRes.id };
|
||||||
}
|
}
|
||||||
|
} else if (name) {
|
||||||
|
try {
|
||||||
|
// Execute the query to check if a user already exists in the '_User' class
|
||||||
|
const userQuery = new Parse.Query(Parse.User);
|
||||||
|
userQuery.equalTo('email', email);
|
||||||
|
const userRes = await userQuery.first({ useMasterKey: true });
|
||||||
|
if (userRes) {
|
||||||
|
const contact = {
|
||||||
|
UserId: { __type: 'Pointer', className: '_User', objectId: userRes.id },
|
||||||
|
Name: name,
|
||||||
|
Email: email,
|
||||||
|
Phone: phone,
|
||||||
|
CreatedBy: _tempRes.CreatedBy,
|
||||||
|
TenantId: _tempRes.ExtUserPtr.TenantId,
|
||||||
|
};
|
||||||
|
const template_json = JSON.parse(JSON.stringify(tempRes));
|
||||||
|
// Create new contract on the basis provided contact details by user and userId from _User class
|
||||||
|
const contactRes = await saveRoleContact(contact);
|
||||||
|
//update contact in placeholder, signers and update ACl in provide document
|
||||||
|
const docRes = await createDocumentFromTemplate(
|
||||||
|
template_json,
|
||||||
|
contactRes,
|
||||||
|
index
|
||||||
|
);
|
||||||
|
if (docRes) {
|
||||||
|
await deductcount(_resSub);
|
||||||
|
//condition will execute only if sendInOrder will be false for send email to all signers at a time.
|
||||||
|
if (!template_json?.SendinOrder) {
|
||||||
|
await sendMailToAllSigners(docRes.id);
|
||||||
|
}
|
||||||
|
return { contactId: contactRes.id, docId: docRes.id };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// create new user in _User class on the basis of details provide by user
|
||||||
|
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 newUserRes = await _user.save();
|
||||||
|
const contact = {
|
||||||
|
UserId: { __type: 'Pointer', className: '_User', objectId: newUserRes.id },
|
||||||
|
Name: name,
|
||||||
|
Email: email,
|
||||||
|
Phone: phone,
|
||||||
|
CreatedBy: _tempRes.CreatedBy,
|
||||||
|
TenantId: _tempRes.ExtUserPtr.TenantId,
|
||||||
|
};
|
||||||
|
const template_json = JSON.parse(JSON.stringify(tempRes));
|
||||||
|
// Create new contract on the basis provided contact details by user and userId from _User class
|
||||||
|
const contactRes = await saveRoleContact(contact);
|
||||||
|
//update contact in placeholder, signers and update ACl in provide document
|
||||||
|
const docRes = await createDocumentFromTemplate(
|
||||||
|
template_json,
|
||||||
|
contactRes,
|
||||||
|
index
|
||||||
|
);
|
||||||
|
if (docRes) {
|
||||||
|
await deductcount(_resSub);
|
||||||
|
//condition will execute only if sendInOrder will be false for send email to all signers at a time.
|
||||||
|
if (!template_json?.SendinOrder) {
|
||||||
|
await sendMailToAllSigners(docRes.id);
|
||||||
|
}
|
||||||
|
return { contactId: contactRes.id, docId: docRes.id };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Err', err);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// create new user in _User class on the basis of details provide by user
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||||
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 newUserRes = await _user.save();
|
|
||||||
const contact = {
|
|
||||||
UserId: { __type: 'Pointer', className: '_User', objectId: newUserRes.id },
|
|
||||||
Name: name,
|
|
||||||
Email: email,
|
|
||||||
Phone: phone,
|
|
||||||
CreatedBy: _tempRes.CreatedBy,
|
|
||||||
TenantId: _tempRes.ExtUserPtr.TenantId,
|
|
||||||
};
|
|
||||||
const template_json = JSON.parse(JSON.stringify(tempRes));
|
|
||||||
// Create new contract on the basis provided contact details by user and userId from _User class
|
|
||||||
const contactRes = await saveRoleContact(contact);
|
|
||||||
//update contact in placeholder, signers and update ACl in provide document
|
|
||||||
const docRes = await createDocumentFromTemplate(template_json, contactRes, index);
|
|
||||||
if (docRes) {
|
|
||||||
//condition will execute only if sendInOrder will be false for send email to all signers at a time.
|
|
||||||
if (!template_json?.SendinOrder) {
|
|
||||||
await sendMailToAllSigners(docRes.id);
|
|
||||||
}
|
|
||||||
return { contactId: contactRes.id, docId: docRes.id };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
console.log('Err', err);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
throw new Parse.Error(
|
||||||
|
Parse.Error.OBJECT_NOT_FOUND,
|
||||||
|
'Please provide required parameters!'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
throw new Parse.Error(Parse.Error.REQUEST_LIMIT_EXCEEDED, 'Insufficient Credit');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Please provide required parameters!');
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Plan expired');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found.');
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found.');
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { smtpenable, updateMailCount } from '../../Utils.js';
|
import { appName, smtpenable, updateMailCount } from '../../Utils.js';
|
||||||
async function getDocument(docId) {
|
async function getDocument(docId) {
|
||||||
try {
|
try {
|
||||||
const query = new Parse.Query('contracts_Document');
|
const query = new Parse.Query('contracts_Document');
|
||||||
@@ -28,12 +28,12 @@ async function sendMailOTPv1(request) {
|
|||||||
const mailsender = smtpenable ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER;
|
const mailsender = smtpenable ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER;
|
||||||
try {
|
try {
|
||||||
await Parse.Cloud.sendEmail({
|
await Parse.Cloud.sendEmail({
|
||||||
from: 'Opensign™' + ' <' + mailsender + '>',
|
from: appName + ' <' + mailsender + '>',
|
||||||
recipient: recipient,
|
recipient: recipient,
|
||||||
subject: 'Your OpenSign™ OTP',
|
subject: `Your ${appName} OTP`,
|
||||||
text: 'This email is a test.',
|
text: 'This email is a test.',
|
||||||
html:
|
html:
|
||||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'><div style='background-color:red;padding:2px;font-family:system-ui; background-color:#47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',>OTP Verification</p></div><div style='padding:20px'><p style='font-family:system-ui;font-size:14px'>Your OTP for OpenSign™ verification is:</p><p style=' text-decoration: none; font-weight: bolder; color:blue;font-size:45px;margin:20px'>" +
|
`<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'><div style='background-color:red;padding:2px;font-family:system-ui; background-color:#47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',>OTP Verification</p></div><div style='padding:20px'><p style='font-family:system-ui;font-size:14px'>Your OTP for ${appName} verification is:</p><p style=' text-decoration: none; font-weight: bolder; color:blue;font-size:45px;margin:20px'>` +
|
||||||
code +
|
code +
|
||||||
'</p></div> </div> </div></body></html>',
|
'</p></div> </div> </div></body></html>',
|
||||||
});
|
});
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user