mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-05 09:17:39 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6d97d587f | ||
|
|
ff9a495775 | ||
|
|
b29c7d5c7f | ||
|
|
fddeba8d44 | ||
|
|
c564b5741c | ||
|
|
179c3c5dfe | ||
|
|
221f71c061 | ||
|
|
a26e65f76f | ||
|
|
9ba05d23fd | ||
|
|
0f67013005 | ||
|
|
65d5c7f337 | ||
|
|
a7dd47f1b1 | ||
|
|
350212c02f | ||
|
|
d9126d6701 | ||
|
|
51c3a0f71a | ||
|
|
a4bf9ff915 | ||
|
|
28a2a113e2 | ||
|
|
07382822bd | ||
|
|
06677d923c | ||
|
|
534dc3d3f5 | ||
|
|
a69682cebf | ||
|
|
2ae7e8ced2 | ||
|
|
e20b75cfc1 | ||
|
|
37b73e36ca | ||
|
|
cc6b64d140 | ||
|
|
4b765a8e1d | ||
|
|
4a7108e4f6 | ||
|
|
66bf577676 | ||
|
|
d04b79001a | ||
|
|
e14b2a2a17 | ||
|
|
6afa97a76b | ||
|
|
3a28b1cdd7 | ||
|
|
23b48838ae | ||
|
|
bddebf2758 | ||
|
|
5a68e18c48 | ||
|
|
082f0569e2 | ||
|
|
b01618c8ca | ||
|
|
7b0f0d5b9f | ||
|
|
1381a65c0b | ||
|
|
961ec2b2ba | ||
|
|
022cb20b64 | ||
|
|
7b4fa4fe23 | ||
|
|
c85c21ef8a | ||
|
|
09fb01862d | ||
|
|
f6ce1b45fb | ||
|
|
8fd2d4210e | ||
|
|
0f7f1f1ba2 | ||
|
|
8693ef29f6 | ||
|
|
dc67d2c23d | ||
|
|
761925fced | ||
|
|
c240eb133d | ||
|
|
9daed4a5ed | ||
|
|
ee18f82fa9 | ||
|
|
4085f8259d | ||
|
|
98f84f6cc8 | ||
|
|
da9363f588 | ||
|
|
5afb60a687 | ||
|
|
a18733ad79 | ||
|
|
400e132f11 | ||
|
|
c56830b7be | ||
|
|
f988c25491 | ||
|
|
53bd13e03b | ||
|
|
68edecae18 | ||
|
|
b421c0f1a9 | ||
|
|
3858746d64 | ||
|
|
41e8aa18a7 | ||
|
|
fb8915e9db | ||
|
|
ba2bb07aa9 | ||
|
|
74083d0606 | ||
|
|
0f2862c52e | ||
|
|
61e11b7105 | ||
|
|
d7de8648e9 | ||
|
|
c279fd6525 | ||
|
|
3599fbee21 | ||
|
|
9ad51a1d6a | ||
|
|
03e22dbf33 | ||
|
|
5693fa230b | ||
|
|
8cd90911a8 | ||
|
|
7cf820d205 | ||
|
|
4d01547fd5 | ||
|
|
6597f67f0a | ||
|
|
14ce91350e | ||
|
|
7a5f75ea79 | ||
|
|
a44cb7168f | ||
|
|
1c6b056d6c | ||
|
|
cf6759ce79 | ||
|
|
d422f46f47 | ||
|
|
85f94c8ffa | ||
|
|
91da331ce6 | ||
|
|
3db6946198 | ||
|
|
94c8caa3e6 | ||
|
|
ed1120927c | ||
|
|
79b4c38587 | ||
|
|
2cc5517bc1 | ||
|
|
eddf70f102 | ||
|
|
b6774519f9 | ||
|
|
d6bb83f997 | ||
|
|
55e8042b0a | ||
|
|
d5bc2df20f | ||
|
|
c623e868f7 | ||
|
|
174b9b9941 | ||
|
|
0eb247ae0c | ||
|
|
f96df699e4 | ||
|
|
dcaca98aec | ||
|
|
d70f4dddb6 | ||
|
|
db34c4248c | ||
|
|
1d39db6d7d | ||
|
|
654dadce93 | ||
|
|
e578981791 | ||
|
|
c4297a260e | ||
|
|
ecc453957c | ||
|
|
498e0c6be6 | ||
|
|
b4d73b2b44 | ||
|
|
f14c98505a | ||
|
|
3f23bdd372 | ||
|
|
440d253124 | ||
|
|
2b6bf7bcaa | ||
|
|
cb6d9e9b9b | ||
|
|
ebeeedc96c | ||
|
|
5cecf3390b | ||
|
|
9890d568fd | ||
|
|
06bcae64be | ||
|
|
fb017c4bcd | ||
|
|
01d3edd262 | ||
|
|
41a025715e | ||
|
|
306768fbd2 | ||
|
|
d82da53258 | ||
|
|
673245df02 | ||
|
|
42549e5792 | ||
|
|
493731a6af | ||
|
|
cc8b4b7157 | ||
|
|
4cbd7e74f7 | ||
|
|
b300a5bb39 | ||
|
|
5422fefc54 | ||
|
|
248b0cac0b | ||
|
|
a388a7c345 | ||
|
|
fc564ca37b | ||
|
|
37b2e4c97a | ||
|
|
a3bc9817e7 | ||
|
|
8a216e6c0d | ||
|
|
613b1cfe07 | ||
|
|
ee77534e35 | ||
|
|
737b33db1e | ||
|
|
ac214d0467 | ||
|
|
f8b21e7a93 | ||
|
|
7e6df13b71 | ||
|
|
3e584cec1a | ||
|
|
bc75dd109f | ||
|
|
6b3abed782 | ||
|
|
f163958cd0 | ||
|
|
ecd461b96c | ||
|
|
1371c2c09a | ||
|
|
3121f35158 | ||
|
|
3c0db9473c | ||
|
|
4f2b72dd4d | ||
|
|
7d9af1db95 | ||
|
|
0e38783560 | ||
|
|
6880ae35a8 | ||
|
|
9a07c67b69 | ||
|
|
33bfdeef15 | ||
|
|
a404247604 | ||
|
|
c48579daa7 | ||
|
|
509f8f9a07 | ||
|
|
5b85d5b277 | ||
|
|
bbf3170398 | ||
|
|
c172a7c55c | ||
|
|
90f3e0066b | ||
|
|
b6e028a2c0 | ||
|
|
11384192ba | ||
|
|
9df63265fb | ||
|
|
ff6a8ce755 | ||
|
|
60c1aa253a | ||
|
|
ad2fec0d66 | ||
|
|
0451a6cae0 | ||
|
|
0d5f8981fe | ||
|
|
cfd8be0eee | ||
|
|
86e5ef6ef5 | ||
|
|
1af47c8425 | ||
|
|
f0395cb2c7 | ||
|
|
598aa2975f | ||
|
|
0742291216 | ||
|
|
94eeceeaf9 | ||
|
|
970fbecb7b | ||
|
|
361e082930 | ||
|
|
3f9b6eb5a9 | ||
|
|
2265bee61f | ||
|
|
6390706d8d | ||
|
|
37e03c1026 | ||
|
|
c6fa6c710d | ||
|
|
2e921e30b6 | ||
|
|
686a773d34 | ||
|
|
b03e1b8f9d | ||
|
|
f1ceae794f | ||
|
|
5a8bcb8f9a | ||
|
|
ce70da7d8e | ||
|
|
db03dfa641 | ||
|
|
7e70a5e111 | ||
|
|
f5f18f1630 | ||
|
|
fa6856c649 | ||
|
|
3b4946e47b | ||
|
|
05fe68d458 | ||
|
|
2f3cdca821 | ||
|
|
4d8a54a6c5 | ||
|
|
4fe5bdaad8 | ||
|
|
b95ede5273 | ||
|
|
5b2684a9f4 | ||
|
|
d779720f26 | ||
|
|
3cf8029978 | ||
|
|
0bb857a942 | ||
|
|
103d32edcb | ||
|
|
eca6ad374b | ||
|
|
d2efe88266 | ||
|
|
450e5ec7f7 | ||
|
|
3bbbda91b8 | ||
|
|
a48db306bb | ||
|
|
2a60b30c75 | ||
|
|
19cfa9d27d | ||
|
|
0fc12c957e | ||
|
|
6fd332f8b4 | ||
|
|
39f7ccecaa | ||
|
|
3bd306809b | ||
|
|
04e9d13206 | ||
|
|
b24739d61b | ||
|
|
9dda211605 | ||
|
|
93708a6875 | ||
|
|
e78f6f6df4 | ||
|
|
ccaaca75ba | ||
|
|
dedff36b35 | ||
|
|
4d561ca19e | ||
|
|
f70e9e2a3f | ||
|
|
e4a3ce405e | ||
|
|
c3be2a1fef | ||
|
|
8b2f7f1e95 | ||
|
|
55465a035f | ||
|
|
d30105299c | ||
|
|
78b038da13 | ||
|
|
d230ad2655 | ||
|
|
367c824918 | ||
|
|
5f8affb1bb | ||
|
|
3bd23f83cf | ||
|
|
ab1dbecab2 | ||
|
|
44c6aa9b0b | ||
|
|
ad922c16c7 | ||
|
|
87ee2e881e | ||
|
|
3659a1de55 | ||
|
|
cc49a2fd4e | ||
|
|
babd43e710 | ||
|
|
8dde38edf1 | ||
|
|
6c16d00031 | ||
|
|
99f444a8a1 | ||
|
|
f0149f6fd8 | ||
|
|
bdb7d9be8f | ||
|
|
27dcd7fefd | ||
|
|
a2467ef1a6 | ||
|
|
824b0a5407 | ||
|
|
ac8195a52d | ||
|
|
e0920bf5d8 | ||
|
|
4a5f030d87 | ||
|
|
ba839b0fc8 | ||
|
|
27130fd223 | ||
|
|
19ba9e3091 | ||
|
|
8c64a89f08 | ||
|
|
1c3d2d5c9a | ||
|
|
b36df32b19 | ||
|
|
155a3eee14 | ||
|
|
7bb46782a3 | ||
|
|
40961936d0 | ||
|
|
db310b0d73 | ||
|
|
f0e9c6b3e4 | ||
|
|
28fd98c0db | ||
|
|
9d81fce956 | ||
|
|
c61be7c35b | ||
|
|
b04d2abbab | ||
|
|
387154c07b | ||
|
|
f7606bce35 | ||
|
|
f08758fd71 | ||
|
|
d3b1a37a7c | ||
|
|
4718c653f7 | ||
|
|
f9b8437981 | ||
|
|
b0c73bc63e | ||
|
|
269246659b | ||
|
|
51fe5d133e | ||
|
|
36a1123535 | ||
|
|
3c1ceb4995 | ||
|
|
53d154fa59 |
Generated
+254
-124
@@ -8,9 +8,9 @@
|
|||||||
"name": "open_sign",
|
"name": "open_sign",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formkit/auto-animate": "^0.8.1",
|
"@formkit/auto-animate": "^0.8.2",
|
||||||
"@radix-ui/themes": "^2.0.3",
|
"@radix-ui/themes": "^2.0.3",
|
||||||
"@react-pdf/renderer": "^3.4.0",
|
"@react-pdf/renderer": "^3.4.4",
|
||||||
"@reduxjs/toolkit": "^2.2.1",
|
"@reduxjs/toolkit": "^2.2.1",
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
"radix-ui": "^1.0.1",
|
"radix-ui": "^1.0.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-bootstrap": "^2.10.2",
|
"react-bootstrap": "^2.10.2",
|
||||||
|
"react-cookie": "^7.1.4",
|
||||||
"react-datepicker": "^6.4.0",
|
"react-datepicker": "^6.4.0",
|
||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
"react-dnd-html5-backend": "^16.0.1",
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
@@ -33,15 +34,17 @@
|
|||||||
"react-konva": "^18.2.10",
|
"react-konva": "^18.2.10",
|
||||||
"react-modal": "^3.16.1",
|
"react-modal": "^3.16.1",
|
||||||
"react-pdf": "^7.7.1",
|
"react-pdf": "^7.7.1",
|
||||||
|
"react-quill": "^2.0.0",
|
||||||
"react-redux": "^9.1.0",
|
"react-redux": "^9.1.0",
|
||||||
"react-rnd": "^10.4.1",
|
"react-rnd": "^10.4.10",
|
||||||
"react-router-dom": "^6.22.3",
|
"react-router-dom": "^6.22.3",
|
||||||
"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.0",
|
||||||
"react-signature-canvas": "^1.0.6",
|
"react-signature-canvas": "^1.0.6",
|
||||||
"react-tooltip": "^5.26.3",
|
"react-tooltip": "^5.26.3",
|
||||||
"reactour": "^1.19.2",
|
"react-web-share": "^2.0.2",
|
||||||
|
"reactour": "^1.19.3",
|
||||||
"redux": "^5.0.1",
|
"redux": "^5.0.1",
|
||||||
"redux-thunk": "^3.1.0",
|
"redux-thunk": "^3.1.0",
|
||||||
"regex-parser": "^2.3.0",
|
"regex-parser": "^2.3.0",
|
||||||
@@ -50,14 +53,14 @@
|
|||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/runtime-corejs2": "^7.24.1",
|
"@babel/runtime-corejs2": "^7.24.5",
|
||||||
"autoprefixer": "^10.4.18",
|
"autoprefixer": "^10.4.19",
|
||||||
"commitizen": "^4.3.0",
|
"commitizen": "^4.3.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-react": "^7.34.1",
|
"eslint-plugin-react": "^7.34.1",
|
||||||
"lint-staged": "^15.2.2",
|
"lint-staged": "^15.2.2",
|
||||||
"postcss": "^8.4.37",
|
"postcss": "^8.4.38",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"pretty-quick": "^3.3.1",
|
"pretty-quick": "^3.3.1",
|
||||||
"tailwindcss": "^3.4.1"
|
"tailwindcss": "^3.4.1"
|
||||||
@@ -1991,9 +1994,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime-corejs2": {
|
"node_modules/@babel/runtime-corejs2": {
|
||||||
"version": "7.24.1",
|
"version": "7.24.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.24.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.24.5.tgz",
|
||||||
"integrity": "sha512-De0q0utpUPiXnc7+B7Ku86mJ0eDItC/v3uFa/lQkq63XnHyZiytDHeCIvechlnVwwpU2ChjGF7c3I+mBrTudwg==",
|
"integrity": "sha512-cC9jiO6s/IN+xwCHYy1AGrcFJ4bwgIwb8HX1KaoEpRsznLlO4x9eBP6AX7RIeMSWlQqEj2WHox637OS8cDq6Ew==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^2.6.12",
|
"core-js": "^2.6.12",
|
||||||
@@ -2986,9 +2989,9 @@
|
|||||||
"integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A=="
|
"integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A=="
|
||||||
},
|
},
|
||||||
"node_modules/@formkit/auto-animate": {
|
"node_modules/@formkit/auto-animate": {
|
||||||
"version": "0.8.1",
|
"version": "0.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/@formkit/auto-animate/-/auto-animate-0.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/@formkit/auto-animate/-/auto-animate-0.8.2.tgz",
|
||||||
"integrity": "sha512-0/Z2cuNXWVVIG/l0SpcHAWFhGdvLJ8DRvEfRWvmojtmRWfEy+LWNwgDazbZqY0qQYtkHcoEK3jBLkhiZaB/4Ig=="
|
"integrity": "sha512-SwPWfeRa5veb1hOIBMdzI+73te5puUBHmqqaF1Bu7FjvxlYSz/kJcZKSa9Cg60zL0uRNeJL2SbRxV6Jp6Q1nFQ=="
|
||||||
},
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.11.14",
|
"version": "0.11.14",
|
||||||
@@ -5378,41 +5381,41 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@react-pdf/font": {
|
"node_modules/@react-pdf/font": {
|
||||||
"version": "2.4.4",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/@react-pdf/font/-/font-2.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/@react-pdf/font/-/font-2.5.1.tgz",
|
||||||
"integrity": "sha512-yjK5eSY+LcbxS0m+sOYln8GdgIbUgti4xjwf14kx8OSsOMJQJyHFALHMh2cLcKJR9yZeqVDo1FwCsY6gw1yCkg==",
|
"integrity": "sha512-Hyb2zBb92Glc3lvhmJfy4dO2Mj29KB26Uk12Ua9EhKAdiuCTLBqgP8Oe1cGwrvDI7xA4OOcwvBMdYh0vhOUHzA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@react-pdf/types": "^2.4.1",
|
"@react-pdf/types": "^2.5.0",
|
||||||
"cross-fetch": "^3.1.5",
|
"cross-fetch": "^3.1.5",
|
||||||
"fontkit": "^2.0.2",
|
"fontkit": "^2.0.2",
|
||||||
"is-url": "^1.2.4"
|
"is-url": "^1.2.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@react-pdf/image": {
|
"node_modules/@react-pdf/image": {
|
||||||
"version": "2.3.5",
|
"version": "2.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/@react-pdf/image/-/image-2.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@react-pdf/image/-/image-2.3.6.tgz",
|
||||||
"integrity": "sha512-YK8oeD4cYTbX2KwdsY5DEDpvsKQoGbf3kwlxAQwYm8wrEol8V/5oCl8H8ZqdZIYQhx2XPp63cocQfMCZGwf+4w==",
|
"integrity": "sha512-7iZDYZrZlJqNzS6huNl2XdMcLFUo68e6mOdzQeJ63d5eApdthhSHBnkGzHfLhH5t8DCpZNtClmklzuLL63ADfw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@react-pdf/png-js": "^2.3.1",
|
"@react-pdf/png-js": "^2.3.1",
|
||||||
"cross-fetch": "^3.1.5",
|
"cross-fetch": "^3.1.5",
|
||||||
"jay-peg": "^1.0.1"
|
"jay-peg": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@react-pdf/layout": {
|
"node_modules/@react-pdf/layout": {
|
||||||
"version": "3.11.3",
|
"version": "3.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/@react-pdf/layout/-/layout-3.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/@react-pdf/layout/-/layout-3.12.1.tgz",
|
||||||
"integrity": "sha512-SwfIWmZl3yZDgb4Qa9ebjAZTd/FyI5E2curSfra6SuAkrsEF037cmVfxCTgYCkPwpVMv/omOENPI+WjhOKPofA==",
|
"integrity": "sha512-BxSeykDxvADlpe4OGtQ7NH46QXq3uImAYsTHOPLCwbXMniQ1O3uCBx7H+HthxkCNshgYVPp9qS3KyvQv/oIZwg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@react-pdf/fns": "2.2.1",
|
"@react-pdf/fns": "2.2.1",
|
||||||
"@react-pdf/image": "^2.3.5",
|
"@react-pdf/image": "^2.3.6",
|
||||||
"@react-pdf/pdfkit": "^3.1.7",
|
"@react-pdf/pdfkit": "^3.1.10",
|
||||||
"@react-pdf/primitives": "^3.1.1",
|
"@react-pdf/primitives": "^3.1.1",
|
||||||
"@react-pdf/stylesheet": "^4.2.4",
|
"@react-pdf/stylesheet": "^4.2.5",
|
||||||
"@react-pdf/textkit": "^4.4.1",
|
"@react-pdf/textkit": "^4.4.1",
|
||||||
"@react-pdf/types": "^2.4.1",
|
"@react-pdf/types": "^2.5.0",
|
||||||
"cross-fetch": "^3.1.5",
|
"cross-fetch": "^3.1.5",
|
||||||
"emoji-regex": "^10.3.0",
|
"emoji-regex": "^10.3.0",
|
||||||
"queue": "^6.0.1",
|
"queue": "^6.0.1",
|
||||||
@@ -5425,16 +5428,16 @@
|
|||||||
"integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw=="
|
"integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw=="
|
||||||
},
|
},
|
||||||
"node_modules/@react-pdf/pdfkit": {
|
"node_modules/@react-pdf/pdfkit": {
|
||||||
"version": "3.1.7",
|
"version": "3.1.10",
|
||||||
"resolved": "https://registry.npmjs.org/@react-pdf/pdfkit/-/pdfkit-3.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@react-pdf/pdfkit/-/pdfkit-3.1.10.tgz",
|
||||||
"integrity": "sha512-iXMmATqW5Aycpzm8nNsZOHV/DX2lpd8l5VkaTy1HjzHgQ3MHoV45BHwRph53soEqoPo7rUfpjuSi7X3hngPWGA==",
|
"integrity": "sha512-P/qPBtCFo2HDJD0i6NfbmoBRrsOVO8CIogYsefwG4fklTo50zNgnMM5U1WLckTuX8Qt1ThiQuokmTG5arheblA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@react-pdf/png-js": "^2.3.1",
|
"@react-pdf/png-js": "^2.3.1",
|
||||||
"browserify-zlib": "^0.2.0",
|
"browserify-zlib": "^0.2.0",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"fontkit": "^2.0.2",
|
"fontkit": "^2.0.2",
|
||||||
"jay-peg": "^1.0.1",
|
"jay-peg": "^1.0.2",
|
||||||
"vite-compatible-readable-stream": "^3.6.1"
|
"vite-compatible-readable-stream": "^3.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -5452,15 +5455,15 @@
|
|||||||
"integrity": "sha512-miwjxLwTnO3IjoqkTVeTI+9CdyDggwekmSLhVCw+a/7FoQc+gF3J2dSKwsHvAcVFM0gvU8mzCeTofgw0zPDq0w=="
|
"integrity": "sha512-miwjxLwTnO3IjoqkTVeTI+9CdyDggwekmSLhVCw+a/7FoQc+gF3J2dSKwsHvAcVFM0gvU8mzCeTofgw0zPDq0w=="
|
||||||
},
|
},
|
||||||
"node_modules/@react-pdf/render": {
|
"node_modules/@react-pdf/render": {
|
||||||
"version": "3.4.3",
|
"version": "3.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/@react-pdf/render/-/render-3.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/@react-pdf/render/-/render-3.4.4.tgz",
|
||||||
"integrity": "sha512-9LL059vfwrK1gA0uIA4utpQ/pUH9EW/yia4bb7pCoARs8IlupY5UP265jgax15ua0p+MdUwShZzQ9rilu7kGsw==",
|
"integrity": "sha512-CfGxWmVgrY3JgmB1iMnz2W6Ck+8pisZeFt8vGlxP+JfT+0onr208pQvGSV5KwA9LGhAdABxqc/+y17V3vtKdFA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@react-pdf/fns": "2.2.1",
|
"@react-pdf/fns": "2.2.1",
|
||||||
"@react-pdf/primitives": "^3.1.1",
|
"@react-pdf/primitives": "^3.1.1",
|
||||||
"@react-pdf/textkit": "^4.4.1",
|
"@react-pdf/textkit": "^4.4.1",
|
||||||
"@react-pdf/types": "^2.4.1",
|
"@react-pdf/types": "^2.5.0",
|
||||||
"abs-svg-path": "^0.1.1",
|
"abs-svg-path": "^0.1.1",
|
||||||
"color-string": "^1.9.1",
|
"color-string": "^1.9.1",
|
||||||
"normalize-svg-path": "^1.1.0",
|
"normalize-svg-path": "^1.1.0",
|
||||||
@@ -5469,17 +5472,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@react-pdf/renderer": {
|
"node_modules/@react-pdf/renderer": {
|
||||||
"version": "3.4.0",
|
"version": "3.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/@react-pdf/renderer/-/renderer-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@react-pdf/renderer/-/renderer-3.4.4.tgz",
|
||||||
"integrity": "sha512-8i/B8xJZ4AwINM/RRBnawBXfNACaehQT/bM19TOTUjHoddYaRKM1g1+qOZx58yfxfr5TFRs4fORxEPU1mGmR1A==",
|
"integrity": "sha512-j1TWMHHXDeHdoQE3xjhBh0MZ2rn7wHIlP/uglr/EJZXqnPbfg6bfLzRJCM6bs+XJV3d8+zLQjHf6sF/fWcBDfg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@react-pdf/font": "^2.4.4",
|
"@react-pdf/font": "^2.5.1",
|
||||||
"@react-pdf/layout": "^3.11.3",
|
"@react-pdf/layout": "^3.12.1",
|
||||||
"@react-pdf/pdfkit": "^3.1.7",
|
"@react-pdf/pdfkit": "^3.1.10",
|
||||||
"@react-pdf/primitives": "^3.1.1",
|
"@react-pdf/primitives": "^3.1.1",
|
||||||
"@react-pdf/render": "^3.4.3",
|
"@react-pdf/render": "^3.4.4",
|
||||||
"@react-pdf/types": "^2.4.1",
|
"@react-pdf/types": "^2.5.0",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
@@ -5500,13 +5503,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@react-pdf/stylesheet": {
|
"node_modules/@react-pdf/stylesheet": {
|
||||||
"version": "4.2.4",
|
"version": "4.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@react-pdf/stylesheet/-/stylesheet-4.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@react-pdf/stylesheet/-/stylesheet-4.2.5.tgz",
|
||||||
"integrity": "sha512-CgRfDzeMtnV0GL7zSn381NubmgwqKhFKcK1YrWX3azl/KWVh52jjFd3HWi6dvcETNT862mjWz5MnExe4WOBJXA==",
|
"integrity": "sha512-XnmapeCW+hDuNdVwpuvO04WKv71wAs8aH+saIq29Bo2fp1SxznHTcQArTZtK6Wgr/E9BHXeB2iAPpUZuI6G+xA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@react-pdf/fns": "2.2.1",
|
"@react-pdf/fns": "2.2.1",
|
||||||
"@react-pdf/types": "^2.4.1",
|
"@react-pdf/types": "^2.5.0",
|
||||||
"color-string": "^1.9.1",
|
"color-string": "^1.9.1",
|
||||||
"hsl-to-hex": "^1.0.0",
|
"hsl-to-hex": "^1.0.0",
|
||||||
"media-engine": "^1.0.3",
|
"media-engine": "^1.0.3",
|
||||||
@@ -5526,9 +5529,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@react-pdf/types": {
|
"node_modules/@react-pdf/types": {
|
||||||
"version": "2.4.1",
|
"version": "2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@react-pdf/types/-/types-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@react-pdf/types/-/types-2.5.0.tgz",
|
||||||
"integrity": "sha512-w8pk7svhjVj5f7d7kjEGXSk26ffCqRSQcgWR4DwcFltNpSM18ZJmzmM6WrNeeP437y48LlykLnmGDA3oATakgw=="
|
"integrity": "sha512-XsVRkt0hQ60I4e3leAVt+aZR3KJCaJd179BfJHAv4F4x6Vq3yqkry8lcbUWKGKDw1j3/8sW4FsgGR41SFvsG9A=="
|
||||||
},
|
},
|
||||||
"node_modules/@reduxjs/toolkit": {
|
"node_modules/@reduxjs/toolkit": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
@@ -6054,6 +6057,11 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/cookie": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
|
||||||
|
},
|
||||||
"node_modules/@types/eslint": {
|
"node_modules/@types/eslint": {
|
||||||
"version": "8.44.4",
|
"version": "8.44.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.4.tgz",
|
||||||
@@ -6108,11 +6116,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/hoist-non-react-statics": {
|
"node_modules/@types/hoist-non-react-statics": {
|
||||||
"version": "3.3.3",
|
"version": "3.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz",
|
||||||
"integrity": "sha512-Wny3a2UXn5FEA1l7gc6BbpoV5mD1XijZqgkp4TRgDCDL5r3B5ieOFGUX5h3n78Tr1MEG7BfvoM8qeztdvNU0fw==",
|
"integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==",
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
"hoist-non-react-statics": "^3.3.0"
|
"hoist-non-react-statics": "^3.3.0"
|
||||||
@@ -6205,6 +6211,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz",
|
||||||
"integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg=="
|
"integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/quill": {
|
||||||
|
"version": "1.3.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/quill/-/quill-1.3.10.tgz",
|
||||||
|
"integrity": "sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==",
|
||||||
|
"dependencies": {
|
||||||
|
"parchment": "^1.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/range-parser": {
|
"node_modules/@types/range-parser": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz",
|
||||||
@@ -7223,9 +7237,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/autoprefixer": {
|
"node_modules/autoprefixer": {
|
||||||
"version": "10.4.18",
|
"version": "10.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz",
|
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz",
|
||||||
"integrity": "sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==",
|
"integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -7242,7 +7256,7 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"browserslist": "^4.23.0",
|
"browserslist": "^4.23.0",
|
||||||
"caniuse-lite": "^1.0.30001591",
|
"caniuse-lite": "^1.0.30001599",
|
||||||
"fraction.js": "^4.3.7",
|
"fraction.js": "^4.3.7",
|
||||||
"normalize-range": "^0.1.2",
|
"normalize-range": "^0.1.2",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
@@ -8094,9 +8108,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001593",
|
"version": "1.0.30001616",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001593.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001616.tgz",
|
||||||
"integrity": "sha512-UWM1zlo3cZfkpBysd7AS+z+v007q9G1+fLTUU42rQnY6t2axoogPW/xol6T7juU5EUoOhML4WgBIdG+9yYqAjQ==",
|
"integrity": "sha512-RHVYKov7IcdNjVHJFNY/78RdG4oGVjbayxv8u5IO74Wv7Hlq4PnJE6mo/OjFijjVFNy5ijnCt6H3IIo4t+wfEw==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -9428,6 +9442,25 @@
|
|||||||
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
|
||||||
"integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA=="
|
"integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/deep-equal": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==",
|
||||||
|
"dependencies": {
|
||||||
|
"is-arguments": "^1.1.1",
|
||||||
|
"is-date-object": "^1.0.5",
|
||||||
|
"is-regex": "^1.1.4",
|
||||||
|
"object-is": "^1.1.5",
|
||||||
|
"object-keys": "^1.1.1",
|
||||||
|
"regexp.prototype.flags": "^1.5.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/deep-extend": {
|
"node_modules/deep-extend": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||||
@@ -10986,6 +11019,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||||
},
|
},
|
||||||
|
"node_modules/extend": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
||||||
|
},
|
||||||
"node_modules/external-editor": {
|
"node_modules/external-editor": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
|
||||||
@@ -11059,11 +11097,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
||||||
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
|
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
|
||||||
},
|
},
|
||||||
"node_modules/fast-memoize": {
|
|
||||||
"version": "2.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz",
|
|
||||||
"integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw=="
|
|
||||||
},
|
|
||||||
"node_modules/fast-url-parser": {
|
"node_modules/fast-url-parser": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz",
|
||||||
@@ -12612,6 +12645,21 @@
|
|||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-arguments": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind": "^1.0.2",
|
||||||
|
"has-tostringtag": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-array-buffer": {
|
"node_modules/is-array-buffer": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
|
||||||
@@ -13332,9 +13380,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jay-peg": {
|
"node_modules/jay-peg": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/jay-peg/-/jay-peg-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/jay-peg/-/jay-peg-1.0.2.tgz",
|
||||||
"integrity": "sha512-zBfjkGbuuNXk8JW+rEePpPEbRRjupS8q+5yPak7kjy3e2GvvNwsLle9okEFvfGyZA6HvtSSiYrVd1/jgnYebaQ==",
|
"integrity": "sha512-fyV3NVvv6pTys/3BTapBUGAWAuU9rM2gRcgijZHzptd5KKL+s+S7hESFN+wOsbDH1MzFwdlRAXi0aGxS6uiMKg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"restructure": "^3.0.0"
|
"restructure": "^3.0.0"
|
||||||
}
|
}
|
||||||
@@ -15889,11 +15937,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/lodash.pick": {
|
|
||||||
"version": "4.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
|
|
||||||
"integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q=="
|
|
||||||
},
|
|
||||||
"node_modules/lodash.sortby": {
|
"node_modules/lodash.sortby": {
|
||||||
"version": "4.7.0",
|
"version": "4.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
|
||||||
@@ -16841,6 +16884,21 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/object-is": {
|
||||||
|
"version": "1.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
|
||||||
|
"integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind": "^1.0.7",
|
||||||
|
"define-properties": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/object-keys": {
|
"node_modules/object-keys": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||||
@@ -17194,6 +17252,11 @@
|
|||||||
"tslib": "^2.0.3"
|
"tslib": "^2.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/parchment": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg=="
|
||||||
|
},
|
||||||
"node_modules/parent-module": {
|
"node_modules/parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
@@ -17577,9 +17640,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.37",
|
"version": "8.4.38",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.37.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
|
||||||
"integrity": "sha512-7iB/v/r7Woof0glKLH8b1SPHrsX7uhdO+Geb41QpF/+mWZHU3uxxSlN+UXGVit1PawOYDToO+AbZzhBzWRDwbQ==",
|
"integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -19134,6 +19197,50 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/quill": {
|
||||||
|
"version": "1.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/quill/-/quill-1.3.7.tgz",
|
||||||
|
"integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==",
|
||||||
|
"dependencies": {
|
||||||
|
"clone": "^2.1.1",
|
||||||
|
"deep-equal": "^1.0.1",
|
||||||
|
"eventemitter3": "^2.0.3",
|
||||||
|
"extend": "^3.0.2",
|
||||||
|
"parchment": "^1.1.4",
|
||||||
|
"quill-delta": "^3.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/quill-delta": {
|
||||||
|
"version": "3.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz",
|
||||||
|
"integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==",
|
||||||
|
"dependencies": {
|
||||||
|
"deep-equal": "^1.0.1",
|
||||||
|
"extend": "^3.0.2",
|
||||||
|
"fast-diff": "1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/quill-delta/node_modules/fast-diff": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig=="
|
||||||
|
},
|
||||||
|
"node_modules/quill/node_modules/clone": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/quill/node_modules/eventemitter3": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg=="
|
||||||
|
},
|
||||||
"node_modules/radix-ui": {
|
"node_modules/radix-ui": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.0.1.tgz",
|
||||||
@@ -19256,12 +19363,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/re-resizable": {
|
"node_modules/re-resizable": {
|
||||||
"version": "6.9.6",
|
"version": "6.9.14",
|
||||||
"resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.9.6.tgz",
|
"resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.9.14.tgz",
|
||||||
"integrity": "sha512-0xYKS5+Z0zk+vICQlcZW+g54CcJTTmHluA7JUUgvERDxnKAnytylcyPsA+BSFi759s5hPlHmBRegFrwXs2FuBQ==",
|
"integrity": "sha512-2UbPrpezMr6gkHKNCRA/N6QGGU237SKOZ78yMHId204A/oXWSAREAIuGZNQ9qlrJosewzcsv2CphZH3u7hC6ng==",
|
||||||
"dependencies": {
|
|
||||||
"fast-memoize": "^2.5.1"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
"react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
||||||
"react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0"
|
"react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0"
|
||||||
@@ -19354,6 +19458,19 @@
|
|||||||
"react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
|
"react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-cookie": {
|
||||||
|
"version": "7.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-7.1.4.tgz",
|
||||||
|
"integrity": "sha512-wDxxa/HYaSXSMlyWJvJ5uZTzIVtQTPf1gMksFgwAz/2/W3lCtY8r4OChCXMPE7wax0PAdMY97UkNJedGv7KnDw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hoist-non-react-statics": "^3.3.5",
|
||||||
|
"hoist-non-react-statics": "^3.3.2",
|
||||||
|
"universal-cookie": "^7.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">= 16.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-datepicker": {
|
"node_modules/react-datepicker": {
|
||||||
"version": "6.4.0",
|
"version": "6.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-6.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-6.4.0.tgz",
|
||||||
@@ -19732,6 +19849,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-quill": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-4qQtv1FtCfLgoD3PXAur5RyxuUbPXQGOHgTlFie3jtxp43mXDtzCKaOgQ3mLyZfi1PUlyjycfivKelFhy13QUg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/quill": "^1.3.10",
|
||||||
|
"lodash": "^4.17.4",
|
||||||
|
"quill": "^1.3.7"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16 || ^17 || ^18",
|
||||||
|
"react-dom": "^16 || ^17 || ^18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-reconciler": {
|
"node_modules/react-reconciler": {
|
||||||
"version": "0.29.0",
|
"version": "0.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz",
|
||||||
@@ -19827,45 +19958,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-rnd": {
|
"node_modules/react-rnd": {
|
||||||
"version": "10.4.1",
|
"version": "10.4.10",
|
||||||
"resolved": "https://registry.npmjs.org/react-rnd/-/react-rnd-10.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-rnd/-/react-rnd-10.4.10.tgz",
|
||||||
"integrity": "sha512-0m887AjQZr6p2ADLNnipquqsDq4XJu/uqVqI3zuoGD19tRm6uB83HmZWydtkilNp5EWsOHbLGF4IjWMdd5du8Q==",
|
"integrity": "sha512-YjQAgEeSbNUoOXSD9ZBvIiLVizFb+bNhpDk8DbIRHA557NW02CXbwsAeOTpJQnsdhEL+NP2I+Ssrwejqcodtjg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"re-resizable": "6.9.6",
|
"re-resizable": "6.9.14",
|
||||||
"react-draggable": "4.4.5",
|
"react-draggable": "4.4.6",
|
||||||
"tslib": "2.3.1"
|
"tslib": "2.6.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": ">=16.3.0",
|
"react": ">=16.3.0",
|
||||||
"react-dom": ">=16.3.0"
|
"react-dom": ">=16.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-rnd/node_modules/clsx": {
|
|
||||||
"version": "1.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
|
||||||
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-rnd/node_modules/react-draggable": {
|
|
||||||
"version": "4.4.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.5.tgz",
|
|
||||||
"integrity": "sha512-OMHzJdyJbYTZo4uQE393fHcqqPYsEtkjfMgvCHr6rejT+Ezn4OZbNyGH50vv+SunC1RMvwOTSWkEODQLzw1M9g==",
|
|
||||||
"dependencies": {
|
|
||||||
"clsx": "^1.1.1",
|
|
||||||
"prop-types": "^15.8.1"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">= 16.3.0",
|
|
||||||
"react-dom": ">= 16.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-rnd/node_modules/tslib": {
|
|
||||||
"version": "2.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
|
||||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
|
||||||
},
|
|
||||||
"node_modules/react-router": {
|
"node_modules/react-router": {
|
||||||
"version": "6.22.3",
|
"version": "6.22.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz",
|
||||||
@@ -20082,16 +20187,24 @@
|
|||||||
"react-dom": ">=16.6.0"
|
"react-dom": ">=16.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-web-share": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-web-share/-/react-web-share-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-bGm1TJc6xtC0MhAnYFsrzT4En7l2oAdLTgCK7nk7b4xGTg3L5gOldiPrmYQ8a/dEXNydgekvOj/tfjduIlIRVA==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16 || ^17 || ^18",
|
||||||
|
"react-dom": "^16 || ^17 || ^18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/reactour": {
|
"node_modules/reactour": {
|
||||||
"version": "1.19.2",
|
"version": "1.19.3",
|
||||||
"resolved": "https://registry.npmjs.org/reactour/-/reactour-1.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/reactour/-/reactour-1.19.3.tgz",
|
||||||
"integrity": "sha512-gbbUiLn8LbpbDW6k+QlVySkblvOICBd3AWMGRKPQghhmuMlOHNqgjW32JrT406lZHUvVlA8+umYD/2MmCHkNOQ==",
|
"integrity": "sha512-a2/j+xmbGlPMQhMy/zdpSmJN1STc0PcLUxhJbAC+bOcYdWHStFR02j6dhNuF/+IeqpX/d44PvlrRXSTt4LGk6w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rooks/use-mutation-observer": "4.11.2",
|
"@rooks/use-mutation-observer": "4.11.2",
|
||||||
"classnames": "2.3.1",
|
"classnames": "2.3.1",
|
||||||
"focus-outline-manager": "^1.0.2",
|
"focus-outline-manager": "^1.0.2",
|
||||||
"lodash.debounce": "4.0.8",
|
"lodash.debounce": "4.0.8",
|
||||||
"lodash.pick": "4.4.0",
|
|
||||||
"prop-types": "15.7.2",
|
"prop-types": "15.7.2",
|
||||||
"react-focus-lock": "2.5.2",
|
"react-focus-lock": "2.5.2",
|
||||||
"scroll-smooth": "1.1.1",
|
"scroll-smooth": "1.1.1",
|
||||||
@@ -20549,9 +20662,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/restructure": {
|
"node_modules/restructure": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.1.tgz",
|
||||||
"integrity": "sha512-Xj8/MEIhhfj9X2rmD9iJ4Gga9EFqVlpMj3vfLnV2r/Mh5jRMryNV+6lWh9GdJtDBcBSPIqzRdfBQ3wDtNFv/uw=="
|
"integrity": "sha512-6neDpI/yE9eogQo22qmWwKIA9wFPRyYjQleDEh6zaNAf2ZPqLJYUvNBJBWEWNoBlCeQMQkvIOe2YI/K2GOag+g=="
|
||||||
},
|
},
|
||||||
"node_modules/retry": {
|
"node_modules/retry": {
|
||||||
"version": "0.13.1",
|
"version": "0.13.1",
|
||||||
@@ -22701,6 +22814,23 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/universal-cookie": {
|
||||||
|
"version": "7.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-7.1.4.tgz",
|
||||||
|
"integrity": "sha512-Q+DVJsdykStWRMtXr2Pdj3EF98qZHUH/fXv/gwFz/unyToy1Ek1w5GsWt53Pf38tT8Gbcy5QNsj61Xe9TggP4g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/cookie": "^0.6.0",
|
||||||
|
"cookie": "^0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/universal-cookie/node_modules/cookie": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/universalify": {
|
"node_modules/universalify": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formkit/auto-animate": "^0.8.1",
|
"@formkit/auto-animate": "^0.8.2",
|
||||||
"@radix-ui/themes": "^2.0.3",
|
"@radix-ui/themes": "^2.0.3",
|
||||||
"@react-pdf/renderer": "^3.4.0",
|
"@react-pdf/renderer": "^3.4.4",
|
||||||
"@reduxjs/toolkit": "^2.2.1",
|
"@reduxjs/toolkit": "^2.2.1",
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
"radix-ui": "^1.0.1",
|
"radix-ui": "^1.0.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-bootstrap": "^2.10.2",
|
"react-bootstrap": "^2.10.2",
|
||||||
|
"react-cookie": "^7.1.4",
|
||||||
"react-datepicker": "^6.4.0",
|
"react-datepicker": "^6.4.0",
|
||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
"react-dnd-html5-backend": "^16.0.1",
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
@@ -28,15 +29,17 @@
|
|||||||
"react-konva": "^18.2.10",
|
"react-konva": "^18.2.10",
|
||||||
"react-modal": "^3.16.1",
|
"react-modal": "^3.16.1",
|
||||||
"react-pdf": "^7.7.1",
|
"react-pdf": "^7.7.1",
|
||||||
|
"react-quill": "^2.0.0",
|
||||||
"react-redux": "^9.1.0",
|
"react-redux": "^9.1.0",
|
||||||
"react-rnd": "^10.4.1",
|
"react-rnd": "^10.4.10",
|
||||||
"react-router-dom": "^6.22.3",
|
"react-router-dom": "^6.22.3",
|
||||||
"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.0",
|
||||||
"react-signature-canvas": "^1.0.6",
|
"react-signature-canvas": "^1.0.6",
|
||||||
"react-tooltip": "^5.26.3",
|
"react-tooltip": "^5.26.3",
|
||||||
"reactour": "^1.19.2",
|
"react-web-share": "^2.0.2",
|
||||||
|
"reactour": "^1.19.3",
|
||||||
"redux": "^5.0.1",
|
"redux": "^5.0.1",
|
||||||
"redux-thunk": "^3.1.0",
|
"redux-thunk": "^3.1.0",
|
||||||
"regex-parser": "^2.3.0",
|
"regex-parser": "^2.3.0",
|
||||||
@@ -80,14 +83,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/runtime-corejs2": "^7.24.1",
|
"@babel/runtime-corejs2": "^7.24.5",
|
||||||
"autoprefixer": "^10.4.18",
|
"autoprefixer": "^10.4.19",
|
||||||
"commitizen": "^4.3.0",
|
"commitizen": "^4.3.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-react": "^7.34.1",
|
"eslint-plugin-react": "^7.34.1",
|
||||||
"lint-staged": "^15.2.2",
|
"lint-staged": "^15.2.2",
|
||||||
"postcss": "^8.4.37",
|
"postcss": "^8.4.38",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"pretty-quick": "^3.3.1",
|
"pretty-quick": "^3.3.1",
|
||||||
"tailwindcss": "^3.4.1"
|
"tailwindcss": "^3.4.1"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<!-- <link rel="icon" type="image/png"
|
<!-- <link rel="icon" type="image/png"
|
||||||
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC"
|
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC"
|
||||||
sizes="40x40" /> -->
|
sizes="40x40" /> -->
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||||
-->
|
-->
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="/manifest.json" />
|
||||||
<!--
|
<!--
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
Notice the use of %PUBLIC_URL% in the tags above.
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
It will be replaced with the URL of the `public` folder during the build.
|
||||||
|
|||||||
@@ -109,6 +109,10 @@ function App() {
|
|||||||
path="/login/:id/:userMail/:contactBookId/:serverUrl"
|
path="/login/:id/:userMail/:contactBookId/:serverUrl"
|
||||||
element={<LazyPage Page={GuestLogin} />}
|
element={<LazyPage Page={GuestLogin} />}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="/login/:base64url"
|
||||||
|
element={<LazyPage Page={GuestLogin} />}
|
||||||
|
/>
|
||||||
<Route path="/debugpdf" element={<LazyPage Page={DebugPdf} />} />
|
<Route path="/debugpdf" element={<LazyPage Page={DebugPdf} />} />
|
||||||
<Route
|
<Route
|
||||||
path="/forgetpassword"
|
path="/forgetpassword"
|
||||||
|
|||||||
@@ -4,18 +4,20 @@ import FullScreenButton from "./FullScreenButton";
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import { useWindowSize } from "../hook/useWindowSize";
|
import { useWindowSize } from "../hook/useWindowSize";
|
||||||
import { checkIsSubscribed, openInNewTab } from "../constant/Utils";
|
import { checkIsSubscribed, getAppLogo, openInNewTab } from "../constant/Utils";
|
||||||
import { isEnableSubscription } from "../constant/const";
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
|
||||||
const Header = ({ showSidebar }) => {
|
const Header = ({ showSidebar }) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
let applogo = localStorage.getItem("appLogo") || "";
|
|
||||||
let username = localStorage.getItem("username");
|
let username = localStorage.getItem("username");
|
||||||
const image = localStorage.getItem("profileImg") || dp;
|
const image = localStorage.getItem("profileImg") || dp;
|
||||||
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [isSubscribe, setIsSubscribe] = useState(true);
|
const [isSubscribe, setIsSubscribe] = useState(true);
|
||||||
|
const [isPro, setIsPro] = useState(false);
|
||||||
|
const [applogo, setAppLogo] = useState(
|
||||||
|
localStorage.getItem("appLogo") || " "
|
||||||
|
);
|
||||||
|
|
||||||
const toggleDropdown = () => {
|
const toggleDropdown = () => {
|
||||||
setIsOpen(!isOpen);
|
setIsOpen(!isOpen);
|
||||||
@@ -27,9 +29,19 @@ const Header = ({ showSidebar }) => {
|
|||||||
async function checkSubscription() {
|
async function checkSubscription() {
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const getIsSubscribe = await checkIsSubscribed();
|
const getIsSubscribe = await checkIsSubscribed();
|
||||||
|
if (getIsSubscribe) {
|
||||||
|
const applogo = await getAppLogo();
|
||||||
|
if (applogo) {
|
||||||
|
setAppLogo(applogo);
|
||||||
|
} else {
|
||||||
|
setAppLogo(localStorage.getItem("appLogo") || "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setIsPro(getIsSubscribe);
|
||||||
setIsSubscribe(getIsSubscribe);
|
setIsSubscribe(getIsSubscribe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeDropdown = () => {
|
const closeDropdown = () => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
Parse.User.logOut();
|
Parse.User.logOut();
|
||||||
@@ -105,6 +117,11 @@ const Header = ({ showSidebar }) => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{isPro && (
|
||||||
|
<div className="w-[35px] h-[35px] rounded-full ring-[1px] ring-offset-2 ring-[#002862] text-[#002862] overflow-hidden font-semibold flex items-center justify-center">
|
||||||
|
PRO
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div>
|
<div>
|
||||||
<FullScreenButton />
|
<FullScreenButton />
|
||||||
</div>
|
</div>
|
||||||
@@ -159,6 +176,14 @@ const Header = ({ showSidebar }) => {
|
|||||||
>
|
>
|
||||||
<i className="fa-solid fa-lock"></i> Change Password
|
<i className="fa-solid fa-lock"></i> Change Password
|
||||||
</li>
|
</li>
|
||||||
|
<li
|
||||||
|
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
|
||||||
|
onClick={() => {
|
||||||
|
window.open("https://console.opensignlabs.com/");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i className="fa-regular fa-id-card"></i> Console
|
||||||
|
</li>
|
||||||
<li
|
<li
|
||||||
className="hover:bg-gray-100 rounded-b-lg py-1 px-2 cursor-pointer font-normal"
|
className="hover:bg-gray-100 rounded-b-lg py-1 px-2 cursor-pointer font-normal"
|
||||||
onClick={closeDropdown}
|
onClick={closeDropdown}
|
||||||
|
|||||||
@@ -115,8 +115,8 @@ const GoogleSignInBtn = ({
|
|||||||
// console.log("payload ", payload);
|
// console.log("payload ", payload);
|
||||||
if (payload && payload.sessiontoken) {
|
if (payload && payload.sessiontoken) {
|
||||||
// setThirdpartyLoader(true);
|
// setThirdpartyLoader(true);
|
||||||
const billingDate =
|
// const billingDate =
|
||||||
extRes.get("Next_billing_date") && extRes.get("Next_billing_date");
|
// extRes.get("Next_billing_date") && extRes.get("Next_billing_date");
|
||||||
// console.log("billingDate expired", billingDate > new Date());
|
// console.log("billingDate expired", billingDate > new Date());
|
||||||
const LocalUserDetails = {
|
const LocalUserDetails = {
|
||||||
name: details.Name,
|
name: details.Name,
|
||||||
@@ -125,7 +125,7 @@ const GoogleSignInBtn = ({
|
|||||||
company: extRes.get("Company")
|
company: extRes.get("Company")
|
||||||
};
|
};
|
||||||
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
||||||
thirdpartyLoginfn(payload.sessiontoken, billingDate);
|
thirdpartyLoginfn(payload.sessiontoken);
|
||||||
}
|
}
|
||||||
return { msg: "exist" };
|
return { msg: "exist" };
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ const DashboardCard = (props) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const listData = res.data?.result.filter(
|
const listData = res.data?.result?.filter(
|
||||||
(x) => x.Signers.length > 0
|
(x) => x.Signers.length > 0
|
||||||
);
|
);
|
||||||
let arr = [];
|
let arr = [];
|
||||||
|
|||||||
@@ -97,11 +97,13 @@ function DashboardReport(props) {
|
|||||||
setIsMoreDocs(false);
|
setIsMoreDocs(false);
|
||||||
}
|
}
|
||||||
setIsNextRecord(false);
|
setIsNextRecord(false);
|
||||||
setList((prevRecord) =>
|
if (!res.data.result.error) {
|
||||||
prevRecord.length > 0
|
setList((prevRecord) =>
|
||||||
? [...prevRecord, ...res.data.result]
|
prevRecord.length > 0
|
||||||
: res.data.result
|
? [...prevRecord, ...res.data.result]
|
||||||
);
|
: res.data.result
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -110,6 +112,7 @@ function DashboardReport(props) {
|
|||||||
console.log("err ", err);
|
console.log("err ", err);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
}
|
}
|
||||||
|
setIsLoader(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ function DriveBody(props) {
|
|||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
props.setPdfData(updatedData);
|
props.setPdfData(updatedData);
|
||||||
|
props.sortingData(null, null, updatedData);
|
||||||
await axios
|
await axios
|
||||||
.put(
|
.put(
|
||||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||||
@@ -214,8 +215,8 @@ function DriveBody(props) {
|
|||||||
? true
|
? true
|
||||||
: false
|
: false
|
||||||
: selecFolderId
|
: selecFolderId
|
||||||
? false
|
? false
|
||||||
: true;
|
: true;
|
||||||
if (!checkExist) {
|
if (!checkExist) {
|
||||||
if (moveFolderId) {
|
if (moveFolderId) {
|
||||||
updateData = {
|
updateData = {
|
||||||
@@ -384,6 +385,7 @@ function DriveBody(props) {
|
|||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
cursor: "pointer"
|
cursor: "pointer"
|
||||||
}}
|
}}
|
||||||
|
data-tut={props.dataTutSeventh}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="no img"
|
alt="no img"
|
||||||
@@ -451,6 +453,7 @@ function DriveBody(props) {
|
|||||||
className="pdf-icon"
|
className="pdf-icon"
|
||||||
src={pdfLogo}
|
src={pdfLogo}
|
||||||
onClick={() => checkPdfStatus(data)}
|
onClick={() => checkPdfStatus(data)}
|
||||||
|
data-tut={props.dataTutSixth}
|
||||||
/>
|
/>
|
||||||
{rename === data.objectId ? (
|
{rename === data.objectId ? (
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import "../../styles/AddUser.css";
|
import "../../styles/AddUser.css";
|
||||||
|
import { getFileName } from "../../constant/Utils";
|
||||||
// import SelectFolder from "../../premitives/SelectFolder";
|
// import SelectFolder from "../../premitives/SelectFolder";
|
||||||
|
|
||||||
const EditTemplate = ({ template, onSuccess }) => {
|
const EditTemplate = ({ template, onSuccess }) => {
|
||||||
@@ -45,7 +46,7 @@ const EditTemplate = ({ template, onSuccess }) => {
|
|||||||
fontWeight: "700"
|
fontWeight: "700"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{template.URL?.split("/")?.pop()?.split("_")[1]}
|
{getFileName(template.URL)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Quill } from "react-quill";
|
||||||
|
|
||||||
|
// Custom Undo button icon component for Quill editor. You can import it directly
|
||||||
|
// from 'quill/assets/icons/undo.svg' but I found that a number of loaders do not
|
||||||
|
// handle them correctly
|
||||||
|
const CustomUndo = () => (
|
||||||
|
<svg viewBox="0 0 18 18">
|
||||||
|
<polygon className="ql-fill ql-stroke" points="6 10 4 12 2 10 6 10" />
|
||||||
|
<path
|
||||||
|
className="ql-stroke"
|
||||||
|
d="M8.09,13.91A4.6,4.6,0,0,0,9,14,5,5,0,1,0,4,9"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Redo button icon component for Quill editor
|
||||||
|
const CustomRedo = () => (
|
||||||
|
<svg viewBox="0 0 18 18">
|
||||||
|
<polygon className="ql-fill ql-stroke" points="12 10 14 12 16 10 12 10" />
|
||||||
|
<path
|
||||||
|
className="ql-stroke"
|
||||||
|
d="M9.91,13.91A4.6,4.6,0,0,1,9,14a5,5,0,1,1,5-5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Undo and redo functions for Custom Toolbar
|
||||||
|
function undoChange() {
|
||||||
|
this.quill.history.undo();
|
||||||
|
}
|
||||||
|
function redoChange() {
|
||||||
|
this.quill.history.redo();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add sizes to whitelist and register them
|
||||||
|
const Size = Quill.import("formats/size");
|
||||||
|
Size.whitelist = ["extra-small", "small", "medium", "large"];
|
||||||
|
Quill.register(Size, true);
|
||||||
|
|
||||||
|
// Add fonts to whitelist and register them
|
||||||
|
const Font = Quill.import("formats/font");
|
||||||
|
Font.whitelist = [
|
||||||
|
"arial",
|
||||||
|
"comic-sans",
|
||||||
|
"courier-new",
|
||||||
|
"georgia",
|
||||||
|
"helvetica",
|
||||||
|
"lucida"
|
||||||
|
];
|
||||||
|
Quill.register(Font, true);
|
||||||
|
|
||||||
|
// Modules object for setting up the Quill editor
|
||||||
|
export const module1 = {
|
||||||
|
toolbar: {
|
||||||
|
container: "#toolbar1",
|
||||||
|
handlers: {
|
||||||
|
undo: undoChange,
|
||||||
|
redo: redoChange
|
||||||
|
}
|
||||||
|
},
|
||||||
|
history: {
|
||||||
|
delay: 500,
|
||||||
|
maxStack: 100,
|
||||||
|
userOnly: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Formats objects for setting up the Quill editor
|
||||||
|
export const formats = [
|
||||||
|
"header",
|
||||||
|
"font",
|
||||||
|
"size",
|
||||||
|
"bold",
|
||||||
|
"italic",
|
||||||
|
"underline",
|
||||||
|
"align",
|
||||||
|
"strike",
|
||||||
|
"script",
|
||||||
|
"blockquote",
|
||||||
|
"background",
|
||||||
|
"list",
|
||||||
|
"bullet",
|
||||||
|
"indent",
|
||||||
|
"link",
|
||||||
|
"image",
|
||||||
|
"color",
|
||||||
|
"code-block"
|
||||||
|
];
|
||||||
|
// Quill Toolbar component
|
||||||
|
export const QuillToolbar = ({ containerId }) => (
|
||||||
|
<div id={containerId}>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<select className="ql-font" defaultValue="arial">
|
||||||
|
<option value="arial">Arial</option>
|
||||||
|
<option value="comic-sans">Comic Sans</option>
|
||||||
|
<option value="courier-new">Courier New</option>
|
||||||
|
<option value="georgia">Georgia</option>
|
||||||
|
<option value="helvetica">Helvetica</option>
|
||||||
|
<option value="lucida">Lucida</option>
|
||||||
|
</select>
|
||||||
|
<select className="ql-size" defaultValue="medium">
|
||||||
|
<option value="extra-small">Size 1</option>
|
||||||
|
<option value="small">Size 2</option>
|
||||||
|
<option value="medium">Size 3</option>
|
||||||
|
<option value="large">Size 4</option>
|
||||||
|
</select>
|
||||||
|
<select className="ql-header" defaultValue="3">
|
||||||
|
<option value="1">Heading</option>
|
||||||
|
<option value="2">Subheading</option>
|
||||||
|
<option value="3">Normal</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-bold" />
|
||||||
|
<button className="ql-italic" />
|
||||||
|
<button className="ql-underline" />
|
||||||
|
<button className="ql-strike" />
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-list" value="ordered" />
|
||||||
|
<button className="ql-list" value="bullet" />
|
||||||
|
<button className="ql-indent" value="-1" />
|
||||||
|
<button className="ql-indent" value="+1" />
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-script" value="super" />
|
||||||
|
<button className="ql-script" value="sub" />
|
||||||
|
<button className="ql-blockquote" />
|
||||||
|
<button className="ql-direction" />
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<select className="ql-align" />
|
||||||
|
<select className="ql-color" />
|
||||||
|
<select className="ql-background" />
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-link" />
|
||||||
|
<button className="ql-image" />
|
||||||
|
<button className="ql-video" />
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-formula" />
|
||||||
|
<button className="ql-code-block" />
|
||||||
|
<button className="ql-clean" />
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-undo">
|
||||||
|
<CustomUndo />
|
||||||
|
</button>
|
||||||
|
<button className="ql-redo">
|
||||||
|
<CustomRedo />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default QuillToolbar;
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Tooltip from "../../primitives/Tooltip";
|
||||||
|
|
||||||
|
import ReactQuill from "react-quill";
|
||||||
|
import "react-quill/dist/quill.snow.css";
|
||||||
|
import EditorToolbar, { module1, formats } from "./EditorToolbar";
|
||||||
|
|
||||||
|
export function EmailBody(props) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<div className={`flex justify-center py-1 p-2`}>
|
||||||
|
<div className=" flex flex-col">
|
||||||
|
<form>
|
||||||
|
<div className="text-lg font-normal text-black">
|
||||||
|
<div className=" m-2 md:m-10 p-3 md:p-10 shadow-md hover:shadow-lg border-[1px] border-indigo-800 rounded-md">
|
||||||
|
<label className="text-sm ml-2">
|
||||||
|
Subject <Tooltip message={"email subject"} />
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
required
|
||||||
|
value={props.requestSubject}
|
||||||
|
onChange={(e) => props.setRequestSubject(e.target.value)}
|
||||||
|
placeholder='${senderName} has requested you to sign "${documentName}"'
|
||||||
|
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||||
|
/>
|
||||||
|
<label className="text-sm ml-2 mt-3">
|
||||||
|
Body <Tooltip message={"email body"} />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div className="px-3 py-2 w-full focus:outline-none text-xs">
|
||||||
|
<EditorToolbar containerId="toolbar1" />
|
||||||
|
<ReactQuill
|
||||||
|
theme="snow"
|
||||||
|
value={props.requestBody}
|
||||||
|
// value={typedText}
|
||||||
|
placeholder="add body of email "
|
||||||
|
// readOnly={loading}
|
||||||
|
// onChangeSelection={handleTextSelection} // Listen for text selection
|
||||||
|
ref={props.editorRef}
|
||||||
|
modules={module1}
|
||||||
|
formats={formats}
|
||||||
|
onChange={props.handleOnchangeRequest}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -16,7 +16,8 @@ function EmailComponent({
|
|||||||
pdfName,
|
pdfName,
|
||||||
sender,
|
sender,
|
||||||
setIsAlert,
|
setIsAlert,
|
||||||
extUserId
|
extUserId,
|
||||||
|
activeMailAdapter
|
||||||
}) {
|
}) {
|
||||||
const [emailList, setEmailList] = useState([]);
|
const [emailList, setEmailList] = useState([]);
|
||||||
const [emailValue, setEmailValue] = useState();
|
const [emailValue, setEmailValue] = useState();
|
||||||
@@ -24,6 +25,7 @@ function EmailComponent({
|
|||||||
//function for send email
|
//function for send email
|
||||||
const sendEmail = async () => {
|
const sendEmail = async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
let sendMail;
|
let sendMail;
|
||||||
for (let i = 0; i < emailList.length; i++) {
|
for (let i = 0; i < emailList.length; i++) {
|
||||||
try {
|
try {
|
||||||
@@ -39,6 +41,7 @@ function EmailComponent({
|
|||||||
const openSignUrl = "https://www.opensignlabs.com/contact-us";
|
const openSignUrl = "https://www.opensignlabs.com/contact-us";
|
||||||
const themeBGcolor = themeColor;
|
const themeBGcolor = themeColor;
|
||||||
let params = {
|
let params = {
|
||||||
|
mailProvider: activeMailAdapter,
|
||||||
extUserId: extUserId,
|
extUserId: extUserId,
|
||||||
pdfName: pdfName,
|
pdfName: pdfName,
|
||||||
url: pdfUrl,
|
url: pdfUrl,
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import PrevNext from "./PrevNext";
|
import PrevNext from "./PrevNext";
|
||||||
import { PDFDownloadLink } from "@react-pdf/renderer";
|
|
||||||
import Certificate from "./Certificate";
|
|
||||||
import printModule from "print-js";
|
import printModule from "print-js";
|
||||||
import { getBase64FromUrl } from "../../constant/Utils";
|
import { getBase64FromUrl } from "../../constant/Utils";
|
||||||
import { saveAs } from "file-saver";
|
import { saveAs } from "file-saver";
|
||||||
@@ -9,18 +7,18 @@ import "../../styles/signature.css";
|
|||||||
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { themeColor } from "../../constant/const";
|
import { themeColor } from "../../constant/const";
|
||||||
|
import axios from "axios";
|
||||||
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
|
import Parse from "parse";
|
||||||
|
|
||||||
function Header({
|
function Header({
|
||||||
isPdfRequestFiles,
|
isPdfRequestFiles,
|
||||||
isPlaceholder,
|
isPlaceholder,
|
||||||
recipient,
|
|
||||||
setIsDecline,
|
setIsDecline,
|
||||||
pageNumber,
|
pageNumber,
|
||||||
isAlreadySign,
|
|
||||||
allPages,
|
allPages,
|
||||||
changePage,
|
changePage,
|
||||||
pdfUrl,
|
pdfUrl,
|
||||||
documentStatus,
|
|
||||||
embedWidgetsData,
|
embedWidgetsData,
|
||||||
pdfDetails,
|
pdfDetails,
|
||||||
signerPos,
|
signerPos,
|
||||||
@@ -42,6 +40,7 @@ function Header({
|
|||||||
signerPos && signerPos?.filter((data) => data.Role !== "prefill");
|
signerPos && signerPos?.filter((data) => data.Role !== "prefill");
|
||||||
const isMobile = window.innerWidth < 767;
|
const isMobile = window.innerWidth < 767;
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [isCertificate, setIsCertificate] = useState(false);
|
||||||
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
||||||
//for go to previous page
|
//for go to previous page
|
||||||
function previousPage() {
|
function previousPage() {
|
||||||
@@ -64,139 +63,95 @@ function Header({
|
|||||||
const handleToPrint = async (event) => {
|
const handleToPrint = async (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const pdf = await getBase64FromUrl(pdfUrl);
|
try {
|
||||||
const isAndroidDevice = navigator.userAgent.match(/Android/i);
|
const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
|
||||||
const isAppleDevice =
|
const pdf = await getBase64FromUrl(url);
|
||||||
(/iPad|iPhone|iPod/.test(navigator.platform) ||
|
const isAndroidDevice = navigator.userAgent.match(/Android/i);
|
||||||
(navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1)) &&
|
const isAppleDevice =
|
||||||
!window.MSStream;
|
(/iPad|iPhone|iPod/.test(navigator.platform) ||
|
||||||
if (isAndroidDevice || isAppleDevice) {
|
(navigator.platform === "MacIntel" &&
|
||||||
const byteArray = Uint8Array.from(
|
navigator.maxTouchPoints > 1)) &&
|
||||||
atob(pdf)
|
!window.MSStream;
|
||||||
.split("")
|
if (isAndroidDevice || isAppleDevice) {
|
||||||
.map((char) => char.charCodeAt(0))
|
const byteArray = Uint8Array.from(
|
||||||
);
|
atob(pdf)
|
||||||
const blob = new Blob([byteArray], { type: "application/pdf" });
|
.split("")
|
||||||
const blobUrl = URL.createObjectURL(blob);
|
.map((char) => char.charCodeAt(0))
|
||||||
window.open(blobUrl, "_blank");
|
);
|
||||||
} else {
|
const blob = new Blob([byteArray], { type: "application/pdf" });
|
||||||
printModule({ printable: pdf, type: "pdf", base64: true });
|
const blobUrl = URL.createObjectURL(blob);
|
||||||
|
window.open(blobUrl, "_blank");
|
||||||
|
} else {
|
||||||
|
printModule({ printable: pdf, type: "pdf", base64: true });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in getsignedurl", err);
|
||||||
|
alert("something went wrong, please try again later.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//handle download signed pdf
|
//handle download signed pdf
|
||||||
const handleDownloadPdf = () => {
|
const handleDownloadPdf = async () => {
|
||||||
const pdfName = pdfDetails[0] && pdfDetails[0].Name;
|
const pdfName = pdfDetails[0] && pdfDetails[0].Name;
|
||||||
saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
|
try {
|
||||||
|
const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
|
||||||
|
saveAs(url, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in getsignedurl", err);
|
||||||
|
alert("something went wrong, please try again later.");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const sanitizeFileName = (pdfName) => {
|
const sanitizeFileName = (pdfName) => {
|
||||||
// Replace spaces with underscore
|
// Replace spaces with underscore
|
||||||
return pdfName.replace(/ /g, "_");
|
return pdfName.replace(/ /g, "_");
|
||||||
};
|
};
|
||||||
//certificate generate and download component in mobile view
|
|
||||||
const CertificateDropDown = () => {
|
|
||||||
//after generate download certifcate pdf
|
|
||||||
const handleDownload = (pdfBlob, fileName) => {
|
|
||||||
if (pdfBlob) {
|
|
||||||
const url = window.URL.createObjectURL(pdfBlob);
|
|
||||||
// Create a temporary anchor element
|
|
||||||
const link = document.createElement("a");
|
|
||||||
link.href = url;
|
|
||||||
link.download = fileName;
|
|
||||||
// Append the anchor to the body
|
|
||||||
document.body.appendChild(link);
|
|
||||||
// Programmatically click the anchor to trigger the download
|
|
||||||
link.click();
|
|
||||||
// Remove the anchor from the body
|
|
||||||
document.body.removeChild(link);
|
|
||||||
// Release the object URL to free up resources
|
|
||||||
window.URL.revokeObjectURL(url);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
//handle download signed pdf
|
||||||
<PDFDownloadLink
|
const handleDownloadCertificate = async () => {
|
||||||
onClick={(e) => e.preventDefault()}
|
if (pdfDetails?.length > 0 && pdfDetails[0]?.CertificateUrl) {
|
||||||
style={{ textDecoration: "none", zIndex: "35" }}
|
try {
|
||||||
document={<Certificate pdfData={pdfDetails} />}
|
await fetch(pdfDetails[0] && pdfDetails[0]?.CertificateUrl);
|
||||||
>
|
const certificateUrl = pdfDetails[0] && pdfDetails[0]?.CertificateUrl;
|
||||||
{({ blob, loading }) => (
|
saveAs(certificateUrl, `Certificate_signed_by_OpenSign™.pdf`);
|
||||||
<>
|
} catch (err) {
|
||||||
{loading ? (
|
console.log("err in download in certificate", err);
|
||||||
<div
|
}
|
||||||
style={{
|
} else {
|
||||||
border: "none",
|
setIsCertificate(true);
|
||||||
backgroundColor: "#fff"
|
try {
|
||||||
}}
|
const data = {
|
||||||
>
|
docId: pdfDetails[0]?.objectId
|
||||||
<i
|
};
|
||||||
className="fa-solid fa-award"
|
const docDetails = await axios.post(
|
||||||
style={{ marginRight: "2px" }}
|
`${localStorage.getItem("baseUrl")}functions/getDocument`,
|
||||||
aria-hidden="true"
|
data,
|
||||||
></i>
|
{
|
||||||
Certificate
|
headers: {
|
||||||
</div>
|
"Content-Type": "application/json",
|
||||||
) : (
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
<div
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
style={{ border: "none", backgroundColor: "#fff" }}
|
}
|
||||||
onClick={() =>
|
}
|
||||||
handleDownload(
|
);
|
||||||
blob,
|
if (docDetails.data && docDetails.data.result) {
|
||||||
`completion certificate-${
|
const doc = docDetails.data.result;
|
||||||
pdfDetails[0] && pdfDetails[0].Name
|
if (doc?.CertificateUrl) {
|
||||||
}.pdf`
|
await fetch(doc?.CertificateUrl);
|
||||||
)
|
const certificateUrl = doc?.CertificateUrl;
|
||||||
}
|
saveAs(certificateUrl, `Certificate_signed_by_OpenSign™.pdf`);
|
||||||
>
|
setIsCertificate(false);
|
||||||
<i
|
} else {
|
||||||
className="fa-solid fa-award"
|
setIsCertificate(true);
|
||||||
style={{ marginRight: "2px" }}
|
}
|
||||||
aria-hidden="true"
|
}
|
||||||
></i>
|
} catch (err) {
|
||||||
Certificate
|
console.log("err in download in certificate", err);
|
||||||
</div>
|
alert("something went wrong, please try again later.");
|
||||||
)}
|
}
|
||||||
</>
|
}
|
||||||
)}
|
|
||||||
</PDFDownloadLink>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const CertificateComponent = () => {
|
|
||||||
return (
|
|
||||||
<PDFDownloadLink
|
|
||||||
style={{ textDecoration: "none" }}
|
|
||||||
document={<Certificate pdfData={pdfDetails} />}
|
|
||||||
fileName={`completion certificate-${
|
|
||||||
pdfDetails[0] && pdfDetails[0].Name
|
|
||||||
}.pdf`}
|
|
||||||
>
|
|
||||||
{({ loading }) => (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="defaultBtn certificateBtn"
|
|
||||||
disabled={loading}
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa-solid fa-award"
|
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Certificate
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</PDFDownloadLink>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: "5px 0px 5px 0px" }} className="mobileHead">
|
<div style={{ padding: "5px 0px 5px 0px" }} className="mobileHead">
|
||||||
{isMobile && isShowHeader ? (
|
{isMobile && isShowHeader ? (
|
||||||
@@ -210,11 +165,7 @@ function Header({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="preBtn2">
|
<div className="preBtn2">
|
||||||
<div
|
<div onClick={() => navigate(-1)}>
|
||||||
onClick={() => {
|
|
||||||
navigate(-1);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
<i
|
||||||
className="fa fa-arrow-left"
|
className="fa fa-arrow-left"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
@@ -266,7 +217,6 @@ function Header({
|
|||||||
<i className="fa fa-ellipsis-v" aria-hidden="true"></i>
|
<i className="fa fa-ellipsis-v" aria-hidden="true"></i>
|
||||||
</div>
|
</div>
|
||||||
</DropdownMenu.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
|
|
||||||
<DropdownMenu.Portal>
|
<DropdownMenu.Portal>
|
||||||
<DropdownMenu.Content
|
<DropdownMenu.Content
|
||||||
className="DropdownMenuContent"
|
className="DropdownMenuContent"
|
||||||
@@ -290,42 +240,45 @@ function Header({
|
|||||||
Download
|
Download
|
||||||
</div>
|
</div>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
{recipient && pdfDetails[0] && pdfDetails.length > 0 ? (
|
{isCompleted && (
|
||||||
<DropdownMenu.Item className="DropdownMenuItem">
|
<DropdownMenu.Item
|
||||||
<CertificateDropDown />
|
className="DropdownMenuItem"
|
||||||
|
onClick={() => handleDownloadCertificate()}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
border: "none",
|
||||||
|
backgroundColor: "#fff"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="fa-solid fa-award"
|
||||||
|
style={{ marginRight: "2px" }}
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
Certificate
|
||||||
|
</div>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
) : isPdfRequestFiles &&
|
)}
|
||||||
alreadySign &&
|
{isSignYourself && (
|
||||||
isCompleted.isCertificate ? (
|
<DropdownMenu.Item
|
||||||
<DropdownMenu.Item className="DropdownMenuItem">
|
className="DropdownMenuItem"
|
||||||
<CertificateDropDown />
|
onClick={() => setIsEmail(true)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="fa fa-envelope"
|
||||||
|
style={{ marginRight: "2px" }}
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
Mail
|
||||||
|
</div>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
) : (
|
|
||||||
isSignYourself && (
|
|
||||||
<>
|
|
||||||
<DropdownMenu.Item className="DropdownMenuItem">
|
|
||||||
<CertificateDropDown />
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
<DropdownMenu.Item
|
|
||||||
className="DropdownMenuItem"
|
|
||||||
onClick={() => setIsEmail(true)}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-envelope"
|
|
||||||
style={{ marginRight: "2px" }}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Mail
|
|
||||||
</div>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
)}
|
)}
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Item
|
||||||
className="DropdownMenuItem"
|
className="DropdownMenuItem"
|
||||||
@@ -337,7 +290,6 @@ function Header({
|
|||||||
flexDirection: "row"
|
flexDirection: "row"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{" "}
|
|
||||||
<i
|
<i
|
||||||
className="fa fa-print"
|
className="fa fa-print"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
@@ -416,217 +368,118 @@ function Header({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="signatureHeader headerBtn">
|
<div className="flex flex-wrap justify-between items-center mt-[5px]">
|
||||||
<PrevNext
|
<PrevNext
|
||||||
pageNumber={pageNumber}
|
pageNumber={pageNumber}
|
||||||
allPages={allPages}
|
allPages={allPages}
|
||||||
changePage={changePage}
|
changePage={changePage}
|
||||||
/>
|
/>
|
||||||
|
{isPlaceholder ? (
|
||||||
{recipient ? (
|
|
||||||
pdfUrl || isAlreadySign.mssg ? (
|
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
|
||||||
{pdfDetails && pdfDetails.length > 0 && (
|
|
||||||
<CertificateComponent />
|
|
||||||
)}
|
|
||||||
<button
|
|
||||||
onClick={handleToPrint}
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
className="defaultBtn printBtn"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-print"
|
|
||||||
style={{
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px",
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Print
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
className="defaultBtn downloadBtn"
|
|
||||||
onClick={() => handleDownloadPdf()}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-download"
|
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Download
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
background: "#de4337"
|
|
||||||
}}
|
|
||||||
className="finishBtn hoverCss"
|
|
||||||
onClick={() => {
|
|
||||||
handleDeclinePdfAlert();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Decline
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
data-tut="reactourThird"
|
|
||||||
style={{
|
|
||||||
background: !pdfUrl ? "#188ae2" : "#d3edeb"
|
|
||||||
}}
|
|
||||||
className="finishBtn sendHover"
|
|
||||||
onClick={() => {
|
|
||||||
if (!pdfUrl) {
|
|
||||||
embedWidgetsData();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Finish
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
) : isPlaceholder ? (
|
|
||||||
<>
|
<>
|
||||||
{!isMailSend &&
|
<div className="flex mx-[100px] lg:mx-0 order-last lg:order-none">
|
||||||
signersdata.length > 0 &&
|
{!isMailSend &&
|
||||||
signersdata.length !== filterPrefill.length && (
|
signersdata.length > 0 &&
|
||||||
<div>
|
signersdata.length !== filterPrefill.length && (
|
||||||
{filterPrefill.length === 0 ? (
|
<div>
|
||||||
<span style={{ fontSize: "13px", color: "#f5405e" }}>
|
{filterPrefill.length === 0 ? (
|
||||||
Add {signersdata.length - filterPrefill.length}{" "}
|
<span style={{ fontSize: "13px", color: "#f5405e" }}>
|
||||||
recipients signature
|
Add {signersdata.length - filterPrefill.length}{" "}
|
||||||
</span>
|
recipients signature
|
||||||
) : (
|
</span>
|
||||||
<span style={{ fontSize: "13px", color: "#f5405e" }}>
|
) : (
|
||||||
Add {signersdata.length - filterPrefill.length} more
|
<span style={{ fontSize: "13px", color: "#f5405e" }}>
|
||||||
recipients signature
|
Add {signersdata.length - filterPrefill.length} more
|
||||||
</span>
|
recipients signature
|
||||||
)}
|
</span>
|
||||||
</div>
|
)}
|
||||||
)}
|
</div>
|
||||||
|
)}
|
||||||
<div>
|
</div>
|
||||||
|
<div className="flex">
|
||||||
{setIsEditTemplate && (
|
{setIsEditTemplate && (
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsEditTemplate(true)}
|
onClick={() => setIsEditTemplate(true)}
|
||||||
style={{
|
className="outline-none border-none text-center mr-[5px]"
|
||||||
border: "none",
|
|
||||||
outline: "none",
|
|
||||||
textAlign: "center"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-gear fa-lg"></i>
|
<i className="fa-solid fa-gear fa-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => navigate(-1)}
|
||||||
navigate(-1);
|
|
||||||
}}
|
|
||||||
type="button"
|
type="button"
|
||||||
className="defaultBtn backBtn"
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-black font-[500] text-sm mr-[5px] bg-white"
|
||||||
>
|
>
|
||||||
Back
|
Back
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
disabled={isMailSend && true}
|
disabled={isMailSend && true}
|
||||||
data-tut="reactourFour"
|
data-tut="reactourFour"
|
||||||
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] font-[500] text-sm mr-[5px]"
|
||||||
style={{
|
style={{
|
||||||
background: isMailSend ? "rgb(203, 203, 203)" : "#188ae2",
|
background: isMailSend ? "rgb(203, 203, 203)" : "#188ae2",
|
||||||
color: isMailSend && "rgb(77, 75, 75)"
|
color: isMailSend ? "rgb(77, 75, 75)" : "white"
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
alertSendEmail();
|
alertSendEmail();
|
||||||
}}
|
}}
|
||||||
className={isMailSend ? "sendMail" : "sendMail sendHover"}
|
|
||||||
>
|
>
|
||||||
{completeBtnTitle ? completeBtnTitle : "Send"}
|
{completeBtnTitle
|
||||||
|
? completeBtnTitle
|
||||||
|
: isMailSend
|
||||||
|
? "Sent"
|
||||||
|
: "Send"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : isPdfRequestFiles ? (
|
) : isPdfRequestFiles ? (
|
||||||
alreadySign ? (
|
alreadySign ? (
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||||
{isCompleted.isCertificate && <CertificateComponent />}
|
{isCompleted && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleDownloadCertificate()}
|
||||||
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#08bc66]"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="fa-solid fa-award py-[3px]"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
<span className="hidden lg:block ml-1">Certificate</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={handleToPrint}
|
onClick={handleToPrint}
|
||||||
type="button"
|
type="button"
|
||||||
className="defaultBtn printBtn"
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#188ae2]"
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<i
|
<i className="fa fa-print py-[3px]" aria-hidden="true"></i>
|
||||||
className="fa fa-print"
|
<span className="hidden lg:block ml-1">Print</span>
|
||||||
style={{
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px",
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Print
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="defaultBtn downloadBtn"
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#f14343]"
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
onClick={() => handleDownloadPdf()}
|
onClick={() => handleDownloadPdf()}
|
||||||
>
|
>
|
||||||
<i
|
<i className="fa fa-download py-[3px]" aria-hidden="true"></i>
|
||||||
className="fa fa-download"
|
<span className="hidden lg:block ml-1">Download</span>
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Download
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div className="flex">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => navigate(-1)}
|
||||||
navigate(-1);
|
|
||||||
}}
|
|
||||||
type="button"
|
type="button"
|
||||||
className="defaultBtn backBtn"
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-black font-[500] text-sm mr-[5px] bg-white"
|
||||||
>
|
>
|
||||||
Back
|
Back
|
||||||
</button>
|
</button>
|
||||||
{currentSigner && (
|
{currentSigner && (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
style={{
|
style={{ background: "#de4337" }}
|
||||||
background: "#de4337"
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-white font-[500] text-[13px] mr-[5px] bg-[#f14343]"
|
||||||
}}
|
|
||||||
className="finishBtn hoverCss"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleDeclinePdfAlert();
|
handleDeclinePdfAlert();
|
||||||
}}
|
}}
|
||||||
@@ -638,7 +491,7 @@ function Header({
|
|||||||
background: "#188ae2"
|
background: "#188ae2"
|
||||||
}}
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
className="finishBtn sendHover"
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-white font-[500] text-[13px] mr-[5px] bg-[#188ae2]"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
embedWidgetsData();
|
embedWidgetsData();
|
||||||
}}
|
}}
|
||||||
@@ -649,93 +502,63 @@ function Header({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
) : pdfUrl || (documentStatus && documentStatus.isCompleted) ? (
|
) : isCompleted ? (
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||||
<CertificateComponent />
|
{isCompleted && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleDownloadCertificate()}
|
||||||
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#08bc66]"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="fa-solid fa-award py-[3px]"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
<span className="hidden lg:block ml-1">Certificate</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={handleToPrint}
|
onClick={handleToPrint}
|
||||||
type="button"
|
type="button"
|
||||||
style={{
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#188ae2]"
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
className="defaultBtn printBtn"
|
|
||||||
>
|
>
|
||||||
<i
|
<i className="fa fa-print py-[3px]" aria-hidden="true"></i>
|
||||||
className="fa fa-print"
|
<span className="hidden lg:block ml-1">Print</span>
|
||||||
style={{
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px",
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Print
|
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="defaultBtn downloadBtn"
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#f14343]"
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
marginLeft: "10px"
|
|
||||||
}}
|
|
||||||
onClick={() => handleDownloadPdf()}
|
onClick={() => handleDownloadPdf()}
|
||||||
>
|
>
|
||||||
<i
|
<i className="fa fa-download py-[3px]" aria-hidden="true"></i>
|
||||||
className="fa fa-download"
|
<span className="hidden lg:block ml-1">Download</span>
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Download
|
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="defaultBtn mailBtn"
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#3ba7e5]"
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
marginLeft: "10px"
|
|
||||||
}}
|
|
||||||
onClick={() => setIsEmail(true)}
|
onClick={() => setIsEmail(true)}
|
||||||
>
|
>
|
||||||
<i
|
<i className="fa fa-envelope py-[3px]" aria-hidden="true"></i>
|
||||||
className="fa fa-envelope"
|
<span className="hidden lg:block ml-1">Mail</span>
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Mail
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div className="flex">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate(-1);
|
navigate(-1);
|
||||||
}}
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
className="defaultBtn backBtn"
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-black font-[500] text-sm mr-[5px] bg-white"
|
||||||
>
|
>
|
||||||
Back
|
Back
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
style={{
|
style={{
|
||||||
background: "#188ae2"
|
background: "#188ae2"
|
||||||
}}
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
className="finishBtn sendHover"
|
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-white font-[500] text-[13px] mr-[5px] bg-[#188ae2]"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!pdfUrl) {
|
if (!pdfUrl) {
|
||||||
embedWidgetsData();
|
embedWidgetsData();
|
||||||
@@ -748,6 +571,16 @@ function Header({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<ModalUi
|
||||||
|
isOpen={isCertificate}
|
||||||
|
title={"Generating certificate"}
|
||||||
|
handleClose={() => setIsCertificate(false)}
|
||||||
|
>
|
||||||
|
<div className="p-3 md:p-5 text-[13px] md:text-base text-center">
|
||||||
|
<p>Completion certificate is generating,</p>
|
||||||
|
<p>please wait for some time if not download try again later</p>
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ function Placeholder(props) {
|
|||||||
|
|
||||||
{props.pos.type !== textWidget && !props.isSignYourself && (
|
{props.pos.type !== textWidget && !props.isSignYourself && (
|
||||||
<i
|
<i
|
||||||
data-tut="reactourLinkUser"
|
data-tut="assignSigner"
|
||||||
className="fa-regular fa-user signUserIcon"
|
className="fa-regular fa-user signUserIcon"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -542,7 +542,15 @@ function Placeholder(props) {
|
|||||||
data-tut={props.pos.key === props.unSignedWidgetId ? "IsSigned" : ""}
|
data-tut={props.pos.key === props.unSignedWidgetId ? "IsSigned" : ""}
|
||||||
key={props.pos.key}
|
key={props.pos.key}
|
||||||
lockAspectRatio={
|
lockAspectRatio={
|
||||||
props.pos.type !== textWidget &&
|
// props.pos.type !== textWidget
|
||||||
|
![
|
||||||
|
textWidget,
|
||||||
|
"email",
|
||||||
|
"name",
|
||||||
|
"company",
|
||||||
|
"job title",
|
||||||
|
textInputWidget
|
||||||
|
].includes(props.pos.type) &&
|
||||||
(props.pos.Width
|
(props.pos.Width
|
||||||
? props.pos.Width / props.pos.Height
|
? props.pos.Width / props.pos.Height
|
||||||
: defaultWidthHeight(props.pos.type).width /
|
: defaultWidthHeight(props.pos.type).width /
|
||||||
|
|||||||
@@ -38,15 +38,17 @@ function PlaceholderType(props) {
|
|||||||
"December"
|
"December"
|
||||||
];
|
];
|
||||||
const validateExpression = (regexValidation) => {
|
const validateExpression = (regexValidation) => {
|
||||||
let regexObject = regexValidation;
|
if (textValue && regexValidation) {
|
||||||
if (props.pos?.options.validation.type === "regex") {
|
let regexObject = regexValidation;
|
||||||
regexObject = RegexParser(regexValidation);
|
if (props.pos?.options?.validation?.type === "regex") {
|
||||||
}
|
regexObject = RegexParser(regexValidation);
|
||||||
// new RegExp(regexValidation);
|
}
|
||||||
let isValidate = regexObject.test(textValue);
|
// new RegExp(regexValidation);
|
||||||
if (!isValidate) {
|
let isValidate = regexObject.test(textValue);
|
||||||
props?.setValidateAlert(true);
|
if (!isValidate) {
|
||||||
inputRef.current.focus();
|
props?.setValidateAlert(true);
|
||||||
|
inputRef.current.focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -54,22 +56,18 @@ function PlaceholderType(props) {
|
|||||||
props.setDraggingEnabled(true);
|
props.setDraggingEnabled(true);
|
||||||
const validateType = props.pos?.options?.validation?.type;
|
const validateType = props.pos?.options?.validation?.type;
|
||||||
let regexValidation;
|
let regexValidation;
|
||||||
if (validateType) {
|
if (validateType && validateType !== "text") {
|
||||||
switch (validateType) {
|
switch (validateType) {
|
||||||
case "email":
|
case "email":
|
||||||
regexValidation = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
regexValidation = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||||
validateExpression(regexValidation);
|
validateExpression(regexValidation);
|
||||||
break;
|
break;
|
||||||
case "number":
|
case "number":
|
||||||
regexValidation = /^\d+$/;
|
regexValidation = /^[0-9\s]*$/;
|
||||||
validateExpression(regexValidation);
|
|
||||||
break;
|
|
||||||
case "text":
|
|
||||||
regexValidation = /^[a-zA-Z\s]+$/;
|
|
||||||
validateExpression(regexValidation);
|
validateExpression(regexValidation);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
regexValidation = props.pos?.options.validation.pattern;
|
regexValidation = props.pos?.options?.validation?.pattern || "";
|
||||||
validateExpression(regexValidation);
|
validateExpression(regexValidation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,11 +85,11 @@ function PlaceholderType(props) {
|
|||||||
case "number":
|
case "number":
|
||||||
setValidatePlaceholder("12345");
|
setValidatePlaceholder("12345");
|
||||||
break;
|
break;
|
||||||
case textInputWidget:
|
case "text":
|
||||||
setValidatePlaceholder("enter text");
|
setValidatePlaceholder("please enter text");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
setValidatePlaceholder("enter text");
|
setValidatePlaceholder("please enter value");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +133,7 @@ function PlaceholderType(props) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [props.pos]);
|
}, [props.pos?.options?.defaultValue]);
|
||||||
|
|
||||||
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
|
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
|
||||||
<div
|
<div
|
||||||
@@ -288,7 +286,7 @@ function PlaceholderType(props) {
|
|||||||
};
|
};
|
||||||
//handle height on enter press in text area
|
//handle height on enter press in text area
|
||||||
const handleEnterPress = (e) => {
|
const handleEnterPress = (e) => {
|
||||||
const height = 15;
|
const height = 18;
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
//function to save height of text area
|
//function to save height of text area
|
||||||
onChangeHeightOfTextArea(
|
onChangeHeightOfTextArea(
|
||||||
@@ -403,19 +401,12 @@ function PlaceholderType(props) {
|
|||||||
case textInputWidget:
|
case textInputWidget:
|
||||||
return props.isSignYourself ||
|
return props.isSignYourself ||
|
||||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||||
<input
|
<textarea
|
||||||
className="inputPlaceholder"
|
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
placeholder={validatePlaceholder}
|
placeholder={validatePlaceholder || "please enter value"}
|
||||||
style={{ fontSize: calculateFontSize() }}
|
rows={1}
|
||||||
|
onKeyDown={handleEnterPress}
|
||||||
value={textValue}
|
value={textValue}
|
||||||
type="text"
|
|
||||||
tabIndex="0"
|
|
||||||
disabled={
|
|
||||||
props.isNeedSign && props.data?.signerObjId !== props.signerObjId
|
|
||||||
? true
|
|
||||||
: props.isPlaceholder
|
|
||||||
}
|
|
||||||
onBlur={handleInputBlur}
|
onBlur={handleInputBlur}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setTextValue(e.target.value);
|
setTextValue(e.target.value);
|
||||||
@@ -429,6 +420,13 @@ function PlaceholderType(props) {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
className={
|
||||||
|
isMobile
|
||||||
|
? "labelTextArea labelWidthMobile"
|
||||||
|
: "labelTextArea labelWidthDesktop"
|
||||||
|
}
|
||||||
|
style={{ whiteSpace: "pre-wrap" }}
|
||||||
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
@@ -506,15 +504,12 @@ function PlaceholderType(props) {
|
|||||||
case "name":
|
case "name":
|
||||||
return props.isSignYourself ||
|
return props.isSignYourself ||
|
||||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||||
<input
|
<textarea
|
||||||
tabIndex="0"
|
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
placeholder={"name"}
|
placeholder={"name"}
|
||||||
style={{ fontSize: calculateFontSize() }}
|
rows={1}
|
||||||
className="inputPlaceholder"
|
onKeyDown={handleEnterPress}
|
||||||
type="text"
|
|
||||||
value={textValue}
|
value={textValue}
|
||||||
onBlur={handleInputBlur}
|
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const isDefault = false;
|
const isDefault = false;
|
||||||
handleTextValid(e);
|
handleTextValid(e);
|
||||||
@@ -528,6 +523,13 @@ function PlaceholderType(props) {
|
|||||||
isDefault
|
isDefault
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
className={
|
||||||
|
isMobile
|
||||||
|
? "labelTextArea labelWidthMobile"
|
||||||
|
: "labelTextArea labelWidthDesktop"
|
||||||
|
}
|
||||||
|
style={{ whiteSpace: "pre-wrap" }}
|
||||||
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
@@ -542,14 +544,12 @@ function PlaceholderType(props) {
|
|||||||
case "company":
|
case "company":
|
||||||
return props.isSignYourself ||
|
return props.isSignYourself ||
|
||||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||||
<input
|
<textarea
|
||||||
className="inputPlaceholder"
|
|
||||||
type="text"
|
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
placeholder={"company"}
|
placeholder="Enter text"
|
||||||
style={{ fontSize: calculateFontSize() }}
|
rows={1}
|
||||||
|
onKeyDown={handleEnterPress}
|
||||||
value={textValue}
|
value={textValue}
|
||||||
onBlur={handleInputBlur}
|
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
handleTextValid(e);
|
handleTextValid(e);
|
||||||
onChangeInput(
|
onChangeInput(
|
||||||
@@ -562,6 +562,13 @@ function PlaceholderType(props) {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
className={
|
||||||
|
isMobile
|
||||||
|
? "labelTextArea labelWidthMobile"
|
||||||
|
: "labelTextArea labelWidthDesktop"
|
||||||
|
}
|
||||||
|
style={{ whiteSpace: "pre-wrap" }}
|
||||||
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
@@ -576,14 +583,12 @@ function PlaceholderType(props) {
|
|||||||
case "job title":
|
case "job title":
|
||||||
return props.isSignYourself ||
|
return props.isSignYourself ||
|
||||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||||
<input
|
<textarea
|
||||||
className="inputPlaceholder"
|
|
||||||
type="text"
|
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
placeholder={"job title"}
|
placeholder={"job title"}
|
||||||
style={{ fontSize: calculateFontSize() }}
|
rows={1}
|
||||||
|
onKeyDown={handleEnterPress}
|
||||||
value={textValue}
|
value={textValue}
|
||||||
onBlur={handleInputBlur}
|
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
handleTextValid(e);
|
handleTextValid(e);
|
||||||
onChangeInput(
|
onChangeInput(
|
||||||
@@ -596,6 +601,13 @@ function PlaceholderType(props) {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
className={
|
||||||
|
isMobile
|
||||||
|
? "labelTextArea labelWidthMobile"
|
||||||
|
: "labelTextArea labelWidthDesktop"
|
||||||
|
}
|
||||||
|
style={{ whiteSpace: "pre-wrap" }}
|
||||||
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
@@ -692,12 +704,11 @@ function PlaceholderType(props) {
|
|||||||
case "email":
|
case "email":
|
||||||
return props.isSignYourself ||
|
return props.isSignYourself ||
|
||||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
||||||
<input
|
<textarea
|
||||||
className="inputPlaceholder"
|
|
||||||
type="text"
|
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
placeholder={"email"}
|
placeholder={"enter email"}
|
||||||
style={{ fontSize: calculateFontSize() }}
|
rows={1}
|
||||||
|
onKeyDown={handleEnterPress}
|
||||||
value={textValue}
|
value={textValue}
|
||||||
onBlur={handleInputBlur}
|
onBlur={handleInputBlur}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
@@ -712,6 +723,13 @@ function PlaceholderType(props) {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
className={
|
||||||
|
isMobile
|
||||||
|
? "labelTextArea labelWidthMobile"
|
||||||
|
: "labelTextArea labelWidthDesktop"
|
||||||
|
}
|
||||||
|
style={{ whiteSpace: "pre-wrap" }}
|
||||||
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
@@ -760,7 +778,7 @@ function PlaceholderType(props) {
|
|||||||
case textWidget:
|
case textWidget:
|
||||||
return (
|
return (
|
||||||
<textarea
|
<textarea
|
||||||
placeholder="Enter label"
|
placeholder="Enter text"
|
||||||
rows={1}
|
rows={1}
|
||||||
onKeyDown={handleEnterPress}
|
onKeyDown={handleEnterPress}
|
||||||
value={textValue}
|
value={textValue}
|
||||||
@@ -782,7 +800,7 @@ function PlaceholderType(props) {
|
|||||||
? "labelTextArea labelWidthMobile"
|
? "labelTextArea labelWidthMobile"
|
||||||
: "labelTextArea labelWidthDesktop"
|
: "labelTextArea labelWidthDesktop"
|
||||||
}
|
}
|
||||||
style={{ whiteSpace: "pre-wrap" }}
|
style={{ whiteSpace: "pre-wrap", overflow: "hidden" }}
|
||||||
cols="50"
|
cols="50"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { themeColor } from "../../constant/const";
|
||||||
|
|
||||||
function PrevNext({ pageNumber, allPages, changePage }) {
|
function PrevNext({ pageNumber, allPages, changePage }) {
|
||||||
//for go to previous page
|
//for go to previous page
|
||||||
@@ -14,41 +15,35 @@ function PrevNext({ pageNumber, allPages, changePage }) {
|
|||||||
<div>
|
<div>
|
||||||
<div className="preBtn1">
|
<div className="preBtn1">
|
||||||
<button
|
<button
|
||||||
style={{
|
className="py-[3px] px-[10px] text-xs bg-[#d3edeb] font-[600] mr-[5px]"
|
||||||
padding: "3px 20px ",
|
|
||||||
fontSize: "10px",
|
|
||||||
background: "#d3edeb",
|
|
||||||
fontWeight: "600",
|
|
||||||
|
|
||||||
border: "0px",
|
|
||||||
marginRight: "5px"
|
|
||||||
}}
|
|
||||||
disabled={pageNumber <= 1}
|
disabled={pageNumber <= 1}
|
||||||
onClick={previousPage}
|
onClick={previousPage}
|
||||||
>
|
>
|
||||||
Prev
|
<span className="block lg:hidden">
|
||||||
|
<i
|
||||||
|
className="fa fa-backward"
|
||||||
|
aria-hidden="true"
|
||||||
|
style={{ color: themeColor, cursor: "pointer" }}
|
||||||
|
></i>
|
||||||
|
</span>
|
||||||
|
<span className="lg:block hidden">Prev</span>
|
||||||
</button>
|
</button>
|
||||||
<span
|
<span className="text-xs font-[500]">
|
||||||
style={{
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: "600"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
|
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
style={{
|
className="py-[3px] px-[10px] text-xs bg-[#d3edeb] font-[600] ml-[5px]"
|
||||||
padding: "3px 20px ",
|
|
||||||
fontSize: "10px",
|
|
||||||
background: "#d3edeb",
|
|
||||||
fontWeight: "600",
|
|
||||||
marginLeft: "5px",
|
|
||||||
border: "0px"
|
|
||||||
}}
|
|
||||||
disabled={pageNumber >= allPages}
|
disabled={pageNumber >= allPages}
|
||||||
onClick={nextPage}
|
onClick={nextPage}
|
||||||
>
|
>
|
||||||
Next
|
<span className="block lg:hidden">
|
||||||
|
<i
|
||||||
|
className="fa fa-forward"
|
||||||
|
aria-hidden="true"
|
||||||
|
style={{ color: themeColor, cursor: "pointer" }}
|
||||||
|
></i>
|
||||||
|
</span>
|
||||||
|
<span className="lg:block hidden">Next</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -230,7 +230,11 @@ const RecipientList = (props) => {
|
|||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{obj.Name && <span className={"useEmail"}>{obj.Role}</span>}
|
{obj.Name && (
|
||||||
|
<span className={"useEmail"}>
|
||||||
|
{obj?.Role || obj?.Email}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{isMobile && props.sendInOrder && (
|
{isMobile && props.sendInOrder && (
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { Document, Page } from "react-pdf";
|
|||||||
import { themeColor } from "../../constant/const";
|
import { themeColor } from "../../constant/const";
|
||||||
|
|
||||||
function RenderAllPdfPage({
|
function RenderAllPdfPage({
|
||||||
pdfUrl,
|
|
||||||
signPdfUrl,
|
signPdfUrl,
|
||||||
allPages,
|
allPages,
|
||||||
setAllPages,
|
setAllPages,
|
||||||
@@ -50,8 +49,7 @@ function RenderAllPdfPage({
|
|||||||
<Document
|
<Document
|
||||||
loading={"Loading Document.."}
|
loading={"Loading Document.."}
|
||||||
onLoadSuccess={onDocumentLoad}
|
onLoadSuccess={onDocumentLoad}
|
||||||
file={pdfUrl ? pdfUrl : signPdfUrl}
|
file={signPdfUrl}
|
||||||
// file="https://api.printnode.com/static/test/pdf/multipage.pdf"
|
|
||||||
>
|
>
|
||||||
{Array.from(new Array(allPages), (el, index) => (
|
{Array.from(new Array(allPages), (el, index) => (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -296,9 +296,11 @@ function RenderPdf({
|
|||||||
{type && (
|
{type && (
|
||||||
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
||||||
)}
|
)}
|
||||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
{Role && (
|
||||||
{`(${Role})`}
|
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
||||||
</div>
|
{`(${Role})`}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -214,8 +214,8 @@ function SignPad({
|
|||||||
const fontfamily = fontStyle
|
const fontfamily = fontStyle
|
||||||
? fontStyle
|
? fontStyle
|
||||||
: fontSelect
|
: fontSelect
|
||||||
? fontSelect
|
? fontSelect
|
||||||
: "Fasthand";
|
: "Fasthand";
|
||||||
|
|
||||||
//creating span for getting text content width
|
//creating span for getting text content width
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
@@ -267,10 +267,10 @@ function SignPad({
|
|||||||
key === 0 && penColor === "blue"
|
key === 0 && penColor === "blue"
|
||||||
? "2px solid blue"
|
? "2px solid blue"
|
||||||
: key === 1 && penColor === "red"
|
: key === 1 && penColor === "red"
|
||||||
? "2px solid red"
|
? "2px solid red"
|
||||||
: key === 2 && penColor === "black"
|
: key === 2 && penColor === "black"
|
||||||
? "2px solid black"
|
? "2px solid black"
|
||||||
: "2px solid white"
|
: "2px solid white"
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
props?.convertToImg &&
|
props?.convertToImg &&
|
||||||
@@ -536,7 +536,6 @@ function SignPad({
|
|||||||
style={{
|
style={{
|
||||||
border: "1.3px solid #007bff",
|
border: "1.3px solid #007bff",
|
||||||
borderRadius: "2px",
|
borderRadius: "2px",
|
||||||
|
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
@@ -553,7 +552,7 @@ function SignPad({
|
|||||||
type="file"
|
type="file"
|
||||||
onChange={onImageChange}
|
onChange={onImageChange}
|
||||||
className="filetype"
|
className="filetype"
|
||||||
accept="image/*"
|
accept="image/png,image/jpeg"
|
||||||
ref={imageRef}
|
ref={imageRef}
|
||||||
hidden
|
hidden
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ function SignerListPlace(props) {
|
|||||||
<div className="signerList">
|
<div className="signerList">
|
||||||
<RecipientList {...props} />
|
<RecipientList {...props} />
|
||||||
</div>
|
</div>
|
||||||
{props.handleAddSigner && (
|
{props.handleAddSigner ? (
|
||||||
<div
|
<div
|
||||||
data-tut="reactourAddbtn"
|
data-tut="reactourAddbtn"
|
||||||
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
|
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
|
||||||
@@ -84,6 +84,19 @@ function SignerListPlace(props) {
|
|||||||
<i className="fa-solid fa-plus"></i>
|
<i className="fa-solid fa-plus"></i>
|
||||||
<span style={{ marginLeft: 2 }}>Add role</span>
|
<span style={{ marginLeft: 2 }}>Add role</span>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
data-tut="reactourAddbtn"
|
||||||
|
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
|
||||||
|
onClick={() => props.setIsAddSigner(true)}
|
||||||
|
style={{
|
||||||
|
opacity: props.isMailSend && "0.5",
|
||||||
|
pointerEvents: props.isMailSend && "none"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i className="fa-solid fa-plus"></i>
|
||||||
|
<span style={{ marginLeft: 2 }}>Add recipients</span>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { rejectBtn, submitBtn, themeColor } from "../../constant/const";
|
||||||
|
|
||||||
|
function VerifyEmail(props) {
|
||||||
|
return (
|
||||||
|
<div className="bg-black bg-opacity-[75%] absolute z-[999] flex flex-col items-center justify-center w-full h-full rounded">
|
||||||
|
<div className="bg-white rounded outline-none md:w-[40%] w-[80%]">
|
||||||
|
<div
|
||||||
|
style={{ backgroundColor: themeColor }}
|
||||||
|
className=" text-white p-[10px] rounded-t"
|
||||||
|
>
|
||||||
|
OTP verification
|
||||||
|
</div>
|
||||||
|
{props.isVerifyModal ? (
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
props.setIsVerifyModal(false);
|
||||||
|
props.handleVerifyEmail(e);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="px-6 py-3">
|
||||||
|
<label className="mb-2">Enter OTP</label>
|
||||||
|
<input
|
||||||
|
required
|
||||||
|
type="tel"
|
||||||
|
pattern="[0-9]{4}"
|
||||||
|
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||||
|
placeholder="Enter OTP received over email"
|
||||||
|
value={props.otp}
|
||||||
|
onChange={(e) => props.setOtp(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div className="px-6 my-3">
|
||||||
|
<button type="submit" className={submitBtn}>
|
||||||
|
Verify
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`${rejectBtn} ml-2`}
|
||||||
|
onClick={(e) => props.handleResend(e)}
|
||||||
|
>
|
||||||
|
Resend
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
) : props.otpLoader ? (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: "150px",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: "45px",
|
||||||
|
color: "#3dd3e0"
|
||||||
|
}}
|
||||||
|
className="loader-37"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="px-6 py-3">
|
||||||
|
<p className="mb-2">Please verify your email !</p>
|
||||||
|
<hr />
|
||||||
|
<div className="px-0 mt-3">
|
||||||
|
<button
|
||||||
|
className={submitBtn}
|
||||||
|
type="submit"
|
||||||
|
onClick={() => {
|
||||||
|
props.handleVerifyBtn();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Send OTP
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VerifyEmail;
|
||||||
@@ -38,7 +38,8 @@ function WidgetComponent({
|
|||||||
sendInOrder,
|
sendInOrder,
|
||||||
isTemplateFlow,
|
isTemplateFlow,
|
||||||
setBlockColor,
|
setBlockColor,
|
||||||
blockColor
|
blockColor,
|
||||||
|
setIsAddSigner
|
||||||
}) {
|
}) {
|
||||||
const [isSignersModal, setIsSignersModal] = useState(false);
|
const [isSignersModal, setIsSignersModal] = useState(false);
|
||||||
|
|
||||||
@@ -319,7 +320,7 @@ function WidgetComponent({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{handleAddSigner && (
|
{handleAddSigner ? (
|
||||||
<div
|
<div
|
||||||
data-tut="reactourAddbtn"
|
data-tut="reactourAddbtn"
|
||||||
style={{
|
style={{
|
||||||
@@ -333,6 +334,22 @@ function WidgetComponent({
|
|||||||
<i className="fa-solid fa-plus"></i>
|
<i className="fa-solid fa-plus"></i>
|
||||||
<span style={{ marginLeft: 2 }}>Add role</span>
|
<span style={{ marginLeft: 2 }}>Add role</span>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
setIsAddSigner && (
|
||||||
|
<div
|
||||||
|
data-tut="reactourAddbtn"
|
||||||
|
style={{
|
||||||
|
margin: "5px 0 5px 0",
|
||||||
|
backgroundColor: themeColor,
|
||||||
|
color: "white"
|
||||||
|
}}
|
||||||
|
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
|
||||||
|
onClick={() => setIsAddSigner(true)}
|
||||||
|
>
|
||||||
|
<i className="fa-solid fa-plus"></i>
|
||||||
|
<span style={{ marginLeft: 2 }}>Add recipients</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -391,7 +408,7 @@ function WidgetComponent({
|
|||||||
)}
|
)}
|
||||||
{isSignersModal && (
|
{isSignersModal && (
|
||||||
<ModalUi
|
<ModalUi
|
||||||
title={"Roles"}
|
title={title ? title : "Recipients"}
|
||||||
isOpen={isSignersModal}
|
isOpen={isSignersModal}
|
||||||
handleClose={handleModal}
|
handleClose={handleModal}
|
||||||
>
|
>
|
||||||
@@ -424,7 +441,7 @@ function WidgetComponent({
|
|||||||
textAlign: "center"
|
textAlign: "center"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Please add a role
|
Please add a {title ? title : "recipients"}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const WidgetNameModal = (props) => {
|
|||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
status: "required",
|
status: "required",
|
||||||
hint: "",
|
hint: "",
|
||||||
textvalidate: "text"
|
textvalidate: ""
|
||||||
});
|
});
|
||||||
const [isValid, setIsValid] = useState(true);
|
const [isValid, setIsValid] = useState(true);
|
||||||
const statusArr = ["Required", "Optional"];
|
const statusArr = ["Required", "Optional"];
|
||||||
@@ -48,12 +48,16 @@ const WidgetNameModal = (props) => {
|
|||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
status: "required",
|
status: "required",
|
||||||
hint: "",
|
hint: "",
|
||||||
textvalidate: "text"
|
textvalidate: ""
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
setFormdata({ ...formdata, [e.target.name]: e.target.value });
|
if (e) {
|
||||||
|
setFormdata({ ...formdata, [e.target.name]: e.target.value });
|
||||||
|
} else {
|
||||||
|
setFormdata({ ...formdata, textvalidate: "" });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handledefaultChange = (e) => {
|
const handledefaultChange = (e) => {
|
||||||
@@ -82,7 +86,7 @@ const WidgetNameModal = (props) => {
|
|||||||
|
|
||||||
function handleBlurRegex() {
|
function handleBlurRegex() {
|
||||||
if (!formdata.textvalidate) {
|
if (!formdata.textvalidate) {
|
||||||
setFormdata({ ...formdata, textvalidate: "text" });
|
setFormdata({ ...formdata, textvalidate: "" });
|
||||||
} else {
|
} else {
|
||||||
if (formdata.defaultValue) {
|
if (formdata.defaultValue) {
|
||||||
const regexObject = RegexParser(
|
const regexObject = RegexParser(
|
||||||
@@ -173,7 +177,10 @@ const WidgetNameModal = (props) => {
|
|||||||
onChange={(e) => handleChange(e)}
|
onChange={(e) => handleChange(e)}
|
||||||
onBlur={() => handleBlurRegex()}
|
onBlur={() => handleBlurRegex()}
|
||||||
>
|
>
|
||||||
<option disabled style={{ fontSize: "13px" }}>
|
<option
|
||||||
|
disabled={formdata?.textvalidate}
|
||||||
|
style={{ fontSize: "13px" }}
|
||||||
|
>
|
||||||
Select...
|
Select...
|
||||||
</option>
|
</option>
|
||||||
{inputOpt.map((data, ind) => {
|
{inputOpt.map((data, ind) => {
|
||||||
|
|||||||
@@ -53,9 +53,22 @@ const SelectSigners = (props) => {
|
|||||||
const contactRes = await contactbook.find();
|
const contactRes = await contactbook.find();
|
||||||
if (contactRes) {
|
if (contactRes) {
|
||||||
const res = JSON.parse(JSON.stringify(contactRes));
|
const res = JSON.parse(JSON.stringify(contactRes));
|
||||||
// console.log("userList ", res);
|
//compareArrays is a function where compare between two array (total signersList and dcument signers list)
|
||||||
setUserList(res);
|
//and filter signers from total signer's list which already present in document's signers list
|
||||||
return await res.map((item) => ({
|
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;
|
||||||
|
setUserList(result);
|
||||||
|
return await result.map((item) => ({
|
||||||
label: item.Email,
|
label: item.Email,
|
||||||
value: item.objectId
|
value: item.objectId
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
|
|||||||
<div className="flex px-2 py-3 gap-2 items-center shadow-md">
|
<div className="flex px-2 py-3 gap-2 items-center shadow-md">
|
||||||
<div className="w-[75px] h-[75px] rounded-full ring-[2px] ring-offset-2 ring-gray-400 overflow-hidden">
|
<div className="w-[75px] h-[75px] rounded-full ring-[2px] ring-offset-2 ring-gray-400 overflow-hidden">
|
||||||
<img
|
<img
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-contain"
|
||||||
src={image}
|
src={image}
|
||||||
alt="Profile"
|
alt="Profile"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { themeColor } from "./const";
|
import { isEnableSubscription, themeColor } from "./const";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { rgb } from "pdf-lib";
|
import { rgb } from "pdf-lib";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
@@ -13,25 +13,62 @@ export const openInNewTab = (url) => {
|
|||||||
window.open(url, "_blank", "noopener,noreferrer");
|
window.open(url, "_blank", "noopener,noreferrer");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export async function fetchSubscription(
|
||||||
|
extUserId,
|
||||||
|
contactObjId,
|
||||||
|
isGuestSign = false
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const extClass = localStorage.getItem("Extand_Class");
|
||||||
|
let extUser;
|
||||||
|
if (extClass) {
|
||||||
|
const jsonSender = JSON.parse(extClass);
|
||||||
|
extUser = jsonSender[0].objectId;
|
||||||
|
} else {
|
||||||
|
extUser = extUserId;
|
||||||
|
}
|
||||||
|
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 = isGuestSign
|
||||||
|
? { contactId: contactObjId }
|
||||||
|
: { extUserId: extUser };
|
||||||
|
const tenatRes = await axios.post(url, params, { headers: headers });
|
||||||
|
let plan, status, billingDate;
|
||||||
|
if (isGuestSign) {
|
||||||
|
plan = tenatRes.data?.result?.result?.plan;
|
||||||
|
status = tenatRes.data?.result?.result?.isSubscribed;
|
||||||
|
} else {
|
||||||
|
plan = tenatRes.data?.result?.result?.PlanCode;
|
||||||
|
billingDate = tenatRes.data?.result?.result?.Next_billing_date?.iso;
|
||||||
|
}
|
||||||
|
return { plan, billingDate, status };
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err in fetch subscription", err);
|
||||||
|
return { plan: "", billingDate: "" };
|
||||||
|
}
|
||||||
|
}
|
||||||
//function to get subcripition details from Extand user class
|
//function to get subcripition details from Extand user class
|
||||||
export async function checkIsSubscribed() {
|
export async function checkIsSubscribed() {
|
||||||
const extClass = localStorage.getItem("Extand_Class");
|
try {
|
||||||
const jsonSender = JSON.parse(extClass);
|
const res = await fetchSubscription();
|
||||||
const user = await Parse.Cloud.run("getUserDetails", {
|
if (res.plan === "freeplan") {
|
||||||
email: jsonSender[0].Email
|
return false;
|
||||||
});
|
} else if (res.billingDate) {
|
||||||
const freeplan = user?.get("Plan") && user?.get("Plan")?.plan_code;
|
if (new Date(res.billingDate) > new Date()) {
|
||||||
const billingDate =
|
return true;
|
||||||
user?.get("Next_billing_date") && user?.get("Next_billing_date");
|
} else {
|
||||||
if (freeplan === "freeplan") {
|
return false;
|
||||||
return false;
|
}
|
||||||
} else if (billingDate) {
|
|
||||||
if (billingDate > new Date()) {
|
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} catch (err) {
|
||||||
|
console.log("Err in fetch subscription", err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,15 +335,15 @@ export const addWidgetOptions = (type) => {
|
|||||||
options: { isReadOnly: false, isHideLabel: false }
|
options: { isReadOnly: false, isHideLabel: false }
|
||||||
};
|
};
|
||||||
case textInputWidget:
|
case textInputWidget:
|
||||||
return { ...defaultOpt, validation: { type: "text", pattern: "" } };
|
return { ...defaultOpt };
|
||||||
case "initials":
|
case "initials":
|
||||||
return defaultOpt;
|
return defaultOpt;
|
||||||
case "name":
|
case "name":
|
||||||
return { ...defaultOpt, validation: { type: "text", pattern: "" } };
|
return { ...defaultOpt };
|
||||||
case "company":
|
case "company":
|
||||||
return { ...defaultOpt, validation: { type: "text", pattern: "" } };
|
return { ...defaultOpt };
|
||||||
case "job title":
|
case "job title":
|
||||||
return { ...defaultOpt, validation: { type: "text", pattern: "" } };
|
return { ...defaultOpt };
|
||||||
case "date":
|
case "date":
|
||||||
return {
|
return {
|
||||||
...defaultOpt,
|
...defaultOpt,
|
||||||
@@ -501,38 +538,96 @@ export const signPdfFun = async (
|
|||||||
base64Url,
|
base64Url,
|
||||||
documentId,
|
documentId,
|
||||||
signerObjectId,
|
signerObjectId,
|
||||||
setIsAlert
|
setIsAlert,
|
||||||
|
objectId,
|
||||||
|
isSubscribed,
|
||||||
|
activeMailAdapter,
|
||||||
|
xyPosition
|
||||||
) => {
|
) => {
|
||||||
let singleSign;
|
let singleSign,
|
||||||
|
isCustomCompletionMail = false;
|
||||||
|
|
||||||
singleSign = {
|
try {
|
||||||
pdfFile: base64Url,
|
//get tenant details
|
||||||
docId: documentId,
|
const tenantDetails = await getTenantDetails(objectId);
|
||||||
userId: signerObjectId
|
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||||
};
|
alert("User does not exist");
|
||||||
|
} else {
|
||||||
const response = await axios
|
if (
|
||||||
.post(`${localStorage.getItem("baseUrl")}functions/signPdf`, singleSign, {
|
tenantDetails?.CompletionBody &&
|
||||||
headers: {
|
tenantDetails?.CompletionSubject &&
|
||||||
"Content-Type": "application/json",
|
(!isEnableSubscription || isSubscribed)
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
) {
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
isCustomCompletionMail = true;
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.then((Listdata) => {
|
|
||||||
const json = Listdata.data;
|
|
||||||
const res = json.result;
|
|
||||||
return res;
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log("Err ", err);
|
|
||||||
setIsAlert({
|
|
||||||
isShow: true,
|
|
||||||
alertMessage: "something went wrong"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
// below for loop is used to get first signature of user to send if to signpdf
|
||||||
|
// for adding it in completion certificate
|
||||||
|
let getSignature;
|
||||||
|
for (let item of xyPosition) {
|
||||||
|
const typeExist = item.pos.some((data) => data?.type);
|
||||||
|
if (typeExist) {
|
||||||
|
getSignature = item.pos.find((data) => data?.type === "signature");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
getSignature = item.pos.find((data) => !data.isStamp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let base64Sign = getSignature.SignUrl;
|
||||||
|
//check https type signature (default signature exist) then convert in base64
|
||||||
|
const isUrl = base64Sign.includes("https");
|
||||||
|
if (isUrl) {
|
||||||
|
try {
|
||||||
|
base64Sign = await fetchImageBase64(base64Sign);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//change image width and height to 104/44 in png base64
|
||||||
|
const getNewse64 = await changeImageWH(base64Sign);
|
||||||
|
//remove suffiix of base64
|
||||||
|
const suffixbase64 = getNewse64 && getNewse64.split(",").pop();
|
||||||
|
|
||||||
|
singleSign = {
|
||||||
|
mailProvider: activeMailAdapter,
|
||||||
|
pdfFile: base64Url,
|
||||||
|
docId: documentId,
|
||||||
|
userId: signerObjectId,
|
||||||
|
isCustomCompletionMail: isCustomCompletionMail,
|
||||||
|
signature: suffixbase64
|
||||||
|
};
|
||||||
|
const response = await axios
|
||||||
|
.post(`${localStorage.getItem("baseUrl")}functions/signPdf`, singleSign, {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
|
// sessionToken: localStorage.getItem("accesstoken")
|
||||||
|
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((Listdata) => {
|
||||||
|
const json = Listdata.data;
|
||||||
|
const res = json.result;
|
||||||
|
return res;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log("Err ", err);
|
||||||
|
setIsAlert({
|
||||||
|
isShow: true,
|
||||||
|
alertMessage: "something went wrong"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (e) {
|
||||||
|
setIsAlert({
|
||||||
|
isShow: true,
|
||||||
|
alertMessage: "something went wrong"
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const randomId = () => {
|
export const randomId = () => {
|
||||||
@@ -1069,7 +1164,6 @@ export const onImageSelect = (event, setImgWH, setImage) => {
|
|||||||
const imageType = event.target.files[0].type;
|
const imageType = event.target.files[0].type;
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsDataURL(event.target.files[0]);
|
reader.readAsDataURL(event.target.files[0]);
|
||||||
|
|
||||||
reader.onloadend = function (e) {
|
reader.onloadend = function (e) {
|
||||||
let width, height;
|
let width, height;
|
||||||
const image = new Image();
|
const image = new Image();
|
||||||
@@ -1097,6 +1191,50 @@ export const onImageSelect = (event, setImgWH, setImage) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//convert https url to base64
|
||||||
|
export const fetchImageBase64 = async (imageUrl) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(imageUrl);
|
||||||
|
const blob = await response.blob();
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
reader.onloadend = () => {
|
||||||
|
const base64data = reader.result;
|
||||||
|
resolve(base64data);
|
||||||
|
};
|
||||||
|
reader.onerror = (error) => {
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error("Error converting URL to base64:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//function for select image and upload image
|
||||||
|
export const changeImageWH = async (base64Image) => {
|
||||||
|
const newWidth = 100;
|
||||||
|
const newHeight = 40;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = base64Image;
|
||||||
|
img.onload = async () => {
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
canvas.width = newWidth;
|
||||||
|
canvas.height = newHeight;
|
||||||
|
ctx.imageSmoothingEnabled = false;
|
||||||
|
ctx.drawImage(img, 0, 0, newWidth, newHeight);
|
||||||
|
const resizedBase64 = canvas.toDataURL("image/png", 1);
|
||||||
|
resolve(resizedBase64);
|
||||||
|
};
|
||||||
|
img.onerror = (error) => {
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
//function for embed multiple signature using pdf-lib
|
//function for embed multiple signature using pdf-lib
|
||||||
export const multiSignEmbed = async (
|
export const multiSignEmbed = async (
|
||||||
pngUrl,
|
pngUrl,
|
||||||
@@ -1135,10 +1273,10 @@ export const multiSignEmbed = async (
|
|||||||
const newUrl = await convertPNGtoJPEG(signUrl);
|
const newUrl = await convertPNGtoJPEG(signUrl);
|
||||||
signUrl = newUrl;
|
signUrl = newUrl;
|
||||||
}
|
}
|
||||||
const checkUrl = urlValidator(signUrl);
|
// const checkUrl = urlValidator(signUrl);
|
||||||
if (checkUrl) {
|
// if (checkUrl) {
|
||||||
signUrl = signUrl + "?get";
|
// signUrl = signUrl + "?get";
|
||||||
}
|
// }
|
||||||
const res = await fetch(signUrl);
|
const res = await fetch(signUrl);
|
||||||
return res.arrayBuffer();
|
return res.arrayBuffer();
|
||||||
}
|
}
|
||||||
@@ -1211,8 +1349,8 @@ export const multiSignEmbed = async (
|
|||||||
position.type === radioButtonWidget
|
position.type === radioButtonWidget
|
||||||
? 10
|
? 10
|
||||||
: position.type === "checkbox"
|
: position.type === "checkbox"
|
||||||
? 10
|
? 10
|
||||||
: newUpdateHeight;
|
: newUpdateHeight;
|
||||||
const newHeight = ind ? (ind > 0 ? widgetHeight : 0) : widgetHeight;
|
const newHeight = ind ? (ind > 0 ? widgetHeight : 0) : widgetHeight;
|
||||||
|
|
||||||
if (signyourself) {
|
if (signyourself) {
|
||||||
@@ -1273,6 +1411,7 @@ export const multiSignEmbed = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const widgetTypeExist = [
|
const widgetTypeExist = [
|
||||||
|
textWidget,
|
||||||
textInputWidget,
|
textInputWidget,
|
||||||
"name",
|
"name",
|
||||||
"company",
|
"company",
|
||||||
@@ -1328,7 +1467,7 @@ export const multiSignEmbed = async (
|
|||||||
checkbox.enableReadOnly();
|
checkbox.enableReadOnly();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (position.type === textWidget) {
|
} else if (widgetTypeExist) {
|
||||||
const font = await pdfDoc.embedFont("Helvetica");
|
const font = await pdfDoc.embedFont("Helvetica");
|
||||||
const fontSize = 12;
|
const fontSize = 12;
|
||||||
let textContent;
|
let textContent;
|
||||||
@@ -1404,24 +1543,8 @@ export const multiSignEmbed = async (
|
|||||||
color: rgb(0, 0, 0),
|
color: rgb(0, 0, 0),
|
||||||
size: fontSize
|
size: fontSize
|
||||||
});
|
});
|
||||||
y -= 15; // Adjust the line height as needed
|
y -= 18; // Adjust the line height as needed
|
||||||
}
|
}
|
||||||
} else if (widgetTypeExist) {
|
|
||||||
const font = await pdfDoc.embedFont("Helvetica");
|
|
||||||
const fontSize = 12;
|
|
||||||
let textContent;
|
|
||||||
if (position?.options?.response) {
|
|
||||||
textContent = position.options?.response;
|
|
||||||
} else if (position?.options?.defaultValue) {
|
|
||||||
textContent = position?.options?.defaultValue;
|
|
||||||
}
|
|
||||||
page.drawText(textContent, {
|
|
||||||
x: xPos(position),
|
|
||||||
y: yPos(position) + 10,
|
|
||||||
size: fontSize,
|
|
||||||
font,
|
|
||||||
color: rgb(0, 0, 0)
|
|
||||||
});
|
|
||||||
} else if (position.type === "dropdown") {
|
} else if (position.type === "dropdown") {
|
||||||
const dropdownRandomId = "dropdown" + randomId();
|
const dropdownRandomId = "dropdown" + randomId();
|
||||||
const dropdown = form.createDropdown(dropdownRandomId);
|
const dropdown = form.createDropdown(dropdownRandomId);
|
||||||
@@ -1792,3 +1915,116 @@ export const handleCopyNextToWidget = (
|
|||||||
setXyPostion(updatePlaceholder);
|
setXyPostion(updatePlaceholder);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getFileName = (fileUrl) => {
|
||||||
|
if (fileUrl) {
|
||||||
|
const url = new URL(fileUrl);
|
||||||
|
const filename = url.pathname.substring(url.pathname.indexOf("_") + 1);
|
||||||
|
return filename || "";
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//fetch tenant app logo from `partners_Tenant` class by domain name
|
||||||
|
export const getAppLogo = async () => {
|
||||||
|
const domainName = window.location.host;
|
||||||
|
try {
|
||||||
|
const tenantCreditsQuery = new Parse.Query("partners_Tenant");
|
||||||
|
tenantCreditsQuery.equalTo("Domain", domainName);
|
||||||
|
const res = await tenantCreditsQuery.first();
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
const updateRes = JSON.parse(JSON.stringify(res));
|
||||||
|
return updateRes?.Logo;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTenantDetails = async (objectId) => {
|
||||||
|
try {
|
||||||
|
const tenantCreditsQuery = new Parse.Query("partners_Tenant");
|
||||||
|
tenantCreditsQuery.equalTo("UserId", {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: "_User",
|
||||||
|
objectId: objectId
|
||||||
|
});
|
||||||
|
const res = await tenantCreditsQuery.first();
|
||||||
|
if (res) {
|
||||||
|
const updateRes = JSON.parse(JSON.stringify(res));
|
||||||
|
return updateRes;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return "user does not exist!";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//function to convert variable string name to variable value of email body and subject
|
||||||
|
export function replaceMailVaribles(subject, body, variables) {
|
||||||
|
let replacedSubject = subject;
|
||||||
|
let replacedBody = body;
|
||||||
|
|
||||||
|
for (const variable in variables) {
|
||||||
|
const regex = new RegExp(`{{${variable}}}`, "g");
|
||||||
|
if (subject) {
|
||||||
|
replacedSubject = replacedSubject.replace(regex, variables[variable]);
|
||||||
|
}
|
||||||
|
if (body) {
|
||||||
|
replacedBody = replacedBody.replace(regex, variables[variable]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
subject: replacedSubject,
|
||||||
|
body: replacedBody
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const copytoData = (text) => {
|
||||||
|
// navigator.clipboard.writeText(text);
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
navigator.clipboard.writeText(text);
|
||||||
|
} else {
|
||||||
|
// Fallback for browsers that don't support navigator.clipboard
|
||||||
|
const textArea = document.createElement("textarea");
|
||||||
|
textArea.value = text;
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.select();
|
||||||
|
document.execCommand("copy");
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const convertPdfArrayBuffer = async (url) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(url);
|
||||||
|
// Check if the response was successful (status 200)
|
||||||
|
if (!response.ok) {
|
||||||
|
return "Error";
|
||||||
|
}
|
||||||
|
// Convert the response to ArrayBuffer
|
||||||
|
const arrayBuffer = await response.arrayBuffer();
|
||||||
|
return arrayBuffer;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching data:", error);
|
||||||
|
return "Error";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//`handleSendOTP` function is used to send otp on user's email using `SendOTPMailV1` cloud function
|
||||||
|
export const handleSendOTP = async (email) => {
|
||||||
|
try {
|
||||||
|
let url = `${localStorage.getItem("baseUrl")}functions/SendOTPMailV1`;
|
||||||
|
const headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
|
||||||
|
};
|
||||||
|
const body = { email: email };
|
||||||
|
await axios.post(url, body, { headers: headers });
|
||||||
|
} catch (error) {
|
||||||
|
alert(error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
const parseAppId = localStorage.getItem("parseAppId");
|
const parseAppId = process.env.REACT_APP_APPID
|
||||||
const serverUrl = localStorage.getItem("baseUrl");
|
? process.env.REACT_APP_APPID
|
||||||
|
: "opensign";
|
||||||
|
const serverUrl = process.env.REACT_APP_SERVERURL
|
||||||
|
? process.env.REACT_APP_SERVERURL
|
||||||
|
: window.location.origin + "/api/app";
|
||||||
|
|
||||||
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
|
||||||
@@ -12,7 +16,7 @@ export const SaveFileSize = async (size, imageUrl, tenantId) => {
|
|||||||
const _tenantPtr = JSON.stringify(tenantPtr);
|
const _tenantPtr = JSON.stringify(tenantPtr);
|
||||||
try {
|
try {
|
||||||
const res = await axios.get(
|
const res = await axios.get(
|
||||||
`${serverUrl}classes/partners_TenantCredits?where={"PartnersTenant":${_tenantPtr}}`,
|
`${serverUrl}/classes/partners_TenantCredits?where={"PartnersTenant":${_tenantPtr}}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -30,7 +34,7 @@ export const SaveFileSize = async (size, imageUrl, tenantId) => {
|
|||||||
: size
|
: size
|
||||||
};
|
};
|
||||||
await axios.put(
|
await axios.put(
|
||||||
`${serverUrl}classes/partners_TenantCredits/${response[0].objectId}`,
|
`${serverUrl}/classes/partners_TenantCredits/${response[0].objectId}`,
|
||||||
data,
|
data,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -41,7 +45,7 @@ export const SaveFileSize = async (size, imageUrl, tenantId) => {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
data = { usedStorage: size, PartnersTenant: tenantPtr };
|
data = { usedStorage: size, PartnersTenant: tenantPtr };
|
||||||
await axios.post(`${serverUrl}classes/partners_TenantCredits`, data, {
|
await axios.post(`${serverUrl}/classes/partners_TenantCredits`, data, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": parseAppId
|
"X-Parse-Application-Id": parseAppId
|
||||||
@@ -64,7 +68,7 @@ const saveDataFile = async (size, imageUrl, tenantPtr) => {
|
|||||||
|
|
||||||
// console.log("data save",file, data)
|
// console.log("data save",file, data)
|
||||||
try {
|
try {
|
||||||
await axios.post(`${serverUrl}classes/partners_DataFiles`, data, {
|
await axios.post(`${serverUrl}/classes/partners_DataFiles`, data, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": parseAppId
|
"X-Parse-Application-Id": parseAppId
|
||||||
@@ -74,4 +78,3 @@ const saveDataFile = async (size, imageUrl, tenantPtr) => {
|
|||||||
console.log("err in save usage ", err);
|
console.log("err in save usage ", err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -4,6 +4,7 @@ import "./index.css";
|
|||||||
import App from "./App";
|
import App from "./App";
|
||||||
import { Provider } from "react-redux";
|
import { Provider } from "react-redux";
|
||||||
import { store } from "./redux/store";
|
import { store } from "./redux/store";
|
||||||
|
import { CookiesProvider } from "react-cookie";
|
||||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||||
import { TouchBackend } from "react-dnd-touch-backend";
|
import { TouchBackend } from "react-dnd-touch-backend";
|
||||||
import {
|
import {
|
||||||
@@ -62,10 +63,12 @@ if (process.env.REACT_APP_GTM) {
|
|||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById("root"));
|
const root = ReactDOM.createRoot(document.getElementById("root"));
|
||||||
root.render(
|
root.render(
|
||||||
<Provider store={store}>
|
<CookiesProvider defaultSetOptions={{ path: "/" }}>
|
||||||
<DndProvider options={HTML5toTouch}>
|
<Provider store={store}>
|
||||||
<Preview>{generatePreview}</Preview>
|
<DndProvider options={HTML5toTouch}>
|
||||||
<App />
|
<Preview>{generatePreview}</Preview>
|
||||||
</DndProvider>
|
<App />
|
||||||
</Provider>
|
</DndProvider>
|
||||||
|
</Provider>
|
||||||
|
</CookiesProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,14 +12,26 @@ export default function reportJson(id) {
|
|||||||
heading: head,
|
heading: head,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "sign",
|
btnId: "1231",
|
||||||
|
hoverLabel: "Edit",
|
||||||
btnColor: "#4bd396",
|
btnColor: "#4bd396",
|
||||||
textColor: "white",
|
textColor: "white",
|
||||||
btnIcon: "fa fa-plus",
|
btnIcon: "fa-solid fa-pen",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "2142",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnColor: "#ff4848",
|
||||||
|
textColor: "white",
|
||||||
|
btnIcon: "fa fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
helpMsg: "These are documents you have started but have not finalized for sending."
|
helpMsg:
|
||||||
|
"These are documents you have started but have not finalized for sending."
|
||||||
};
|
};
|
||||||
// Need your sign report
|
// Need your sign report
|
||||||
case "4Hhwbp482K":
|
case "4Hhwbp482K":
|
||||||
@@ -28,11 +40,14 @@ export default function reportJson(id) {
|
|||||||
heading: head,
|
heading: head,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
btnId: "4536",
|
||||||
btnLabel: "sign",
|
btnLabel: "sign",
|
||||||
|
hoverLabel: "Sign",
|
||||||
btnColor: "#3ac9d6",
|
btnColor: "#3ac9d6",
|
||||||
textColor: "white",
|
textColor: "white",
|
||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa-solid fa-signature",
|
||||||
redirectUrl: "pdfRequestFiles"
|
redirectUrl: "pdfRequestFiles",
|
||||||
|
action: "redirect"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
helpMsg:
|
helpMsg:
|
||||||
@@ -45,11 +60,48 @@ export default function reportJson(id) {
|
|||||||
heading: head,
|
heading: head,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "View",
|
btnId: "8901",
|
||||||
|
hoverLabel: "Share",
|
||||||
|
btnColor: "#4bd396",
|
||||||
|
textColor: "white",
|
||||||
|
btnIcon: "fa-solid fa-share",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "share"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1588",
|
||||||
|
hoverLabel: "View",
|
||||||
btnColor: "#3ac9d6",
|
btnColor: "#3ac9d6",
|
||||||
textColor: "white",
|
textColor: "white",
|
||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa fa-eye",
|
||||||
redirectUrl: "pdfRequestFiles"
|
redirectUrl: "pdfRequestFiles",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "2234",
|
||||||
|
hoverLabel: "option",
|
||||||
|
btnColor: "transparent",
|
||||||
|
textColor: "black",
|
||||||
|
btnIcon: "fa-solid fa-ellipsis-vertical fa-lg",
|
||||||
|
action: "option",
|
||||||
|
subaction: [
|
||||||
|
{
|
||||||
|
btnId: "1688",
|
||||||
|
btnLabel: "Revoke",
|
||||||
|
hoverLabel: "Revoke",
|
||||||
|
btnIcon: "fa-solid fa-file-circle-xmark",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "revoke"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1488",
|
||||||
|
btnLabel: "Delete",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnIcon: "fa fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
helpMsg:
|
helpMsg:
|
||||||
@@ -62,14 +114,26 @@ export default function reportJson(id) {
|
|||||||
heading: head,
|
heading: head,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "View",
|
btnId: "1378",
|
||||||
|
hoverLabel: "Edit",
|
||||||
btnColor: "#4bd396",
|
btnColor: "#4bd396",
|
||||||
textColor: "white",
|
textColor: "white",
|
||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa fa-eye",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1278",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnColor: "#ff4848",
|
||||||
|
textColor: "white",
|
||||||
|
btnIcon: "fa fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
helpMsg: "This is a list of documents that have been signed by all parties."
|
helpMsg:
|
||||||
|
"This is a list of documents that have been signed by all parties."
|
||||||
};
|
};
|
||||||
// declined documents report
|
// declined documents report
|
||||||
case "UPr2Fm5WY3":
|
case "UPr2Fm5WY3":
|
||||||
@@ -78,14 +142,26 @@ export default function reportJson(id) {
|
|||||||
heading: head,
|
heading: head,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "View",
|
btnId: "1458",
|
||||||
|
hoverLabel: "View",
|
||||||
btnColor: "#4bd396",
|
btnColor: "#4bd396",
|
||||||
textColor: "white",
|
textColor: "white",
|
||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa fa-eye",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1358",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnColor: "#ff4848",
|
||||||
|
textColor: "white",
|
||||||
|
btnIcon: "fa fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
helpMsg: "This is a list of documents that have been declined by one of the signers."
|
helpMsg:
|
||||||
|
"This is a list of documents that have been declined by one of the signers."
|
||||||
};
|
};
|
||||||
// Expired Documents report
|
// Expired Documents report
|
||||||
case "zNqBHXHsYH":
|
case "zNqBHXHsYH":
|
||||||
@@ -94,14 +170,26 @@ export default function reportJson(id) {
|
|||||||
heading: head,
|
heading: head,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "View",
|
btnId: "1898",
|
||||||
|
hoverLabel: "View",
|
||||||
btnColor: "#4bd396",
|
btnColor: "#4bd396",
|
||||||
textColor: "white",
|
textColor: "white",
|
||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa fa-eye",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1998",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnColor: "#ff4848",
|
||||||
|
textColor: "white",
|
||||||
|
btnIcon: "fa fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
helpMsg: "This is a list of documents that have reached their expiration date."
|
helpMsg:
|
||||||
|
"This is a list of documents that have reached their expiration date."
|
||||||
};
|
};
|
||||||
// Recently sent for signatures report show on dashboard
|
// Recently sent for signatures report show on dashboard
|
||||||
case "d9k3UfYHBc":
|
case "d9k3UfYHBc":
|
||||||
@@ -110,11 +198,48 @@ export default function reportJson(id) {
|
|||||||
heading: dashboardReportHead,
|
heading: dashboardReportHead,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "View",
|
btnId: "1999",
|
||||||
|
hoverLabel: "Share",
|
||||||
btnColor: "#4bd396",
|
btnColor: "#4bd396",
|
||||||
textColor: "white",
|
textColor: "white",
|
||||||
|
btnIcon: "fa-solid fa-share",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "share"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1999",
|
||||||
|
hoverLabel: "View",
|
||||||
|
btnColor: "#3ac9d6",
|
||||||
|
textColor: "white",
|
||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa fa-eye",
|
||||||
redirectUrl: "pdfRequestFiles"
|
redirectUrl: "pdfRequestFiles",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "2234",
|
||||||
|
hoverLabel: "option",
|
||||||
|
btnColor: "transparent",
|
||||||
|
textColor: "black",
|
||||||
|
btnIcon: "fa-solid fa-ellipsis-vertical fa-lg",
|
||||||
|
action: "option",
|
||||||
|
subaction: [
|
||||||
|
{
|
||||||
|
btnId: "6788",
|
||||||
|
btnLabel: "Revoke",
|
||||||
|
hoverLabel: "Revoke",
|
||||||
|
btnIcon: "fa-solid fa-file-circle-xmark",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "revoke"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "2000",
|
||||||
|
btnLabel: "Delete",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnIcon: "fa fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@@ -125,11 +250,14 @@ export default function reportJson(id) {
|
|||||||
heading: dashboardReportHead,
|
heading: dashboardReportHead,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "Sign",
|
btnId: "2001",
|
||||||
btnColor: "#4bd396",
|
btnLabel: "sign",
|
||||||
|
hoverLabel: "Sign",
|
||||||
|
btnColor: "#3ac9d6",
|
||||||
textColor: "white",
|
textColor: "white",
|
||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa-solid fa-signature",
|
||||||
redirectUrl: "pdfRequestFiles"
|
redirectUrl: "pdfRequestFiles",
|
||||||
|
action: "redirect"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@@ -140,11 +268,22 @@ export default function reportJson(id) {
|
|||||||
heading: ["Title", "Note", "Folder", "File", "Owner", "Signers"],
|
heading: ["Title", "Note", "Folder", "File", "Owner", "Signers"],
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "sign",
|
btnId: "2003",
|
||||||
|
hoverLabel: "Edit",
|
||||||
btnColor: "#4bd396",
|
btnColor: "#4bd396",
|
||||||
textColor: "white",
|
textColor: "white",
|
||||||
btnIcon: "fa fa-plus",
|
btnIcon: "fa-solid fa-pen",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "2004",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnColor: "#ff4848",
|
||||||
|
textColor: "white",
|
||||||
|
btnIcon: "fa fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@@ -155,14 +294,17 @@ export default function reportJson(id) {
|
|||||||
heading: contactbook,
|
heading: contactbook,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "",
|
btnId: "2204",
|
||||||
|
hoverLabel: "Delete",
|
||||||
btnColor: "#f55a42",
|
btnColor: "#f55a42",
|
||||||
textColor: "white",
|
textColor: "white",
|
||||||
btnIcon: "fa-solid fa-trash"
|
btnIcon: "fa-solid fa-trash",
|
||||||
|
action: "delete"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
form: "ContactBook",
|
form: "ContactBook",
|
||||||
helpMsg: "This is a list of contacts/signers added by you. These will appear as suggestions when you try to add signers to a new document."
|
helpMsg:
|
||||||
|
"This is a list of contacts/signers added by you. These will appear as suggestions when you try to add signers to a new document."
|
||||||
};
|
};
|
||||||
// template report
|
// template report
|
||||||
case "6TeaPr321t":
|
case "6TeaPr321t":
|
||||||
@@ -171,18 +313,46 @@ export default function reportJson(id) {
|
|||||||
heading: head,
|
heading: head,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
btnId: "2234",
|
||||||
btnLabel: "Use",
|
btnLabel: "Use",
|
||||||
|
hoverLabel: "Use",
|
||||||
btnColor: "#4bd396",
|
btnColor: "#4bd396",
|
||||||
textColor: "white",
|
textColor: "white",
|
||||||
btnIcon: "fa fa-plus",
|
btnIcon: "fa fa-plus",
|
||||||
redirectUrl: "placeHolderSign"
|
redirectUrl: "placeHolderSign",
|
||||||
|
action: "redirect",
|
||||||
|
selector: "reactourSecond",
|
||||||
|
message:
|
||||||
|
"Click the 'Use' button to create a new document from an existing template. "
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
btnLabel: "Edit",
|
btnId: "2234",
|
||||||
btnColor: "#00c9d5",
|
hoverLabel: "option",
|
||||||
textColor: "white",
|
btnColor: "transparent",
|
||||||
btnIcon: "fa fa-plus",
|
textColor: "black",
|
||||||
redirectUrl: "template"
|
btnIcon: "fa-solid fa-ellipsis-vertical fa-lg",
|
||||||
|
action: "option",
|
||||||
|
selector: "reactourThird",
|
||||||
|
message:
|
||||||
|
"This menu reveals more options such as Edit & Delete. Use the 'Edit' button to add signer roles, modify fields, and update your template. Changes will apply to all future documents created from this template but won’t affect existing documents.Use the Delete button you can delete template. ",
|
||||||
|
subaction: [
|
||||||
|
{
|
||||||
|
btnId: "2434",
|
||||||
|
btnLabel: "Edit",
|
||||||
|
hoverLabel: "Edit",
|
||||||
|
btnIcon: "fa-solid fa-pen",
|
||||||
|
redirectUrl: "template",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1834",
|
||||||
|
btnLabel: "Delete",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnIcon: "fa fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
helpMsg:
|
helpMsg:
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
const plans = [
|
||||||
|
{
|
||||||
|
planName: "OPENSIGN™ FREE",
|
||||||
|
currency: "",
|
||||||
|
monthlyPrice: "Free",
|
||||||
|
yearlyPrice: "Free",
|
||||||
|
subtitle: "Free Unlimited E-signatures, Forever.",
|
||||||
|
btnText: "Subscribe",
|
||||||
|
url: "",
|
||||||
|
target: "_blank",
|
||||||
|
benefits: [
|
||||||
|
"Unlimited envelopes",
|
||||||
|
"Sign documents yourself",
|
||||||
|
"Request signatures from others",
|
||||||
|
"14 field types",
|
||||||
|
"Automatic e-signatures",
|
||||||
|
"Completion certificates",
|
||||||
|
"Send in order",
|
||||||
|
"Document templates",
|
||||||
|
"Import from Dropbox",
|
||||||
|
"Contact book",
|
||||||
|
"Document expiry support",
|
||||||
|
"Decline document support",
|
||||||
|
"Email notifications",
|
||||||
|
"Recipient authentication using OTP",
|
||||||
|
"And much more"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
planName: "OPENSIGN™ PROFESSIONAL",
|
||||||
|
currency: "$",
|
||||||
|
monthlyPrice: "29.99",
|
||||||
|
yearlyPrice: "329.99",
|
||||||
|
subtitle: "Exclusive Access to advanced features.",
|
||||||
|
btnText: "Subscribe",
|
||||||
|
url:
|
||||||
|
window.location.origin === "https://staging-app.opensignlabs.com"
|
||||||
|
? "https://billing.zoho.in/subscribe/9627f62a09df1c8ce500f2f4dc8328dd84ecda20eeae13878ce581d60240f206/pro-weekly"
|
||||||
|
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d1a09dfa8085585cdd4ec4d7f32137f3/professional-monthly",
|
||||||
|
yearlyUrl:
|
||||||
|
window.location.origin === "https://staging-app.opensignlabs.com"
|
||||||
|
? "https://billing.zoho.in/subscribe/9627f62a09df1c8ce500f2f4dc8328ddc184411129224f1f29ed84f6cef3b862/pro-yearly"
|
||||||
|
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d8ad1135190dff951330360e47585a71/professional-yearly",
|
||||||
|
target: "_self",
|
||||||
|
benefits: [
|
||||||
|
"Everything in OpenSign™ free",
|
||||||
|
"Field validations",
|
||||||
|
"Regular expression validations",
|
||||||
|
"Organize docs in OpenSign™ Drive",
|
||||||
|
"Webhooks",
|
||||||
|
"Zapier integration",
|
||||||
|
"API Access",
|
||||||
|
"100 API signatures included",
|
||||||
|
"DocumentId removal from signed docs",
|
||||||
|
"Custom email templates"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
planName: "OPENSIGN™ ENTERPRISE",
|
||||||
|
currency: "",
|
||||||
|
monthlyPrice: "Request Price",
|
||||||
|
yearlyPrice: "Request Price",
|
||||||
|
subtitle: "Scalable Features with priority support.",
|
||||||
|
btnText: "Contact us",
|
||||||
|
url: "https://www.opensignlabs.com/contact-us",
|
||||||
|
target: "_blank",
|
||||||
|
benefits: [
|
||||||
|
"All features",
|
||||||
|
"Custom domain",
|
||||||
|
"Custom branding",
|
||||||
|
"Uptime SLA",
|
||||||
|
"SSO support",
|
||||||
|
"Priority support"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default plans;
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"planName": "OPENSIGN™ FREE",
|
|
||||||
"currency": "",
|
|
||||||
"monthlyPrice": "Free",
|
|
||||||
"yearlyPrice": "Free",
|
|
||||||
"subtitle": "Free Unlimited E-signatures, Forever.",
|
|
||||||
"btnText": "Subscribe",
|
|
||||||
"url": "",
|
|
||||||
"target": "_blank",
|
|
||||||
"benefits": [
|
|
||||||
"Unlimited envelopes",
|
|
||||||
"Sign documents yourself",
|
|
||||||
"Request signatures from others",
|
|
||||||
"14 field types",
|
|
||||||
"Automatic e-signatures",
|
|
||||||
"Completion certificates",
|
|
||||||
"Send in order",
|
|
||||||
"Document templates",
|
|
||||||
"Import from Dropbox",
|
|
||||||
"Contact book",
|
|
||||||
"Document expiry support",
|
|
||||||
"Decline document support",
|
|
||||||
"Email notifications",
|
|
||||||
"Recipient authentication using OTP",
|
|
||||||
"And much more"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"planName": "OPENSIGN™ PROFESSIONAL",
|
|
||||||
"currency": "$",
|
|
||||||
"monthlyPrice": "29.99",
|
|
||||||
"yearlyPrice": "329.99",
|
|
||||||
"subtitle": "Exclusive Access to advanced features.",
|
|
||||||
"btnText": "Subscribe",
|
|
||||||
"url": "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d1a09dfa8085585cdd4ec4d7f32137f3/professional-monthly",
|
|
||||||
"yearlyUrl": "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d8ad1135190dff951330360e47585a71/professional-yearly",
|
|
||||||
"target": "_self",
|
|
||||||
"benefits": [
|
|
||||||
"Everything in OpenSign™ professional",
|
|
||||||
"Field validations",
|
|
||||||
"Regular expression validations",
|
|
||||||
"Organize docs in OpenSign™ Drive",
|
|
||||||
"Webhooks",
|
|
||||||
"Zapier integration",
|
|
||||||
"API Access",
|
|
||||||
"100 API signatures included",
|
|
||||||
"DocumentId removal from signed docs",
|
|
||||||
"Custom email templates(coming soon)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"planName": "OPENSIGN™ ENTERPRISE",
|
|
||||||
"currency": "",
|
|
||||||
"monthlyPrice": "Request Price",
|
|
||||||
"yearlyPrice": "Request Price",
|
|
||||||
"subtitle": "Scalable Features with priority support.",
|
|
||||||
"btnText": "Contact us",
|
|
||||||
"url": "https://www.opensignlabs.com/contact-us",
|
|
||||||
"target": "_blank",
|
|
||||||
"benefits": [
|
|
||||||
"All features",
|
|
||||||
"Custom domain",
|
|
||||||
"Custom branding",
|
|
||||||
"Uptime SLA",
|
|
||||||
"SSO support",
|
|
||||||
"Priority support"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -10,6 +10,8 @@ import Parse from "parse";
|
|||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import { useNavigate, useLocation, Outlet } from "react-router-dom";
|
import { useNavigate, useLocation, Outlet } from "react-router-dom";
|
||||||
import { isEnableSubscription } from "../constant/const";
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
import { useCookies } from "react-cookie";
|
||||||
|
import { fetchSubscription } from "../constant/Utils";
|
||||||
|
|
||||||
const HomeLayout = () => {
|
const HomeLayout = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -24,6 +26,7 @@ const HomeLayout = () => {
|
|||||||
const [isTour, setIsTour] = useState(false);
|
const [isTour, setIsTour] = useState(false);
|
||||||
const [tourStatusArr, setTourStatusArr] = useState([]);
|
const [tourStatusArr, setTourStatusArr] = useState([]);
|
||||||
const [tourConfigs, setTourConfigs] = useState([]);
|
const [tourConfigs, setTourConfigs] = useState([]);
|
||||||
|
const [, setCookie] = useCookies(["accesstoken", "main_Domain"]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
@@ -34,6 +37,7 @@ const HomeLayout = () => {
|
|||||||
sessionToken: localStorage.getItem("accesstoken")
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
});
|
});
|
||||||
if (user) {
|
if (user) {
|
||||||
|
localStorage.setItem("profileImg", user.get("ProfilePic") || "");
|
||||||
checkIsSubscribed();
|
checkIsSubscribed();
|
||||||
} else {
|
} else {
|
||||||
setIsUserValid(false);
|
setIsUserValid(false);
|
||||||
@@ -43,23 +47,36 @@ const HomeLayout = () => {
|
|||||||
setIsUserValid(false);
|
setIsUserValid(false);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
saveCookies();
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
//function to use save data in cookies storage
|
||||||
|
const saveCookies = () => {
|
||||||
|
const main_Domain = window.location.origin;
|
||||||
|
const domainName = window.location.hostname; //app.opensignlabs.com
|
||||||
|
// Find the index of the first dot in the string
|
||||||
|
const indexOfFirstDot = domainName.indexOf(".");
|
||||||
|
// Remove the first dot and get the substring starting from the next character
|
||||||
|
const updateDomain = domainName.substring(indexOfFirstDot); //.opensignlabs.com
|
||||||
|
setCookie("accesstoken", localStorage.getItem("accesstoken"), {
|
||||||
|
secure: true,
|
||||||
|
domain: updateDomain
|
||||||
|
});
|
||||||
|
setCookie("main_Domain", main_Domain, {
|
||||||
|
secure: true,
|
||||||
|
domain: updateDomain
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
async function checkIsSubscribed() {
|
async function checkIsSubscribed() {
|
||||||
const currentUser = Parse.User.current();
|
|
||||||
const user = await Parse.Cloud.run("getUserDetails", {
|
|
||||||
email: currentUser.get("email")
|
|
||||||
});
|
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const freeplan = user?.get("Plan") && user?.get("Plan").plan_code;
|
const res = await fetchSubscription();
|
||||||
const billingDate =
|
if (res.plan === "freeplan") {
|
||||||
user?.get("Next_billing_date") && user?.get("Next_billing_date");
|
|
||||||
if (freeplan === "freeplan") {
|
|
||||||
setIsUserValid(true);
|
setIsUserValid(true);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
} else if (billingDate) {
|
} else if (res.billingDate) {
|
||||||
if (billingDate > new Date()) {
|
if (new Date(res.billingDate) > new Date()) {
|
||||||
setIsUserValid(true);
|
setIsUserValid(true);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { useNavigate, useParams } from "react-router-dom";
|
|||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { saveTourSteps } from "../redux/reducers/TourStepsReducer";
|
import { saveTourSteps } from "../redux/reducers/TourStepsReducer";
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|||||||
+536
-202
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, 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 AddUser from "../components/AddUser";
|
||||||
@@ -11,6 +11,11 @@ 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 { getFileName, toDataUrl } from "../constant/Utils";
|
||||||
|
import { PDFDocument } from "pdf-lib";
|
||||||
|
import axios from "axios";
|
||||||
|
import { isEnableSubscription, submitBtn } from "../constant/const";
|
||||||
|
import ModalUi from "../primitives/ModalUi";
|
||||||
|
|
||||||
// `Form` render all type of Form on this basis of their provided in path
|
// `Form` render all type of Form on this basis of their provided in path
|
||||||
function Form() {
|
function Form() {
|
||||||
@@ -30,6 +35,8 @@ function Form() {
|
|||||||
|
|
||||||
const Forms = (props) => {
|
const Forms = (props) => {
|
||||||
const maxFileSize = 20;
|
const maxFileSize = 20;
|
||||||
|
const abortController = new AbortController();
|
||||||
|
const inputFileRef = useRef(null);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [signers, setSigners] = useState([]);
|
const [signers, setSigners] = useState([]);
|
||||||
const [folder, setFolder] = useState({ ObjectId: "", Name: "" });
|
const [folder, setFolder] = useState({ ObjectId: "", Name: "" });
|
||||||
@@ -38,37 +45,234 @@ const Forms = (props) => {
|
|||||||
Description: "",
|
Description: "",
|
||||||
Note: "",
|
Note: "",
|
||||||
TimeToCompleteDays: 15,
|
TimeToCompleteDays: 15,
|
||||||
SendinOrder: "false"
|
SendinOrder: "false",
|
||||||
|
password: "",
|
||||||
|
file: ""
|
||||||
});
|
});
|
||||||
const [fileupload, setFileUpload] = useState([]);
|
const [fileupload, setFileUpload] = useState("");
|
||||||
const [fileload, setfileload] = useState(false);
|
const [fileload, setfileload] = useState(false);
|
||||||
const [percentage, setpercentage] = useState(0);
|
const [percentage, setpercentage] = useState(0);
|
||||||
const [isReset, setIsReset] = useState(false);
|
const [isReset, setIsReset] = useState(false);
|
||||||
const [isAlert, setIsAlert] = useState(false);
|
const [isAlert, setIsAlert] = useState(false);
|
||||||
const [isSubmit, setIsSubmit] = useState(false);
|
const [isSubmit, setIsSubmit] = useState(false);
|
||||||
const [isErr, setIsErr] = useState("");
|
const [isErr, setIsErr] = useState("");
|
||||||
|
const [isPassword, setIsPassword] = useState(false);
|
||||||
|
const [isDecrypting, setIsDecrypting] = useState(false);
|
||||||
|
const [isCorrectPass, setIsCorrectPass] = useState(true);
|
||||||
const handleStrInput = (e) => {
|
const handleStrInput = (e) => {
|
||||||
|
setIsCorrectPass(true);
|
||||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleReset();
|
handleReset();
|
||||||
|
return () => abortController.abort();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [props.title]);
|
}, [props.title]);
|
||||||
const handleFileInput = (e) => {
|
|
||||||
|
function getFileAsArrayBuffer(file) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onload = (e) => {
|
||||||
|
resolve(e.target.result);
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.onerror = (e) => {
|
||||||
|
reject(e.target.error);
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsArrayBuffer(file);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const handleFileInput = async (e) => {
|
||||||
setpercentage(0);
|
setpercentage(0);
|
||||||
try {
|
try {
|
||||||
let files = e.target.files;
|
let files = e.target.files;
|
||||||
|
setFormData((prev) => ({ ...prev, file: e.target.files[0] }));
|
||||||
if (typeof files[0] !== "undefined") {
|
if (typeof files[0] !== "undefined") {
|
||||||
const mb = Math.round(files[0].size / Math.pow(1024, 2));
|
const mb = Math.round(files[0].size / Math.pow(1024, 2));
|
||||||
if (mb > maxFileSize) {
|
if (mb > maxFileSize) {
|
||||||
alert(
|
alert(
|
||||||
`The selected file size is too large. Please select a file less than ${maxFileSize} MB`
|
`The selected file size is too large. Please select a file less than ${maxFileSize} MB`
|
||||||
);
|
);
|
||||||
setFileUpload([]);
|
setFileUpload("");
|
||||||
e.target.value = "";
|
e.target.value = "";
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
handleFileUpload(files[0]);
|
if (files?.[0]?.type === "application/pdf") {
|
||||||
|
try {
|
||||||
|
const res = await getFileAsArrayBuffer(files[0]);
|
||||||
|
await PDFDocument.load(res);
|
||||||
|
handleFileUpload(files[0]);
|
||||||
|
} catch (err) {
|
||||||
|
if (err?.message?.includes("is encrypted")) {
|
||||||
|
try {
|
||||||
|
await Parse.Cloud.run("encryptedpdf", {
|
||||||
|
email: Parse.User.current().getEmail()
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in sending posthog encryptedpdf", err);
|
||||||
|
}
|
||||||
|
// console.log("err ", err);
|
||||||
|
try {
|
||||||
|
setIsDecrypting(true);
|
||||||
|
const fileName = files?.[0].name;
|
||||||
|
const size = files?.[0].size;
|
||||||
|
const name = sanitizeFileName(fileName);
|
||||||
|
const url = "https://ai.nxglabs.in/decryptpdf"; //"https://ai.nxglabs.in/decryptpdf"; //
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append("file", files[0]);
|
||||||
|
formData.append("password", "");
|
||||||
|
const config = {
|
||||||
|
headers: {
|
||||||
|
"content-type": "multipart/form-data"
|
||||||
|
// sessiontoken: Parse.User.current().getSessionToken()
|
||||||
|
},
|
||||||
|
responseType: "blob"
|
||||||
|
};
|
||||||
|
const response = await axios.post(url, formData, config);
|
||||||
|
const pdfBlob = new Blob([response.data], {
|
||||||
|
type: "application/pdf"
|
||||||
|
});
|
||||||
|
const pdfFile = new File([pdfBlob], name, {
|
||||||
|
type: "application/pdf"
|
||||||
|
});
|
||||||
|
setIsDecrypting(false);
|
||||||
|
setfileload(true);
|
||||||
|
|
||||||
|
// Upload the file to Parse Server
|
||||||
|
const parseFile = new Parse.File(
|
||||||
|
name,
|
||||||
|
pdfFile,
|
||||||
|
"application/pdf"
|
||||||
|
);
|
||||||
|
|
||||||
|
await parseFile.save({
|
||||||
|
progress: (progressValue, loaded, total, { type }) => {
|
||||||
|
if (type === "upload" && progressValue !== null) {
|
||||||
|
const percentCompleted = Math.round(
|
||||||
|
(loaded * 100) / total
|
||||||
|
);
|
||||||
|
setpercentage(percentCompleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Retrieve the URL of the uploaded file
|
||||||
|
if (parseFile.url()) {
|
||||||
|
setFileUpload(parseFile.url());
|
||||||
|
setfileload(false);
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
SaveFileSize(size, parseFile.url(), tenantId);
|
||||||
|
return parseFile.url();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setfileload(false);
|
||||||
|
setpercentage(0);
|
||||||
|
if (err?.response?.status === 401) {
|
||||||
|
setIsPassword(true);
|
||||||
|
} else {
|
||||||
|
console.log("Error uploading file: ", err?.response);
|
||||||
|
setIsDecrypting(false);
|
||||||
|
e.target.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("err ", err);
|
||||||
|
setFileUpload("");
|
||||||
|
e.target.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const isImage = files?.[0]?.type.includes("image/");
|
||||||
|
if (isImage) {
|
||||||
|
const image = await toDataUrl(files[0]);
|
||||||
|
const pdfDoc = await PDFDocument.create();
|
||||||
|
let embedImg;
|
||||||
|
if (files?.[0]?.type === "image/png") {
|
||||||
|
embedImg = await pdfDoc.embedPng(image);
|
||||||
|
} else {
|
||||||
|
embedImg = await pdfDoc.embedJpg(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get image dimensions
|
||||||
|
const imageWidth = embedImg.width;
|
||||||
|
const imageHeight = embedImg.height;
|
||||||
|
const page = pdfDoc.addPage([imageWidth, imageHeight]);
|
||||||
|
page.drawImage(embedImg, {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: imageWidth,
|
||||||
|
height: imageHeight
|
||||||
|
});
|
||||||
|
const getFile = await pdfDoc.save({
|
||||||
|
useObjectStreams: false
|
||||||
|
});
|
||||||
|
setfileload(true);
|
||||||
|
const fileName = files[0].name;
|
||||||
|
const size = files[0].size;
|
||||||
|
const name = sanitizeFileName(fileName);
|
||||||
|
const pdfName = `${name?.split(".")[0]}.pdf`;
|
||||||
|
const parseFile = new Parse.File(
|
||||||
|
pdfName,
|
||||||
|
[...getFile],
|
||||||
|
"application/pdf"
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await parseFile.save({
|
||||||
|
progress: (progressValue, loaded, total, { type }) => {
|
||||||
|
if (type === "upload" && progressValue !== null) {
|
||||||
|
const percentCompleted = Math.round(
|
||||||
|
(loaded * 100) / total
|
||||||
|
);
|
||||||
|
setpercentage(percentCompleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// The response object will contain information about the uploaded file
|
||||||
|
// You can access the URL of the uploaded file using response.url()
|
||||||
|
setFileUpload(response.url());
|
||||||
|
setfileload(false);
|
||||||
|
if (response.url()) {
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
SaveFileSize(size, response.url(), tenantId);
|
||||||
|
return response.url();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
e.target.value = "";
|
||||||
|
setfileload(false);
|
||||||
|
setpercentage(0);
|
||||||
|
console.error("Error uploading file:", error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
try {
|
||||||
|
setfileload(true);
|
||||||
|
const url = "https://ai.nxglabs.in/docxtopdf";
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append("file", files[0]);
|
||||||
|
const config = {
|
||||||
|
headers: {
|
||||||
|
"content-type": "multipart/form-data",
|
||||||
|
sessiontoken: Parse.User.current().getSessionToken()
|
||||||
|
},
|
||||||
|
signal: abortController.signal
|
||||||
|
};
|
||||||
|
const res = await axios.post(url, formData, config);
|
||||||
|
if (res.data) {
|
||||||
|
setFileUpload(res.data.url);
|
||||||
|
setfileload(false);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
e.target.value = "";
|
||||||
|
setfileload(false);
|
||||||
|
setpercentage(0);
|
||||||
|
console.log("err in libreconverter ", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
alert("Please select file.");
|
alert("Please select file.");
|
||||||
@@ -161,64 +365,68 @@ const Forms = (props) => {
|
|||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIsSubmit(true);
|
if (fileupload) {
|
||||||
try {
|
setIsSubmit(true);
|
||||||
const currentUser = Parse.User.current();
|
try {
|
||||||
const object = new Parse.Object(props.Cls);
|
const currentUser = Parse.User.current();
|
||||||
object.set("Name", formData?.Name);
|
const object = new Parse.Object(props.Cls);
|
||||||
object.set("Description", formData?.Description);
|
object.set("Name", formData?.Name);
|
||||||
object.set("Note", formData?.Note);
|
object.set("Description", formData?.Description);
|
||||||
if (props.title === "Request Signatures") {
|
object.set("Note", formData?.Note);
|
||||||
object.set(
|
if (props.title === "Request Signatures") {
|
||||||
"TimeToCompleteDays",
|
object.set(
|
||||||
parseInt(formData?.TimeToCompleteDays)
|
"TimeToCompleteDays",
|
||||||
);
|
parseInt(formData?.TimeToCompleteDays)
|
||||||
}
|
);
|
||||||
if (props.title !== "Sign Yourself") {
|
}
|
||||||
const isChecked = formData.SendinOrder === "false" ? false : true;
|
if (props.title !== "Sign Yourself") {
|
||||||
object.set("SendinOrder", isChecked);
|
const isChecked = formData.SendinOrder === "false" ? false : true;
|
||||||
}
|
object.set("SendinOrder", isChecked);
|
||||||
object.set("URL", fileupload);
|
}
|
||||||
object.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
|
object.set("URL", fileupload);
|
||||||
if (folder && folder.ObjectId) {
|
object.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
|
||||||
object.set("Folder", {
|
if (folder && folder.ObjectId) {
|
||||||
|
object.set("Folder", {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: props.Cls,
|
||||||
|
objectId: folder.ObjectId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (signers && signers.length > 0) {
|
||||||
|
object.set("Signers", signers);
|
||||||
|
}
|
||||||
|
const ExtCls = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||||
|
object.set("ExtUserPtr", {
|
||||||
__type: "Pointer",
|
__type: "Pointer",
|
||||||
className: props.Cls,
|
className: "contracts_Users",
|
||||||
objectId: folder.ObjectId
|
objectId: ExtCls[0].objectId
|
||||||
});
|
});
|
||||||
}
|
|
||||||
if (signers && signers.length > 0) {
|
|
||||||
object.set("Signers", signers);
|
|
||||||
}
|
|
||||||
const ExtCls = JSON.parse(localStorage.getItem("Extand_Class"));
|
|
||||||
object.set("ExtUserPtr", {
|
|
||||||
__type: "Pointer",
|
|
||||||
className: "contracts_Users",
|
|
||||||
objectId: ExtCls[0].objectId
|
|
||||||
});
|
|
||||||
|
|
||||||
const res = await object.save();
|
const res = await object.save();
|
||||||
if (res) {
|
if (res) {
|
||||||
setSigners([]);
|
setSigners([]);
|
||||||
setFolder({ ObjectId: "", Name: "" });
|
setFolder({ ObjectId: "", Name: "" });
|
||||||
setFormData({
|
setFormData({
|
||||||
Name: "",
|
Name: "",
|
||||||
Description: "",
|
Description: "",
|
||||||
Note: ""
|
Note: ""
|
||||||
});
|
});
|
||||||
setFileUpload([]);
|
setFileUpload("");
|
||||||
setpercentage(0);
|
setpercentage(0);
|
||||||
navigate(`/${props?.redirectRoute}/${res.id}`);
|
navigate(`/${props?.redirectRoute}/${res.id}`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err ", err);
|
||||||
|
setIsErr(true);
|
||||||
|
} finally {
|
||||||
|
setIsAlert(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsAlert(false);
|
||||||
|
}, 1000);
|
||||||
|
setIsSubmit(false);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} else {
|
||||||
console.log("err ", err);
|
alert("Please wait until the PDF has been uploading.");
|
||||||
setIsErr(true);
|
|
||||||
} finally {
|
|
||||||
setIsAlert(true);
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsAlert(false);
|
|
||||||
}, 1000);
|
|
||||||
setIsSubmit(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -250,10 +458,83 @@ const Forms = (props) => {
|
|||||||
TimeToCompleteDays: 15,
|
TimeToCompleteDays: 15,
|
||||||
SendinOrder: "true"
|
SendinOrder: "true"
|
||||||
});
|
});
|
||||||
setFileUpload([]);
|
setFileUpload("");
|
||||||
setpercentage(0);
|
setpercentage(0);
|
||||||
setTimeout(() => setIsReset(false), 50);
|
setTimeout(() => setIsReset(false), 50);
|
||||||
};
|
};
|
||||||
|
const handlePasswordSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setIsPassword(false);
|
||||||
|
setfileload(true);
|
||||||
|
try {
|
||||||
|
const fileName = formData?.file?.name;
|
||||||
|
const size = formData?.file?.size;
|
||||||
|
const name = sanitizeFileName(fileName);
|
||||||
|
const url = "https://ai.nxglabs.in/decryptpdf"; //
|
||||||
|
let Data = new FormData();
|
||||||
|
Data.append("file", formData?.file);
|
||||||
|
Data.append("password", formData.password);
|
||||||
|
const config = {
|
||||||
|
headers: {
|
||||||
|
"content-type": "multipart/form-data"
|
||||||
|
// sessiontoken: Parse.User.current().getSessionToken()
|
||||||
|
},
|
||||||
|
responseType: "blob"
|
||||||
|
};
|
||||||
|
const response = await axios.post(url, Data, config);
|
||||||
|
const pdfBlob = new Blob([response.data], {
|
||||||
|
type: "application/pdf"
|
||||||
|
});
|
||||||
|
const pdfFile = new File([pdfBlob], name, {
|
||||||
|
type: "application/pdf"
|
||||||
|
});
|
||||||
|
setIsDecrypting(false);
|
||||||
|
// Upload the file to Parse Server
|
||||||
|
const parseFile = new Parse.File(name, pdfFile, "application/pdf");
|
||||||
|
|
||||||
|
await parseFile.save({
|
||||||
|
progress: (progressValue, loaded, total, { type }) => {
|
||||||
|
if (type === "upload" && progressValue !== null) {
|
||||||
|
const percentCompleted = Math.round((loaded * 100) / total);
|
||||||
|
setpercentage(percentCompleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Retrieve the URL of the uploaded file
|
||||||
|
if (parseFile.url()) {
|
||||||
|
setFormData((prev) => ({ ...prev, password: "" }));
|
||||||
|
setFileUpload(parseFile.url());
|
||||||
|
setfileload(false);
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
SaveFileSize(size, parseFile.url(), tenantId);
|
||||||
|
return parseFile.url();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setfileload(false);
|
||||||
|
setpercentage(0);
|
||||||
|
if (err?.response?.status === 401) {
|
||||||
|
setIsPassword(true);
|
||||||
|
setIsCorrectPass(false);
|
||||||
|
} else {
|
||||||
|
console.log("Error uploading file: ", err?.response);
|
||||||
|
setFormData((prev) => ({ ...prev, password: "" }));
|
||||||
|
setIsDecrypting(false);
|
||||||
|
if (inputFileRef.current) {
|
||||||
|
inputFileRef.current.value = ""; // Set file input value to empty string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handeCloseModal = () => {
|
||||||
|
setIsPassword(false);
|
||||||
|
setFormData((prev) => ({ ...prev, file: "", password: "" }));
|
||||||
|
setIsDecrypting(false);
|
||||||
|
setfileload(false);
|
||||||
|
if (inputFileRef.current) {
|
||||||
|
inputFileRef.current.value = ""; // Set file input value to empty string
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="shadow-md rounded my-2 p-3 bg-[#ffffff] md:border-[1px] md:border-gray-600/50">
|
<div className="shadow-md rounded my-2 p-3 bg-[#ffffff] md:border-[1px] md:border-gray-600/50">
|
||||||
<Title title={props?.title} />
|
<Title title={props?.title} />
|
||||||
@@ -277,169 +558,222 @@ const Forms = (props) => {
|
|||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<form onSubmit={handleSubmit}>
|
<>
|
||||||
<h1 className="text-[20px] font-semibold mb-4">{props?.title}</h1>
|
<ModalUi
|
||||||
{fileload && (
|
isOpen={isPassword}
|
||||||
<div className="flex items-center gap-x-2">
|
handleClose={() => handeCloseModal()}
|
||||||
<div className="h-2 rounded-full w-[200px] md:w-[400px] bg-gray-200">
|
title={"Enter Pdf Password"}
|
||||||
<div
|
>
|
||||||
className="h-2 rounded-full bg-blue-500"
|
<form onSubmit={handlePasswordSubmit}>
|
||||||
style={{ width: `${percentage}%` }}
|
<div className="px-6 pt-3 pb-2">
|
||||||
></div>
|
<label className="mb-2 text-xs">Password</label>
|
||||||
</div>
|
|
||||||
<span className="text-black text-sm">{percentage}%</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="text-xs">
|
|
||||||
<label className="block">
|
|
||||||
File<span className="text-red-500 text-[13px]">*</span>
|
|
||||||
</label>
|
|
||||||
{fileupload.length > 0 ? (
|
|
||||||
<div className="flex gap-2 justify-center items-center">
|
|
||||||
<div className="flex justify-between items-center px-2 py-2 w-full font-bold rounded border-[1px] border-[#ccc] text-gray-500 bg-white text-[13px]">
|
|
||||||
<div className="break-all">
|
|
||||||
file selected :{" "}
|
|
||||||
{fileupload?.split("/")?.pop()?.split("_")[1]}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
setFileUpload([]);
|
|
||||||
}}
|
|
||||||
className="cursor-pointer px-[10px] text-[20px] font-bold bg-white text-red-500"
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-xmark"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{process.env.REACT_APP_DROPBOX_API_KEY && (
|
|
||||||
<DropboxChooser
|
|
||||||
onSuccess={dropboxSuccess}
|
|
||||||
onCancel={dropboxCancel}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="flex gap-2 justify-center items-center">
|
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="text"
|
||||||
className="bg-white px-2 py-1.5 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
name="password"
|
||||||
onChange={(e) => handleFileInput(e)}
|
value={formData.password}
|
||||||
accept="application/pdf"
|
onChange={(e) => handleStrInput(e)}
|
||||||
|
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||||
|
placeholder="Enter pdf password"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
{process.env.REACT_APP_DROPBOX_API_KEY && (
|
{!isCorrectPass ? (
|
||||||
<DropboxChooser
|
<p className="ml-2 text-[11px] text-red-600">
|
||||||
onSuccess={dropboxSuccess}
|
Please provide correct password
|
||||||
onCancel={dropboxCancel}
|
</p>
|
||||||
/>
|
) : (
|
||||||
|
<p className="ml-2 text-[11px] text-transparent text-red-600">
|
||||||
|
.
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div className="px-6 my-3">
|
||||||
|
<button type="submit" className={submitBtn}>
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</ModalUi>
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<h1 className="text-[20px] font-semibold mb-4">{props?.title}</h1>
|
||||||
|
{fileload && (
|
||||||
|
<div className="flex items-center gap-x-2">
|
||||||
|
<div className="h-2 rounded-full w-[200px] md:w-[400px] bg-gray-200">
|
||||||
|
<div
|
||||||
|
className="h-2 rounded-full bg-blue-500"
|
||||||
|
style={{ width: `${percentage}%` }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<span className="text-black text-sm">{percentage}%</span>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
{isDecrypting && (
|
||||||
<div className="text-xs mt-2">
|
<div className="flex items-center gap-x-2">
|
||||||
<label className="block">
|
<span className="text-black text-sm">
|
||||||
{props.title === "New Template"
|
Decrypting pdf please wait...
|
||||||
? "Template Title"
|
</span>
|
||||||
: "Document Title"}
|
</div>
|
||||||
<span className="text-red-500 text-[13px]">*</span>
|
)}
|
||||||
</label>
|
<div className="text-xs">
|
||||||
<input
|
<label className="block">
|
||||||
name="Name"
|
{`File (pdf, png, jpg, jpeg${
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
isEnableSubscription ? ", docx)" : ")"
|
||||||
value={formData.Name}
|
}`}
|
||||||
onChange={(e) => handleStrInput(e)}
|
<span className="text-red-500 text-[13px]">*</span>
|
||||||
required
|
</label>
|
||||||
/>
|
{fileupload.length > 0 ? (
|
||||||
</div>
|
<div className="flex gap-2 justify-center items-center">
|
||||||
<div className="text-xs mt-2">
|
<div className="flex justify-between items-center px-2 py-2 w-full font-bold rounded border-[1px] border-[#ccc] text-gray-500 bg-white text-[13px]">
|
||||||
<label className="block">Description</label>
|
<div className="break-all">
|
||||||
<input
|
file selected : {getFileName(fileupload)}
|
||||||
name="Description"
|
</div>
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
<div
|
||||||
value={formData.Description}
|
onClick={() => setFileUpload("")}
|
||||||
onChange={(e) => handleStrInput(e)}
|
className="cursor-pointer px-[10px] text-[20px] font-bold bg-white text-red-500"
|
||||||
/>
|
>
|
||||||
</div>
|
<i className="fa-solid fa-xmark"></i>
|
||||||
{props.signers && (
|
</div>
|
||||||
<SignersInput onChange={handleSigners} isReset={isReset} required />
|
</div>
|
||||||
)}
|
{process.env.REACT_APP_DROPBOX_API_KEY && (
|
||||||
<div className="text-xs mt-2">
|
<DropboxChooser
|
||||||
<label className="block">
|
onSuccess={dropboxSuccess}
|
||||||
Note<span className="text-red-500 text-[13px]">*</span>
|
onCancel={dropboxCancel}
|
||||||
</label>
|
/>
|
||||||
<input
|
)}
|
||||||
name="Note"
|
</div>
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
) : (
|
||||||
value={formData.Note}
|
<div className="flex gap-2 justify-center items-center">
|
||||||
onChange={(e) => handleStrInput(e)}
|
<input
|
||||||
required
|
type="file"
|
||||||
/>
|
className="bg-white px-2 py-1.5 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||||
</div>
|
onChange={(e) => handleFileInput(e)}
|
||||||
<SelectFolder
|
ref={inputFileRef}
|
||||||
onSuccess={handleFolder}
|
accept={
|
||||||
folderCls={props.Cls}
|
isEnableSubscription
|
||||||
isReset={isReset}
|
? "application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document,image/png,image/jpeg"
|
||||||
/>
|
: "application/pdf,image/png,image/jpeg"
|
||||||
|
}
|
||||||
{props.title === "Request Signatures" && (
|
required
|
||||||
|
/>
|
||||||
|
{process.env.REACT_APP_DROPBOX_API_KEY && (
|
||||||
|
<DropboxChooser
|
||||||
|
onSuccess={dropboxSuccess}
|
||||||
|
onCancel={dropboxCancel}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div className="text-xs mt-2">
|
<div className="text-xs mt-2">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
Time To Complete (Days)
|
{props.title === "New Template"
|
||||||
|
? "Template Title"
|
||||||
|
: "Document Title"}
|
||||||
<span className="text-red-500 text-[13px]">*</span>
|
<span className="text-red-500 text-[13px]">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
name="Name"
|
||||||
name="TimeToCompleteDays"
|
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||||
value={formData.TimeToCompleteDays}
|
value={formData.Name}
|
||||||
onChange={(e) => handleStrInput(e)}
|
onChange={(e) => handleStrInput(e)}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
{props.title !== "Sign Yourself" && (
|
|
||||||
<div className="text-xs mt-2">
|
<div className="text-xs mt-2">
|
||||||
<label className="block">Send In Order</label>
|
<label className="block">Description</label>
|
||||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
<input
|
||||||
|
name="Description"
|
||||||
|
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||||
|
value={formData.Description}
|
||||||
|
onChange={(e) => handleStrInput(e)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{props.signers && (
|
||||||
|
<SignersInput
|
||||||
|
onChange={handleSigners}
|
||||||
|
isReset={isReset}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<div className="text-xs mt-2">
|
||||||
|
<label className="block">
|
||||||
|
Note<span className="text-red-500 text-[13px]">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
name="Note"
|
||||||
|
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||||
|
value={formData.Note}
|
||||||
|
onChange={(e) => handleStrInput(e)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<SelectFolder
|
||||||
|
onSuccess={handleFolder}
|
||||||
|
folderCls={props.Cls}
|
||||||
|
isReset={isReset}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{props.title === "Request Signatures" && (
|
||||||
|
<div className="text-xs mt-2">
|
||||||
|
<label className="block">
|
||||||
|
Time To Complete (Days)
|
||||||
|
<span className="text-red-500 text-[13px]">*</span>
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="number"
|
||||||
value={"true"}
|
name="TimeToCompleteDays"
|
||||||
name="SendinOrder"
|
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||||
checked={formData.SendinOrder === "true"}
|
value={formData.TimeToCompleteDays}
|
||||||
className=""
|
onChange={(e) => handleStrInput(e)}
|
||||||
onChange={handleStrInput}
|
required
|
||||||
/>
|
/>
|
||||||
<div className="text-center">Yes</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 ml-2 mb-1">
|
)}
|
||||||
<input
|
{props.title !== "Sign Yourself" && (
|
||||||
type="radio"
|
<div className="text-xs mt-2">
|
||||||
value={"false"}
|
<label className="block">Send In Order</label>
|
||||||
name="SendinOrder"
|
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||||
checked={formData.SendinOrder === "false"}
|
<input
|
||||||
onChange={handleStrInput}
|
type="radio"
|
||||||
/>
|
value={"true"}
|
||||||
<div className="text-center">No</div>
|
name="SendinOrder"
|
||||||
|
checked={formData.SendinOrder === "true"}
|
||||||
|
className=""
|
||||||
|
onChange={handleStrInput}
|
||||||
|
/>
|
||||||
|
<div className="text-center">Yes</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 ml-2 mb-1">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={"false"}
|
||||||
|
name="SendinOrder"
|
||||||
|
checked={formData.SendinOrder === "false"}
|
||||||
|
onChange={handleStrInput}
|
||||||
|
/>
|
||||||
|
<div className="text-center">No</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="flex items-center mt-3 gap-2 text-white">
|
||||||
|
<button
|
||||||
|
className={`${
|
||||||
|
isSubmit && "cursor-progress"
|
||||||
|
} bg-[#1ab6ce] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 focus:outline-none`}
|
||||||
|
type="submit"
|
||||||
|
disabled={isSubmit}
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
className="cursor-pointer bg-[#188ae2] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 text-center ml-[2px] focus:outline-none"
|
||||||
|
onClick={() => handleReset()}
|
||||||
|
>
|
||||||
|
Reset
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</form>
|
||||||
<div className="flex items-center mt-3 gap-2 text-white">
|
</>
|
||||||
<button
|
|
||||||
className={`${
|
|
||||||
isSubmit && "cursor-progress"
|
|
||||||
} bg-[#1ab6ce] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 focus:outline-none`}
|
|
||||||
type="submit"
|
|
||||||
disabled={isSubmit}
|
|
||||||
>
|
|
||||||
Next
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
className="cursor-pointer bg-[#188ae2] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 text-center ml-[2px] focus:outline-none"
|
|
||||||
onClick={() => handleReset()}
|
|
||||||
>
|
|
||||||
Reset
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useNavigate } from "react-router-dom";
|
|||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import { isEnableSubscription, rejectBtn, submitBtn } from "../constant/const";
|
import { isEnableSubscription, rejectBtn, submitBtn } from "../constant/const";
|
||||||
import { checkIsSubscribed, openInNewTab } from "../constant/Utils";
|
import { checkIsSubscribed, copytoData, openInNewTab } from "../constant/Utils";
|
||||||
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||||
import Tooltip from "../primitives/Tooltip";
|
import Tooltip from "../primitives/Tooltip";
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ function GenerateToken() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const copytoclipboard = (text) => {
|
const copytoclipboard = (text) => {
|
||||||
navigator.clipboard.writeText(text);
|
copytoData(text);
|
||||||
setCopied(true);
|
setCopied(true);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setCopied(false);
|
setCopied(false);
|
||||||
|
|||||||
@@ -3,36 +3,59 @@ import { useNavigate, useParams } from "react-router-dom";
|
|||||||
import "../styles/loginPage.css";
|
import "../styles/loginPage.css";
|
||||||
import loader from "../assets/images/loader2.gif";
|
import loader from "../assets/images/loader2.gif";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { themeColor } from "../constant/const";
|
import { isEnableSubscription, themeColor } from "../constant/const";
|
||||||
import { contractUsers } from "../constant/Utils";
|
import { contractUsers, getAppLogo } from "../constant/Utils";
|
||||||
|
import logo from "../assets/images/logo.png";
|
||||||
|
import { appInfo } from "../constant/appinfo";
|
||||||
|
|
||||||
function GuestLogin() {
|
function GuestLogin() {
|
||||||
const { id, userMail, contactBookId, serverUrl } = useParams();
|
const { id, userMail, contactBookId, base64url } = useParams();
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
const [email, setEmail] = useState(userMail);
|
const [email, setEmail] = useState(userMail);
|
||||||
const [OTP, setOTP] = useState("");
|
const [OTP, setOTP] = useState("");
|
||||||
const [EnterOTP, setEnterOtp] = useState(false);
|
const [EnterOTP, setEnterOtp] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [appLogo, setAppLogo] = useState("");
|
||||||
|
const [documentId, setDocumentId] = useState(id);
|
||||||
|
const [contactId, setContactId] = useState(contactBookId);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleServerUrl();
|
handleServerUrl();
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
//function generate serverUrl and parseAppId from url and save it in local storage
|
//function generate serverUrl and parseAppId from url and save it in local storage
|
||||||
const handleServerUrl = () => {
|
const handleServerUrl = async () => {
|
||||||
//split url in array from '&'
|
if (isEnableSubscription) {
|
||||||
localStorage.clear();
|
const applogo = await getAppLogo();
|
||||||
const checkSplit = serverUrl.split("&");
|
if (applogo) {
|
||||||
const server = checkSplit[0];
|
setAppLogo(applogo);
|
||||||
const parseId = checkSplit[1];
|
} else {
|
||||||
const appName = checkSplit[2];
|
setAppLogo(logo);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setAppLogo(logo);
|
||||||
|
}
|
||||||
|
|
||||||
const newServer = server.replaceAll("%2F", "/");
|
localStorage.clear();
|
||||||
|
const parseId = appInfo.appId;
|
||||||
|
const newServer = `${appInfo.baseUrl}/`;
|
||||||
|
const appName = appInfo.appname;
|
||||||
localStorage.setItem("baseUrl", newServer);
|
localStorage.setItem("baseUrl", newServer);
|
||||||
localStorage.setItem("parseAppId", parseId);
|
localStorage.setItem("parseAppId", parseId);
|
||||||
localStorage.setItem("_appName", appName);
|
localStorage.setItem("_appName", appName);
|
||||||
|
//this condition is used decode base64 to string and get userEmail,documentId, contactBoookId data.
|
||||||
|
if (!id) {
|
||||||
|
//`atob` function is used to decode base64
|
||||||
|
const decodebase64 = atob(base64url);
|
||||||
|
//split url in array from '/'
|
||||||
|
const checkSplit = decodebase64.split("/");
|
||||||
|
setDocumentId(checkSplit[0]);
|
||||||
|
setEmail(checkSplit[1]);
|
||||||
|
setContactId(checkSplit[2]);
|
||||||
|
}
|
||||||
|
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -60,7 +83,7 @@ function GuestLogin() {
|
|||||||
};
|
};
|
||||||
let body = {
|
let body = {
|
||||||
email: email.toString(),
|
email: email.toString(),
|
||||||
docId: id
|
docId: documentId
|
||||||
};
|
};
|
||||||
let Otp = await axios.post(url, body, { headers: headers });
|
let Otp = await axios.post(url, body, { headers: headers });
|
||||||
|
|
||||||
@@ -123,7 +146,7 @@ function GuestLogin() {
|
|||||||
//save isGuestSigner true in local to handle login flow header in mobile view
|
//save isGuestSigner true in local to handle login flow header in mobile view
|
||||||
localStorage.setItem("isGuestSigner", true);
|
localStorage.setItem("isGuestSigner", true);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
navigate(`/load/recipientSignPdf/${id}/${contactBookId}`);
|
navigate(`/load/recipientSignPdf/${documentId}/${contactId}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("err ", error);
|
console.log("err ", error);
|
||||||
@@ -164,12 +187,14 @@ function GuestLogin() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="main_head">
|
<div className="main_head">
|
||||||
<div className="main-logo">
|
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
||||||
<img
|
{appLogo && (
|
||||||
alt="sign img"
|
<img
|
||||||
src="https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"
|
src={appLogo}
|
||||||
width="100%"
|
className="object-contain h-full"
|
||||||
/>
|
alt="logo"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import Alert from "../primitives/Alert";
|
|||||||
import { appInfo } from "../constant/appinfo";
|
import { appInfo } from "../constant/appinfo";
|
||||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
import { showTenant } from "../redux/reducers/ShowTenant";
|
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||||
|
import { fetchSubscription, getAppLogo } from "../constant/Utils";
|
||||||
function Login() {
|
function Login() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -43,7 +44,7 @@ function Login() {
|
|||||||
Destination: ""
|
Destination: ""
|
||||||
});
|
});
|
||||||
const [isModal, setIsModal] = useState(false);
|
const [isModal, setIsModal] = useState(false);
|
||||||
const image = appInfo?.applogo || undefined;
|
const [image, setImage] = useState();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (localStorage.getItem("accesstoken")) {
|
if (localStorage.getItem("accesstoken")) {
|
||||||
@@ -51,8 +52,23 @@ function Login() {
|
|||||||
GetLoginData();
|
GetLoginData();
|
||||||
}
|
}
|
||||||
dispatch(fetchAppInfo());
|
dispatch(fetchAppInfo());
|
||||||
|
saveLogo();
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const saveLogo = async () => {
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const logo = await getAppLogo();
|
||||||
|
if (logo) {
|
||||||
|
setImage(logo);
|
||||||
|
} else {
|
||||||
|
setImage(appInfo?.applogo || undefined);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setImage(appInfo?.applogo || undefined);
|
||||||
|
}
|
||||||
|
};
|
||||||
const handleChange = (event) => {
|
const handleChange = (event) => {
|
||||||
const { name, value } = event.target;
|
const { name, value } = event.target;
|
||||||
setState({ ...state, [name]: value });
|
setState({ ...state, [name]: value });
|
||||||
@@ -153,7 +169,7 @@ function Login() {
|
|||||||
await Parse.Cloud.run("getUserDetails", {
|
await Parse.Cloud.run("getUserDetails", {
|
||||||
email: currentUser.get("email")
|
email: currentUser.get("email")
|
||||||
}).then(
|
}).then(
|
||||||
(result) => {
|
async (result) => {
|
||||||
let tenentInfo = [];
|
let tenentInfo = [];
|
||||||
const results = [result];
|
const results = [result];
|
||||||
if (results) {
|
if (results) {
|
||||||
@@ -254,16 +270,15 @@ function Login() {
|
|||||||
"userDetails",
|
"userDetails",
|
||||||
JSON.stringify(LocalUserDetails)
|
JSON.stringify(LocalUserDetails)
|
||||||
);
|
);
|
||||||
const freeplan =
|
const res = await fetchSubscription();
|
||||||
results[0].get("Plan") &&
|
const freeplan = res.plan;
|
||||||
results[0].get("Plan").plan_code;
|
const billingDate = res.billingDate;
|
||||||
const billingDate =
|
|
||||||
results[0].get("Next_billing_date") &&
|
|
||||||
results[0].get("Next_billing_date");
|
|
||||||
if (freeplan === "freeplan") {
|
if (freeplan === "freeplan") {
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
} else if (billingDate) {
|
} else if (billingDate) {
|
||||||
if (billingDate > new Date()) {
|
if (
|
||||||
|
new Date(billingDate) > new Date()
|
||||||
|
) {
|
||||||
localStorage.removeItem(
|
localStorage.removeItem(
|
||||||
"userDetails"
|
"userDetails"
|
||||||
);
|
);
|
||||||
@@ -407,7 +422,7 @@ function Login() {
|
|||||||
alert("Somenthing went wrong, please try again later!");
|
alert("Somenthing went wrong, please try again later!");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const thirdpartyLoginfn = async (sessionToken, billingDate) => {
|
const thirdpartyLoginfn = async (sessionToken) => {
|
||||||
const baseUrl = localStorage.getItem("baseUrl");
|
const baseUrl = localStorage.getItem("baseUrl");
|
||||||
const parseAppId = localStorage.getItem("parseAppId");
|
const parseAppId = localStorage.getItem("parseAppId");
|
||||||
const res = await axios.get(baseUrl + "users/me", {
|
const res = await axios.get(baseUrl + "users/me", {
|
||||||
@@ -506,7 +521,7 @@ function Login() {
|
|||||||
await Parse.Cloud.run("getUserDetails", {
|
await Parse.Cloud.run("getUserDetails", {
|
||||||
email: currentUser.get("email")
|
email: currentUser.get("email")
|
||||||
}).then(
|
}).then(
|
||||||
(result) => {
|
async (result) => {
|
||||||
let tenentInfo = [];
|
let tenentInfo = [];
|
||||||
const results = [result];
|
const results = [result];
|
||||||
if (results) {
|
if (results) {
|
||||||
@@ -556,7 +571,7 @@ function Login() {
|
|||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
navigate("/");
|
navigate("/");
|
||||||
} else {
|
} else {
|
||||||
extendedInfo.forEach((x) => {
|
extendedInfo.forEach(async (x) => {
|
||||||
if (x.TenantId) {
|
if (x.TenantId) {
|
||||||
let obj = {
|
let obj = {
|
||||||
tenentId: x.TenantId.objectId,
|
tenentId: x.TenantId.objectId,
|
||||||
@@ -593,8 +608,13 @@ function Login() {
|
|||||||
setThirdpartyLoader(false);
|
setThirdpartyLoader(false);
|
||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
if (billingDate) {
|
const res = await fetchSubscription();
|
||||||
if (billingDate > new Date()) {
|
const freeplan = res.plan;
|
||||||
|
const billingDate = res.billingDate;
|
||||||
|
if (freeplan === "freeplan") {
|
||||||
|
navigate(redirectUrl);
|
||||||
|
} else if (billingDate) {
|
||||||
|
if (new Date(billingDate) > new Date()) {
|
||||||
localStorage.removeItem("userDetails");
|
localStorage.removeItem("userDetails");
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
} else {
|
} else {
|
||||||
@@ -629,8 +649,13 @@ function Login() {
|
|||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
setThirdpartyLoader(false);
|
setThirdpartyLoader(false);
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
if (billingDate) {
|
const res = await fetchSubscription();
|
||||||
if (billingDate > new Date()) {
|
const freeplan = res.plan;
|
||||||
|
const billingDate = res.billingDate;
|
||||||
|
if (freeplan === "freeplan") {
|
||||||
|
navigate(redirectUrl);
|
||||||
|
} else if (billingDate) {
|
||||||
|
if (new Date(billingDate) > new Date()) {
|
||||||
localStorage.removeItem("userDetails");
|
localStorage.removeItem("userDetails");
|
||||||
// Redirect to the appropriate URL after successful login
|
// Redirect to the appropriate URL after successful login
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
@@ -798,7 +823,7 @@ function Login() {
|
|||||||
await Parse.Cloud.run("getUserDetails", {
|
await Parse.Cloud.run("getUserDetails", {
|
||||||
email: currentUser.get("email")
|
email: currentUser.get("email")
|
||||||
}).then(
|
}).then(
|
||||||
(result) => {
|
async (result) => {
|
||||||
let tenentInfo = [];
|
let tenentInfo = [];
|
||||||
const results = [result];
|
const results = [result];
|
||||||
if (results) {
|
if (results) {
|
||||||
@@ -850,17 +875,13 @@ function Login() {
|
|||||||
"userDetails",
|
"userDetails",
|
||||||
JSON.stringify(LocalUserDetails)
|
JSON.stringify(LocalUserDetails)
|
||||||
);
|
);
|
||||||
const billingDate =
|
const res = await fetchSubscription();
|
||||||
results[0].get("Next_billing_date") &&
|
const billingDate = res.billingDate;
|
||||||
results[0].get("Next_billing_date");
|
const freeplan = res.plan;
|
||||||
const freeplan =
|
|
||||||
results[0]?.get("Plan") &&
|
|
||||||
results[0]?.get("Plan").plan_code;
|
|
||||||
|
|
||||||
if (freeplan === "freeplan") {
|
if (freeplan === "freeplan") {
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
} else if (billingDate) {
|
} else if (billingDate) {
|
||||||
if (billingDate > new Date()) {
|
if (new Date(billingDate) > new Date()) {
|
||||||
localStorage.removeItem("userDetails");
|
localStorage.removeItem("userDetails");
|
||||||
// Redirect to the appropriate URL after successful login
|
// Redirect to the appropriate URL after successful login
|
||||||
navigate(redirectUrl);
|
navigate(redirectUrl);
|
||||||
@@ -1055,12 +1076,14 @@ function Login() {
|
|||||||
<>
|
<>
|
||||||
<div aria-labelledby="loginHeading" role="region">
|
<div aria-labelledby="loginHeading" role="region">
|
||||||
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-4 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-4 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
||||||
<div className="w-[250px] h-[66px] inline-block">
|
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
||||||
<img
|
{image && (
|
||||||
src={image}
|
<img
|
||||||
width="100%"
|
src={image}
|
||||||
alt="The image displays the OpenSign logo with a stylized blue square with an open corner, accompanied by the tagline Seal the Deal, Openly."
|
className="object-contain h-full"
|
||||||
/>
|
alt="The image displays the OpenSign logo with a stylized blue square with an open corner, accompanied by the tagline Seal the Deal, Openly."
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-2">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-2">
|
||||||
<div>
|
<div>
|
||||||
@@ -1164,25 +1187,12 @@ function Login() {
|
|||||||
</form>
|
</form>
|
||||||
<br />
|
<br />
|
||||||
{(appInfo.fbAppId || appInfo.googleClietId) && (
|
{(appInfo.fbAppId || appInfo.googleClietId) && (
|
||||||
<div
|
<div className="text-sm flex justify-center items-center">
|
||||||
style={{
|
<hr className="border-[1px] border-gray-300 w-full" />
|
||||||
display: "flex",
|
<span className="px-2 text-gray-500 cursor-default">
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
className="text-sm"
|
|
||||||
>
|
|
||||||
<hr
|
|
||||||
className={"border-[1px] border-gray-300 w-full"}
|
|
||||||
style={{ color: "grey" }}
|
|
||||||
/>
|
|
||||||
<span style={{ color: "grey" }} className="px-2 ">
|
|
||||||
OR
|
OR
|
||||||
</span>
|
</span>
|
||||||
<hr
|
<hr className="border-[1px] border-gray-300 w-full" />
|
||||||
className={"border-[1px] border-gray-300 w-full"}
|
|
||||||
style={{ color: "grey" }}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<br />
|
<br />
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ import { useNavigate } from "react-router-dom";
|
|||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
|
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
||||||
|
import Tour from "reactour";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
const DriveBody = React.lazy(
|
const DriveBody = React.lazy(
|
||||||
() => import("../components/opensigndrive/DriveBody")
|
() => import("../components/opensigndrive/DriveBody")
|
||||||
);
|
);
|
||||||
@@ -42,6 +46,8 @@ function Opensigndrive() {
|
|||||||
const [error, setError] = useState();
|
const [error, setError] = useState();
|
||||||
const [folderLoader, setIsFolderLoader] = useState(false);
|
const [folderLoader, setIsFolderLoader] = useState(false);
|
||||||
const [isShowSort, setIsShowSort] = useState(false);
|
const [isShowSort, setIsShowSort] = useState(false);
|
||||||
|
const [isTour, setIsTour] = useState(false);
|
||||||
|
const [tourStatusArr, setTourStatusArr] = useState([]);
|
||||||
const [isLoading, setIsLoading] = useState({
|
const [isLoading, setIsLoading] = useState({
|
||||||
isLoad: true,
|
isLoad: true,
|
||||||
message: "This might take some time"
|
message: "This might take some time"
|
||||||
@@ -56,6 +62,9 @@ function Opensigndrive() {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const sortOrder = ["Ascending", "Descending"];
|
const sortOrder = ["Ascending", "Descending"];
|
||||||
const sortingValue = ["Name", "Date"];
|
const sortingValue = ["Name", "Date"];
|
||||||
|
const [isDontShow, setIsDontShow] = useState(false);
|
||||||
|
const [tourData, setTourData] = useState();
|
||||||
|
const [showTourFirstTIme, setShowTourFirstTime] = useState(true);
|
||||||
const orderName = {
|
const orderName = {
|
||||||
Ascending: "Ascending",
|
Ascending: "Ascending",
|
||||||
Descending: "Descending",
|
Descending: "Descending",
|
||||||
@@ -73,12 +82,62 @@ function Opensigndrive() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getPdfDocumentList();
|
getPdfDocumentList();
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [docId]);
|
}, [docId]);
|
||||||
|
|
||||||
|
const tourConfigs = [
|
||||||
|
{
|
||||||
|
selector: '[data-tut="reactourFirst"]',
|
||||||
|
content: () => (
|
||||||
|
<TourContentWithBtn
|
||||||
|
message={`Click on the breadcrumb links to easily navigate through the folder hierarchy and view the documents within each folder.`}
|
||||||
|
isChecked={handleDontShow}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
position: "top",
|
||||||
|
style: { fontSize: "13px" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: '[data-tut="reactourSecond"]',
|
||||||
|
content: () => (
|
||||||
|
<TourContentWithBtn
|
||||||
|
message={`Click the add button to create a new folder or document.`}
|
||||||
|
isChecked={handleDontShow}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
position: "top",
|
||||||
|
style: { fontSize: "13px" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: '[data-tut="reactourThird"]',
|
||||||
|
content: () => (
|
||||||
|
<TourContentWithBtn
|
||||||
|
message={`Sort your documents by Date or Name using this menu.`}
|
||||||
|
isChecked={handleDontShow}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
position: "top",
|
||||||
|
style: { fontSize: "13px" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: '[data-tut="reactourForth"]',
|
||||||
|
content: () => (
|
||||||
|
<TourContentWithBtn
|
||||||
|
message={`Click on this menu to display the documents in list view.`}
|
||||||
|
isChecked={handleDontShow}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
position: "top",
|
||||||
|
style: { fontSize: "13px" }
|
||||||
|
}
|
||||||
|
];
|
||||||
//function for get all pdf document list
|
//function for get all pdf document list
|
||||||
const getPdfDocumentList = async (disbaleLoading) => {
|
const getPdfDocumentList = async (disbaleLoading) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
if (showTourFirstTIme) {
|
||||||
|
checkTourStatus();
|
||||||
|
}
|
||||||
if (!disbaleLoading) {
|
if (!disbaleLoading) {
|
||||||
setIsLoading({ isLoad: true, message: "This might take some time" });
|
setIsLoading({ isLoad: true, message: "This might take some time" });
|
||||||
}
|
}
|
||||||
@@ -87,8 +146,61 @@ function Opensigndrive() {
|
|||||||
if (driveDetails && driveDetails === "Error: Something went wrong!") {
|
if (driveDetails && driveDetails === "Error: Something went wrong!") {
|
||||||
setHandleError("Error: Something went wrong!");
|
setHandleError("Error: Something went wrong!");
|
||||||
} else if (driveDetails && driveDetails.length > 0) {
|
} else if (driveDetails && driveDetails.length > 0) {
|
||||||
|
const addMoreTour = [
|
||||||
|
{
|
||||||
|
selector: '[data-tut="reactourFifth"]',
|
||||||
|
content: () => (
|
||||||
|
<TourContentWithBtn
|
||||||
|
message={`The document list is displayed according to the selected sorting option. Icons next to each document indicate its current status.`}
|
||||||
|
isChecked={handleDontShow}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
position: "bottom",
|
||||||
|
style: { fontSize: "13px" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: '[data-tut="reactourSixth"]',
|
||||||
|
content: () => (
|
||||||
|
<TourContentWithBtn
|
||||||
|
message={`Right-click on a document to see options such as Download, Rename, Move, and Delete. Click on the document to open it.`}
|
||||||
|
isChecked={handleDontShow}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
position: "bottom",
|
||||||
|
style: { fontSize: "13px" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: '[data-tut="reactourSeventh"]',
|
||||||
|
content: () => (
|
||||||
|
<TourContentWithBtn
|
||||||
|
message={`Right-click on any folder to see options. Choose ‘Rename’ to change the folder’s name or click on the folder to navigate through its contents.`}
|
||||||
|
isChecked={handleDontShow}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
position: "bottom",
|
||||||
|
style: { fontSize: "13px" }
|
||||||
|
}
|
||||||
|
];
|
||||||
|
let newTour = [...tourConfigs, ...addMoreTour];
|
||||||
|
const isFolderExist = driveDetails.some(
|
||||||
|
(data) => data.Type === "Folder"
|
||||||
|
);
|
||||||
|
if (!isFolderExist) {
|
||||||
|
newTour = newTour.filter(
|
||||||
|
(data) => data.selector !== '[data-tut="reactourSeventh"]'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const isDocumentExist = driveDetails.some((data) => data.URL);
|
||||||
|
if (!isDocumentExist) {
|
||||||
|
newTour = newTour.filter(
|
||||||
|
(data) => data.selector !== '[data-tut="reactourSixth"]'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setTourData(newTour);
|
||||||
setSkip((prevSkip) => prevSkip + limit);
|
setSkip((prevSkip) => prevSkip + limit);
|
||||||
sortingData(null, null, driveDetails, true);
|
sortingData(null, null, driveDetails, true);
|
||||||
|
} else {
|
||||||
|
setTourData(tourConfigs);
|
||||||
}
|
}
|
||||||
if (!docId) {
|
if (!docId) {
|
||||||
setFolderName([{ name: "OpenSign™ Drive", objectId: "" }]);
|
setFolderName([{ name: "OpenSign™ Drive", objectId: "" }]);
|
||||||
@@ -141,17 +253,23 @@ function Opensigndrive() {
|
|||||||
}, [loading, sortingOrder, selectedSort]); // Add/remove scroll event listener when loading changes
|
}, [loading, sortingOrder, selectedSort]); // Add/remove scroll event listener when loading changes
|
||||||
|
|
||||||
//function for handle folder name path
|
//function for handle folder name path
|
||||||
const handleRoute = (index) => {
|
const handleRoute = (index, folderData) => {
|
||||||
setPdfData([]);
|
|
||||||
setSkip(0);
|
setSkip(0);
|
||||||
|
// after onclick on route filter route from that index
|
||||||
const updateFolderName = folderName.filter((x, i) => {
|
const updateFolderName = folderName.filter((x, i) => {
|
||||||
if (i <= index) {
|
if (i <= index) {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setFolderName(updateFolderName);
|
setFolderName(updateFolderName);
|
||||||
|
//get route details after onclick path of folder name
|
||||||
|
const getCurrentId = folderData[index];
|
||||||
const getLastId = updateFolderName[updateFolderName.length - 1];
|
const getLastId = updateFolderName[updateFolderName.length - 1];
|
||||||
setDocId(getLastId.objectId);
|
//below condition is used to check if user click on same route which already open then don't change any thing
|
||||||
|
if (docId !== getCurrentId.objectId) {
|
||||||
|
setPdfData([]);
|
||||||
|
setDocId(getLastId.objectId);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//function for add new folder name
|
//function for add new folder name
|
||||||
@@ -203,6 +321,7 @@ function Opensigndrive() {
|
|||||||
const result = JSON.parse(JSON.stringify(res));
|
const result = JSON.parse(JSON.stringify(res));
|
||||||
|
|
||||||
setPdfData((prev) => [...prev, result]);
|
setPdfData((prev) => [...prev, result]);
|
||||||
|
sortingData(null, null, [result], true);
|
||||||
setNewFolderName();
|
setNewFolderName();
|
||||||
setIsFolderLoader(false);
|
setIsFolderLoader(false);
|
||||||
setIsFolder(false);
|
setIsFolder(false);
|
||||||
@@ -223,9 +342,13 @@ function Opensigndrive() {
|
|||||||
const sortedBy = (appInfo, type, order) => {
|
const sortedBy = (appInfo, type, order) => {
|
||||||
if (type === orderName.Name) {
|
if (type === orderName.Name) {
|
||||||
if (order === orderName.Ascending) {
|
if (order === orderName.Ascending) {
|
||||||
return appInfo.sort((a, b) => (a.Name > b.Name ? 1 : -1));
|
return appInfo.sort((a, b) =>
|
||||||
|
a.Name.toLowerCase() < b.Name.toLowerCase() ? -1 : 1
|
||||||
|
);
|
||||||
} else if (order === orderName.Descending) {
|
} else if (order === orderName.Descending) {
|
||||||
return appInfo.sort((a, b) => (a.Name > b.Name ? -1 : 1));
|
return appInfo.sort((a, b) =>
|
||||||
|
a.Name.toLowerCase() < b.Name.toLowerCase() ? 1 : -1
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (type === orderName.Date) {
|
} else if (type === orderName.Date) {
|
||||||
if (order === orderName.Ascending) {
|
if (order === orderName.Ascending) {
|
||||||
@@ -325,7 +448,7 @@ function Opensigndrive() {
|
|||||||
return (
|
return (
|
||||||
<React.Fragment key={id}>
|
<React.Fragment key={id}>
|
||||||
<span
|
<span
|
||||||
onClick={() => handleRoute(id)}
|
onClick={() => handleRoute(id, folderData)}
|
||||||
style={{
|
style={{
|
||||||
color: "#a64b4e",
|
color: "#a64b4e",
|
||||||
fontWeight: "400",
|
fontWeight: "400",
|
||||||
@@ -353,9 +476,77 @@ function Opensigndrive() {
|
|||||||
setNewFolderName("");
|
setNewFolderName("");
|
||||||
setError("");
|
setError("");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDontShow = (isChecked) => {
|
||||||
|
setIsDontShow(isChecked);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeTour = async () => {
|
||||||
|
setIsTour(false);
|
||||||
|
setShowTourFirstTime(false);
|
||||||
|
if (isDontShow) {
|
||||||
|
const serverUrl = localStorage.getItem("baseUrl");
|
||||||
|
const appId = localStorage.getItem("parseAppId");
|
||||||
|
const extUserClass = localStorage.getItem("extended_class");
|
||||||
|
const json = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||||
|
const extUserId = json && json.length > 0 && json[0].objectId;
|
||||||
|
let updatedTourStatus = [];
|
||||||
|
if (tourStatusArr.length > 0) {
|
||||||
|
updatedTourStatus = [...tourStatusArr];
|
||||||
|
const driveTourIndex = tourStatusArr.findIndex(
|
||||||
|
(obj) => obj["driveTour"] === false || obj["driveTour"] === true
|
||||||
|
);
|
||||||
|
if (driveTourIndex !== -1) {
|
||||||
|
updatedTourStatus[driveTourIndex] = { driveTour: true };
|
||||||
|
} else {
|
||||||
|
updatedTourStatus.push({ driveTour: true });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updatedTourStatus = [{ driveTour: true }];
|
||||||
|
}
|
||||||
|
await axios.put(
|
||||||
|
serverUrl + "classes/" + extUserClass + "/" + extUserId,
|
||||||
|
{
|
||||||
|
TourStatus: updatedTourStatus
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"X-Parse-Application-Id": appId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//function to use check tour status of open sign drive
|
||||||
|
async function checkTourStatus() {
|
||||||
|
const currentUser = Parse.User.current();
|
||||||
|
const cloudRes = await Parse.Cloud.run("getUserDetails", {
|
||||||
|
email: currentUser.get("email")
|
||||||
|
});
|
||||||
|
const res = { data: cloudRes.toJSON() };
|
||||||
|
if (res.data && res.data.TourStatus && res.data.TourStatus.length > 0) {
|
||||||
|
const tourStatus = res.data.TourStatus;
|
||||||
|
setTourStatusArr(tourStatus);
|
||||||
|
const filteredtourStatus = tourStatus.filter((obj) => obj["driveTour"]);
|
||||||
|
if (filteredtourStatus.length > 0) {
|
||||||
|
const driveTour = filteredtourStatus[0]["driveTour"];
|
||||||
|
// console.log("loginTour", loginTour);
|
||||||
|
if (driveTour) {
|
||||||
|
setIsTour(false);
|
||||||
|
} else {
|
||||||
|
setIsTour(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsTour(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsTour(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div style={{ backgroundColor: "white" }} className="folderComponent">
|
<div style={{ backgroundColor: "white" }} className="folderComponent">
|
||||||
<Title title={"OpenSign™ Drive"} drive={true} />
|
<Title title={"OpenSign™ Drive"} drive={true} />
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<ModalUi
|
<ModalUi
|
||||||
headerColor={"#dc3545"}
|
headerColor={"#dc3545"}
|
||||||
@@ -518,7 +709,19 @@ function Opensigndrive() {
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="folderContainer">
|
<div className="folderContainer">
|
||||||
|
{tourData && (
|
||||||
|
<Tour
|
||||||
|
onRequestClose={closeTour}
|
||||||
|
steps={tourData}
|
||||||
|
isOpen={isTour}
|
||||||
|
closeWithMask={false}
|
||||||
|
scrollOffset={-100}
|
||||||
|
rounded={5}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
data-tut="reactourFirst"
|
||||||
onMouseEnter={(e) => handleMouseEnter(e)}
|
onMouseEnter={(e) => handleMouseEnter(e)}
|
||||||
ref={scrollRef}
|
ref={scrollRef}
|
||||||
style={{
|
style={{
|
||||||
@@ -536,7 +739,7 @@ function Opensigndrive() {
|
|||||||
}
|
}
|
||||||
onClick={() => setIsNewFol(!isNewFol)}
|
onClick={() => setIsNewFol(!isNewFol)}
|
||||||
>
|
>
|
||||||
<div className="sort">
|
<div className="sort" data-tut="reactourSecond">
|
||||||
<i
|
<i
|
||||||
className="fa fa-plus-square"
|
className="fa fa-plus-square"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
@@ -597,7 +800,11 @@ function Opensigndrive() {
|
|||||||
className={isShowSort ? "dropdown show" : "dropdown"}
|
className={isShowSort ? "dropdown show" : "dropdown"}
|
||||||
onClick={() => setIsShowSort(!isShowSort)}
|
onClick={() => setIsShowSort(!isShowSort)}
|
||||||
>
|
>
|
||||||
<div className=" sort " data-toggle="dropdown">
|
<div
|
||||||
|
data-tut="reactourThird"
|
||||||
|
className=" sort "
|
||||||
|
data-toggle="dropdown"
|
||||||
|
>
|
||||||
<i
|
<i
|
||||||
className="fa fa-sort-amount-asc"
|
className="fa fa-sort-amount-asc"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
@@ -687,7 +894,11 @@ function Opensigndrive() {
|
|||||||
></i>
|
></i>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="sort" onClick={() => setIsList(!isList)}>
|
<div
|
||||||
|
data-tut="reactourForth"
|
||||||
|
className="sort"
|
||||||
|
onClick={() => setIsList(!isList)}
|
||||||
|
>
|
||||||
<i
|
<i
|
||||||
className="fa fa-list"
|
className="fa fa-list"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
@@ -712,23 +923,28 @@ function Opensigndrive() {
|
|||||||
<span style={{ fontWeight: "bold" }}>No Data Found!</span>
|
<span style={{ fontWeight: "bold" }}>No Data Found!</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<React.Suspense fallback={<Loader />}>
|
<div data-tut="reactourFifth">
|
||||||
<DriveBody
|
<React.Suspense fallback={<Loader />}>
|
||||||
pdfData={pdfData}
|
<DriveBody
|
||||||
setFolderName={setFolderName}
|
dataTutSixth="reactourSixth"
|
||||||
setIsLoading={setIsLoading}
|
dataTutSeventh="reactourSeventh"
|
||||||
setDocId={setDocId}
|
pdfData={pdfData}
|
||||||
getPdfDocumentList={getPdfDocumentList}
|
setFolderName={setFolderName}
|
||||||
isDocId={docId}
|
setIsLoading={setIsLoading}
|
||||||
setPdfData={setPdfData}
|
setDocId={setDocId}
|
||||||
isList={isList}
|
getPdfDocumentList={getPdfDocumentList}
|
||||||
setIsAlert={setIsAlert}
|
isDocId={docId}
|
||||||
setSkip={setSkip}
|
setPdfData={setPdfData}
|
||||||
/>
|
isList={isList}
|
||||||
{loading && (
|
setIsAlert={setIsAlert}
|
||||||
<div style={{ textAlign: "center" }}>Loading...</div>
|
setSkip={setSkip}
|
||||||
)}
|
sortingData={sortingData}
|
||||||
</React.Suspense>
|
/>
|
||||||
|
{loading && (
|
||||||
|
<div style={{ textAlign: "center" }}>Loading...</div>
|
||||||
|
)}
|
||||||
|
</React.Suspense>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, { useState, useRef, useEffect } from "react";
|
|||||||
import { isEnableSubscription, themeColor } from "../constant/const";
|
import { isEnableSubscription, themeColor } from "../constant/const";
|
||||||
import { PDFDocument } from "pdf-lib";
|
import { PDFDocument } from "pdf-lib";
|
||||||
import "../styles/signature.css";
|
import "../styles/signature.css";
|
||||||
|
import Parse from "parse";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import loader from "../assets/images/loader2.gif";
|
import loader from "../assets/images/loader2.gif";
|
||||||
import { DndProvider } from "react-dnd";
|
import { DndProvider } from "react-dnd";
|
||||||
@@ -21,7 +22,12 @@ import {
|
|||||||
onSaveSign,
|
onSaveSign,
|
||||||
onSaveImage,
|
onSaveImage,
|
||||||
addDefaultSignatureImg,
|
addDefaultSignatureImg,
|
||||||
radioButtonWidget
|
radioButtonWidget,
|
||||||
|
replaceMailVaribles,
|
||||||
|
fetchSubscription,
|
||||||
|
convertPdfArrayBuffer,
|
||||||
|
contractUsers,
|
||||||
|
handleSendOTP
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import Loader from "../primitives/LoaderWithMsg";
|
import Loader from "../primitives/LoaderWithMsg";
|
||||||
import HandleError from "../primitives/HandleError";
|
import HandleError from "../primitives/HandleError";
|
||||||
@@ -31,7 +37,7 @@ import PdfDeclineModal from "../primitives/PdfDeclineModal";
|
|||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import DefaultSignature from "../components/pdf/DefaultSignature";
|
import DefaultSignature from "../components/pdf/DefaultSignature";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import Parse from "parse";
|
import VerifyEmail from "../components/pdf/VerifyEmail";
|
||||||
|
|
||||||
function PdfRequestFiles() {
|
function PdfRequestFiles() {
|
||||||
const { docId } = useParams();
|
const { docId } = useParams();
|
||||||
@@ -54,10 +60,12 @@ function PdfRequestFiles() {
|
|||||||
const imageRef = useRef(null);
|
const imageRef = useRef(null);
|
||||||
const [handleError, setHandleError] = useState();
|
const [handleError, setHandleError] = useState();
|
||||||
const [selectWidgetId, setSelectWidgetId] = useState("");
|
const [selectWidgetId, setSelectWidgetId] = useState("");
|
||||||
|
const [otpLoader, setOtpLoader] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState({
|
const [isLoading, setIsLoading] = useState({
|
||||||
isLoad: true,
|
isLoad: true,
|
||||||
message: "This might take some time"
|
message: "This might take some time"
|
||||||
});
|
});
|
||||||
|
|
||||||
const [defaultSignImg, setDefaultSignImg] = useState();
|
const [defaultSignImg, setDefaultSignImg] = useState();
|
||||||
const [isDocId, setIsDocId] = useState(false);
|
const [isDocId, setIsDocId] = useState(false);
|
||||||
const [pdfNewWidth, setPdfNewWidth] = useState();
|
const [pdfNewWidth, setPdfNewWidth] = useState();
|
||||||
@@ -74,6 +82,7 @@ function PdfRequestFiles() {
|
|||||||
isShow: false,
|
isShow: false,
|
||||||
alertMessage: ""
|
alertMessage: ""
|
||||||
});
|
});
|
||||||
|
const [isSubscribed, setIsSubscribed] = useState(false);
|
||||||
const [isCompleted, setIsCompleted] = useState({
|
const [isCompleted, setIsCompleted] = useState({
|
||||||
isCertificate: false,
|
isCertificate: false,
|
||||||
isModal: false
|
isModal: false
|
||||||
@@ -93,8 +102,12 @@ function PdfRequestFiles() {
|
|||||||
const [minRequiredCount, setminRequiredCount] = useState();
|
const [minRequiredCount, setminRequiredCount] = useState();
|
||||||
const [sendInOrder, setSendInOrder] = useState(false);
|
const [sendInOrder, setSendInOrder] = useState(false);
|
||||||
const [currWidgetsDetails, setCurrWidgetsDetails] = useState({});
|
const [currWidgetsDetails, setCurrWidgetsDetails] = useState({});
|
||||||
const [isSubscribed, setIsSubscribed] = useState(false);
|
const [isSubscriptionExpired, setIsSubscriptionExpired] = useState(false);
|
||||||
const [extUserId, setExtUserId] = useState("");
|
const [extUserId, setExtUserId] = useState("");
|
||||||
|
const [pdfArrayBuffer, setPdfArrayBuffer] = useState("");
|
||||||
|
const [isEmailVerified, setIsEmailVerified] = useState(true);
|
||||||
|
const [isVerifyModal, setIsVerifyModal] = useState(false);
|
||||||
|
const [otp, setOtp] = useState("");
|
||||||
const divRef = useRef(null);
|
const divRef = useRef(null);
|
||||||
const isMobile = window.innerWidth < 767;
|
const isMobile = window.innerWidth < 767;
|
||||||
const rowLevel =
|
const rowLevel =
|
||||||
@@ -134,28 +147,73 @@ function PdfRequestFiles() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [divRef.current]);
|
}, [divRef.current]);
|
||||||
|
|
||||||
async function checkIsSubscribed(email) {
|
//function to use resend otp for email verification
|
||||||
const user = await Parse.Cloud.run("getUserDetails", {
|
const handleResend = async (e) => {
|
||||||
email: email
|
e.preventDefault();
|
||||||
});
|
setOtpLoader(true);
|
||||||
const freeplan = user?.get("Plan") && user?.get("Plan").plan_code;
|
await handleSendOTP(Parse.User.current().getEmail());
|
||||||
const billingDate =
|
setOtpLoader(false);
|
||||||
user?.get("Next_billing_date") && user?.get("Next_billing_date");
|
alert("OTP sent on you email");
|
||||||
if (freeplan === "freeplan") {
|
};
|
||||||
|
//`handleVerifyEmail` function is used to verify email with otp
|
||||||
|
const handleVerifyEmail = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setOtpLoader(true);
|
||||||
|
try {
|
||||||
|
const resEmail = await Parse.Cloud.run("verifyemail", {
|
||||||
|
otp: otp,
|
||||||
|
email: Parse.User.current().getEmail()
|
||||||
|
});
|
||||||
|
if (resEmail?.message === "Email is verified.") {
|
||||||
|
setIsEmailVerified(true);
|
||||||
|
} else if (resEmail?.message === "Email is already verified.") {
|
||||||
|
setIsEmailVerified(true);
|
||||||
|
}
|
||||||
|
setOtp("");
|
||||||
|
alert(resEmail.message);
|
||||||
|
setIsVerifyModal(false);
|
||||||
|
// handleRecipientSign();
|
||||||
|
} catch (error) {
|
||||||
|
alert(error.message);
|
||||||
|
} finally {
|
||||||
|
setOtpLoader(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//`handleVerifyBtn` function is used to send otp on user mail
|
||||||
|
const handleVerifyBtn = async () => {
|
||||||
|
setIsVerifyModal(true);
|
||||||
|
await handleSendOTP(Parse.User.current().getEmail());
|
||||||
|
};
|
||||||
|
async function checkIsSubscribed(extUserId, contactId) {
|
||||||
|
const isGuestSign = location.pathname.includes("/load/") || false;
|
||||||
|
const res = await fetchSubscription(extUserId, contactId, isGuestSign);
|
||||||
|
const plan = res.plan;
|
||||||
|
const billingDate = res?.billingDate;
|
||||||
|
const status = res?.status;
|
||||||
|
if (plan === "freeplan") {
|
||||||
return true;
|
return true;
|
||||||
} else if (billingDate) {
|
} else if (billingDate) {
|
||||||
if (billingDate > new Date()) {
|
if (new Date(billingDate) > new Date()) {
|
||||||
|
setIsSubscribed(true);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (location.pathname.includes("/load/")) {
|
if (location.pathname.includes("/load/")) {
|
||||||
setIsSubscribed(true);
|
setIsSubscriptionExpired(true);
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`);
|
navigate(`/subscription`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if (isGuestSign) {
|
||||||
if (location.pathname.includes("/load/")) {
|
if (status) {
|
||||||
setIsSubscribed(true);
|
setIsSubscribed(true);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
setIsSubscriptionExpired(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isGuestSign) {
|
||||||
|
setIsSubscriptionExpired(true);
|
||||||
} else {
|
} else {
|
||||||
navigate(`/subscription`);
|
navigate(`/subscription`);
|
||||||
}
|
}
|
||||||
@@ -167,9 +225,16 @@ function PdfRequestFiles() {
|
|||||||
//getting document details
|
//getting document details
|
||||||
const documentData = await contractDocument(documentId);
|
const documentData = await contractDocument(documentId);
|
||||||
if (documentData && documentData.length > 0) {
|
if (documentData && documentData.length > 0) {
|
||||||
if (isEnableSubscription) {
|
const url =
|
||||||
await checkIsSubscribed(documentData[0]?.ExtUserPtr?.Email);
|
documentData[0] && (documentData[0]?.SignedUrl || documentData[0]?.URL);
|
||||||
|
//convert document url in array buffer format to use embed widgets in pdf using pdf-lib
|
||||||
|
const arrayBuffer = await convertPdfArrayBuffer(url);
|
||||||
|
if (arrayBuffer === "Error") {
|
||||||
|
setHandleError("Error: Something went wrong!");
|
||||||
|
} else {
|
||||||
|
setPdfArrayBuffer(arrayBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
setExtUserId(documentData[0]?.ExtUserPtr?.objectId);
|
setExtUserId(documentData[0]?.ExtUserPtr?.objectId);
|
||||||
const isCompleted =
|
const isCompleted =
|
||||||
documentData[0].IsCompleted && documentData[0].IsCompleted;
|
documentData[0].IsCompleted && documentData[0].IsCompleted;
|
||||||
@@ -185,6 +250,12 @@ function PdfRequestFiles() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
currUserId = getCurrentSigner[0] ? getCurrentSigner[0].objectId : "";
|
currUserId = getCurrentSigner[0] ? getCurrentSigner[0].objectId : "";
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
await checkIsSubscribed(
|
||||||
|
documentData[0]?.ExtUserPtr?.objectId,
|
||||||
|
currUserId
|
||||||
|
);
|
||||||
|
}
|
||||||
setSignerObjectId(currUserId);
|
setSignerObjectId(currUserId);
|
||||||
if (documentData[0].SignedUrl) {
|
if (documentData[0].SignedUrl) {
|
||||||
setPdfUrl(documentData[0].SignedUrl);
|
setPdfUrl(documentData[0].SignedUrl);
|
||||||
@@ -213,6 +284,33 @@ function PdfRequestFiles() {
|
|||||||
setExpiredDate(expireDateFormat);
|
setExpiredDate(expireDateFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isGuestSign = location.pathname.includes("/load/");
|
||||||
|
if (
|
||||||
|
!isGuestSign &&
|
||||||
|
!isCompleted &&
|
||||||
|
!declined &&
|
||||||
|
currDate < expireUpdateDate
|
||||||
|
) {
|
||||||
|
const currentUser = JSON.parse(JSON.stringify(Parse.User.current()));
|
||||||
|
let isEmailVerified;
|
||||||
|
isEmailVerified = currentUser?.emailVerified;
|
||||||
|
if (isEmailVerified) {
|
||||||
|
setIsEmailVerified(isEmailVerified);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const userQuery = new Parse.Query(Parse.User);
|
||||||
|
const user = await userQuery.get(currentUser.objectId, {
|
||||||
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
|
});
|
||||||
|
if (user) {
|
||||||
|
isEmailVerified = user?.get("emailVerified");
|
||||||
|
setIsEmailVerified(isEmailVerified);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
setHandleError("Error: Something went wrong!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (documentData.length > 0) {
|
if (documentData.length > 0) {
|
||||||
const checkDocIdExist =
|
const checkDocIdExist =
|
||||||
documentData[0].AuditTrail &&
|
documentData[0].AuditTrail &&
|
||||||
@@ -246,6 +344,7 @@ function PdfRequestFiles() {
|
|||||||
) {
|
) {
|
||||||
const params = {
|
const params = {
|
||||||
event: "viewed",
|
event: "viewed",
|
||||||
|
contactId: currUserId,
|
||||||
body: {
|
body: {
|
||||||
objectId: documentData?.[0].objectId,
|
objectId: documentData?.[0].objectId,
|
||||||
file: documentData?.[0]?.SignedUrl || documentData?.[0]?.URL,
|
file: documentData?.[0]?.SignedUrl || documentData?.[0]?.URL,
|
||||||
@@ -384,36 +483,37 @@ function PdfRequestFiles() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkSendInOrder = () => {
|
// const checkSendInOrder = () => {
|
||||||
if (sendInOrder) {
|
// if (sendInOrder) {
|
||||||
const index = pdfDetails?.[0].Signers.findIndex(
|
// const index = pdfDetails?.[0].Signers.findIndex(
|
||||||
(x) => x.Email === jsonSender.email
|
// (x) => x.Email === jsonSender.email
|
||||||
);
|
// );
|
||||||
const newIndex = index - 1;
|
// const newIndex = index - 1;
|
||||||
if (newIndex !== -1) {
|
// if (newIndex !== -1) {
|
||||||
const user = pdfDetails?.[0].Signers[newIndex];
|
// const user = pdfDetails?.[0].Signers[newIndex];
|
||||||
const isPrevUserSigned =
|
// const isPrevUserSigned =
|
||||||
pdfDetails?.[0].AuditTrail &&
|
// pdfDetails?.[0].AuditTrail &&
|
||||||
pdfDetails?.[0].AuditTrail.some(
|
// pdfDetails?.[0].AuditTrail.some(
|
||||||
(x) =>
|
// (x) =>
|
||||||
x.UserPtr.objectId === user.objectId && x.Activity === "Signed"
|
// x.UserPtr.objectId === user.objectId && x.Activity === "Signed"
|
||||||
);
|
// );
|
||||||
if (isPrevUserSigned) {
|
// if (isPrevUserSigned) {
|
||||||
return true;
|
// return true;
|
||||||
} else {
|
// } else {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
//function for embed signature or image url in pdf
|
//function for embed signature or image url in pdf
|
||||||
async function embedWidgetsData() {
|
async function embedWidgetsData() {
|
||||||
const validateSigning = checkSendInOrder();
|
// const validateSigning = checkSendInOrder();
|
||||||
if (validateSigning) {
|
// if (validateSigning) {
|
||||||
|
try {
|
||||||
const checkUser = signerPos.filter(
|
const checkUser = signerPos.filter(
|
||||||
(data) => data.signerObjId === signerObjectId
|
(data) => data.signerObjId === signerObjectId
|
||||||
);
|
);
|
||||||
@@ -544,134 +644,215 @@ function PdfRequestFiles() {
|
|||||||
setIsUiLoading(true);
|
setIsUiLoading(true);
|
||||||
const pngUrl = checkUser[0].placeHolder;
|
const pngUrl = checkUser[0].placeHolder;
|
||||||
// Load a PDFDocument from the existing PDF bytes
|
// Load a PDFDocument from the existing PDF bytes
|
||||||
const existingPdfBytes = await fetch(pdfUrl).then((res) =>
|
const existingPdfBytes = pdfArrayBuffer;
|
||||||
res.arrayBuffer()
|
|
||||||
);
|
|
||||||
const pdfDoc = await PDFDocument.load(existingPdfBytes, {
|
|
||||||
ignoreEncryption: true
|
|
||||||
});
|
|
||||||
const flag = false;
|
|
||||||
const extUserPtr = pdfDetails[0].ExtUserPtr;
|
|
||||||
const HeaderDocId = extUserPtr?.HeaderDocId;
|
|
||||||
//embed document's object id to all pages in pdf document
|
|
||||||
if (!HeaderDocId) {
|
|
||||||
if (!isDocId) {
|
|
||||||
await embedDocId(pdfDoc, documentId, allPages);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//embed multi signature in pdf
|
|
||||||
const pdfBytes = await multiSignEmbed(
|
|
||||||
pngUrl,
|
|
||||||
pdfDoc,
|
|
||||||
pdfOriginalWidth,
|
|
||||||
flag,
|
|
||||||
containerWH
|
|
||||||
);
|
|
||||||
|
|
||||||
//function for call to embed signature in pdf and get digital signature pdf
|
|
||||||
try {
|
try {
|
||||||
const res = await signPdfFun(
|
const pdfDoc = await PDFDocument.load(existingPdfBytes);
|
||||||
pdfBytes,
|
const isSignYourSelfFlow = false;
|
||||||
documentId,
|
const extUserPtr = pdfDetails[0].ExtUserPtr;
|
||||||
signerObjectId,
|
const HeaderDocId = extUserPtr?.HeaderDocId;
|
||||||
setIsAlert
|
//embed document's object id to all pages in pdf document
|
||||||
|
if (!HeaderDocId) {
|
||||||
|
if (!isDocId) {
|
||||||
|
await embedDocId(pdfDoc, documentId, allPages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//embed multi signature in pdf
|
||||||
|
const pdfBytes = await multiSignEmbed(
|
||||||
|
pngUrl,
|
||||||
|
pdfDoc,
|
||||||
|
pdfOriginalWidth,
|
||||||
|
isSignYourSelfFlow,
|
||||||
|
containerWH
|
||||||
);
|
);
|
||||||
if (res && res.status === "success") {
|
//get ExistUserPtr object id of user class to get tenantDetails
|
||||||
setPdfUrl(res.data);
|
const objectId = pdfDetails?.[0]?.ExtUserPtr?.UserId?.objectId;
|
||||||
setIsSigned(true);
|
//get ExistUserPtr email to get userDetails
|
||||||
setSignedSigners([]);
|
const currentUserEmail = pdfDetails?.[0]?.ExtUserPtr?.Email;
|
||||||
setUnSignedSigners([]);
|
const res = await contractUsers(currentUserEmail);
|
||||||
getDocumentDetails();
|
let activeMailAdapter = "";
|
||||||
if (sendInOrder) {
|
if (res === "Error: Something went wrong!") {
|
||||||
|
setHandleError("Error: Something went wrong!");
|
||||||
|
setIsLoading({
|
||||||
|
isLoad: false
|
||||||
|
});
|
||||||
|
} else if (!res || res?.length === 0) {
|
||||||
|
activeMailAdapter = "";
|
||||||
|
} else if (res[0] && res.length) {
|
||||||
|
activeMailAdapter = res[0]?.active_mail_adapter;
|
||||||
|
}
|
||||||
|
//function for call to embed signature in pdf and get digital signature pdf
|
||||||
|
try {
|
||||||
|
const res = await signPdfFun(
|
||||||
|
pdfBytes,
|
||||||
|
documentId,
|
||||||
|
signerObjectId,
|
||||||
|
setIsAlert,
|
||||||
|
objectId,
|
||||||
|
isSubscribed,
|
||||||
|
activeMailAdapter,
|
||||||
|
pngUrl
|
||||||
|
);
|
||||||
|
if (res && res.status === "success") {
|
||||||
|
setPdfUrl(res.data);
|
||||||
|
setIsSigned(true);
|
||||||
|
setSignedSigners([]);
|
||||||
|
setUnSignedSigners([]);
|
||||||
|
getDocumentDetails();
|
||||||
const index = pdfDetails?.[0].Signers.findIndex(
|
const index = pdfDetails?.[0].Signers.findIndex(
|
||||||
(x) => x.Email === jsonSender.email
|
(x) => x.Email === jsonSender.email
|
||||||
);
|
);
|
||||||
const newIndex = index + 1;
|
const newIndex = index + 1;
|
||||||
const user = pdfDetails?.[0].Signers[newIndex];
|
const user = pdfDetails?.[0].Signers[newIndex];
|
||||||
if (user) {
|
if (user) {
|
||||||
// console.log("pdfDetails", pdfDetails);
|
setIsCompleted({
|
||||||
const expireDate = pdfDetails?.[0].ExpiryDate.iso;
|
isModal: true,
|
||||||
const newDate = new Date(expireDate);
|
message:
|
||||||
const localExpireDate = newDate.toLocaleDateString("en-US", {
|
"You have successfully signed the document. You can download or print a copy of the partially signed document. A copy of the digitally signed document will be sent to the owner over email once it is signed by all signers."
|
||||||
day: "numeric",
|
|
||||||
month: "long",
|
|
||||||
year: "numeric"
|
|
||||||
});
|
});
|
||||||
let sender = pdfDetails?.[0].ExtUserPtr.Email;
|
}
|
||||||
|
if (sendInOrder) {
|
||||||
|
const requestBody = pdfDetails?.[0]?.RequestBody;
|
||||||
|
const requestSubject = pdfDetails?.[0]?.RequestSubject;
|
||||||
|
if (user) {
|
||||||
|
const expireDate = pdfDetails?.[0].ExpiryDate.iso;
|
||||||
|
const newDate = new Date(expireDate);
|
||||||
|
const localExpireDate = newDate.toLocaleDateString(
|
||||||
|
"en-US",
|
||||||
|
{
|
||||||
|
day: "numeric",
|
||||||
|
month: "long",
|
||||||
|
year: "numeric"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
let senderEmail = pdfDetails?.[0].ExtUserPtr.Email;
|
||||||
|
let senderPhone = pdfDetails?.[0]?.ExtUserPtr?.Phone;
|
||||||
|
const senderName = `${pdfDetails?.[0].ExtUserPtr.Name}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const imgPng =
|
const imgPng =
|
||||||
"https://qikinnovation.ams3.digitaloceanspaces.com/logo.png";
|
"https://qikinnovation.ams3.digitaloceanspaces.com/logo.png";
|
||||||
let url = `${localStorage.getItem(
|
let url = `${localStorage.getItem(
|
||||||
"baseUrl"
|
"baseUrl"
|
||||||
)}functions/sendmailv3/`;
|
)}functions/sendmailv3/`;
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id":
|
"X-Parse-Application-Id":
|
||||||
localStorage.getItem("parseAppId"),
|
localStorage.getItem("parseAppId"),
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
};
|
};
|
||||||
const serverUrl = localStorage.getItem("baseUrl");
|
const objectId = user.objectId;
|
||||||
const newServer = serverUrl.replaceAll("/", "%2F");
|
const hostUrl = window.location.origin;
|
||||||
const objectId = user.objectId;
|
//encode this url value `${pdfDetails?.[0].objectId}/${user.Email}/${objectId}` to base64 using `btoa` function
|
||||||
const serverParams = `${newServer}&${localStorage.getItem(
|
const encodeBase64 = btoa(
|
||||||
"parseAppId"
|
`${pdfDetails?.[0].objectId}/${user.Email}/${objectId}`
|
||||||
)}&${localStorage.getItem("_appName")}`;
|
);
|
||||||
const hostUrl = window.location.origin;
|
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
||||||
let signPdf = `${hostUrl}/login/${pdfDetails?.[0].objectId}/${user.Email}/${objectId}/${serverParams}`;
|
const openSignUrl =
|
||||||
const openSignUrl =
|
"https://www.opensignlabs.com/contact-us";
|
||||||
"https://www.opensignlabs.com/contact-us";
|
const orgName = pdfDetails[0]?.ExtUserPtr.Company
|
||||||
const orgName = pdfDetails[0]?.ExtUserPtr.Company
|
? pdfDetails[0].ExtUserPtr.Company
|
||||||
? pdfDetails[0].ExtUserPtr.Company
|
: "";
|
||||||
: "";
|
const themeBGcolor = themeColor;
|
||||||
const themeBGcolor = themeColor;
|
let replaceVar;
|
||||||
let params = {
|
if (
|
||||||
extUserId: extUserId,
|
requestBody &&
|
||||||
recipient: user.Email,
|
requestSubject &&
|
||||||
subject: `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign ${pdfDetails?.[0].Name}`,
|
(!isEnableSubscription || isSubscribed)
|
||||||
from: sender,
|
) {
|
||||||
html:
|
const replacedRequestBody = requestBody.replace(
|
||||||
"<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=" +
|
/"/g,
|
||||||
imgPng +
|
"'"
|
||||||
" height='50' style='padding: 20px,width:170px,height:40px' /></div> <div style=' padding: 2px;font-family: system-ui;background-color:" +
|
);
|
||||||
themeBGcolor +
|
const htmlReqBody =
|
||||||
";'><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;'> " +
|
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
|
||||||
pdfDetails?.[0].ExtUserPtr.Name +
|
replacedRequestBody +
|
||||||
" has requested you to review and sign <strong> " +
|
"</body> </html>";
|
||||||
pdfDetails?.[0].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'>" +
|
const variables = {
|
||||||
sender +
|
document_title: pdfDetails?.[0].Name,
|
||||||
"</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'> " +
|
sender_name: senderName,
|
||||||
orgName +
|
sender_mail: senderEmail,
|
||||||
"</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'>" +
|
sender_phone: senderPhone,
|
||||||
localExpireDate +
|
receiver_name: user.Name,
|
||||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
receiver_email: user.Email,
|
||||||
signPdf +
|
receiver_phone: user.Phone,
|
||||||
"> <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 " +
|
expiry_date: localExpireDate,
|
||||||
sender +
|
company_name: orgName,
|
||||||
" directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href= " +
|
signing_url: `<a href=${signPdf}>Sign here</a>`
|
||||||
openSignUrl +
|
};
|
||||||
" target=_blank>here</a>.</p> </div></div></body> </html>"
|
replaceVar = replaceMailVaribles(
|
||||||
};
|
requestSubject,
|
||||||
await axios.post(url, params, {
|
htmlReqBody,
|
||||||
headers: headers
|
variables
|
||||||
});
|
);
|
||||||
} catch (error) {
|
}
|
||||||
console.log("error", error);
|
|
||||||
|
let params = {
|
||||||
|
mailProvider: activeMailAdapter,
|
||||||
|
extUserId: extUserId,
|
||||||
|
recipient: user.Email,
|
||||||
|
subject: requestSubject
|
||||||
|
? replaceVar?.subject
|
||||||
|
: `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign "${pdfDetails?.[0].Name}"`,
|
||||||
|
from: senderEmail,
|
||||||
|
html: requestBody
|
||||||
|
? replaceVar?.body
|
||||||
|
: "<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;'> " +
|
||||||
|
pdfDetails?.[0].ExtUserPtr.Name +
|
||||||
|
" has requested you to review and sign <strong> " +
|
||||||
|
pdfDetails?.[0].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'>" +
|
||||||
|
senderEmail +
|
||||||
|
"</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 " +
|
||||||
|
senderEmail +
|
||||||
|
" 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>"
|
||||||
|
};
|
||||||
|
await axios.post(url, params, {
|
||||||
|
headers: headers
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log("error", error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setIsAlert({
|
||||||
|
isShow: true,
|
||||||
|
alertMessage: "something went wrong"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} catch (err) {
|
||||||
setIsAlert({
|
setIsAlert({
|
||||||
isShow: true,
|
isShow: true,
|
||||||
alertMessage: "something went wrong"
|
alertMessage: "something went wrong"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setIsAlert({
|
setIsUiLoading(false);
|
||||||
isShow: true,
|
if (err && err.message.includes("is encrypted.")) {
|
||||||
alertMessage: "something went wrong"
|
setIsAlert({
|
||||||
});
|
isShow: true,
|
||||||
|
alertMessage: `Currently encrypted pdf files are not supported.`
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log("err in request signing", err);
|
||||||
|
setIsAlert({
|
||||||
|
isShow: true,
|
||||||
|
alertMessage: `Something went wrong.`
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setIsSignPad(false);
|
setIsSignPad(false);
|
||||||
@@ -681,14 +862,25 @@ function PdfRequestFiles() {
|
|||||||
alertMessage: "something went wrong"
|
alertMessage: "something went wrong"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} catch (err) {
|
||||||
|
console.log("err in embedsign", err);
|
||||||
|
setIsUiLoading(false);
|
||||||
setIsAlert({
|
setIsAlert({
|
||||||
isShow: true,
|
isShow: true,
|
||||||
alertMessage:
|
alertMessage: "something went wrong, please try again later."
|
||||||
"Please wait for your turn to sign this document, as it has been set up by the creator to be signed in a specific order; you'll be notified when it's your turn."
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// setIsAlert({
|
||||||
|
// isShow: true,
|
||||||
|
// alertMessage:
|
||||||
|
// "Please wait for your turn to sign this document, as it has been set up by the creator to be signed in a specific order; you'll be notified when it's your turn."
|
||||||
|
// });
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
//function for update TourStatus
|
//function for update TourStatus
|
||||||
const closeTour = async () => {
|
const closeTour = async () => {
|
||||||
setWidgetsTour(false);
|
setWidgetsTour(false);
|
||||||
@@ -937,10 +1129,10 @@ function PdfRequestFiles() {
|
|||||||
return (
|
return (
|
||||||
<DndProvider backend={HTML5Backend}>
|
<DndProvider backend={HTML5Backend}>
|
||||||
<Title title={"Request Sign"} />
|
<Title title={"Request Sign"} />
|
||||||
{isSubscribed ? (
|
{isSubscriptionExpired ? (
|
||||||
<ModalUi
|
<ModalUi
|
||||||
title={"Subscription Expired"}
|
title={"Subscription Expired"}
|
||||||
isOpen={isSubscribed}
|
isOpen={isSubscriptionExpired}
|
||||||
showClose={false}
|
showClose={false}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col justify-center items-center py-4 md:py-5 gap-5">
|
<div className="flex flex-col justify-center items-center py-4 md:py-5 gap-5">
|
||||||
@@ -984,7 +1176,7 @@ function PdfRequestFiles() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="signatureContainer"
|
className="relative flex flex-col md:flex-row justify-between bg-[#ebebeb]"
|
||||||
style={{
|
style={{
|
||||||
pointerEvents:
|
pointerEvents:
|
||||||
isExpired ||
|
isExpired ||
|
||||||
@@ -1046,16 +1238,15 @@ function PdfRequestFiles() {
|
|||||||
|
|
||||||
{/* this modal is used to show decline alert */}
|
{/* this modal is used to show decline alert */}
|
||||||
<PdfDeclineModal
|
<PdfDeclineModal
|
||||||
containerWH={containerWH}
|
|
||||||
show={isDecline.isDeclined}
|
show={isDecline.isDeclined}
|
||||||
headMsg="Document Declined"
|
headMsg="Document Declined"
|
||||||
bodyMssg={
|
bodyMssg={
|
||||||
isDecline.currnt === "Sure"
|
isDecline.currnt === "Sure"
|
||||||
? "Are you sure want to decline this document ?"
|
? "Are you sure want to decline this document ?"
|
||||||
: isDecline.currnt === "YouDeclined"
|
: isDecline.currnt === "YouDeclined"
|
||||||
? "You have declined this document!"
|
? "You have declined this document!"
|
||||||
: isDecline.currnt === "another" &&
|
: isDecline.currnt === "another" &&
|
||||||
"You cannot sign this document as it has been declined by one or more recipient(s)."
|
"You can not sign this document as it has been declined/revoked."
|
||||||
}
|
}
|
||||||
footerMessage={isDecline.currnt === "Sure"}
|
footerMessage={isDecline.currnt === "Sure"}
|
||||||
declineDoc={declineDoc}
|
declineDoc={declineDoc}
|
||||||
@@ -1063,11 +1254,22 @@ function PdfRequestFiles() {
|
|||||||
/>
|
/>
|
||||||
{/* this modal is used for show expired alert */}
|
{/* this modal is used for show expired alert */}
|
||||||
<PdfDeclineModal
|
<PdfDeclineModal
|
||||||
containerWH={containerWH}
|
|
||||||
show={isExpired}
|
show={isExpired}
|
||||||
headMsg="Document Expired!"
|
headMsg="Document Expired!"
|
||||||
bodyMssg={`This document expired on ${expiredDate} and is no longer available to sign.`}
|
bodyMssg={`This document expired on ${expiredDate} and is no longer available to sign.`}
|
||||||
/>
|
/>
|
||||||
|
{!isEmailVerified && (
|
||||||
|
<VerifyEmail
|
||||||
|
isVerifyModal={isVerifyModal}
|
||||||
|
setIsVerifyModal={setIsVerifyModal}
|
||||||
|
handleVerifyEmail={handleVerifyEmail}
|
||||||
|
setOtp={setOtp}
|
||||||
|
otp={otp}
|
||||||
|
otpLoader={otpLoader}
|
||||||
|
handleVerifyBtn={handleVerifyBtn}
|
||||||
|
handleResend={handleResend}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<ModalUi
|
<ModalUi
|
||||||
headerColor={defaultSignImg ? themeColor : "#dc3545"}
|
headerColor={defaultSignImg ? themeColor : "#dc3545"}
|
||||||
@@ -1135,7 +1337,10 @@ function PdfRequestFiles() {
|
|||||||
</ModalUi>
|
</ModalUi>
|
||||||
{/* this component used to render all pdf pages in left side */}
|
{/* this component used to render all pdf pages in left side */}
|
||||||
<RenderAllPdfPage
|
<RenderAllPdfPage
|
||||||
signPdfUrl={pdfDetails[0].URL}
|
signPdfUrl={
|
||||||
|
pdfDetails[0] &&
|
||||||
|
(pdfDetails[0]?.SignedUrl || pdfDetails[0]?.URL)
|
||||||
|
}
|
||||||
allPages={allPages}
|
allPages={allPages}
|
||||||
setAllPages={setAllPages}
|
setAllPages={setAllPages}
|
||||||
setPageNumber={setPageNumber}
|
setPageNumber={setPageNumber}
|
||||||
@@ -1154,11 +1359,15 @@ function PdfRequestFiles() {
|
|||||||
isOpen={isCompleted.isModal}
|
isOpen={isCompleted.isModal}
|
||||||
title={"Sign Documents"}
|
title={"Sign Documents"}
|
||||||
handleClose={() => {
|
handleClose={() => {
|
||||||
setIsCompleted({ isModal: false, isCertificate: true });
|
setIsCompleted((prev) => ({ ...prev, isModal: false }));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ height: "100%", padding: 20 }}>
|
<div style={{ height: "100%", padding: 20 }}>
|
||||||
<p>This document has been signed by all Signers.</p>
|
<p>
|
||||||
|
{" "}
|
||||||
|
{isCompleted?.message ||
|
||||||
|
"This document has been signed by all Signers."}
|
||||||
|
</p>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -1172,12 +1381,12 @@ function PdfRequestFiles() {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="finishBtn cancelBtn"
|
className="finishBtn cancelBtn"
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
setIsCompleted({
|
setIsCompleted((prev) => ({
|
||||||
isModal: false,
|
...prev,
|
||||||
isCertificate: true
|
isModal: false
|
||||||
})
|
}));
|
||||||
}
|
}}
|
||||||
>
|
>
|
||||||
Close
|
Close
|
||||||
</button>
|
</button>
|
||||||
@@ -1215,7 +1424,7 @@ function PdfRequestFiles() {
|
|||||||
pdfDetails={pdfDetails}
|
pdfDetails={pdfDetails}
|
||||||
signerPos={signerPos}
|
signerPos={signerPos}
|
||||||
isSigned={isSigned}
|
isSigned={isSigned}
|
||||||
isCompleted={isCompleted}
|
isCompleted={isCompleted.isCertificate}
|
||||||
embedWidgetsData={embedWidgetsData}
|
embedWidgetsData={embedWidgetsData}
|
||||||
isShowHeader={true}
|
isShowHeader={true}
|
||||||
setIsDecline={setIsDecline}
|
setIsDecline={setIsDecline}
|
||||||
|
|||||||
@@ -41,12 +41,8 @@ const PgSignUp = () => {
|
|||||||
const url = window.location.href;
|
const url = window.location.href;
|
||||||
let paramString = url.split("?")[1];
|
let paramString = url.split("?")[1];
|
||||||
let queryString = new URLSearchParams(paramString);
|
let queryString = new URLSearchParams(paramString);
|
||||||
// console.log("url ", queryString);
|
|
||||||
|
|
||||||
let obj = { ...formData };
|
let obj = { ...formData };
|
||||||
for (let pair of queryString.entries()) {
|
for (let pair of queryString.entries()) {
|
||||||
// console.log("Key is: " + pair[0]);
|
|
||||||
// console.log("Value is: " + pair[1]);
|
|
||||||
obj = { ...obj, [pair[0]]: pair[1] };
|
obj = { ...obj, [pair[0]]: pair[1] };
|
||||||
}
|
}
|
||||||
const zohoRes = await axios.post(
|
const zohoRes = await axios.post(
|
||||||
@@ -61,34 +57,27 @@ const PgSignUp = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// console.log("zohoRes ", zohoRes);
|
|
||||||
const userSettings = JSON.parse(localStorage.getItem("userSettings"));
|
const userSettings = JSON.parse(localStorage.getItem("userSettings"));
|
||||||
const extClass = userSettings[0].extended_class;
|
const params = { subscription: zohoRes.data.result.subscription };
|
||||||
// console.log("extClass ", extClass);
|
const baseurl = `${parseBaseUrl}functions/savesubscription`;
|
||||||
const params = { email: userDetails.email };
|
try {
|
||||||
const res = await Parse.Cloud.run("getUserDetails", params);
|
const res = await axios.post(baseurl, params, {
|
||||||
// console.log("res", res);
|
headers: {
|
||||||
if (res) {
|
"Content-Type": "application/json",
|
||||||
const updateQuery = new Parse.Object(extClass);
|
"X-Parse-Application-Id": parseAppId,
|
||||||
updateQuery.id = res.id;
|
sessiontoken: localStorage.getItem("accesstoken")
|
||||||
updateQuery.set(
|
}
|
||||||
"Next_billing_date",
|
});
|
||||||
new Date(zohoRes.data.result.nextBillingDate)
|
if (res) {
|
||||||
);
|
|
||||||
updateQuery.set("Plan", zohoRes.data.result.plan);
|
|
||||||
updateQuery.set("Customer_id", zohoRes.data.result.customer_id);
|
|
||||||
updateQuery.set(
|
|
||||||
"Subscription_id",
|
|
||||||
zohoRes.data.result.subscription_id
|
|
||||||
);
|
|
||||||
const updateRes = await updateQuery.save();
|
|
||||||
if (updateRes) {
|
|
||||||
localStorage.removeItem("userDetails");
|
localStorage.removeItem("userDetails");
|
||||||
navigate(
|
navigate(
|
||||||
"/" + userSettings[0].pageType + "/" + userSettings[0].pageId
|
"/" + userSettings[0].pageType + "/" + userSettings[0].pageId
|
||||||
);
|
);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err ", err.message);
|
||||||
|
setIsLoader(false);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err ", err);
|
console.log("err ", err);
|
||||||
@@ -108,12 +97,8 @@ const PgSignUp = () => {
|
|||||||
const url = window.location.href;
|
const url = window.location.href;
|
||||||
let paramString = url.split("?")[1];
|
let paramString = url.split("?")[1];
|
||||||
let queryString = new URLSearchParams(paramString);
|
let queryString = new URLSearchParams(paramString);
|
||||||
// console.log("url ", queryString);
|
|
||||||
|
|
||||||
let obj = { ...formData };
|
let obj = { ...formData };
|
||||||
for (let pair of queryString.entries()) {
|
for (let pair of queryString.entries()) {
|
||||||
// console.log("Key is: " + pair[0]);
|
|
||||||
// console.log("Value is: " + pair[1]);
|
|
||||||
obj = { ...obj, [pair[0]]: pair[1] };
|
obj = { ...obj, [pair[0]]: pair[1] };
|
||||||
}
|
}
|
||||||
saveUser(obj);
|
saveUser(obj);
|
||||||
@@ -157,19 +142,8 @@ const PgSignUp = () => {
|
|||||||
email: zohoRes.data.result.email,
|
email: zohoRes.data.result.email,
|
||||||
phone: zohoRes.data.result.phone,
|
phone: zohoRes.data.result.phone,
|
||||||
role: obj.role
|
role: obj.role
|
||||||
// "pincode": "",
|
|
||||||
// "address": "",
|
|
||||||
// "country": "",
|
|
||||||
// "state": "",
|
|
||||||
// "city": ""
|
|
||||||
},
|
},
|
||||||
|
subscription: zohoRes.data.result.subscription
|
||||||
planDetails: {
|
|
||||||
plan: zohoRes.data.result.plan || {},
|
|
||||||
nextBillingDate: zohoRes.data.result.nextBillingDate || "",
|
|
||||||
customer_id: zohoRes.data.result.customer_id || "",
|
|
||||||
subscription_id: zohoRes.data.result.subscription_id || ""
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const usersignup = await Parse.Cloud.run("usersignup", params);
|
const usersignup = await Parse.Cloud.run("usersignup", params);
|
||||||
// console.log("usersignup ", usersignup);
|
// console.log("usersignup ", usersignup);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { NavLink, useNavigate } from "react-router-dom";
|
import { NavLink, useNavigate } from "react-router-dom";
|
||||||
import checkmark from "../assets/images/checkmark.png";
|
import checkmark from "../assets/images/checkmark.png";
|
||||||
import plansArr from "../json/plansArr.json";
|
import plansArr from "../json/plansArr";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
const listItemStyle = {
|
const listItemStyle = {
|
||||||
@@ -19,15 +19,22 @@ const PlanSubscriptions = () => {
|
|||||||
|
|
||||||
const userDetails = JSON.parse(localStorage.getItem("userDetails"));
|
const userDetails = JSON.parse(localStorage.getItem("userDetails"));
|
||||||
const name =
|
const name =
|
||||||
userDetails && userDetails.name ? "first_name=" + userDetails.name : "";
|
userDetails && userDetails.name
|
||||||
|
? "first_name=" + encodeURIComponent(userDetails.name)
|
||||||
|
: "";
|
||||||
const email =
|
const email =
|
||||||
userDetails && userDetails.email ? "&email=" + userDetails.email : "";
|
userDetails && userDetails.email
|
||||||
|
? "&email=" + encodeURIComponent(userDetails.email)
|
||||||
|
: "";
|
||||||
const company =
|
const company =
|
||||||
userDetails && userDetails.company
|
userDetails && userDetails.company
|
||||||
? "&company_name=" + userDetails.company
|
? "&company_name=" + encodeURIComponent(userDetails.company)
|
||||||
: "";
|
: "";
|
||||||
const phone =
|
const phone =
|
||||||
userDetails && userDetails.phone ? "&mobile=" + userDetails.phone : "";
|
userDetails && userDetails.phone
|
||||||
|
? "&mobile=" + encodeURIComponent(userDetails.phone)
|
||||||
|
: "";
|
||||||
|
|
||||||
const details =
|
const details =
|
||||||
"?shipping_country_code=US&billing_country_code=US&billing_state_code=CA&" +
|
"?shipping_country_code=US&billing_country_code=US&billing_state_code=CA&" +
|
||||||
name +
|
name +
|
||||||
@@ -92,7 +99,7 @@ const PlanSubscriptions = () => {
|
|||||||
maxHeight: "100%"
|
maxHeight: "100%"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div id="monthlyPlans" 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">
|
||||||
<div className="mb-6 mt-2 flex flex-row border-[1px] p-2 border-gray-300 rounded text-sm">
|
<div className="mb-6 mt-2 flex flex-row border-[1px] p-2 border-gray-300 rounded text-sm">
|
||||||
<span
|
<span
|
||||||
@@ -119,10 +126,10 @@ const PlanSubscriptions = () => {
|
|||||||
<ul className="flex flex-col md:flex-row h-full bg-white justify-center">
|
<ul className="flex flex-col md:flex-row h-full bg-white justify-center">
|
||||||
{plansArr.map((item) => (
|
{plansArr.map((item) => (
|
||||||
<li
|
<li
|
||||||
className="flex flex-col md:my-0 text-center border-collapse border-[1px] border-gray-300 w-[260px]"
|
className="flex flex-col text-center border-collapse border-[1px] border-gray-300 max-w-[250px]"
|
||||||
key={item.planName}
|
key={item.planName}
|
||||||
>
|
>
|
||||||
<div className="p-2 flex flex-col justify-center items-center min-h-[320px]">
|
<div className="p-2 flex flex-col justify-center items-center max-h-[310px]">
|
||||||
<h3 className="text-[#002862] uppercase">
|
<h3 className="text-[#002862] uppercase">
|
||||||
{item.planName}
|
{item.planName}
|
||||||
</h3>
|
</h3>
|
||||||
@@ -133,7 +140,7 @@ const PlanSubscriptions = () => {
|
|||||||
alt="freeimg"
|
alt="freeimg"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="">
|
<div>
|
||||||
<span className="text-3xl">
|
<span className="text-3xl">
|
||||||
{item.currency && <small>{item.currency}</small>}
|
{item.currency && <small>{item.currency}</small>}
|
||||||
{yearlyVisible
|
{yearlyVisible
|
||||||
@@ -143,13 +150,7 @@ const PlanSubscriptions = () => {
|
|||||||
<p className="font-semibold pt-2 text-sm">
|
<p className="font-semibold pt-2 text-sm">
|
||||||
{yearlyVisible ? "Billed Yearly" : "Billed Monthly"}
|
{yearlyVisible ? "Billed Yearly" : "Billed Monthly"}
|
||||||
</p>
|
</p>
|
||||||
<div
|
<div className="max-w-[250px] h-[40px] text-center text-sm my-2">
|
||||||
className={`${
|
|
||||||
item.subtitle.length <= 32
|
|
||||||
? "w-[150px] h-[40px] text-center"
|
|
||||||
: ""
|
|
||||||
} text-sm text-center my-2`}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
@@ -179,14 +180,14 @@ const PlanSubscriptions = () => {
|
|||||||
: item.url + details
|
: item.url + details
|
||||||
: item.url
|
: item.url
|
||||||
}
|
}
|
||||||
className="bg-[#002862] w-full mt-1 text-white py-2 rounded uppercase hover:no-underline hover:text-white cursor-pointer"
|
className="bg-[#002862] w-full text-white py-2 rounded uppercase hover:no-underline hover:text-white cursor-pointer"
|
||||||
target={item.target}
|
target={item.target}
|
||||||
>
|
>
|
||||||
{item.btnText}
|
{item.btnText}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
className="bg-[#002862] w-full mt-1 text-white py-2 rounded uppercase hover:no-underline hover:text-white cursor-pointer"
|
className="bg-[#002862] w-full text-white py-2 rounded uppercase hover:text-white cursor-pointer"
|
||||||
onClick={() => handleFreePlan()}
|
onClick={() => handleFreePlan()}
|
||||||
>
|
>
|
||||||
{item.btnText}
|
{item.btnText}
|
||||||
@@ -207,25 +208,10 @@ const PlanSubscriptions = () => {
|
|||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="text-sm flex justify-center items-center">
|
||||||
style={{
|
<hr className="border-[1px] border-gray-300 w-[20%]" />
|
||||||
display: "flex",
|
<span className="px-2 text-gray-500 cursor-default">or</span>
|
||||||
alignItems: "center",
|
<hr className="border-[1px] border-gray-300 w-[20%]" />
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
className="text-sm"
|
|
||||||
>
|
|
||||||
<hr
|
|
||||||
className={"border-[1px] border-gray-300 w-[20%]"}
|
|
||||||
style={{ color: "grey" }}
|
|
||||||
/>
|
|
||||||
<span style={{ color: "grey" }} className="px-2 ">
|
|
||||||
or
|
|
||||||
</span>
|
|
||||||
<hr
|
|
||||||
className={"border-[1px] border-gray-300 w-[20%]"}
|
|
||||||
style={{ color: "grey" }}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col justify-center w-full items-center">
|
<div className="flex flex-col justify-center w-full items-center">
|
||||||
<h3 className="text-[#002862] mt-1 mb-2">
|
<h3 className="text-[#002862] mt-1 mb-2">
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import reportJson from "../json/ReportJson";
|
|||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import PageNotFound from "./PageNotFound";
|
import PageNotFound from "./PageNotFound";
|
||||||
|
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
||||||
|
|
||||||
const Report = () => {
|
const Report = () => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
@@ -18,6 +19,8 @@ const Report = () => {
|
|||||||
const [isNextRecord, setIsNextRecord] = useState(false);
|
const [isNextRecord, setIsNextRecord] = useState(false);
|
||||||
const [isMoreDocs, setIsMoreDocs] = useState(true);
|
const [isMoreDocs, setIsMoreDocs] = useState(true);
|
||||||
const [form, setForm] = useState("");
|
const [form, setForm] = useState("");
|
||||||
|
const [tourData, setTourData] = useState([]);
|
||||||
|
const [isDontShow, setIsDontShow] = useState(false);
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
const docPerPage = 10;
|
const docPerPage = 10;
|
||||||
|
|
||||||
@@ -46,6 +49,9 @@ const Report = () => {
|
|||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [isNextRecord]);
|
}, [isNextRecord]);
|
||||||
|
|
||||||
|
const handleDontShow = (isChecked) => {
|
||||||
|
setIsDontShow(isChecked);
|
||||||
|
};
|
||||||
const getReportData = async (skipUserRecord = 0, limit = 200) => {
|
const getReportData = async (skipUserRecord = 0, limit = 200) => {
|
||||||
// setIsLoader(true);
|
// setIsLoader(true);
|
||||||
const json = reportJson(id);
|
const json = reportJson(id);
|
||||||
@@ -54,7 +60,7 @@ const Report = () => {
|
|||||||
setHeading(json.heading);
|
setHeading(json.heading);
|
||||||
setReportName(json.reportName);
|
setReportName(json.reportName);
|
||||||
setForm(json.form);
|
setForm(json.form);
|
||||||
setReportHelp(json?.helpMsg)
|
setReportHelp(json?.helpMsg);
|
||||||
const currentUser = Parse.User.current().id;
|
const currentUser = Parse.User.current().id;
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
@@ -69,6 +75,42 @@ const Report = () => {
|
|||||||
headers: headers,
|
headers: headers,
|
||||||
signal: abortController.signal // is used to cancel fetch query
|
signal: abortController.signal // is used to cancel fetch query
|
||||||
});
|
});
|
||||||
|
if (id === "6TeaPr321t") {
|
||||||
|
const tourConfig = [
|
||||||
|
{
|
||||||
|
selector: "[data-tut=reactourFirst]",
|
||||||
|
content: () => (
|
||||||
|
<TourContentWithBtn
|
||||||
|
message={
|
||||||
|
"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. "
|
||||||
|
}
|
||||||
|
isChecked={handleDontShow}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
position: "top",
|
||||||
|
style: { fontSize: "13px" }
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
if (res.data.result && res.data.result?.length > 0) {
|
||||||
|
json.actions.map((data) => {
|
||||||
|
const newConfig = {
|
||||||
|
selector: `[data-tut="${data?.selector}"]`,
|
||||||
|
content: () => (
|
||||||
|
<TourContentWithBtn
|
||||||
|
message={data?.message}
|
||||||
|
isChecked={handleDontShow}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
position: "top",
|
||||||
|
style: { fontSize: "13px" }
|
||||||
|
};
|
||||||
|
tourConfig.push(newConfig);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setTourData(tourConfig);
|
||||||
|
}
|
||||||
if (id === "4Hhwbp482K") {
|
if (id === "4Hhwbp482K") {
|
||||||
const listData = res.data?.result.filter((x) => x.Signers.length > 0);
|
const listData = res.data?.result.filter((x) => x.Signers.length > 0);
|
||||||
let arr = [];
|
let arr = [];
|
||||||
@@ -106,12 +148,14 @@ const Report = () => {
|
|||||||
} else {
|
} else {
|
||||||
setIsMoreDocs(false);
|
setIsMoreDocs(false);
|
||||||
}
|
}
|
||||||
setIsNextRecord(false);
|
if (!res.data.result.error) {
|
||||||
setList((prevRecord) =>
|
setIsNextRecord(false);
|
||||||
prevRecord.length > 0
|
setList((prevRecord) =>
|
||||||
? [...prevRecord, ...res.data.result]
|
prevRecord.length > 0
|
||||||
: res.data.result
|
? [...prevRecord, ...res.data.result]
|
||||||
);
|
: res.data.result
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -159,6 +203,8 @@ const Report = () => {
|
|||||||
docPerPage={docPerPage}
|
docPerPage={docPerPage}
|
||||||
form={form}
|
form={form}
|
||||||
report_help={reporthelp}
|
report_help={reporthelp}
|
||||||
|
tourData={tourData}
|
||||||
|
isDontShow={isDontShow}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<PageNotFound prefix={"Report"} />
|
<PageNotFound prefix={"Report"} />
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { useDispatch } from "react-redux";
|
|||||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
import { showTenant } from "../redux/reducers/ShowTenant";
|
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||||
import { isEnableSubscription } from "../constant/const";
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
import { getAppLogo } from "../constant/Utils";
|
||||||
const Signup = () => {
|
const Signup = () => {
|
||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -22,6 +23,7 @@ const Signup = () => {
|
|||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
const [company, setCompany] = useState("");
|
const [company, setCompany] = useState("");
|
||||||
const [jobTitle, setJobTitle] = useState("");
|
const [jobTitle, setJobTitle] = useState("");
|
||||||
|
const [image, setImage] = useState();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
loading: false,
|
loading: false,
|
||||||
alertType: "success",
|
alertType: "success",
|
||||||
@@ -33,7 +35,6 @@ const Signup = () => {
|
|||||||
const [specialCharValid, setSpecialCharValid] = useState(false);
|
const [specialCharValid, setSpecialCharValid] = useState(false);
|
||||||
|
|
||||||
const togglePasswordVisibility = () => setShowPassword(!showPassword);
|
const togglePasswordVisibility = () => setShowPassword(!showPassword);
|
||||||
const image = appInfo.applogo;
|
|
||||||
|
|
||||||
const clearStorage = async () => {
|
const clearStorage = async () => {
|
||||||
if (Parse.User.current()) {
|
if (Parse.User.current()) {
|
||||||
@@ -469,9 +470,23 @@ const Signup = () => {
|
|||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchAppInfo());
|
dispatch(fetchAppInfo());
|
||||||
|
saveLogo();
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const saveLogo = async () => {
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const logo = await getAppLogo();
|
||||||
|
if (logo) {
|
||||||
|
setImage(logo);
|
||||||
|
} else {
|
||||||
|
setImage(appInfo?.applogo || undefined);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setImage(appInfo?.applogo || undefined);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handlePasswordChange = (e) => {
|
const handlePasswordChange = (e) => {
|
||||||
const newPassword = e.target.value;
|
const newPassword = e.target.value;
|
||||||
setPassword(newPassword);
|
setPassword(newPassword);
|
||||||
@@ -517,8 +532,10 @@ const Signup = () => {
|
|||||||
{appInfo && appInfo.applogo ? (
|
{appInfo && appInfo.applogo ? (
|
||||||
<div>
|
<div>
|
||||||
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
||||||
<div className="w-[250px] h-[66px] inline-block">
|
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
||||||
<img src={image} width="100%" alt="" />
|
{image && (
|
||||||
|
<img src={image} className="object-contain h-full" alt="logo" />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-2">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-2">
|
||||||
<div className="">
|
<div className="">
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React, { useState, useRef, useEffect } from "react";
|
import React, { useState, useRef, useEffect } from "react";
|
||||||
import { PDFDocument } from "pdf-lib";
|
import { PDFDocument } from "pdf-lib";
|
||||||
import "../styles/signature.css";
|
import "../styles/signature.css";
|
||||||
import { themeColor } from "../constant/const";
|
import Parse from "parse";
|
||||||
|
import { isEnableSubscription, themeColor } from "../constant/const";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Loader from "../primitives/LoaderWithMsg";
|
import Loader from "../primitives/LoaderWithMsg";
|
||||||
import loader from "../assets/images/loader2.gif";
|
import loader from "../assets/images/loader2.gif";
|
||||||
@@ -26,7 +27,13 @@ import {
|
|||||||
contactBook,
|
contactBook,
|
||||||
randomId,
|
randomId,
|
||||||
getDate,
|
getDate,
|
||||||
textWidget
|
textWidget,
|
||||||
|
getTenantDetails,
|
||||||
|
checkIsSubscribed,
|
||||||
|
convertPdfArrayBuffer,
|
||||||
|
fetchImageBase64,
|
||||||
|
changeImageWH,
|
||||||
|
handleSendOTP
|
||||||
} 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";
|
||||||
@@ -39,6 +46,7 @@ import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
|||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
||||||
|
import VerifyEmail from "../components/pdf/VerifyEmail";
|
||||||
|
|
||||||
//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() {
|
||||||
@@ -67,7 +75,6 @@ function SignYourSelf() {
|
|||||||
const [pdfOriginalWidth, setPdfOriginalWidth] = useState();
|
const [pdfOriginalWidth, setPdfOriginalWidth] = useState();
|
||||||
const [successEmail, setSuccessEmail] = useState(false);
|
const [successEmail, setSuccessEmail] = useState(false);
|
||||||
const imageRef = useRef(null);
|
const imageRef = useRef(null);
|
||||||
const [documentStatus, setDocumentStatus] = useState({ isCompleted: false });
|
|
||||||
const [myInitial, setMyInitial] = useState("");
|
const [myInitial, setMyInitial] = useState("");
|
||||||
const [isInitial, setIsInitial] = useState(false);
|
const [isInitial, setIsInitial] = useState(false);
|
||||||
const [isUiLoading, setIsUiLoading] = useState(false);
|
const [isUiLoading, setIsUiLoading] = useState(false);
|
||||||
@@ -87,6 +94,7 @@ function SignYourSelf() {
|
|||||||
const [containerWH, setContainerWH] = useState({});
|
const [containerWH, setContainerWH] = useState({});
|
||||||
const [isPageCopy, setIsPageCopy] = useState(false);
|
const [isPageCopy, setIsPageCopy] = useState(false);
|
||||||
const [selectWidgetId, setSelectWidgetId] = useState("");
|
const [selectWidgetId, setSelectWidgetId] = useState("");
|
||||||
|
const [otpLoader, setOtpLoader] = useState(false);
|
||||||
const [showAlreadySignDoc, setShowAlreadySignDoc] = useState({
|
const [showAlreadySignDoc, setShowAlreadySignDoc] = useState({
|
||||||
status: false
|
status: false
|
||||||
});
|
});
|
||||||
@@ -100,6 +108,12 @@ function SignYourSelf() {
|
|||||||
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
|
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
|
||||||
const [isDontShow, setIsDontShow] = useState(false);
|
const [isDontShow, setIsDontShow] = useState(false);
|
||||||
const [extUserId, setExtUserId] = useState("");
|
const [extUserId, setExtUserId] = useState("");
|
||||||
|
const [isCompleted, setIsCompleted] = useState(false);
|
||||||
|
const [pdfArrayBuffer, setPdfArrayBuffer] = useState("");
|
||||||
|
const [activeMailAdapter, setActiveMailAdapter] = useState("");
|
||||||
|
const [isEmailVerified, setIsEmailVerified] = useState(true);
|
||||||
|
const [isVerifyModal, setIsVerifyModal] = useState(false);
|
||||||
|
const [otp, setOtp] = useState("");
|
||||||
const divRef = useRef(null);
|
const divRef = useRef(null);
|
||||||
const nodeRef = useRef(null);
|
const nodeRef = useRef(null);
|
||||||
const [, drop] = useDrop({
|
const [, drop] = useDrop({
|
||||||
@@ -188,12 +202,22 @@ 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 url = documentData[0] && documentData[0]?.URL;
|
||||||
|
if (url) {
|
||||||
|
//convert document url in array buffer format to use embed widgets in pdf using pdf-lib
|
||||||
|
const arrayBuffer = await convertPdfArrayBuffer(url);
|
||||||
|
if (arrayBuffer === "Error") {
|
||||||
|
setHandleError("Error: Something went wrong!");
|
||||||
|
} else {
|
||||||
|
setPdfArrayBuffer(arrayBuffer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setHandleError("Error: Something went wrong!");
|
||||||
|
}
|
||||||
|
|
||||||
isCompleted = documentData[0].IsCompleted && documentData[0].IsCompleted;
|
isCompleted = documentData[0].IsCompleted && documentData[0].IsCompleted;
|
||||||
if (isCompleted) {
|
if (isCompleted) {
|
||||||
const docStatus = {
|
setIsCompleted(true);
|
||||||
isCompleted: isCompleted
|
|
||||||
};
|
|
||||||
setDocumentStatus(docStatus);
|
|
||||||
setPdfUrl(documentData[0].SignedUrl);
|
setPdfUrl(documentData[0].SignedUrl);
|
||||||
const alreadySign = {
|
const alreadySign = {
|
||||||
status: true,
|
status: true,
|
||||||
@@ -209,6 +233,29 @@ function SignYourSelf() {
|
|||||||
setSignBtnPosition([]);
|
setSignBtnPosition([]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isCompleted) {
|
||||||
|
//check current user email verified or not
|
||||||
|
const currentUser = JSON.parse(JSON.stringify(Parse.User.current()));
|
||||||
|
let isEmailVerified;
|
||||||
|
isEmailVerified = currentUser?.emailVerified;
|
||||||
|
if (isEmailVerified) {
|
||||||
|
setIsEmailVerified(isEmailVerified);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const userQuery = new Parse.Query(Parse.User);
|
||||||
|
const user = await userQuery.get(currentUser.objectId, {
|
||||||
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
|
});
|
||||||
|
if (user) {
|
||||||
|
isEmailVerified = user?.get("emailVerified");
|
||||||
|
setIsEmailVerified(isEmailVerified);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
setHandleError("Error: Something went wrong!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (
|
} else if (
|
||||||
documentData === "Error: Something went wrong!" ||
|
documentData === "Error: Something went wrong!" ||
|
||||||
(documentData.result && documentData.result.error)
|
(documentData.result && documentData.result.error)
|
||||||
@@ -256,10 +303,15 @@ function SignYourSelf() {
|
|||||||
setHandleError("Error: Something went wrong!");
|
setHandleError("Error: Something went wrong!");
|
||||||
setIsLoading(loadObj);
|
setIsLoading(loadObj);
|
||||||
});
|
});
|
||||||
|
|
||||||
const contractUsersRes = await contractUsers(jsonSender.email);
|
const contractUsersRes = await contractUsers(jsonSender.email);
|
||||||
|
if (contractUsersRes === "Error: Something went wrong!") {
|
||||||
if (contractUsersRes[0] && contractUsersRes.length > 0) {
|
const loadObj = {
|
||||||
|
isLoad: false
|
||||||
|
};
|
||||||
|
setHandleError("Error: Something went wrong!");
|
||||||
|
setIsLoading(loadObj);
|
||||||
|
} else if (contractUsersRes[0] && contractUsersRes.length > 0) {
|
||||||
|
setActiveMailAdapter(contractUsersRes[0]?.active_mail_adapter);
|
||||||
setContractName("_Users");
|
setContractName("_Users");
|
||||||
setSignerUserId(contractUsersRes[0].objectId);
|
setSignerUserId(contractUsersRes[0].objectId);
|
||||||
const tourstatuss =
|
const tourstatuss =
|
||||||
@@ -279,12 +331,6 @@ function SignYourSelf() {
|
|||||||
isLoad: false
|
isLoad: false
|
||||||
};
|
};
|
||||||
setIsLoading(loadObj);
|
setIsLoading(loadObj);
|
||||||
} else if (contractUsersRes === "Error: Something went wrong!") {
|
|
||||||
const loadObj = {
|
|
||||||
isLoad: false
|
|
||||||
};
|
|
||||||
setHandleError("Error: Something went wrong!");
|
|
||||||
setIsLoading(loadObj);
|
|
||||||
} else if (contractUsersRes.length === 0) {
|
} else if (contractUsersRes.length === 0) {
|
||||||
const contractContactBook = await contactBook(jsonSender.objectId);
|
const contractContactBook = await contactBook(jsonSender.objectId);
|
||||||
if (contractContactBook && contractContactBook.length > 0) {
|
if (contractContactBook && contractContactBook.length > 0) {
|
||||||
@@ -518,89 +564,185 @@ function SignYourSelf() {
|
|||||||
setSignKey(key);
|
setSignKey(key);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//`handleResend` function is used to resend otp for email verification
|
||||||
|
const handleResend = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setOtpLoader(true);
|
||||||
|
await handleSendOTP(Parse.User.current().getEmail());
|
||||||
|
setOtpLoader(false);
|
||||||
|
alert("OTP sent on you email");
|
||||||
|
};
|
||||||
|
//`handleVerifyEmail` function is used to verify email with otp
|
||||||
|
const handleVerifyEmail = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setOtpLoader(true);
|
||||||
|
try {
|
||||||
|
const resEmail = await Parse.Cloud.run("verifyemail", {
|
||||||
|
otp: otp,
|
||||||
|
email: Parse.User.current().getEmail()
|
||||||
|
});
|
||||||
|
if (resEmail?.message === "Email is verified.") {
|
||||||
|
setIsEmailVerified(true);
|
||||||
|
} else if (resEmail?.message === "Email is already verified.") {
|
||||||
|
setIsEmailVerified(true);
|
||||||
|
}
|
||||||
|
setOtp("");
|
||||||
|
alert(resEmail.message);
|
||||||
|
setIsVerifyModal(false);
|
||||||
|
// handleRecipientSign();
|
||||||
|
} catch (error) {
|
||||||
|
alert(error.message);
|
||||||
|
} finally {
|
||||||
|
setOtpLoader(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//`handleVerifyBtn` function is used to send otp on user mail
|
||||||
|
const handleVerifyBtn = async () => {
|
||||||
|
setIsVerifyModal(true);
|
||||||
|
await handleSendOTP(Parse.User.current().getEmail());
|
||||||
|
};
|
||||||
//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() {
|
||||||
let showAlert = false;
|
let showAlert = false;
|
||||||
|
try {
|
||||||
for (let i = 0; i < xyPostion?.length; i++) {
|
for (let i = 0; i < xyPostion?.length; i++) {
|
||||||
const requiredWidgets = xyPostion[i].pos.filter(
|
const requiredWidgets = xyPostion[i].pos.filter(
|
||||||
(position) => position.type !== "checkbox"
|
(position) => position.type !== "checkbox"
|
||||||
);
|
);
|
||||||
if (requiredWidgets && requiredWidgets?.length > 0) {
|
if (requiredWidgets && requiredWidgets?.length > 0) {
|
||||||
let checkSigned;
|
let checkSigned;
|
||||||
for (let i = 0; i < requiredWidgets?.length; i++) {
|
for (let i = 0; i < requiredWidgets?.length; i++) {
|
||||||
checkSigned = requiredWidgets[i]?.options?.response;
|
checkSigned = requiredWidgets[i]?.options?.response;
|
||||||
if (!checkSigned) {
|
if (!checkSigned) {
|
||||||
const checkSignUrl = requiredWidgets[i]?.pos?.SignUrl;
|
const checkSignUrl = requiredWidgets[i]?.pos?.SignUrl;
|
||||||
let checkDefaultSigned = requiredWidgets[i]?.options?.defaultValue;
|
let checkDefaultSigned =
|
||||||
if (!checkSignUrl) {
|
requiredWidgets[i]?.options?.defaultValue;
|
||||||
if (!checkDefaultSigned) {
|
if (!checkSignUrl) {
|
||||||
if (!showAlert) {
|
if (!checkDefaultSigned) {
|
||||||
showAlert = true;
|
if (!showAlert) {
|
||||||
|
showAlert = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (xyPostion.length === 0) {
|
||||||
if (xyPostion.length === 0) {
|
setIsAlert({
|
||||||
setIsAlert({
|
isShow: true,
|
||||||
isShow: true,
|
alertMessage: "Please complete your signature!"
|
||||||
alertMessage: "Please complete your signature!"
|
});
|
||||||
});
|
return;
|
||||||
return;
|
} else if (showAlert) {
|
||||||
} else if (showAlert) {
|
setIsAlert({
|
||||||
setIsAlert({
|
isShow: true,
|
||||||
isShow: true,
|
alertMessage: "Please complete your signature!"
|
||||||
alertMessage: "Please complete your signature!"
|
});
|
||||||
});
|
return;
|
||||||
return;
|
} else {
|
||||||
} else {
|
setIsCeleb(true);
|
||||||
setIsCeleb(true);
|
setTimeout(() => {
|
||||||
setTimeout(() => {
|
setIsCeleb(false);
|
||||||
setIsCeleb(false);
|
}, 3000);
|
||||||
}, 3000);
|
setIsUiLoading(true);
|
||||||
setIsUiLoading(true);
|
const existingPdfBytes = pdfArrayBuffer;
|
||||||
const url = pdfDetails[0] && pdfDetails[0].URL;
|
// Load a PDFDocument from the existing PDF bytes
|
||||||
|
try {
|
||||||
const existingPdfBytes = await fetch(url).then((res) =>
|
const pdfDoc = await PDFDocument.load(existingPdfBytes);
|
||||||
res.arrayBuffer()
|
const isSignYourSelfFlow = true;
|
||||||
);
|
const extUserPtr = pdfDetails[0].ExtUserPtr;
|
||||||
|
const HeaderDocId = extUserPtr?.HeaderDocId;
|
||||||
// Load a PDFDocument from the existing PDF bytes
|
//embed document's object id to all pages in pdf document
|
||||||
const pdfDoc = await PDFDocument.load(existingPdfBytes, {
|
if (!HeaderDocId) {
|
||||||
ignoreEncryption: true
|
await embedDocId(pdfDoc, documentId, allPages);
|
||||||
});
|
}
|
||||||
|
//embed multi signature in pdf
|
||||||
const flag = true;
|
const pdfBytes = await multiSignEmbed(
|
||||||
|
xyPostion,
|
||||||
const extUserPtr = pdfDetails[0].ExtUserPtr;
|
pdfDoc,
|
||||||
const HeaderDocId = extUserPtr?.HeaderDocId;
|
pdfOriginalWidth,
|
||||||
|
isSignYourSelfFlow,
|
||||||
//embed document's object id to all pages in pdf document
|
containerWH
|
||||||
if (!HeaderDocId) {
|
);
|
||||||
await embedDocId(pdfDoc, documentId, allPages);
|
// console.log("pdf", pdfBytes);
|
||||||
|
//function for call to embed signature in pdf and get digital signature pdf
|
||||||
|
await signPdfFun(pdfBytes, documentId);
|
||||||
|
} catch (err) {
|
||||||
|
setIsUiLoading(false);
|
||||||
|
if (err && err.message.includes("is encrypted.")) {
|
||||||
|
setIsAlert({
|
||||||
|
isShow: true,
|
||||||
|
alertMessage: `Currently encrypted pdf files are not supported.`
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log("err in signing", err);
|
||||||
|
setIsAlert({
|
||||||
|
isShow: true,
|
||||||
|
alertMessage: `Something went wrong.`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//embed multi signature in pdf
|
} catch (err) {
|
||||||
const pdfBytes = await multiSignEmbed(
|
console.log("err in embedselfsign ", err);
|
||||||
xyPostion,
|
setIsUiLoading(false);
|
||||||
pdfDoc,
|
setIsAlert({
|
||||||
pdfOriginalWidth,
|
isShow: true,
|
||||||
flag,
|
alertMessage: "something went wrong, please try again later."
|
||||||
containerWH
|
});
|
||||||
);
|
|
||||||
// console.log("pdf", pdfBytes);
|
|
||||||
//function for call to embed signature in pdf and get digital signature pdf
|
|
||||||
await signPdfFun(pdfBytes, documentId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// console.log("signyourself", xyPostion);
|
|
||||||
//function for get digital signature
|
//function for get digital signature
|
||||||
const signPdfFun = async (base64Url, documentId) => {
|
const signPdfFun = async (base64Url, documentId) => {
|
||||||
|
let isCustomCompletionMail = false;
|
||||||
|
const getIsSubscribe = await checkIsSubscribed();
|
||||||
|
const tenantDetails = await getTenantDetails(jsonSender.objectId);
|
||||||
|
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||||
|
alert("User does not exist");
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
tenantDetails?.CompletionBody &&
|
||||||
|
tenantDetails?.CompletionSubject &&
|
||||||
|
(!isEnableSubscription || getIsSubscribe)
|
||||||
|
) {
|
||||||
|
isCustomCompletionMail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// below for loop is used to get first signature of user to send if to signpdf
|
||||||
|
// for adding it in completion certificate
|
||||||
|
let getSignature;
|
||||||
|
for (let item of xyPostion) {
|
||||||
|
const typeExist = item.pos.some((data) => data?.type);
|
||||||
|
if (typeExist) {
|
||||||
|
getSignature = item.pos.find((data) => data?.type === "signature");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
getSignature = item.pos.find((data) => !data.isStamp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let base64Sign = getSignature.SignUrl;
|
||||||
|
//check https type signature (default signature exist) then convert in base64
|
||||||
|
const isUrl = base64Sign.includes("https");
|
||||||
|
if (isUrl) {
|
||||||
|
try {
|
||||||
|
base64Sign = await fetchImageBase64(base64Sign);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//change image width and height to 104/44 in png base64
|
||||||
|
const getNewse64 = await changeImageWH(base64Sign);
|
||||||
|
//remove suffiix of base64
|
||||||
|
const suffixbase64 = getNewse64 && getNewse64.split(",").pop();
|
||||||
|
|
||||||
let singleSign = {
|
let singleSign = {
|
||||||
pdfFile: base64Url,
|
pdfFile: base64Url,
|
||||||
docId: documentId
|
docId: documentId,
|
||||||
|
isCustomCompletionMail: isCustomCompletionMail,
|
||||||
|
mailProvider: activeMailAdapter,
|
||||||
|
signature: suffixbase64
|
||||||
};
|
};
|
||||||
|
|
||||||
await axios
|
await axios
|
||||||
@@ -608,7 +750,8 @@ function SignYourSelf() {
|
|||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
// sessionToken: localStorage.getItem("accesstoken")
|
||||||
|
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then((Listdata) => {
|
.then((Listdata) => {
|
||||||
@@ -972,6 +1115,18 @@ function SignYourSelf() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="signatureContainer" ref={divRef}>
|
<div className="signatureContainer" ref={divRef}>
|
||||||
|
{!isEmailVerified && (
|
||||||
|
<VerifyEmail
|
||||||
|
isVerifyModal={isVerifyModal}
|
||||||
|
setIsVerifyModal={setIsVerifyModal}
|
||||||
|
handleVerifyEmail={handleVerifyEmail}
|
||||||
|
setOtp={setOtp}
|
||||||
|
otp={otp}
|
||||||
|
otpLoader={otpLoader}
|
||||||
|
handleVerifyBtn={handleVerifyBtn}
|
||||||
|
handleResend={handleResend}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{/* this component used for UI interaction and show their functionality */}
|
{/* this component used for UI interaction and show their functionality */}
|
||||||
{pdfLoadFail && !checkTourStatus && (
|
{pdfLoadFail && !checkTourStatus && (
|
||||||
<Tour
|
<Tour
|
||||||
@@ -986,8 +1141,9 @@ function SignYourSelf() {
|
|||||||
{/* this component used to render all pdf pages in left side */}
|
{/* this component used to render all pdf pages in left side */}
|
||||||
|
|
||||||
<RenderAllPdfPage
|
<RenderAllPdfPage
|
||||||
pdfUrl={pdfUrl}
|
signPdfUrl={
|
||||||
signPdfUrl={pdfDetails[0] && pdfDetails[0].URL}
|
pdfDetails[0] && (pdfDetails[0].SignedUrl || pdfDetails[0].URL)
|
||||||
|
}
|
||||||
allPages={allPages}
|
allPages={allPages}
|
||||||
setAllPages={setAllPages}
|
setAllPages={setAllPages}
|
||||||
setPageNumber={setPageNumber}
|
setPageNumber={setPageNumber}
|
||||||
@@ -1122,6 +1278,7 @@ function SignYourSelf() {
|
|||||||
sender={jsonSender}
|
sender={jsonSender}
|
||||||
setIsAlert={setIsAlert}
|
setIsAlert={setIsAlert}
|
||||||
extUserId={extUserId}
|
extUserId={extUserId}
|
||||||
|
activeMailAdapter={activeMailAdapter}
|
||||||
/>
|
/>
|
||||||
{/* pdf header which contain funish back button */}
|
{/* pdf header which contain funish back button */}
|
||||||
<Header
|
<Header
|
||||||
@@ -1129,7 +1286,6 @@ function SignYourSelf() {
|
|||||||
allPages={allPages}
|
allPages={allPages}
|
||||||
changePage={changePage}
|
changePage={changePage}
|
||||||
pdfUrl={pdfUrl}
|
pdfUrl={pdfUrl}
|
||||||
documentStatus={documentStatus}
|
|
||||||
embedWidgetsData={embedWidgetsData}
|
embedWidgetsData={embedWidgetsData}
|
||||||
pdfDetails={pdfDetails}
|
pdfDetails={pdfDetails}
|
||||||
isShowHeader={true}
|
isShowHeader={true}
|
||||||
@@ -1137,6 +1293,7 @@ function SignYourSelf() {
|
|||||||
alreadySign={pdfUrl ? true : false}
|
alreadySign={pdfUrl ? true : false}
|
||||||
isSignYourself={true}
|
isSignYourself={true}
|
||||||
setIsEmail={setIsEmail}
|
setIsEmail={setIsEmail}
|
||||||
|
isCompleted={isCompleted}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div data-tut="reactourSecond">
|
<div data-tut="reactourSecond">
|
||||||
@@ -1189,7 +1346,7 @@ function SignYourSelf() {
|
|||||||
}}
|
}}
|
||||||
className="autoSignScroll"
|
className="autoSignScroll"
|
||||||
>
|
>
|
||||||
{!documentStatus.isCompleted ? (
|
{!isCompleted ? (
|
||||||
<div>
|
<div>
|
||||||
<WidgetComponent
|
<WidgetComponent
|
||||||
dataTut="reactourFirst"
|
dataTut="reactourFirst"
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ import {
|
|||||||
defaultWidthHeight,
|
defaultWidthHeight,
|
||||||
addWidgetOptions,
|
addWidgetOptions,
|
||||||
textInputWidget,
|
textInputWidget,
|
||||||
radioButtonWidget
|
radioButtonWidget,
|
||||||
|
fetchSubscription
|
||||||
} 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";
|
||||||
@@ -35,7 +36,6 @@ import AddRoleModal from "../components/pdf/AddRoleModal";
|
|||||||
import PlaceholderCopy from "../components/pdf/PlaceholderCopy";
|
import PlaceholderCopy from "../components/pdf/PlaceholderCopy";
|
||||||
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
||||||
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
||||||
import Parse from "parse";
|
|
||||||
const TemplatePlaceholder = () => {
|
const TemplatePlaceholder = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { templateId } = useParams();
|
const { templateId } = useParams();
|
||||||
@@ -145,6 +145,7 @@ const TemplatePlaceholder = () => {
|
|||||||
const [currWidgetsDetails, setCurrWidgetsDetails] = useState([]);
|
const [currWidgetsDetails, setCurrWidgetsDetails] = useState([]);
|
||||||
const [isCheckbox, setIsCheckbox] = useState(false);
|
const [isCheckbox, setIsCheckbox] = useState(false);
|
||||||
const [widgetName, setWidgetName] = useState(false);
|
const [widgetName, setWidgetName] = useState(false);
|
||||||
|
const [isAddRole, setIsAddRole] = useState(false);
|
||||||
const senderUser =
|
const senderUser =
|
||||||
localStorage.getItem(
|
localStorage.getItem(
|
||||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
@@ -170,17 +171,14 @@ const TemplatePlaceholder = () => {
|
|||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [divRef.current]);
|
}, [divRef.current]);
|
||||||
async function checkIsSubscribed(email) {
|
async function checkIsSubscribed() {
|
||||||
const user = await Parse.Cloud.run("getUserDetails", {
|
const res = await fetchSubscription();
|
||||||
email: email
|
const freeplan = res.plan;
|
||||||
});
|
const billingDate = res.billingDate;
|
||||||
const freeplan = user?.get("Plan") && user?.get("Plan").plan_code;
|
|
||||||
const billingDate =
|
|
||||||
user?.get("Next_billing_date") && user?.get("Next_billing_date");
|
|
||||||
if (freeplan === "freeplan") {
|
if (freeplan === "freeplan") {
|
||||||
return true;
|
return true;
|
||||||
} else if (billingDate) {
|
} else if (billingDate) {
|
||||||
if (billingDate > new Date()) {
|
if (new Date(billingDate) > new Date()) {
|
||||||
setIsSubscribe(true);
|
setIsSubscribe(true);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@@ -311,10 +309,10 @@ const TemplatePlaceholder = () => {
|
|||||||
if (tourstatus && tourstatus.length > 0) {
|
if (tourstatus && tourstatus.length > 0) {
|
||||||
setTourStatus(tourstatus);
|
setTourStatus(tourstatus);
|
||||||
const checkTourRecipients = tourstatus.filter(
|
const checkTourRecipients = tourstatus.filter(
|
||||||
(data) => data.templatetour
|
(data) => data.templateTour
|
||||||
);
|
);
|
||||||
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
||||||
setCheckTourStatus(checkTourRecipients[0].templatetour);
|
setCheckTourStatus(checkTourRecipients[0].templateTour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const loadObj = {
|
const loadObj = {
|
||||||
@@ -484,9 +482,20 @@ const TemplatePlaceholder = () => {
|
|||||||
} else {
|
} else {
|
||||||
setIsReceipent(false);
|
setIsReceipent(false);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setIsAddRole(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const tourAddRole = [
|
||||||
|
{
|
||||||
|
selector: '[data-tut="reactourAddbtn"]',
|
||||||
|
content: "You need to add a role before you can add fields for it. ",
|
||||||
|
position: "top",
|
||||||
|
style: { fontSize: "13px" }
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
//function for get pdf page details
|
//function for get pdf page details
|
||||||
const pageDetails = async (pdf) => {
|
const pageDetails = async (pdf) => {
|
||||||
const load = {
|
const load = {
|
||||||
@@ -765,7 +774,7 @@ const TemplatePlaceholder = () => {
|
|||||||
selector: '[data-tut="reactourSecond"]',
|
selector: '[data-tut="reactourSecond"]',
|
||||||
content: () => (
|
content: () => (
|
||||||
<TourContentWithBtn
|
<TourContentWithBtn
|
||||||
message={`Drag a widget placeholder onto the PDF to choose your desired signing location.`}
|
message={`Drag or click on a field to add it to the document.`}
|
||||||
isChecked={handleDontShow}
|
isChecked={handleDontShow}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
@@ -787,7 +796,7 @@ const TemplatePlaceholder = () => {
|
|||||||
selector: '[data-tut="reactourFour"]',
|
selector: '[data-tut="reactourFour"]',
|
||||||
content: () => (
|
content: () => (
|
||||||
<TourContentWithBtn
|
<TourContentWithBtn
|
||||||
message={`Clicking "Save" button will save the template and will ask you if you want to create a new document using this template.`}
|
message={`Clicking ‘Save’ will store the current template. After saving, you’ll be prompted to create a new document from this template if you wish.`}
|
||||||
isChecked={handleDontShow}
|
isChecked={handleDontShow}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
@@ -805,15 +814,15 @@ const TemplatePlaceholder = () => {
|
|||||||
if (tourStatus.length > 0) {
|
if (tourStatus.length > 0) {
|
||||||
updatedTourStatus = [...tourStatus];
|
updatedTourStatus = [...tourStatus];
|
||||||
const templatetourIndex = tourStatus.findIndex(
|
const templatetourIndex = tourStatus.findIndex(
|
||||||
(obj) => obj["templatetour"] === false || obj["templatetour"] === true
|
(obj) => obj["templateTour"] === false || obj["templateTour"] === true
|
||||||
);
|
);
|
||||||
if (templatetourIndex !== -1) {
|
if (templatetourIndex !== -1) {
|
||||||
updatedTourStatus[templatetourIndex] = { templatetour: true };
|
updatedTourStatus[templatetourIndex] = { templateTour: true };
|
||||||
} else {
|
} else {
|
||||||
updatedTourStatus.push({ templatetour: true });
|
updatedTourStatus.push({ templateTour: true });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
updatedTourStatus = [{ templatetour: true }];
|
updatedTourStatus = [{ templateTour: true }];
|
||||||
}
|
}
|
||||||
await axios
|
await axios
|
||||||
.put(
|
.put(
|
||||||
@@ -1123,8 +1132,6 @@ const TemplatePlaceholder = () => {
|
|||||||
inputype = options.includes(defaultdata.textvalidate)
|
inputype = options.includes(defaultdata.textvalidate)
|
||||||
? defaultdata.textvalidate
|
? defaultdata.textvalidate
|
||||||
: "regex";
|
: "regex";
|
||||||
} else {
|
|
||||||
inputype = "text";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
|
const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
|
||||||
@@ -1149,11 +1156,14 @@ const TemplatePlaceholder = () => {
|
|||||||
status: defaultdata?.status || "required",
|
status: defaultdata?.status || "required",
|
||||||
hint: defaultdata?.hint || "",
|
hint: defaultdata?.hint || "",
|
||||||
defaultValue: defaultdata?.defaultValue || "",
|
defaultValue: defaultdata?.defaultValue || "",
|
||||||
validation: {
|
validation:
|
||||||
type: inputype,
|
(isSubscribe || !isEnableSubscription) && inputype
|
||||||
pattern:
|
? {
|
||||||
inputype === "regex" ? defaultdata.textvalidate : ""
|
type: inputype,
|
||||||
}
|
pattern:
|
||||||
|
inputype === "regex" ? defaultdata.textvalidate : ""
|
||||||
|
}
|
||||||
|
: {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@@ -1197,6 +1207,7 @@ const TemplatePlaceholder = () => {
|
|||||||
setIsCheckbox(false);
|
setIsCheckbox(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log("signerpos", signerPos);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Title title={"Template"} />
|
<Title title={"Template"} />
|
||||||
@@ -1221,6 +1232,15 @@ const TemplatePlaceholder = () => {
|
|||||||
closeWithMask={false}
|
closeWithMask={false}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{isAddRole && (
|
||||||
|
<Tour
|
||||||
|
onRequestClose={() => setIsAddRole(false)}
|
||||||
|
steps={tourAddRole}
|
||||||
|
isOpen={isAddRole}
|
||||||
|
rounded={5}
|
||||||
|
closeWithMask={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{/* this component used to render all pdf pages in left side */}
|
{/* this component used to render all pdf pages in left side */}
|
||||||
<RenderAllPdfPage
|
<RenderAllPdfPage
|
||||||
signPdfUrl={pdfDetails[0].URL}
|
signPdfUrl={pdfDetails[0].URL}
|
||||||
@@ -1246,7 +1266,7 @@ const TemplatePlaceholder = () => {
|
|||||||
handleClose={() => setIsSendAlert(false)}
|
handleClose={() => setIsSendAlert(false)}
|
||||||
>
|
>
|
||||||
<div style={{ height: "100%", padding: 20 }}>
|
<div style={{ height: "100%", padding: 20 }}>
|
||||||
<p>Please add field for all recipients.</p>
|
<p>Please add at least one signature field for all roles.</p>
|
||||||
</div>
|
</div>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
<ModalUi
|
<ModalUi
|
||||||
@@ -1551,6 +1571,7 @@ const TemplatePlaceholder = () => {
|
|||||||
isAddUser={isAddUser}
|
isAddUser={isAddUser}
|
||||||
uniqueId={uniqueId}
|
uniqueId={uniqueId}
|
||||||
closePopup={closePopup}
|
closePopup={closePopup}
|
||||||
|
signersData={signersdata}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ModalUi
|
<ModalUi
|
||||||
|
|||||||
@@ -8,13 +8,15 @@ import sanitizeFileName from "../primitives/sanitizeFileName";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||||
import Tooltip from "../primitives/Tooltip";
|
import Tooltip from "../primitives/Tooltip";
|
||||||
import { isEnableSubscription } from "../constant/const";
|
import { isEnableSubscription, rejectBtn, submitBtn } from "../constant/const";
|
||||||
import { checkIsSubscribed } from "../constant/Utils";
|
import { checkIsSubscribed, handleSendOTP } from "../constant/Utils";
|
||||||
import Upgrade from "../primitives/Upgrade";
|
import Upgrade from "../primitives/Upgrade";
|
||||||
|
import ModalUi from "../primitives/ModalUi";
|
||||||
|
|
||||||
function UserProfile() {
|
function UserProfile() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
let UserProfile = JSON.parse(localStorage.getItem("UserInformation"));
|
let UserProfile = JSON.parse(localStorage.getItem("UserInformation"));
|
||||||
|
let extendUser = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||||
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
|
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
|
||||||
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
|
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
|
||||||
const [editmode, setEditMode] = useState(false);
|
const [editmode, setEditMode] = useState(false);
|
||||||
@@ -25,12 +27,22 @@ function UserProfile() {
|
|||||||
const [percentage, setpercentage] = useState(0);
|
const [percentage, setpercentage] = useState(0);
|
||||||
const [isDisableDocId, setIsDisableDocId] = useState(false);
|
const [isDisableDocId, setIsDisableDocId] = useState(false);
|
||||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||||
|
const [company, setCompany] = useState(
|
||||||
|
extendUser && extendUser?.[0]?.Company
|
||||||
|
);
|
||||||
|
const [jobTitle, setJobTitle] = useState(
|
||||||
|
extendUser && extendUser?.[0]?.JobTitle
|
||||||
|
);
|
||||||
|
const [isVerifyModal, setIsVerifyModal] = useState(false);
|
||||||
|
const [otp, setOtp] = useState("");
|
||||||
|
const [otpLoader, setOtpLoader] = useState(false);
|
||||||
|
const [isEmailVerified, setIsEmailVerified] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getUserDetail();
|
getUserDetail();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getUserDetail = async () => {
|
const getUserDetail = async () => {
|
||||||
|
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 HeaderDocId = jsonSender[0]?.HeaderDocId;
|
const HeaderDocId = jsonSender[0]?.HeaderDocId;
|
||||||
@@ -41,6 +53,26 @@ function UserProfile() {
|
|||||||
if (HeaderDocId) {
|
if (HeaderDocId) {
|
||||||
setIsDisableDocId(HeaderDocId);
|
setIsDisableDocId(HeaderDocId);
|
||||||
}
|
}
|
||||||
|
const currentUser = JSON.parse(JSON.stringify(Parse.User.current()));
|
||||||
|
let isEmailVerified = currentUser?.emailVerified || false;
|
||||||
|
if (isEmailVerified) {
|
||||||
|
setIsEmailVerified(isEmailVerified);
|
||||||
|
setIsLoader(false);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const userQuery = new Parse.Query(Parse.User);
|
||||||
|
const user = await userQuery.get(currentUser.objectId, {
|
||||||
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
|
});
|
||||||
|
if (user) {
|
||||||
|
isEmailVerified = user?.get("emailVerified");
|
||||||
|
setIsEmailVerified(isEmailVerified);
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert("something went wrong!");
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -66,6 +98,7 @@ function UserProfile() {
|
|||||||
SetPhone(res.phone);
|
SetPhone(res.phone);
|
||||||
setImage(res.ProfilePic);
|
setImage(res.ProfilePic);
|
||||||
localStorage.setItem("username", res.name);
|
localStorage.setItem("username", res.name);
|
||||||
|
localStorage.setItem("profileImg", res.ProfilePic);
|
||||||
await updateExtUser({ Name: res.name, Phone: res.phone });
|
await updateExtUser({ Name: res.name, Phone: res.phone });
|
||||||
alert("Profile updated successfully.");
|
alert("Profile updated successfully.");
|
||||||
setEditMode(false);
|
setEditMode(false);
|
||||||
@@ -93,7 +126,9 @@ function UserProfile() {
|
|||||||
const body = {
|
const body = {
|
||||||
Phone: obj.Phone,
|
Phone: obj.Phone,
|
||||||
Name: obj.Name,
|
Name: obj.Name,
|
||||||
HeaderDocId: isDisableDocId
|
HeaderDocId: isDisableDocId,
|
||||||
|
JobTitle: jobTitle,
|
||||||
|
Company: company
|
||||||
};
|
};
|
||||||
await axios.put(
|
await axios.put(
|
||||||
parseBaseUrl + "classes/" + extClass + "/" + ExtUserId,
|
parseBaseUrl + "classes/" + extClass + "/" + ExtUserId,
|
||||||
@@ -147,7 +182,6 @@ function UserProfile() {
|
|||||||
// console.log("File URL:", response.url());
|
// console.log("File URL:", response.url());
|
||||||
if (response.url()) {
|
if (response.url()) {
|
||||||
setImage(response.url());
|
setImage(response.url());
|
||||||
localStorage.setItem("profileImg", response.url());
|
|
||||||
setpercentage(0);
|
setpercentage(0);
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
SaveFileSize(size, response.url(), tenantId);
|
SaveFileSize(size, response.url(), tenantId);
|
||||||
@@ -168,6 +202,45 @@ function UserProfile() {
|
|||||||
const handleDisableDocId = () => {
|
const handleDisableDocId = () => {
|
||||||
setIsDisableDocId((prevChecked) => !prevChecked);
|
setIsDisableDocId((prevChecked) => !prevChecked);
|
||||||
};
|
};
|
||||||
|
//`handleVerifyBtn` function is used to send otp on user mail
|
||||||
|
const handleVerifyBtn = async () => {
|
||||||
|
setIsVerifyModal(true);
|
||||||
|
await handleSendOTP(Parse.User.current().getEmail());
|
||||||
|
};
|
||||||
|
const handleCloseVerifyModal = async () => {
|
||||||
|
setIsVerifyModal(false);
|
||||||
|
};
|
||||||
|
//`handleVerifyEmail` function is used to verify email with otp
|
||||||
|
const handleVerifyEmail = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setOtpLoader(true);
|
||||||
|
try {
|
||||||
|
const resEmail = await Parse.Cloud.run("verifyemail", {
|
||||||
|
otp: otp,
|
||||||
|
email: Parse.User.current().getEmail()
|
||||||
|
});
|
||||||
|
if (resEmail?.message === "Email is verified.") {
|
||||||
|
setIsEmailVerified(true);
|
||||||
|
} else if (resEmail?.message === "Email is already verified.") {
|
||||||
|
setIsEmailVerified(true);
|
||||||
|
}
|
||||||
|
setOtp("");
|
||||||
|
alert(resEmail.message);
|
||||||
|
setIsVerifyModal(false);
|
||||||
|
} catch (error) {
|
||||||
|
alert(error.message);
|
||||||
|
} finally {
|
||||||
|
setOtpLoader(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//function to use resend otp for email verification
|
||||||
|
const handleResend = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setOtpLoader(true);
|
||||||
|
await handleSendOTP();
|
||||||
|
setOtpLoader(false);
|
||||||
|
alert("OTP sent on you email");
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Title title={"Profile"} />
|
<Title title={"Profile"} />
|
||||||
@@ -264,12 +337,57 @@ function UserProfile() {
|
|||||||
<span className="font-semibold">Email:</span>{" "}
|
<span className="font-semibold">Email:</span>{" "}
|
||||||
<span>{UserProfile && UserProfile.email}</span>
|
<span>{UserProfile && UserProfile.email}</span>
|
||||||
</li>
|
</li>
|
||||||
|
<li
|
||||||
|
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
|
||||||
|
editmode ? "py-1" : "py-2"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span className="font-semibold">Company:</span>{" "}
|
||||||
|
{editmode ? (
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={company}
|
||||||
|
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
|
||||||
|
onChange={(e) => setCompany(e.target.value)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span>{extendUser?.[0].Company}</span>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
|
||||||
|
editmode ? "py-1" : "py-2"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span className="font-semibold">Job title:</span>{" "}
|
||||||
|
{editmode ? (
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={jobTitle}
|
||||||
|
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
|
||||||
|
onChange={(e) => setJobTitle(e.target.value)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span>{extendUser?.[0]?.JobTitle}</span>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
<li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all">
|
<li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all">
|
||||||
<span className="font-semibold">Is Email verified:</span>{" "}
|
<span className="font-semibold">Is Email verified:</span>{" "}
|
||||||
<span>
|
<span>
|
||||||
{UserProfile && UserProfile.emailVerified
|
{isEmailVerified ? (
|
||||||
? "Verified"
|
"Verified"
|
||||||
: "Not verified"}
|
) : (
|
||||||
|
<span>
|
||||||
|
Not verified(
|
||||||
|
<span
|
||||||
|
onClick={() => handleVerifyBtn()}
|
||||||
|
className="hover:underline text-blue-600 cursor-pointer"
|
||||||
|
>
|
||||||
|
verify
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="border-y-[1px] border-gray-300 break-all">
|
<li className="border-y-[1px] border-gray-300 break-all">
|
||||||
@@ -356,6 +474,60 @@ function UserProfile() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{isVerifyModal && (
|
||||||
|
<ModalUi
|
||||||
|
isOpen
|
||||||
|
title={"OTP verification"}
|
||||||
|
handleClose={handleCloseVerifyModal}
|
||||||
|
>
|
||||||
|
{otpLoader ? (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: "150px",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: "45px",
|
||||||
|
color: "#3dd3e0"
|
||||||
|
}}
|
||||||
|
className="loader-37"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<form onSubmit={(e) => handleVerifyEmail(e)}>
|
||||||
|
<div className="px-6 py-3">
|
||||||
|
<label className="mb-2">Enter OTP</label>
|
||||||
|
<input
|
||||||
|
required
|
||||||
|
type="tel"
|
||||||
|
pattern="[0-9]{4}"
|
||||||
|
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||||
|
placeholder="Enter OTP received over email"
|
||||||
|
value={otp}
|
||||||
|
onChange={(e) => setOtp(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div className="px-6 my-3">
|
||||||
|
<button type="submit" className={submitBtn}>
|
||||||
|
Verify
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`${rejectBtn} ml-2`}
|
||||||
|
onClick={(e) => handleResend(e)}
|
||||||
|
>
|
||||||
|
Resend
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
</ModalUi>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,12 +7,16 @@ const LinkUserModal = (props) => {
|
|||||||
return (
|
return (
|
||||||
<ModalUi
|
<ModalUi
|
||||||
title={"Add/Choose Signer"}
|
title={"Add/Choose Signer"}
|
||||||
isOpen={props.isAddUser[props.uniqueId]}
|
isOpen={
|
||||||
|
props?.isAddSigner ||
|
||||||
|
(props?.isAddUser && props?.isAddUser[props?.uniqueId])
|
||||||
|
}
|
||||||
handleClose={props.closePopup}
|
handleClose={props.closePopup}
|
||||||
>
|
>
|
||||||
<SelectSigners
|
<SelectSigners
|
||||||
details={props.handleAddUser}
|
details={props.handleAddUser}
|
||||||
closePopup={props.closePopup}
|
closePopup={props.closePopup}
|
||||||
|
signersData={props?.signersData}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
import PremiumAlertHeader from "./PremiumAlertHeader";
|
||||||
|
|
||||||
const ModalUi = ({
|
const ModalUi = ({
|
||||||
children,
|
children,
|
||||||
@@ -8,12 +10,13 @@ const ModalUi = ({
|
|||||||
handleClose,
|
handleClose,
|
||||||
showHeader = true,
|
showHeader = true,
|
||||||
showClose = true,
|
showClose = true,
|
||||||
styleClass
|
styleClass,
|
||||||
|
showHeaderMessage
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<div className="fixed z-[999] top-0 left-0 w-[100%] h-[100%] bg-black bg-opacity-[75%]">
|
<div className="fixed z-[999] 2 top-0 left-0 w-[100%] h-[100%] bg-black bg-opacity-[75%]">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
styleClass
|
styleClass
|
||||||
@@ -37,6 +40,13 @@ const ModalUi = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{!isEnableSubscription && showHeaderMessage && (
|
||||||
|
<PremiumAlertHeader
|
||||||
|
message={
|
||||||
|
"Cutomize Email is free in beta, this feature will incur a fee later."
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div>{children}</div>
|
<div>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,19 +8,11 @@ function CustomModal({
|
|||||||
bodyMssg,
|
bodyMssg,
|
||||||
footerMessage,
|
footerMessage,
|
||||||
declineDoc,
|
declineDoc,
|
||||||
setIsDecline,
|
setIsDecline
|
||||||
containerWH
|
|
||||||
}) {
|
}) {
|
||||||
const isMobile = window.innerWidth < 767;
|
|
||||||
return (
|
return (
|
||||||
show && (
|
show && (
|
||||||
<div
|
<div className="bg-black bg-opacity-[75%] absolute z-[999] flex flex-col items-center justify-center w-full h-full rounded">
|
||||||
className="bg-black bg-opacity-[75%] absolute z-[999] flex flex-col items-center justify-center"
|
|
||||||
style={{
|
|
||||||
width: containerWH && containerWH.width,
|
|
||||||
height: isMobile ? "100%" : containerWH && containerWH.height
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="bg-white rounded outline-none md:w-[40%] w-[80%]">
|
<div className="bg-white rounded outline-none md:w-[40%] w-[80%]">
|
||||||
<div className="bg-[#de4337] text-white p-[10px] rounded-t">
|
<div className="bg-[#de4337] text-white p-[10px] rounded-t">
|
||||||
{headMsg && headMsg}
|
{headMsg && headMsg}
|
||||||
|
|||||||
@@ -1,16 +1,24 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { openInNewTab } from "../constant/Utils";
|
||||||
|
|
||||||
function Upgrade() {
|
function Upgrade({ message, newWindow }) {
|
||||||
const navigation = useNavigate();
|
const navigation = useNavigate();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<sup>
|
<sup>
|
||||||
<span
|
<span
|
||||||
onClick={() => navigation("/subscription")}
|
onClick={() => {
|
||||||
className="text-blue-800 text-sm cursor-pointer hover:underline"
|
if (newWindow) {
|
||||||
|
const url = window.location.origin + "/subscription";
|
||||||
|
openInNewTab(url);
|
||||||
|
} else {
|
||||||
|
navigation("/subscription");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="text-blue-800 text-sm cursor-pointer underline"
|
||||||
>
|
>
|
||||||
Upgrade now
|
{message ? message : "Upgrade now"}
|
||||||
</span>
|
</span>
|
||||||
</sup>
|
</sup>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,9 +9,15 @@ const Validate = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
|
const userDetails = JSON.parse(
|
||||||
|
localStorage.getItem(
|
||||||
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
// Use the session token to validate the user
|
// Use the session token to validate the user
|
||||||
const userQuery = new Parse.Query(Parse.User);
|
const userQuery = new Parse.Query(Parse.User);
|
||||||
const user = await userQuery.get(Parse.User.current().id, {
|
const user = await userQuery.get(userDetails?.objectId, {
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
});
|
});
|
||||||
if (user) {
|
if (user) {
|
||||||
@@ -24,6 +30,7 @@ const Validate = () => {
|
|||||||
setIsUserValid(false);
|
setIsUserValid(false);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@@ -395,14 +395,6 @@
|
|||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.backBtn {
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.backBtn:hover {
|
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
|
||||||
}
|
|
||||||
|
|
||||||
.defaultBtn {
|
.defaultBtn {
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||||
padding: 3px 26px;
|
padding: 3px 26px;
|
||||||
@@ -420,42 +412,6 @@
|
|||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.downloadBtn {
|
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
|
||||||
padding: 3px 15px !important;
|
|
||||||
background-color: rgb(241 79 79);
|
|
||||||
border: none !important;
|
|
||||||
color: white !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.downloadBtn:hover {
|
|
||||||
box-shadow: 0 2px 4px rgba(154, 36, 36, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
|
||||||
}
|
|
||||||
|
|
||||||
.printBtn {
|
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
|
||||||
padding: 3px 15px !important;
|
|
||||||
background: #188ae2;
|
|
||||||
border: none !important;
|
|
||||||
color: white !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.printBtn:hover {
|
|
||||||
box-shadow: 0 2px 4px rgba(23, 48, 137, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
|
||||||
}
|
|
||||||
|
|
||||||
.certificateBtn {
|
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
|
||||||
padding: 3px 15px !important;
|
|
||||||
background: #08bc66;
|
|
||||||
border: none !important;
|
|
||||||
color: white !important;
|
|
||||||
text-decoration: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.certificateBtn:hover {
|
|
||||||
box-shadow: 0 2px 4px rgba(15, 150, 87, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
|
||||||
}
|
|
||||||
|
|
||||||
.signerList {
|
.signerList {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
@@ -496,11 +452,15 @@
|
|||||||
overflow: hidden !important;
|
overflow: hidden !important;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.disabled {
|
.disabled {
|
||||||
opacity: 0.5; /* Example: reduce opacity to visually indicate disabled state */
|
opacity: 0.5;
|
||||||
pointer-events: none; /* Prevents mouse clicks and other events */
|
/* Example: reduce opacity to visually indicate disabled state */
|
||||||
|
pointer-events: none;
|
||||||
|
/* Prevents mouse clicks and other events */
|
||||||
/* background-color: #888; */
|
/* background-color: #888; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.useEmail {
|
.useEmail {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
color: #424242;
|
color: #424242;
|
||||||
@@ -557,13 +517,6 @@
|
|||||||
position: "relative";
|
position: "relative";
|
||||||
}
|
}
|
||||||
|
|
||||||
.signatureHeader {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signerComponent {
|
.signerComponent {
|
||||||
/* box-shadow: rgba(17, 12, 46, 0.15) 0px 48px 100px 0px; */
|
/* box-shadow: rgba(17, 12, 46, 0.15) 0px 48px 100px 0px; */
|
||||||
@@ -851,6 +804,7 @@ option {
|
|||||||
z-index: 999;
|
z-index: 999;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
resize: none;
|
resize: none;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.labelTextArea:focus {
|
.labelTextArea:focus {
|
||||||
@@ -1014,6 +968,9 @@ option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scroll-hide::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
@media screen and (max-width: 350px) and (min-width: 311px) {
|
@media screen and (max-width: 350px) and (min-width: 311px) {
|
||||||
.signatureCanvas {
|
.signatureCanvas {
|
||||||
width: 280px;
|
width: 280px;
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
const appId = process.env.APP_ID;
|
const appId = process.env.APP_ID;
|
||||||
const serverUrl = process.env.SERVER_URL;
|
const serverUrl = process.env.SERVER_URL;
|
||||||
@@ -150,3 +152,98 @@ export const updateMailCount = async extUserId => {
|
|||||||
console.log('Error updating EmailCount in contracts_users: ' + error.message);
|
console.log('Error updating EmailCount in contracts_users: ' + error.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function formatWidgetOptions(type, options) {
|
||||||
|
const status = options?.required === true ? 'required' : 'optional' || 'required';
|
||||||
|
const defaultValue = options?.default || '';
|
||||||
|
const values = options?.values || [];
|
||||||
|
switch (type) {
|
||||||
|
case 'signature':
|
||||||
|
return { name: 'signature', status: 'required' };
|
||||||
|
case 'stamp':
|
||||||
|
return { status: status, name: 'stamp' };
|
||||||
|
case 'initials':
|
||||||
|
return { status: status, name: options.name || 'initials' };
|
||||||
|
case 'image':
|
||||||
|
return { status: status, name: options.name || 'image' };
|
||||||
|
case 'email':
|
||||||
|
return { status: status, name: options.name || 'email', validation: { type: 'email' } };
|
||||||
|
case 'name':
|
||||||
|
return { status: status, name: options.name || 'name' };
|
||||||
|
case 'job title':
|
||||||
|
return { status: status, name: options.name || 'job title' };
|
||||||
|
case 'company':
|
||||||
|
return { status: status, name: options.name || 'company' };
|
||||||
|
case 'date': {
|
||||||
|
let today = new Date();
|
||||||
|
let dd = String(today.getDate()).padStart(2, '0');
|
||||||
|
let mm = String(today.getMonth() + 1).padStart(2, '0'); // January is 0!
|
||||||
|
let yyyy = today.getFullYear();
|
||||||
|
today = dd + '-' + mm + '-' + yyyy;
|
||||||
|
let dateFormat = options?.format;
|
||||||
|
dateFormat = dateFormat.replace(/m/g, 'M');
|
||||||
|
return {
|
||||||
|
status: status,
|
||||||
|
name: options.name || 'date',
|
||||||
|
response: defaultValue || today,
|
||||||
|
validation: { format: dateFormat || 'dd-MM-yyyy', type: 'date-format' },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'textbox':
|
||||||
|
return {
|
||||||
|
status: status,
|
||||||
|
name: 'textbox',
|
||||||
|
defaultValue: defaultValue,
|
||||||
|
hint: options.hint,
|
||||||
|
validation: { type: 'regex', pattern: options?.regularexpression || '/^[a-zA-Z0-9s]+$/' },
|
||||||
|
};
|
||||||
|
case 'checkbox': {
|
||||||
|
const arr = options?.values;
|
||||||
|
let selectedvalues = [];
|
||||||
|
for (const obj of options.selectedvalues) {
|
||||||
|
const index = arr.indexOf(obj);
|
||||||
|
selectedvalues.push(index);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
status: status,
|
||||||
|
name: options.name || 'checkbox',
|
||||||
|
values: values,
|
||||||
|
isReadOnly: options?.readonly || false,
|
||||||
|
isHideLabel: options?.hidelabel || false,
|
||||||
|
validation: {
|
||||||
|
minRequiredCount: options?.validation?.minselections || 0,
|
||||||
|
maxRequiredCount: options?.validation?.maxselections || 0,
|
||||||
|
},
|
||||||
|
defaultValue: selectedvalues || [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'radio button': {
|
||||||
|
return {
|
||||||
|
status: status,
|
||||||
|
name: options.name || 'radio',
|
||||||
|
values: values,
|
||||||
|
isReadOnly: options?.readonly || false,
|
||||||
|
isHideLabel: options?.hidelabel || false,
|
||||||
|
defaultValue: defaultValue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'dropdown':
|
||||||
|
return {
|
||||||
|
status: status,
|
||||||
|
name: options.name || 'dropdown',
|
||||||
|
values: values,
|
||||||
|
defaultValue: defaultValue,
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sanitizeFileName(fileName) {
|
||||||
|
// Remove spaces and invalid characters
|
||||||
|
const file = fileName.replace(/[^a-zA-Z0-9._-]/g, '');
|
||||||
|
const removedot = file.replace(/\.(?=.*\.)/g, '');
|
||||||
|
return removedot.replace(/[^a-zA-Z0-9._-]/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useLocal = process.env.USE_LOCAL ? process.env.USE_LOCAL.toLowerCase() : 'false';
|
||||||
|
|||||||
@@ -1,12 +1,25 @@
|
|||||||
//--npm modules
|
//--npm modules
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
export const app = express();
|
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
|
import uploadFile from './uploadFile.js';
|
||||||
|
import saveSubscription from './saveSubscription.js';
|
||||||
|
import saveInvoice from './saveInvoice.js';
|
||||||
|
import savePayments from './savePayments.js';
|
||||||
|
import gooogleauth from './googleauth.js';
|
||||||
|
export const app = express();
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
app.use(express.json());
|
app.use(express.json({ limit: '50mb' }));
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ limit: '50mb', extended: true }));
|
||||||
import uploadFile from './uploadFile.js';
|
|
||||||
|
|
||||||
app.post('/file_upload', uploadFile);
|
app.post('/file_upload', uploadFile);
|
||||||
|
|
||||||
|
app.post('/savesubscription', saveSubscription)
|
||||||
|
app.post('/saveinvoice', saveInvoice)
|
||||||
|
app.post('/savepayment', savePayments)
|
||||||
|
app.post('/googleauth', gooogleauth)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
const appId = process.env.APP_ID;
|
||||||
|
const serverUrl = process.env.SERVER_URL;
|
||||||
|
export default async function gooogleauth(request, response) {
|
||||||
|
const code = request.body.code;
|
||||||
|
const baseUrl = new URL(process.env.SERVER_URL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||||
|
headers: {
|
||||||
|
'X-Parse-Application-Id': appId,
|
||||||
|
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const userId = userRes.data && userRes.data.objectId;
|
||||||
|
if (userId) {
|
||||||
|
const clientId = process.env.GOOGLE_CLIENT_ID;
|
||||||
|
const clientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
||||||
|
const redirectUri =
|
||||||
|
baseUrl?.hostname === 'localhost'
|
||||||
|
? 'http://localhost:3000'
|
||||||
|
: 'https://console.opensignlabs.com'; // Should match the redirect URI used in the authorization request
|
||||||
|
const tokenEndpoint = 'https://oauth2.googleapis.com/token';
|
||||||
|
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.append('code', code);
|
||||||
|
params.append('client_id', clientId);
|
||||||
|
params.append('client_secret', clientSecret);
|
||||||
|
params.append('redirect_uri', redirectUri);
|
||||||
|
params.append('grant_type', 'authorization_code');
|
||||||
|
|
||||||
|
const res = await axios.post(tokenEndpoint, params);
|
||||||
|
// console.log('oauthres ', res.data);
|
||||||
|
const refresh_token = res.data.refresh_token;
|
||||||
|
const extUserCls = new Parse.Query('contracts_Users');
|
||||||
|
extUserCls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
|
||||||
|
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||||
|
|
||||||
|
if (extUser) {
|
||||||
|
const extUserCls = new Parse.Object('contracts_Users');
|
||||||
|
extUserCls.id = extUser.id;
|
||||||
|
extUserCls.set('google_refresh_token', refresh_token);
|
||||||
|
extUserCls.set('active_mail_adapter', 'google');
|
||||||
|
const updateExtUser = await extUserCls.save(null, { useMasterKey: true });
|
||||||
|
// console.log('updateExtUser ', updateExtUser);
|
||||||
|
}
|
||||||
|
return response.status(200).json({ status: 'success' });
|
||||||
|
} else {
|
||||||
|
return response.status(404).json({ message: 'user not found!' });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err in google auth', err);
|
||||||
|
if (err?.response?.data?.error) {
|
||||||
|
return response.status(404).json({ message: err.response.data.error });
|
||||||
|
} else {
|
||||||
|
return response.status(404).json({ message: err.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
export default async function saveInvoice(request, response) {
|
||||||
|
const InvoiceId = request.body.data.invoice.invoice_id;
|
||||||
|
const body = request.body;
|
||||||
|
const Email = request.body.data.invoice.email;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const extUserCls = new Parse.Query('contracts_Users');
|
||||||
|
extUserCls.equalTo('Email', Email);
|
||||||
|
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||||
|
if (extUser) {
|
||||||
|
const invoiceCls = new Parse.Query('contracts_Invoices');
|
||||||
|
invoiceCls.equalTo('InvoiceId', InvoiceId);
|
||||||
|
const invoice = await invoiceCls.first({ useMasterKey: true });
|
||||||
|
if (invoice) {
|
||||||
|
const updateInvoice = new Parse.Object('contracts_Invoices');
|
||||||
|
updateInvoice.id = invoice.id;
|
||||||
|
updateInvoice.set('InvoiceDetails', body);
|
||||||
|
await updateInvoice.save(null, { useMasterKey: true });
|
||||||
|
return response.status(200).json({ status: 'update invoice!' });
|
||||||
|
} else {
|
||||||
|
const createInvoice = new Parse.Object('contracts_Invoices');
|
||||||
|
createInvoice.set('InvoiceId', InvoiceId);
|
||||||
|
createInvoice.set('InvoiceDetails', body);
|
||||||
|
createInvoice.set('ExtUserPtr', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Users',
|
||||||
|
objectId: extUser.id,
|
||||||
|
});
|
||||||
|
createInvoice.set('CreatedBy', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: '_User',
|
||||||
|
objectId: extUser.get('UserId').id,
|
||||||
|
});
|
||||||
|
if (extUser?.get('TenantId')?.id) {
|
||||||
|
createInvoice.set('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: extUser.get('TenantId').id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createInvoice.save(null, { useMasterKey: true });
|
||||||
|
return response.status(200).json({ status: 'create invoice!' });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return response.status(404).json({ status: 'user not found!' });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Err in save invoice', err);
|
||||||
|
return response.status(400).json({ status: 'error:' + err.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
export default async function savePayments(request, response) {
|
||||||
|
const PaymentId = request.body.data.payment.payment_id;
|
||||||
|
const body = request.body;
|
||||||
|
const Email = request.body.data.payment.email;
|
||||||
|
try {
|
||||||
|
const extUserCls = new Parse.Query('contracts_Users');
|
||||||
|
extUserCls.equalTo('Email', Email);
|
||||||
|
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||||
|
if (extUser) {
|
||||||
|
const paymentCls = new Parse.Query('contracts_Payments');
|
||||||
|
paymentCls.equalTo('PaymentId', PaymentId);
|
||||||
|
const payment = await paymentCls.first({ useMasterKey: true });
|
||||||
|
if (payment) {
|
||||||
|
const updatePayment = new Parse.Object('contracts_Payments');
|
||||||
|
updatePayment.id = payment.id;
|
||||||
|
updatePayment.set('PaymentDetails', body);
|
||||||
|
await updatePayment.save(null, { useMasterKey: true });
|
||||||
|
return response.status(200).json({ status: 'update Payment!' });
|
||||||
|
} else {
|
||||||
|
const createPayment = new Parse.Object('contracts_Payments');
|
||||||
|
createPayment.set('PaymentId', PaymentId);
|
||||||
|
createPayment.set('PaymentDetails', body);
|
||||||
|
createPayment.set('ExtUserPtr', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Users',
|
||||||
|
objectId: extUser.id,
|
||||||
|
});
|
||||||
|
createPayment.set('CreatedBy', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: '_User',
|
||||||
|
objectId: extUser.get('UserId').id,
|
||||||
|
});
|
||||||
|
if (extUser?.get('TenantId')?.id) {
|
||||||
|
createPayment.set('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: extUser.get('TenantId').id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createPayment.save(null, { useMasterKey: true });
|
||||||
|
return response.status(200).json({ status: 'create payments!' });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return response.status(404).json({ status: 'user not found!' });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Err in save payment', err);
|
||||||
|
return response.status(400).json({ status: 'error:' + err.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
export default async function saveSubscription(request, response) {
|
||||||
|
const SubscriptionId = request.body.data.subscription.subscription_id;
|
||||||
|
const body = request.body;
|
||||||
|
const Email = request.body.data.subscription.customer.email;
|
||||||
|
const Next_billing_date = request.body.data.subscription.next_billing_at;
|
||||||
|
const planCode = request.body.data.subscription.plan.plan_code
|
||||||
|
|
||||||
|
try {
|
||||||
|
const extUserCls = new Parse.Query('contracts_Users');
|
||||||
|
extUserCls.equalTo('Email', Email);
|
||||||
|
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||||
|
if (extUser) {
|
||||||
|
const subcriptionCls = new Parse.Query('contracts_Subscriptions');
|
||||||
|
subcriptionCls.equalTo('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: extUser.get('TenantId').id,
|
||||||
|
});
|
||||||
|
const subscription = await subcriptionCls.first({ useMasterKey: true });
|
||||||
|
if (subscription) {
|
||||||
|
const updateSubscription = new Parse.Object('contracts_Subscriptions');
|
||||||
|
updateSubscription.id = subscription.id;
|
||||||
|
updateSubscription.set('SubscriptionId', SubscriptionId);
|
||||||
|
updateSubscription.set('SubscriptionDetails', body);
|
||||||
|
updateSubscription.set('Next_billing_date', new Date(Next_billing_date));
|
||||||
|
updateSubscription.set('PlanCode', planCode);
|
||||||
|
await updateSubscription.save(null, { useMasterKey: true });
|
||||||
|
return response.status(200).json({ status: 'update subscription!' });
|
||||||
|
} else {
|
||||||
|
const createSubscription = new Parse.Object('contracts_Subscriptions');
|
||||||
|
createSubscription.set('SubscriptionId', SubscriptionId);
|
||||||
|
createSubscription.set('SubscriptionDetails', body);
|
||||||
|
createSubscription.set('ExtUserPtr', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Users',
|
||||||
|
objectId: extUser.id,
|
||||||
|
});
|
||||||
|
createSubscription.set('CreatedBy', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: '_User',
|
||||||
|
objectId: extUser.get('UserId').id,
|
||||||
|
});
|
||||||
|
createSubscription.set('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: extUser.get('TenantId').id,
|
||||||
|
});
|
||||||
|
createSubscription.set('Next_billing_date', new Date(Next_billing_date));
|
||||||
|
createSubscription.set('PlanCode', planCode);
|
||||||
|
await createSubscription.save(null, { useMasterKey: true });
|
||||||
|
return response.status(200).json({ status: 'create subscription!' });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return response.status(404).json({ status: 'user not found!' });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Err in save subscription', err);
|
||||||
|
return response.status(400).json({ status: 'error:' + err.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import multer from 'multer';
|
|||||||
import multerS3 from 'multer-s3';
|
import multerS3 from 'multer-s3';
|
||||||
import aws from 'aws-sdk';
|
import aws from 'aws-sdk';
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
|
import { useLocal } from '../../Utils.js';
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
function sanitizeFileName(fileName) {
|
function sanitizeFileName(fileName) {
|
||||||
@@ -51,7 +52,7 @@ async function uploadFile(req, res) {
|
|||||||
const parseBaseUrl = process.env.SERVER_URL;
|
const parseBaseUrl = process.env.SERVER_URL;
|
||||||
const parseAppId = process.env.APP_ID;
|
const parseAppId = process.env.APP_ID;
|
||||||
let fileStorage;
|
let fileStorage;
|
||||||
if (process.env.USE_LOCAL == 'TRUE') {
|
if (useLocal === 'true') {
|
||||||
fileStorage = multer.diskStorage({
|
fileStorage = multer.diskStorage({
|
||||||
destination: function (req, file, cb) {
|
destination: function (req, file, cb) {
|
||||||
cb(null, 'files/files');
|
cb(null, 'files/files');
|
||||||
@@ -147,7 +148,7 @@ async function uploadFile(req, res) {
|
|||||||
const status = 'Success';
|
const status = 'Success';
|
||||||
//res.header("Access-Control-Allow-Headers", "Content-Type");
|
//res.header("Access-Control-Allow-Headers", "Content-Type");
|
||||||
//res.setHeader("Access-Control-Allow-Origin", "*");
|
//res.setHeader("Access-Control-Allow-Origin", "*");
|
||||||
if (process.env.USE_LOCAL == 'TRUE') {
|
if (useLocal === 'true') {
|
||||||
console.log(req.file);
|
console.log(req.file);
|
||||||
var fileUrl = `${parseBaseUrl}/files/${parseAppId}/${req.file.filename}`;
|
var fileUrl = `${parseBaseUrl}/files/${parseAppId}/${req.file.filename}`;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -217,9 +217,10 @@ export default async function createDocumentWithTemplate(request, response) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const objectId = contactMail[i].contactPtr.objectId;
|
const objectId = contactMail[i].contactPtr.objectId;
|
||||||
|
|
||||||
const hostUrl = baseUrl.origin;
|
const hostUrl = baseUrl.origin;
|
||||||
let signPdf = `${hostUrl}/login/${res.id}/${contactMail[i].email}/${objectId}/${serverParams}`;
|
//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 openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
||||||
const orgName = template.ExtUserPtr.Company ? template.ExtUserPtr.Company : '';
|
const orgName = template.ExtUserPtr.Company ? template.ExtUserPtr.Company : '';
|
||||||
const themeBGcolor = '#47a3ad';
|
const themeBGcolor = '#47a3ad';
|
||||||
@@ -266,13 +267,13 @@ export default async function createDocumentWithTemplate(request, response) {
|
|||||||
replaceVar = { subject: replaceVar.subject, body: email_html };
|
replaceVar = { subject: replaceVar.subject, body: email_html };
|
||||||
} else if (email_body) {
|
} else if (email_body) {
|
||||||
replaceVar = replaceMailVaribles(
|
replaceVar = replaceMailVaribles(
|
||||||
`${template.ExtUserPtr.Name} has requested you to sign ${template.Name}`,
|
`${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`,
|
||||||
email_body,
|
email_body,
|
||||||
variables
|
variables
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
replaceVar = {
|
replaceVar = {
|
||||||
subject: `${template.ExtUserPtr.Name} has requested you to sign ${template.Name}`,
|
subject: `${template.ExtUserPtr.Name} has requested you to sign "${template.Name}"`,
|
||||||
body: email_html,
|
body: email_html,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -320,7 +321,9 @@ export default async function createDocumentWithTemplate(request, response) {
|
|||||||
objectId: res.id,
|
objectId: res.id,
|
||||||
signurl: contact.map(x => ({
|
signurl: contact.map(x => ({
|
||||||
email: x.email,
|
email: x.email,
|
||||||
url: `${baseUrl.origin}/login/${res.id}/${x.email}/${x.contactPtr.objectId}/${serverParams}`,
|
url: `${baseUrl.origin}/login/${btoa(
|
||||||
|
`${res.id}/${x.email}/${x.contactPtr.objectId}`
|
||||||
|
)}`,
|
||||||
})),
|
})),
|
||||||
message: 'Document sent successfully!',
|
message: 'Document sent successfully!',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { color, customAPIurl, replaceMailVaribles, saveFileUsage } from '../../../../Utils.js';
|
import {
|
||||||
|
color,
|
||||||
|
customAPIurl,
|
||||||
|
replaceMailVaribles,
|
||||||
|
saveFileUsage,
|
||||||
|
formatWidgetOptions,
|
||||||
|
sanitizeFileName,
|
||||||
|
} from '../../../../Utils.js';
|
||||||
|
|
||||||
// `sendDoctoWebhook` is used to send res data of document on webhook
|
// `sendDoctoWebhook` is used to send res data of document on webhook
|
||||||
async function sendDoctoWebhook(doc, WebhookUrl, userId) {
|
async function sendDoctoWebhook(doc, WebhookUrl, userId) {
|
||||||
@@ -92,9 +99,8 @@ export default async function createDocumentwithCoordinate(request, response) {
|
|||||||
const buffer = Buffer.from(base64, 'base64');
|
const buffer = Buffer.from(base64, 'base64');
|
||||||
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||||
} else {
|
} else {
|
||||||
const file = new Parse.File(`${name}.pdf`, {
|
const filename = sanitizeFileName(`${name}.pdf`);
|
||||||
base64: base64File,
|
const file = new Parse.File(filename, { base64: base64File }, 'application/pdf');
|
||||||
});
|
|
||||||
await file.save({ useMasterKey: true });
|
await file.save({ useMasterKey: true });
|
||||||
fileUrl = file.url();
|
fileUrl = file.url();
|
||||||
const buffer = Buffer.from(base64File, 'base64');
|
const buffer = Buffer.from(base64File, 'base64');
|
||||||
@@ -177,17 +183,17 @@ export default async function createDocumentwithCoordinate(request, response) {
|
|||||||
|
|
||||||
for (const widget of signer.widgets) {
|
for (const widget of signer.widgets) {
|
||||||
const pageNumber = widget.page;
|
const pageNumber = widget.page;
|
||||||
|
const options = formatWidgetOptions(widget.type, widget.options);
|
||||||
const page = placeHolder.find(page => page.pageNumber === pageNumber);
|
const page = placeHolder.find(page => page.pageNumber === pageNumber);
|
||||||
const signOpt = { name: 'signature', status: 'required' };
|
|
||||||
const widgetData = {
|
const widgetData = {
|
||||||
isStamp: widget.type === 'stamp',
|
isStamp: widget.type === 'stamp' || widget.type === 'image',
|
||||||
key: randomId(),
|
key: randomId(),
|
||||||
isDrag: false,
|
isDrag: false,
|
||||||
scale: 1,
|
scale: 1,
|
||||||
isMobile: false,
|
isMobile: false,
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
type: widget.type,
|
type: widget.type === 'textbox' ? 'text input' : widget.type,
|
||||||
options: widget.type === 'signature' ? signOpt : widget.options,
|
options: options,
|
||||||
Width: widget.w,
|
Width: widget.w,
|
||||||
Height: widget.h,
|
Height: widget.h,
|
||||||
xPosition: widget.x,
|
xPosition: widget.x,
|
||||||
@@ -272,7 +278,9 @@ export default async function createDocumentwithCoordinate(request, response) {
|
|||||||
|
|
||||||
const objectId = contactMail[i].contactPtr.objectId;
|
const objectId = contactMail[i].contactPtr.objectId;
|
||||||
const hostUrl = baseUrl.origin;
|
const hostUrl = baseUrl.origin;
|
||||||
let signPdf = `${hostUrl}/login/${res.id}/${contactMail[i].email}/${objectId}/${serverParams}`;
|
//encode this url value `${response.id}/${contactMail[i].email}/${objectId}` to base64 using `btoa` function
|
||||||
|
const encodeBase64 = btoa(`${response.id}/${contactMail[i].email}/${objectId}`);
|
||||||
|
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
||||||
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
|
||||||
const orgName = parseExtUser.Company ? parseExtUser.Company : '';
|
const orgName = parseExtUser.Company ? parseExtUser.Company : '';
|
||||||
const themeBGcolor = '#47a3ad';
|
const themeBGcolor = '#47a3ad';
|
||||||
@@ -318,13 +326,13 @@ export default async function createDocumentwithCoordinate(request, response) {
|
|||||||
replaceVar = { subject: replaceVar.subject, body: email_html };
|
replaceVar = { subject: replaceVar.subject, body: email_html };
|
||||||
} else if (email_body) {
|
} else if (email_body) {
|
||||||
replaceVar = replaceMailVaribles(
|
replaceVar = replaceMailVaribles(
|
||||||
`${parseExtUser.Name} has requested you to sign ${name}`,
|
`${parseExtUser.Name} has requested you to sign "${name}"`,
|
||||||
email_body,
|
email_body,
|
||||||
variables
|
variables
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
replaceVar = {
|
replaceVar = {
|
||||||
subject: `${parseExtUser.Name} has requested you to sign ${parseExtUser.Name}`,
|
subject: `${parseExtUser.Name} has requested you to sign "${parseExtUser.Name}"`,
|
||||||
body: email_html,
|
body: email_html,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -357,7 +365,7 @@ export default async function createDocumentwithCoordinate(request, response) {
|
|||||||
objectId: res.id,
|
objectId: res.id,
|
||||||
signurl: contact.map(x => ({
|
signurl: contact.map(x => ({
|
||||||
email: x.email,
|
email: x.email,
|
||||||
url: `${baseUrl.origin}/login/${res.id}/${x.email}/${x.contactPtr.objectId}/${serverParams}`,
|
url: `${baseUrl.origin}/login/${btoa(`${res.id}/${x.email}/${x.contactPtr.objectId}`)}`,
|
||||||
})),
|
})),
|
||||||
message: 'Document sent successfully!',
|
message: 'Document sent successfully!',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { color, customAPIurl, saveFileUsage } from '../../../../Utils.js';
|
import {
|
||||||
|
color,
|
||||||
|
customAPIurl,
|
||||||
|
saveFileUsage,
|
||||||
|
formatWidgetOptions,
|
||||||
|
sanitizeFileName,
|
||||||
|
} from '../../../../Utils.js';
|
||||||
|
|
||||||
const randomId = () => Math.floor(1000 + Math.random() * 9000);
|
const randomId = () => Math.floor(1000 + Math.random() * 9000);
|
||||||
export default async function createTemplatewithCoordinate(request, response) {
|
export default async function createTemplatewithCoordinate(request, response) {
|
||||||
@@ -43,9 +49,8 @@ export default async function createTemplatewithCoordinate(request, response) {
|
|||||||
const buffer = Buffer.from(base64, 'base64');
|
const buffer = Buffer.from(base64, 'base64');
|
||||||
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
|
||||||
} else {
|
} else {
|
||||||
const file = new Parse.File(`${name}.pdf`, {
|
const filename = sanitizeFileName(`${name}.pdf`);
|
||||||
base64: base64File,
|
const file = new Parse.File(filename, { base64: base64File }, 'application/pdf');
|
||||||
});
|
|
||||||
await file.save({ useMasterKey: true });
|
await file.save({ useMasterKey: true });
|
||||||
fileUrl = file.url();
|
fileUrl = file.url();
|
||||||
const buffer = Buffer.from(base64File, 'base64');
|
const buffer = Buffer.from(base64File, 'base64');
|
||||||
@@ -134,16 +139,16 @@ export default async function createTemplatewithCoordinate(request, response) {
|
|||||||
for (const widget of signer.widgets) {
|
for (const widget of signer.widgets) {
|
||||||
const pageNumber = widget.page;
|
const pageNumber = widget.page;
|
||||||
const page = placeHolder.find(page => page.pageNumber === pageNumber);
|
const page = placeHolder.find(page => page.pageNumber === pageNumber);
|
||||||
const signOpt = { name: 'signature', status: 'required' };
|
const options = formatWidgetOptions(widget.type, widget.options);
|
||||||
const widgetData = {
|
const widgetData = {
|
||||||
isStamp: widget.type === 'stamp',
|
isStamp: widget.type === 'stamp' || widget.type === 'image',
|
||||||
key: randomId(),
|
key: randomId(),
|
||||||
isDrag: false,
|
isDrag: false,
|
||||||
scale: 1,
|
scale: 1,
|
||||||
isMobile: false,
|
isMobile: false,
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
type: widget.type,
|
type: widget.type === 'textbox' ? 'text input' : widget.type,
|
||||||
options: widget.type === 'signature' ? signOpt : widget.options,
|
options: options,
|
||||||
Width: widget.w,
|
Width: widget.w,
|
||||||
Height: widget.h,
|
Height: widget.h,
|
||||||
xPosition: widget.x,
|
xPosition: widget.x,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { customAPIurl } from '../../../../Utils.js';
|
import { customAPIurl, saveFileUsage } from '../../../../Utils.js';
|
||||||
|
|
||||||
// const randomId = () => Math.floor(1000 + Math.random() * 9000);
|
// const randomId = () => Math.floor(1000 + Math.random() * 9000);
|
||||||
export default async function draftDocument(request, response) {
|
export default async function draftDocument(request, response) {
|
||||||
|
|||||||
@@ -25,6 +25,18 @@ import callWebhook from './parsefunction/callWebhook.js';
|
|||||||
import SubscribeFree from './parsefunction/SubscribeFree.js';
|
import SubscribeFree from './parsefunction/SubscribeFree.js';
|
||||||
import DocumentBeforesave from './parsefunction/DocumentBeforesave.js';
|
import DocumentBeforesave from './parsefunction/DocumentBeforesave.js';
|
||||||
import TemplateBeforeSave from './parsefunction/TemplateBeforesave.js';
|
import TemplateBeforeSave from './parsefunction/TemplateBeforesave.js';
|
||||||
|
import DocumentBeforeFind from './parsefunction/DocumentAfterFind.js';
|
||||||
|
import TemplateAfterFind from './parsefunction/TemplateAfterFind.js';
|
||||||
|
import UserAfterFind from './parsefunction/UserAfterFInd.js';
|
||||||
|
import SignatureAfterFind from './parsefunction/SignatureAfterFind.js';
|
||||||
|
import getInvoices from './parsefunction/getInvoices.js';
|
||||||
|
import getPayments from './parsefunction/getPayments.js';
|
||||||
|
import getSubscriptions from './parsefunction/getSubscriptions.js';
|
||||||
|
import TenantAterFind from './parsefunction/TenantAfterFind.js';
|
||||||
|
import saveSubscription from './parsefunction/saveSubscription.js';
|
||||||
|
import VerifyEmail from './parsefunction/VerifyEmail.js';
|
||||||
|
import encryptedpdf from './parsefunction/encryptedPdf.js';
|
||||||
|
import { getSignedUrl } from './parsefunction/getSignedUrl.js';
|
||||||
|
|
||||||
Parse.Cloud.define('AddUserToRole', addUserToGroups);
|
Parse.Cloud.define('AddUserToRole', addUserToGroups);
|
||||||
Parse.Cloud.define('UserGroups', getUserGroups);
|
Parse.Cloud.define('UserGroups', getUserGroups);
|
||||||
@@ -47,9 +59,21 @@ Parse.Cloud.define('getTemplate', GetTemplate);
|
|||||||
Parse.Cloud.define('savewebhook', savewebhook);
|
Parse.Cloud.define('savewebhook', savewebhook);
|
||||||
Parse.Cloud.define('callwebhook', callWebhook);
|
Parse.Cloud.define('callwebhook', callWebhook);
|
||||||
Parse.Cloud.define('freesubscription', SubscribeFree);
|
Parse.Cloud.define('freesubscription', SubscribeFree);
|
||||||
|
Parse.Cloud.define('getinvoices', getInvoices);
|
||||||
|
Parse.Cloud.define('getpayments', getPayments);
|
||||||
|
Parse.Cloud.define('getsubscriptions', getSubscriptions);
|
||||||
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
|
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
|
||||||
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
|
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
|
||||||
Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
|
Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
|
||||||
Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave);
|
Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave);
|
||||||
Parse.Cloud.beforeSave('contracts_Document', DocumentBeforesave);
|
Parse.Cloud.beforeSave('contracts_Document', DocumentBeforesave);
|
||||||
Parse.Cloud.beforeSave('contracts_Template', TemplateBeforeSave);
|
Parse.Cloud.beforeSave('contracts_Template', TemplateBeforeSave);
|
||||||
|
Parse.Cloud.afterFind(Parse.User, UserAfterFind);
|
||||||
|
Parse.Cloud.afterFind('contracts_Document', DocumentBeforeFind);
|
||||||
|
Parse.Cloud.afterFind('contracts_Template', TemplateAfterFind);
|
||||||
|
Parse.Cloud.afterFind('contracts_Signature', SignatureAfterFind);
|
||||||
|
Parse.Cloud.afterFind('partners_Tenant', TenantAterFind);
|
||||||
|
Parse.Cloud.define('savesubscription', saveSubscription);
|
||||||
|
Parse.Cloud.define('verifyemail', VerifyEmail);
|
||||||
|
Parse.Cloud.define('encryptedpdf', encryptedpdf);
|
||||||
|
Parse.Cloud.define('getsignedurl', getSignedUrl);
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { useLocal } from '../../Utils.js';
|
||||||
|
import getPresignedUrl from './getSignedUrl.js';
|
||||||
|
|
||||||
|
async function DocumentAfterFind(request) {
|
||||||
|
if (useLocal !== 'true') {
|
||||||
|
if (request.objects.length === 1) {
|
||||||
|
if (request.objects) {
|
||||||
|
const obj = request.objects[0];
|
||||||
|
const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl');
|
||||||
|
const Url = obj?.get('URL') && obj?.get('URL');
|
||||||
|
const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl');
|
||||||
|
if (SignedUrl) {
|
||||||
|
obj.set('SignedUrl', getPresignedUrl(SignedUrl));
|
||||||
|
}
|
||||||
|
if (Url) {
|
||||||
|
obj.set('URL', getPresignedUrl(Url));
|
||||||
|
}
|
||||||
|
if (certificateUrl) {
|
||||||
|
obj.set('CertificateUrl', getPresignedUrl(certificateUrl));
|
||||||
|
}
|
||||||
|
return [obj];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default DocumentAfterFind;
|
||||||
@@ -4,6 +4,7 @@ async function DocumentAftersave(request) {
|
|||||||
console.log('new entry is insert in contracts_Document');
|
console.log('new entry is insert in contracts_Document');
|
||||||
const createdAt = request.object.get('createdAt');
|
const createdAt = request.object.get('createdAt');
|
||||||
const Folder = request.object.get('Type');
|
const Folder = request.object.get('Type');
|
||||||
|
const ip = request?.headers?.['x-real-ip'] || '';
|
||||||
if (createdAt && Folder === undefined) {
|
if (createdAt && Folder === undefined) {
|
||||||
// console.log("IN If condition")
|
// console.log("IN If condition")
|
||||||
const TimeToCompleteDays = request.object.get('TimeToCompleteDays');
|
const TimeToCompleteDays = request.object.get('TimeToCompleteDays');
|
||||||
@@ -12,6 +13,7 @@ async function DocumentAftersave(request) {
|
|||||||
const documentQuery = new Parse.Query('contracts_Document');
|
const documentQuery = new Parse.Query('contracts_Document');
|
||||||
const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true });
|
const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true });
|
||||||
updateQuery.set('ExpiryDate', ExpiryDate);
|
updateQuery.set('ExpiryDate', ExpiryDate);
|
||||||
|
updateQuery.set('OriginIp', ip);
|
||||||
await updateQuery.save(null, { useMasterKey: true });
|
await updateQuery.save(null, { useMasterKey: true });
|
||||||
} else if (createdAt && Folder === 'AIDoc') {
|
} else if (createdAt && Folder === 'AIDoc') {
|
||||||
const TimeToCompleteDays = request.object.get('TimeToCompleteDays');
|
const TimeToCompleteDays = request.object.get('TimeToCompleteDays');
|
||||||
@@ -24,6 +26,7 @@ async function DocumentAftersave(request) {
|
|||||||
const documentQuery = new Parse.Query('contracts_Document');
|
const documentQuery = new Parse.Query('contracts_Document');
|
||||||
const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true });
|
const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true });
|
||||||
updateQuery.set('ExpiryDate', ExpiryDate);
|
updateQuery.set('ExpiryDate', ExpiryDate);
|
||||||
|
updateQuery.set('OriginIp', ip);
|
||||||
await updateQuery.save(null, { useMasterKey: true });
|
await updateQuery.save(null, { useMasterKey: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +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?.get('SignedUrl') && document?.get('SignedUrl')) {
|
||||||
const 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);
|
||||||
@@ -27,6 +25,10 @@ async function DocumentBeforesave(request) {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('Error updating document count in contracts_users: ' + error.message);
|
console.log('Error updating document count in contracts_users: ' + error.message);
|
||||||
}
|
}
|
||||||
|
if (document?.get('Signers') && document.get('Signers').length > 0) {
|
||||||
|
document.set('DocSentAt', new Date());
|
||||||
|
document.save(null, { useMasterKey: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err in document beforesave', err.message);
|
console.log('err in document beforesave', err.message);
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { useLocal } from '../../Utils.js';
|
||||||
|
import getPresignedUrl from './getSignedUrl.js';
|
||||||
|
|
||||||
|
async function SignatureAfterFind(request) {
|
||||||
|
if (useLocal !== 'true') {
|
||||||
|
if (request.objects.length === 1) {
|
||||||
|
if (request.objects) {
|
||||||
|
const obj = request.objects[0];
|
||||||
|
const ImageURL = obj?.get('ImageURL') && obj?.get('ImageURL');
|
||||||
|
const Initials = obj?.get('Initials') && obj?.get('Initials');
|
||||||
|
if (ImageURL) {
|
||||||
|
obj.set('ImageURL', getPresignedUrl(ImageURL));
|
||||||
|
}
|
||||||
|
if (Initials) {
|
||||||
|
obj.set('Initials', getPresignedUrl(Initials));
|
||||||
|
}
|
||||||
|
return [obj];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default SignatureAfterFind;
|
||||||
@@ -6,27 +6,51 @@ export default async function SubscribeFree(request) {
|
|||||||
extQuery.equalTo('UserId', userPtr);
|
extQuery.equalTo('UserId', userPtr);
|
||||||
const extUser = await extQuery.first({ useMasterKey: true });
|
const extUser = await extQuery.first({ useMasterKey: true });
|
||||||
if (extUser) {
|
if (extUser) {
|
||||||
if (extUser?.get('Plan')?.plan_code === 'freeplan') {
|
const subscriptionCls = new Parse.Query('contracts_Subscriptions');
|
||||||
|
subscriptionCls.equalTo('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: extUser.get('TenantId').id,
|
||||||
|
});
|
||||||
|
subscriptionCls.descending('createdAt');
|
||||||
|
const subcripitions = await subscriptionCls.first({ useMasterKey: true });
|
||||||
|
if (subcripitions?.get('PlanCode') === 'freeplan') {
|
||||||
return { status: 'success', result: 'already subscribed!' };
|
return { status: 'success', result: 'already subscribed!' };
|
||||||
} else if (extUser?.get('Next_billing_date') < new Date()) {
|
} else if (subcripitions?.get('Next_billing_date') < new Date()) {
|
||||||
try {
|
try {
|
||||||
const extUpdate = new Parse.Object('contracts_Users');
|
const updateSubscription = new Parse.Object('contracts_Subscriptions');
|
||||||
extUpdate.id = extUser.id;
|
updateSubscription.id = subcripitions.id;
|
||||||
extUpdate.set('Plan', { plan_code: 'freeplan' });
|
updateSubscription.set('PlanCode', 'freeplan');
|
||||||
await extUpdate.save(null, { useMasterKey: true });
|
await updateSubscription.save(null, { useMasterKey: true });
|
||||||
return { status: 'success', result: 'subscribed!' };
|
return { status: 'success', result: 'subscribed!' };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err ', err);
|
console.log('err ', err);
|
||||||
return { status: 'error', result: err.message };
|
return { status: 'error', result: err.message };
|
||||||
}
|
}
|
||||||
} else if (extUser?.get('Next_billing_date') > new Date()) {
|
} else if (subcripitions?.get('Next_billing_date') > new Date()) {
|
||||||
return { status: 'success', result: 'already subscribed!' };
|
return { status: 'success', result: 'already subscribed!' };
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const extUpdate = new Parse.Object('contracts_Users');
|
const createSubscription = new Parse.Object('contracts_Subscriptions');
|
||||||
extUpdate.id = extUser.id;
|
createSubscription.set('PlanCode', 'freeplan');
|
||||||
extUpdate.set('Plan', { plan_code: 'freeplan' });
|
createSubscription.set('ExtUserPtr', {
|
||||||
await extUpdate.save(null, { useMasterKey: true });
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Users',
|
||||||
|
objectId: extUser.id,
|
||||||
|
});
|
||||||
|
createSubscription.set('CreatedBy', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: '_User',
|
||||||
|
objectId: extUser.get('UserId').id,
|
||||||
|
});
|
||||||
|
if (extUser?.get('TenantId')) {
|
||||||
|
createSubscription.set('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: extUser.get('TenantId').id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await createSubscription.save(null, { useMasterKey: true });
|
||||||
return { status: 'success', result: 'subscribed!' };
|
return { status: 'success', result: 'subscribed!' };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err ', err);
|
console.log('err ', err);
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { useLocal } from '../../Utils.js';
|
||||||
|
import getPresignedUrl from './getSignedUrl.js';
|
||||||
|
|
||||||
|
async function TemplateAfterFind(request) {
|
||||||
|
if (useLocal !== 'true') {
|
||||||
|
if (request.objects.length === 1) {
|
||||||
|
if (request.objects) {
|
||||||
|
const obj = request.objects[0];
|
||||||
|
const SignedUrl = obj?.get('SignedUrl') && obj?.get('SignedUrl');
|
||||||
|
const Url = obj?.get('URL') && obj?.get('URL');
|
||||||
|
const certificateUrl = obj.get('CertificateUrl') && obj.get('CertificateUrl');
|
||||||
|
if (SignedUrl) {
|
||||||
|
obj.set('SignedUrl', getPresignedUrl(SignedUrl));
|
||||||
|
}
|
||||||
|
if (Url) {
|
||||||
|
obj.set('URL', getPresignedUrl(Url));
|
||||||
|
}
|
||||||
|
if (certificateUrl) {
|
||||||
|
obj.set('CertificateUrl', getPresignedUrl(certificateUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [obj];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default TemplateAfterFind;
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { useLocal } from '../../Utils.js';
|
||||||
|
import getPresignedUrl from './getSignedUrl.js';
|
||||||
|
|
||||||
|
async function TenantAterFind(request) {
|
||||||
|
if (useLocal !== 'true') {
|
||||||
|
if (request.objects.length === 1) {
|
||||||
|
if (request.objects) {
|
||||||
|
const obj = request.objects[0];
|
||||||
|
const Logo = obj?.get('Logo') && obj?.get('Logo');
|
||||||
|
if (Logo) {
|
||||||
|
obj.set('Logo', getPresignedUrl(Logo));
|
||||||
|
}
|
||||||
|
return [obj];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default TenantAterFind;
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { useLocal } from '../../Utils.js';
|
||||||
|
import getPresignedUrl from './getSignedUrl.js';
|
||||||
|
|
||||||
|
async function UserAfterFind(request) {
|
||||||
|
if (useLocal !== 'true') {
|
||||||
|
if (request.objects.length === 1) {
|
||||||
|
if (request.objects) {
|
||||||
|
const obj = request.objects[0];
|
||||||
|
const ProfilePic = obj?.get('ProfilePic') && obj?.get('ProfilePic');
|
||||||
|
if (ProfilePic) {
|
||||||
|
obj.set('ProfilePic', getPresignedUrl(ProfilePic));
|
||||||
|
}
|
||||||
|
return [obj];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default UserAfterFind;
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
export default async function VerifyEmail(request) {
|
||||||
|
try {
|
||||||
|
if (!request?.user) {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||||
|
} else {
|
||||||
|
let otpN = request.params.otp;
|
||||||
|
let otp = parseInt(otpN);
|
||||||
|
let email = request.params.email;
|
||||||
|
|
||||||
|
//checking otp is correct or not which already save in defaultdata_Otp class
|
||||||
|
const checkOtp = new Parse.Query('defaultdata_Otp');
|
||||||
|
checkOtp.equalTo('Email', email);
|
||||||
|
checkOtp.equalTo('OTP', otp);
|
||||||
|
|
||||||
|
const res = await checkOtp.first({ useMasterKey: true });
|
||||||
|
if (res) {
|
||||||
|
// Fetch the user by their objectId
|
||||||
|
const isEmailVerified = request?.user?.get('emailVerified');
|
||||||
|
if (isEmailVerified) {
|
||||||
|
return { message: 'Email is already verified.' };
|
||||||
|
} else {
|
||||||
|
const userQuery = new Parse.Query(Parse.User);
|
||||||
|
const user = await userQuery.get(request?.user.id, {
|
||||||
|
sessionToken: request?.user.getSessionToken(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update the emailVerified field to true
|
||||||
|
user.set('emailVerified', true);
|
||||||
|
// Save the user object
|
||||||
|
const res = await user.save(null, { useMasterKey: true });
|
||||||
|
if (res) {
|
||||||
|
return { message: 'Email is verified.' };
|
||||||
|
} else {
|
||||||
|
const error = new Error('Something went wrong, please try again later!');
|
||||||
|
error.code = 400; // Set the error code (e.g., 400 for bad request)
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const error = new Error('OTP is invalid.');
|
||||||
|
error.code = 400; // Set the error code (e.g., 400 for bad request)
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err ', err.code + ' ' + err.message);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,23 +23,16 @@ export default async function ZohoDetails(request) {
|
|||||||
};
|
};
|
||||||
// Make the POST request using Axios
|
// Make the POST request using Axios
|
||||||
const res = await axios.post(url, formData, { headers });
|
const res = await axios.post(url, formData, { headers });
|
||||||
|
|
||||||
// console.log("Access Token:", res.data);
|
// console.log("Access Token:", res.data);
|
||||||
|
|
||||||
if (res.data.access_token) {
|
if (res.data.access_token) {
|
||||||
const hostedpages = request.params.hostedpagesId;
|
const hostedpages = request.params.hostedpagesId;
|
||||||
const userData = await axios.get('https://billing.zoho.in/api/v1/hostedpages/' + hostedpages, {
|
const userData = await axios.get('https://billing.zoho.in/api/v1/hostedpages/' + hostedpages, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
|
Authorization: 'Zoho-oauthtoken ' + res.data.access_token,
|
||||||
'X-com-zoho-billing-organizationid': process.env.ZOHO_BILLING_ORG_ID,
|
'X-com-zoho-subscriptions-organizationid': process.env.ZOHO_BILLING_ORG_ID,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// console.log(
|
|
||||||
// "userData.data.data.subscription.contactpersons ",
|
|
||||||
// userData.data.data.subscription.contactpersons
|
|
||||||
// );
|
|
||||||
|
|
||||||
// console.log("userData.data.expiring_time ", userData.data.expiring_time);
|
|
||||||
const first_name = userData.data.data.subscription.contactpersons[0].first_name || '';
|
const first_name = userData.data.data.subscription.contactpersons[0].first_name || '';
|
||||||
const last_name = userData.data.data.subscription.contactpersons[0].last_name || '';
|
const last_name = userData.data.data.subscription.contactpersons[0].last_name || '';
|
||||||
const company_name =
|
const company_name =
|
||||||
@@ -60,6 +53,7 @@ export default async function ZohoDetails(request) {
|
|||||||
customer_id: userData.data.data.subscription.customer_id,
|
customer_id: userData.data.data.subscription.customer_id,
|
||||||
subscription_id: userData.data.data.subscription.subscription_id,
|
subscription_id: userData.data.data.subscription.subscription_id,
|
||||||
jobTitle: jobTitle,
|
jobTitle: jobTitle,
|
||||||
|
subscription: userData.data,
|
||||||
};
|
};
|
||||||
return resData;
|
return resData;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import axios from 'axios';
|
|||||||
export default async function callWebhook(request) {
|
export default async function callWebhook(request) {
|
||||||
const event = request.params.event;
|
const event = request.params.event;
|
||||||
const body = request.params.body;
|
const body = request.params.body;
|
||||||
|
const docId = body.objectId;
|
||||||
|
const contactId = request.params.contactId;
|
||||||
const serverUrl = process.env.SERVER_URL;
|
const serverUrl = process.env.SERVER_URL;
|
||||||
const appId = process.env.APP_ID;
|
const appId = process.env.APP_ID;
|
||||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||||
@@ -13,6 +15,39 @@ export default async function callWebhook(request) {
|
|||||||
|
|
||||||
const userId = userRes.data && userRes.data.objectId;
|
const userId = userRes.data && userRes.data.objectId;
|
||||||
if (userId) {
|
if (userId) {
|
||||||
|
if (event === 'viewed' && contactId) {
|
||||||
|
const docQuery = new Parse.Query('contracts_Document');
|
||||||
|
const res = await docQuery.get(docId, { useMasterKey: true });
|
||||||
|
if (res) {
|
||||||
|
const _res = res.toJSON();
|
||||||
|
const userPtr = {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Contactbook',
|
||||||
|
objectId: contactId,
|
||||||
|
};
|
||||||
|
const date = new Date().toISOString();
|
||||||
|
const obj = {
|
||||||
|
UserPtr: userPtr,
|
||||||
|
SignedUrl: _res.SignedUrl,
|
||||||
|
Activity: 'Viewed',
|
||||||
|
ipAddress: request.headers['x-real-ip'],
|
||||||
|
ViewedOn: date,
|
||||||
|
};
|
||||||
|
const isUserExist = _res?.AuditTrail?.some(
|
||||||
|
x => x.UserPtr.objectId === contactId && x?.ViewedOn
|
||||||
|
);
|
||||||
|
if (!isUserExist) {
|
||||||
|
const updateDoc = new Parse.Object('contracts_Document');
|
||||||
|
updateDoc.id = res.id;
|
||||||
|
if (_res?.AuditTrail && _res?.AuditTrail?.length > 0) {
|
||||||
|
updateDoc.set('AuditTrail', [..._res?.AuditTrail, obj]);
|
||||||
|
} else {
|
||||||
|
updateDoc.set('AuditTrail', [obj]);
|
||||||
|
}
|
||||||
|
await updateDoc.save(null, { useMasterKey: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
const extendcls = new Parse.Query('contracts_Users');
|
const extendcls = new Parse.Query('contracts_Users');
|
||||||
extendcls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
|
extendcls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
|
||||||
const res = await extendcls.first({ useMasterKey: true });
|
const res = await extendcls.first({ useMasterKey: true });
|
||||||
@@ -39,11 +74,11 @@ export default async function callWebhook(request) {
|
|||||||
});
|
});
|
||||||
webhook.save(null, { useMasterKey: true });
|
webhook.save(null, { useMasterKey: true });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err save in contracts_Webhook', err);
|
console.log('err save in contracts_Webhook', err.message);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.log('Err send data to webhook', err);
|
console.log('Err send data to webhook', err.message);
|
||||||
try {
|
try {
|
||||||
const webhook = new Parse.Object('contracts_Webhook');
|
const webhook = new Parse.Object('contracts_Webhook');
|
||||||
webhook.set('Log', err?.status);
|
webhook.set('Log', err?.status);
|
||||||
@@ -54,7 +89,7 @@ export default async function callWebhook(request) {
|
|||||||
});
|
});
|
||||||
webhook.save(null, { useMasterKey: true });
|
webhook.save(null, { useMasterKey: true });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err save in contracts_Webhook', err);
|
console.log('err save in contracts_Webhook', err.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { PostHog } from 'posthog-node';
|
||||||
|
const ph_project_api_key = process.env.PH_PROJECT_API_KEY;
|
||||||
|
const client = ph_project_api_key ? new PostHog(ph_project_api_key) : '';
|
||||||
|
export default async function encryptedpdf(request) {
|
||||||
|
const email = request.params.email;
|
||||||
|
if (client) {
|
||||||
|
client?.capture({
|
||||||
|
distinctId: email,
|
||||||
|
event: 'encrypted_pdf_error',
|
||||||
|
properties: { response_code: 200 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return { message: 'success' };
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ export default async function getDocument(request) {
|
|||||||
query.include('Signers');
|
query.include('Signers');
|
||||||
query.include('AuditTrail.UserPtr');
|
query.include('AuditTrail.UserPtr');
|
||||||
query.include('Placeholders');
|
query.include('Placeholders');
|
||||||
query.notEqualTo('IsArchive', true)
|
query.notEqualTo('IsArchive', true);
|
||||||
const res = await query.first({ useMasterKey: true });
|
const res = await query.first({ useMasterKey: true });
|
||||||
if (res) {
|
if (res) {
|
||||||
const acl = res.getACL();
|
const acl = res.getACL();
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
const serverUrl = process.env.SERVER_URL;
|
||||||
|
const appId = process.env.APP_ID;
|
||||||
|
export default async function getInvoices(request) {
|
||||||
|
const limit = request.params.limit || 100;
|
||||||
|
const skip = request.params.skip || 0;
|
||||||
|
const extUserId = request.params.extUserId;
|
||||||
|
try {
|
||||||
|
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||||
|
headers: {
|
||||||
|
'X-Parse-Application-Id': appId,
|
||||||
|
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const userId = userRes.data && userRes.data.objectId;
|
||||||
|
if (userId) {
|
||||||
|
if (!extUserId) {
|
||||||
|
return { status: 'error', result: 'Please provide parameter!' };
|
||||||
|
}
|
||||||
|
const invoiceCls = new Parse.Query('contracts_Invoices');
|
||||||
|
invoiceCls.equalTo('ExtUserPtr', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Users',
|
||||||
|
objectId: extUserId,
|
||||||
|
});
|
||||||
|
invoiceCls.limit(limit);
|
||||||
|
invoiceCls.skip(skip);
|
||||||
|
invoiceCls.descending('createdAt');
|
||||||
|
const invoices = await invoiceCls.find({ useMasterKey: true });
|
||||||
|
if (invoices?.length > 0) {
|
||||||
|
const _invoices = JSON.parse(JSON.stringify(invoices));
|
||||||
|
return { status: 'success', result: _invoices };
|
||||||
|
} else {
|
||||||
|
return { status: 'success', result: [] };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { status: 'error', result: 'Invalid session token!' };
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Err in get invoices', err.message);
|
||||||
|
return { status: 'error', result: err.message };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
const serverUrl = process.env.SERVER_URL;
|
||||||
|
const appId = process.env.APP_ID;
|
||||||
|
export default async function getPayments(request) {
|
||||||
|
const limit = request.params.limit || 100;
|
||||||
|
const skip = request.params.skip || 0;
|
||||||
|
const extUserId = request.params.extUserId;
|
||||||
|
try {
|
||||||
|
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||||
|
headers: {
|
||||||
|
'X-Parse-Application-Id': appId,
|
||||||
|
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const userId = userRes.data && userRes.data.objectId;
|
||||||
|
if (userId) {
|
||||||
|
const paymentsCls = new Parse.Query('contracts_Payments');
|
||||||
|
paymentsCls.equalTo('ExtUserPtr', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_User',
|
||||||
|
objectId: extUserId,
|
||||||
|
});
|
||||||
|
paymentsCls.limit(limit);
|
||||||
|
paymentsCls.skip(skip);
|
||||||
|
paymentsCls.descending('createdAt');
|
||||||
|
const payments = await paymentsCls.find({ useMasterKey: true });
|
||||||
|
if (payments?.length > 0) {
|
||||||
|
const _payments = JSON.parse(JSON.stringify(payments));
|
||||||
|
return { status: 'success', result: _payments };
|
||||||
|
} else {
|
||||||
|
return { status: 'success', result: [] };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { status: 'error', result: 'Invalid session token!' };
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Err in get Payments', err.message);
|
||||||
|
return { status: 'error', result: err.message };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ export default async function getReport(request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err', err);
|
console.log('err', err.message);
|
||||||
if (err.code == 209) {
|
if (err.code == 209) {
|
||||||
return { error: 'Invalid session token' };
|
return { error: 'Invalid session token' };
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import AWS from 'aws-sdk';
|
||||||
|
import { useLocal } from '../../Utils.js';
|
||||||
|
const credentials = {
|
||||||
|
accessKeyId: process.env.DO_ACCESS_KEY_ID,
|
||||||
|
secretAccessKey: process.env.DO_SECRET_ACCESS_KEY,
|
||||||
|
};
|
||||||
|
AWS.config.update({ credentials: credentials, region: process.env.DO_REGION });
|
||||||
|
const spacesEndpoint = new AWS.Endpoint(process.env.DO_ENDPOINT);
|
||||||
|
|
||||||
|
const s3 = new AWS.S3({ endpoint: spacesEndpoint });
|
||||||
|
|
||||||
|
export default function getPresignedUrl(url) {
|
||||||
|
// Create a new URL object
|
||||||
|
const parsedUrl = new URL(url);
|
||||||
|
// Get the pathname of the URL
|
||||||
|
const pathname = parsedUrl.pathname;
|
||||||
|
// Extract the filename from the pathname
|
||||||
|
const filename = pathname.substring(pathname.lastIndexOf('/') + 1);
|
||||||
|
|
||||||
|
// presignedGETURL return presignedUrl with expires time
|
||||||
|
const presignedGETURL = s3.getSignedUrl('getObject', {
|
||||||
|
Bucket: process.env.DO_SPACE,
|
||||||
|
Key: filename, //filename
|
||||||
|
Expires: 160, //time to expire in seconds
|
||||||
|
});
|
||||||
|
return presignedGETURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSignedUrl(request) {
|
||||||
|
try {
|
||||||
|
const url = request.params.url;
|
||||||
|
if (!request?.user) {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||||
|
} else {
|
||||||
|
if (useLocal !== 'true') {
|
||||||
|
const presignedUrl = getPresignedUrl(url);
|
||||||
|
return presignedUrl;
|
||||||
|
} else {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('error in getsignedurl', err);
|
||||||
|
const code = err.code || 400;
|
||||||
|
const msg = err.message;
|
||||||
|
const error = new Parse.Error(code, msg);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
const serverUrl = process.env.SERVER_URL;
|
||||||
|
const appId = process.env.APP_ID;
|
||||||
|
export default async function getSubscription(request) {
|
||||||
|
const extUserId = request.params.extUserId || '';
|
||||||
|
const contactId = request.params.contactId || '';
|
||||||
|
|
||||||
|
if (extUserId) {
|
||||||
|
try {
|
||||||
|
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||||
|
headers: {
|
||||||
|
'X-Parse-Application-Id': appId,
|
||||||
|
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const userId = userRes.data && userRes.data.objectId;
|
||||||
|
if (userId) {
|
||||||
|
const extCls = new Parse.Query('contracts_Users');
|
||||||
|
const exUser = await extCls.get(extUserId, { useMasterKey: true });
|
||||||
|
if (exUser) {
|
||||||
|
const subscriptionCls = new Parse.Query('contracts_Subscriptions');
|
||||||
|
subscriptionCls.equalTo('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: exUser.get('TenantId').id,
|
||||||
|
});
|
||||||
|
subscriptionCls.descending('createdAt');
|
||||||
|
const subcripitions = await subscriptionCls.first({ useMasterKey: true });
|
||||||
|
if (subcripitions) {
|
||||||
|
const _subcripitions = JSON.parse(JSON.stringify(subcripitions));
|
||||||
|
return { status: 'success', result: _subcripitions };
|
||||||
|
} else {
|
||||||
|
return { status: 'success', result: {} };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { status: 'error', result: 'User not found!' };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { status: 'error', result: 'Invalid session token!' };
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Err in get subscription', err.message);
|
||||||
|
return { status: 'error', result: err.message };
|
||||||
|
}
|
||||||
|
} else if (contactId) {
|
||||||
|
try {
|
||||||
|
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||||
|
headers: {
|
||||||
|
'X-Parse-Application-Id': appId,
|
||||||
|
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const userId = userRes.data && userRes.data.objectId;
|
||||||
|
if (userId) {
|
||||||
|
const contactCls = new Parse.Query('contracts_Contactbook');
|
||||||
|
const contactUser = await contactCls.get(contactId, { useMasterKey: true });
|
||||||
|
if (contactUser) {
|
||||||
|
const subscriptionCls = new Parse.Query('contracts_Subscriptions');
|
||||||
|
subscriptionCls.equalTo('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: contactUser.get('TenantId').id,
|
||||||
|
});
|
||||||
|
subscriptionCls.descending('createdAt');
|
||||||
|
const subcripitions = await subscriptionCls.first({ useMasterKey: true });
|
||||||
|
|
||||||
|
if (subcripitions) {
|
||||||
|
const _subcripitions = JSON.parse(JSON.stringify(subcripitions));
|
||||||
|
if (_subcripitions.PlanCode === 'freeplan') {
|
||||||
|
return { status: 'success', result: { isSubscribed: false, plan: 'freeplan' } };
|
||||||
|
} else if (_subcripitions?.Next_billing_date?.iso) {
|
||||||
|
if (new Date(_subcripitions.Next_billing_date.iso) > new Date()) {
|
||||||
|
return { status: 'success', result: { isSubscribed: true } };
|
||||||
|
} else {
|
||||||
|
return { status: 'success', result: { isSubscribed: false } };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { status: 'success', result: { isSubscribed: false } };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { status: 'success', result: { isSubscribed: false } };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { status: 'error', result: 'User not found!' };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { status: 'error', result: 'Invalid session token!' };
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Err in get subscription2', err.message);
|
||||||
|
return { status: 'error', result: err.message };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { status: 'error', result: 'Invalid session token!' };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ async function getUserDetails(request) {
|
|||||||
userQuery.equalTo('Email', request.params.email);
|
userQuery.equalTo('Email', request.params.email);
|
||||||
userQuery.include('TenantId');
|
userQuery.include('TenantId');
|
||||||
userQuery.include('UserId');
|
userQuery.include('UserId');
|
||||||
|
userQuery.exclude('google_refresh_token')
|
||||||
if (userId) {
|
if (userId) {
|
||||||
userQuery.equalTo('CreatedBy', { __type: 'Pointer', className: '_User', objectId: userId });
|
userQuery.equalTo('CreatedBy', { __type: 'Pointer', className: '_User', objectId: userId });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,576 @@
|
|||||||
|
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
export default async function GenerateCertificate(docDetails) {
|
||||||
|
const pdfDoc = await PDFDocument.create();
|
||||||
|
const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman);
|
||||||
|
const pngUrl = fs.readFileSync('./logo.png').buffer;
|
||||||
|
const pngImage = await pdfDoc.embedPng(pngUrl);
|
||||||
|
const page = pdfDoc.addPage();
|
||||||
|
const { width, height } = page.getSize();
|
||||||
|
const startX = 15;
|
||||||
|
const startY = 15;
|
||||||
|
const borderColor = rgb(0.12, 0.12, 0.12);
|
||||||
|
const titleColor = rgb(0, 0.2, 0.4); //rgb(0, 0.53, 0.71);
|
||||||
|
const titleUnderline = rgb(0, 0.2, 0.4); // rgb(0.12, 0.12, 0.12);
|
||||||
|
const title = 25;
|
||||||
|
const subtitle = 20;
|
||||||
|
const text = 14;
|
||||||
|
const timeText = 11;
|
||||||
|
const textKeyColor = rgb(0.12, 0.12, 0.12);
|
||||||
|
const textValueColor = rgb(0.3, 0.3, 0.3);
|
||||||
|
const completedAt = new Date();
|
||||||
|
const completedUTCtime = completedAt.toUTCString();
|
||||||
|
const signersCount = docDetails?.Signers?.length || 1;
|
||||||
|
const generateAt = new Date();
|
||||||
|
const generatedUTCTime = generateAt.toUTCString();
|
||||||
|
const generatedOn = 'Generated On ' + generatedUTCTime;
|
||||||
|
const OriginIp = docDetails?.OriginIp || '';
|
||||||
|
const company = docDetails?.ExtUserPtr?.Company || '';
|
||||||
|
const createdAt = docDetails?.DocSentAt?.iso || docDetails.createdAt;
|
||||||
|
const auditTrail =
|
||||||
|
docDetails.AuditTrail?.length > 1
|
||||||
|
? docDetails.AuditTrail.map(x => {
|
||||||
|
const data = docDetails.Signers.find(y => y.objectId === x.UserPtr.objectId);
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
ipAddress: x.ipAddress,
|
||||||
|
SignedOn: x?.SignedOn || generatedUTCTime,
|
||||||
|
ViewedOn: x?.ViewedOn || x?.SignedOn || generatedUTCTime,
|
||||||
|
Signature: x?.Signature || '',
|
||||||
|
};
|
||||||
|
})
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
...docDetails.ExtUserPtr,
|
||||||
|
ipAddress: docDetails?.AuditTrail[0].ipAddress,
|
||||||
|
SignedOn: docDetails?.AuditTrail[0]?.SignedOn || generatedUTCTime,
|
||||||
|
ViewedOn:
|
||||||
|
docDetails?.AuditTrail[0]?.ViewedOn ||
|
||||||
|
docDetails?.AuditTrail[0]?.SignedOn ||
|
||||||
|
generatedUTCTime,
|
||||||
|
Signature: docDetails?.AuditTrail[0]?.Signature || '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const half = width / 2;
|
||||||
|
// Draw a border
|
||||||
|
page.drawRectangle({
|
||||||
|
x: startX,
|
||||||
|
y: startY,
|
||||||
|
width: width - 2 * startX,
|
||||||
|
height: height - 2 * startY,
|
||||||
|
borderColor: borderColor,
|
||||||
|
borderWidth: 1,
|
||||||
|
});
|
||||||
|
page.drawImage(pngImage, {
|
||||||
|
x: 30,
|
||||||
|
y: 790,
|
||||||
|
width: 100,
|
||||||
|
height: 25,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText(generatedOn, {
|
||||||
|
x: 320,
|
||||||
|
y: 810,
|
||||||
|
size: 12,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: rgb(0.12, 0.12, 0.12),
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText('Certificate of Completion', {
|
||||||
|
x: 160,
|
||||||
|
y: 750,
|
||||||
|
size: title,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: titleColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
const underlineY = 740;
|
||||||
|
page.drawLine({
|
||||||
|
start: { x: 30, y: underlineY },
|
||||||
|
end: { x: width - 30, y: underlineY },
|
||||||
|
color: titleUnderline,
|
||||||
|
thickness: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText('Summary', {
|
||||||
|
x: 30,
|
||||||
|
y: 710,
|
||||||
|
size: subtitle,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: titleColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText('Document Id :', {
|
||||||
|
x: 30,
|
||||||
|
y: 685,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText(docDetails.objectId, {
|
||||||
|
x: 115,
|
||||||
|
y: 685,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText('Document Name :', {
|
||||||
|
x: 30,
|
||||||
|
y: 665,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText(docDetails.Name, {
|
||||||
|
x: 140,
|
||||||
|
y: 665,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText('Organization :', {
|
||||||
|
x: 30,
|
||||||
|
y: 645,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText(company, {
|
||||||
|
x: 115,
|
||||||
|
y: 645,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
page.drawText('Created on :', {
|
||||||
|
x: 30,
|
||||||
|
y: 625,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText(`${new Date(createdAt).toUTCString()}`, {
|
||||||
|
x: 105,
|
||||||
|
y: 625,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
page.drawText('Completed on :', {
|
||||||
|
x: 30,
|
||||||
|
y: 605,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText(`${completedUTCtime}`, {
|
||||||
|
x: 125,
|
||||||
|
y: 605,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
page.drawText('Signers :', {
|
||||||
|
x: 30,
|
||||||
|
y: 585,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText(`${signersCount}`, {
|
||||||
|
x: 80,
|
||||||
|
y: 585,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
page.drawText('Document originator', {
|
||||||
|
x: 30,
|
||||||
|
y: 565,
|
||||||
|
size: 17,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: titleColor,
|
||||||
|
});
|
||||||
|
page.drawText('Name :', {
|
||||||
|
x: 60,
|
||||||
|
y: 545,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
page.drawText(`${docDetails.ExtUserPtr.Name}`, {
|
||||||
|
x: 105,
|
||||||
|
y: 545,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
page.drawText('Email :', {
|
||||||
|
x: 60,
|
||||||
|
y: 525,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
page.drawText(`${docDetails.ExtUserPtr.Email}`, {
|
||||||
|
x: 105,
|
||||||
|
y: 525,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
page.drawText('IP address :', {
|
||||||
|
x: 60,
|
||||||
|
y: 505,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
page.drawText(`${OriginIp}`, {
|
||||||
|
x: 130,
|
||||||
|
y: 505,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawLine({
|
||||||
|
start: { x: 30, y: 495 },
|
||||||
|
end: { x: width - 30, y: 495 },
|
||||||
|
color: rgb(0.12, 0.12, 0.12),
|
||||||
|
thickness: 0.5,
|
||||||
|
});
|
||||||
|
let yPosition1 = 475;
|
||||||
|
let yPosition2 = 455;
|
||||||
|
let yPosition3 = 435;
|
||||||
|
let yPosition4 = 415;
|
||||||
|
let yPosition5 = 395;
|
||||||
|
let yPosition6 = 360;
|
||||||
|
auditTrail.slice(0, 3).forEach(async (x, i) => {
|
||||||
|
const embedPng = x.Signature ? await pdfDoc.embedPng(x.Signature) : '';
|
||||||
|
page.drawText(`Signer ${i + 1}`, {
|
||||||
|
x: 30,
|
||||||
|
y: yPosition1,
|
||||||
|
size: subtitle,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: titleColor,
|
||||||
|
});
|
||||||
|
page.drawText('Name :', {
|
||||||
|
x: 30,
|
||||||
|
y: yPosition2,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText(x?.Name, {
|
||||||
|
x: 75,
|
||||||
|
y: yPosition2,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText('Viewed on :', {
|
||||||
|
x: half +55,
|
||||||
|
y: yPosition2,
|
||||||
|
size: timeText,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText(`${new Date(x.ViewedOn).toUTCString()}`, {
|
||||||
|
x: half + 112,
|
||||||
|
y: yPosition2,
|
||||||
|
size: timeText,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText('Email :', {
|
||||||
|
x: 30,
|
||||||
|
y: yPosition3,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText(x?.Email, {
|
||||||
|
x: 75,
|
||||||
|
y: yPosition3,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText('Signed on :', {
|
||||||
|
x: half + 55,
|
||||||
|
y: yPosition3 + 5,
|
||||||
|
size: timeText,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText(`${new Date(x.SignedOn).toUTCString()}`, {
|
||||||
|
x: half + 108,
|
||||||
|
y: yPosition3 + 5,
|
||||||
|
size: timeText,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText('IP address :', {
|
||||||
|
x: 30,
|
||||||
|
y: yPosition4,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText(x?.ipAddress, {
|
||||||
|
x: 100,
|
||||||
|
y: yPosition4,
|
||||||
|
size: 13,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
page.drawText('Security level :', {
|
||||||
|
x: half + 55,
|
||||||
|
y: yPosition4 + 10,
|
||||||
|
size: timeText,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText(`Email, OTP Auth`, {
|
||||||
|
x: half + 125,
|
||||||
|
y: yPosition4 + 10,
|
||||||
|
size: timeText,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawText('Signature :', {
|
||||||
|
x: 30,
|
||||||
|
y: yPosition5,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
page.drawRectangle({
|
||||||
|
x: 98,
|
||||||
|
y: yPosition5 - 30,
|
||||||
|
width: 104,
|
||||||
|
height: 44,
|
||||||
|
borderColor: rgb(0.22, 0.18, 0.47),
|
||||||
|
borderWidth: 1,
|
||||||
|
});
|
||||||
|
if (embedPng) {
|
||||||
|
page.drawImage(embedPng, {
|
||||||
|
x: 100,
|
||||||
|
y: yPosition5 - 27,
|
||||||
|
width: 100,
|
||||||
|
height: 40,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
page.drawLine({
|
||||||
|
start: { x: 30, y: yPosition6 },
|
||||||
|
end: { x: width - 30, y: yPosition6 },
|
||||||
|
color: rgb(0.12, 0.12, 0.12),
|
||||||
|
thickness: 0.5,
|
||||||
|
});
|
||||||
|
|
||||||
|
yPosition1 = yPosition6 - 20;
|
||||||
|
yPosition2 = yPosition1 - 20;
|
||||||
|
yPosition3 = yPosition2 - 20;
|
||||||
|
yPosition4 = yPosition3 - 20;
|
||||||
|
yPosition5 = yPosition4 - 20;
|
||||||
|
yPosition6 = yPosition6 - 140;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (auditTrail.length > 3) {
|
||||||
|
let currentPageIndex = 1;
|
||||||
|
let currentPage = page;
|
||||||
|
auditTrail.slice(3).forEach(async (x, i) => {
|
||||||
|
const embedPng = x.Signature ? await pdfDoc.embedPng(x.Signature) : '';
|
||||||
|
|
||||||
|
// Calculate remaining space on current page
|
||||||
|
const remainingSpace = yPosition6;
|
||||||
|
|
||||||
|
// If there's not enough space for the next entry, create a new page
|
||||||
|
if (remainingSpace < 90) {
|
||||||
|
// Adjust the value as needed
|
||||||
|
currentPageIndex++;
|
||||||
|
currentPage = pdfDoc.addPage();
|
||||||
|
currentPage.drawRectangle({
|
||||||
|
x: startX,
|
||||||
|
y: startY,
|
||||||
|
width: width - 2 * startX,
|
||||||
|
height: height - 2 * startY,
|
||||||
|
borderColor: borderColor,
|
||||||
|
borderWidth: 1,
|
||||||
|
});
|
||||||
|
yPosition1 = currentPage.getHeight() - 40;
|
||||||
|
yPosition2 = yPosition1 - 20;
|
||||||
|
yPosition3 = yPosition2 - 20;
|
||||||
|
yPosition4 = yPosition3 - 20;
|
||||||
|
yPosition5 = yPosition4 - 20;
|
||||||
|
yPosition6 = currentPage.getHeight() - 160;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPage.drawText(`Signer ${4 + i}`, {
|
||||||
|
x: 30,
|
||||||
|
y: yPosition1,
|
||||||
|
size: subtitle,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: titleColor,
|
||||||
|
});
|
||||||
|
currentPage.drawText('Name :', {
|
||||||
|
x: 30,
|
||||||
|
y: yPosition2,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
currentPage.drawText(x?.Name, {
|
||||||
|
x: 75,
|
||||||
|
y: yPosition2,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
currentPage.drawText('Viewed on :', {
|
||||||
|
x: half,
|
||||||
|
y: yPosition2,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
currentPage.drawText(`${new Date(x.ViewedOn).toUTCString()}`, {
|
||||||
|
x: half + 75,
|
||||||
|
y: yPosition2,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
currentPage.drawText('Email :', {
|
||||||
|
x: 30,
|
||||||
|
y: yPosition3,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
currentPage.drawText(x?.Email, {
|
||||||
|
x: 75,
|
||||||
|
y: yPosition3,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
currentPage.drawText('Signed on :', {
|
||||||
|
x: half,
|
||||||
|
y: yPosition3,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
currentPage.drawText(`${new Date(x.SignedOn).toUTCString()}`, {
|
||||||
|
x: half + 70,
|
||||||
|
y: yPosition3,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
currentPage.drawText('IP address :', {
|
||||||
|
x: 30,
|
||||||
|
y: yPosition4,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
currentPage.drawText(x?.ipAddress, {
|
||||||
|
x: 100,
|
||||||
|
y: yPosition4,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
currentPage.drawText('Security level :', {
|
||||||
|
x: half,
|
||||||
|
y: yPosition4,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
currentPage.drawText(`Email, OTP Auth`, {
|
||||||
|
x: half + 90,
|
||||||
|
y: yPosition4,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textValueColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
currentPage.drawText('Signature :', {
|
||||||
|
x: 30,
|
||||||
|
y: yPosition5,
|
||||||
|
size: text,
|
||||||
|
font: timesRomanFont,
|
||||||
|
color: textKeyColor,
|
||||||
|
});
|
||||||
|
currentPage.drawRectangle({
|
||||||
|
x: 98,
|
||||||
|
y: yPosition5 - 27,
|
||||||
|
width: 104,
|
||||||
|
height: 44,
|
||||||
|
borderColor: rgb(0.22, 0.18, 0.47),
|
||||||
|
borderWidth: 1,
|
||||||
|
});
|
||||||
|
if (embedPng) {
|
||||||
|
currentPage.drawImage(embedPng, {
|
||||||
|
x: 100,
|
||||||
|
y: yPosition5 - 25,
|
||||||
|
width: 100,
|
||||||
|
height: 40,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPage.drawLine({
|
||||||
|
start: { x: 30, y: yPosition6 },
|
||||||
|
end: { x: width - 30, y: yPosition6 },
|
||||||
|
color: rgb(0.12, 0.12, 0.12),
|
||||||
|
thickness: 0.5,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update y positions for the next entry
|
||||||
|
yPosition1 = yPosition6 - 20;
|
||||||
|
yPosition2 = yPosition1 - 20;
|
||||||
|
yPosition3 = yPosition2 - 20;
|
||||||
|
yPosition4 = yPosition3 - 20;
|
||||||
|
yPosition5 = yPosition4 - 20;
|
||||||
|
yPosition6 = yPosition6 - 140;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const pdfBytes = await pdfDoc.save();
|
||||||
|
return pdfBytes;
|
||||||
|
}
|
||||||
+258
-223
@@ -3,67 +3,119 @@ import fs from 'node:fs';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { pdflibAddPlaceholder } from './customSignPdf/pdflibplaceholder.min.js';
|
import { pdflibAddPlaceholder } from './customSignPdf/pdflibplaceholder.min.js';
|
||||||
import { PDFDocument } from 'pdf-lib';
|
import { PDFDocument } from 'pdf-lib';
|
||||||
import { saveFileUsage } from '../../../Utils.js';
|
import { replaceMailVaribles, saveFileUsage } from '../../../Utils.js';
|
||||||
|
import GenerateCertificate from './GenerateCertificate.js';
|
||||||
const serverUrl = process.env.SERVER_URL,
|
const serverUrl = process.env.SERVER_URL,
|
||||||
APPID = process.env.APP_ID,
|
APPID = process.env.APP_ID,
|
||||||
masterKEY = process.env.MASTER_KEY;
|
masterKEY = process.env.MASTER_KEY;
|
||||||
async function uploadFile(e, a) {
|
async function uploadFile(e, t) {
|
||||||
try {
|
try {
|
||||||
var t = fs.readFileSync(a),
|
var a = fs.readFileSync(t),
|
||||||
s = new Parse.File(e, [...t]),
|
r = new Parse.File(e, [...a], 'application/pdf'),
|
||||||
r = (await s.save({ useMasterKey: !0 }), s.url());
|
i = (await r.save({ useMasterKey: !0 }), r.url());
|
||||||
return { imageUrl: r };
|
return { imageUrl: i };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('Err ', e), fs.unlinkSync(a);
|
console.log('Err ', e), fs.unlinkSync(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function updateDoc(t, s, r, o, i, n) {
|
async function updateDoc(a, r, i, s, o, n, l) {
|
||||||
try {
|
try {
|
||||||
var d = {
|
var c,
|
||||||
UserPtr: { __type: 'Pointer', className: n, objectId: r },
|
d,
|
||||||
SignedUrl: s,
|
p = {
|
||||||
Activity: 'Signed',
|
UserPtr: { __type: 'Pointer', className: n, objectId: i },
|
||||||
ipAddress: o,
|
SignedUrl: r,
|
||||||
};
|
Activity: 'Signed',
|
||||||
|
ipAddress: s,
|
||||||
|
SignedOn: new Date(),
|
||||||
|
Signature: l,
|
||||||
|
};
|
||||||
let e;
|
let e;
|
||||||
var l = (e = i.AuditTrail && 0 < i.AuditTrail.length ? [...i.AuditTrail, d] : [d]).filter(
|
var m = (e =
|
||||||
e => 'Signed' === e.Activity
|
o.AuditTrail && 0 < o.AuditTrail.length
|
||||||
);
|
? (-1 !==
|
||||||
let a = !1;
|
(d = (c = JSON.parse(JSON.stringify(o.AuditTrail))).findIndex(
|
||||||
!((i.Signers && 0 < i.Signers.length && l.length !== i.Signers.length) || !(a = !0));
|
e => e.UserPtr.objectId === i && 'Created' !== e.Activity
|
||||||
var c = { SignedUrl: s, AuditTrail: e, IsCompleted: a };
|
))
|
||||||
await axios.put(serverUrl + '/classes/contracts_Document/' + t, c, {
|
? (c[d] = { ...c[d], ...p })
|
||||||
|
: c.push(p),
|
||||||
|
c)
|
||||||
|
: [p]).filter(e => 'Signed' === e.Activity);
|
||||||
|
let t = !1;
|
||||||
|
!((o.Signers && 0 < o.Signers.length && m.length !== o.Signers.length) || !(t = !0));
|
||||||
|
var g = { SignedUrl: r, AuditTrail: e, IsCompleted: t };
|
||||||
|
await axios.put(serverUrl + '/classes/contracts_Document/' + a, g, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'X-Parse-Application-Id': APPID,
|
'X-Parse-Application-Id': APPID,
|
||||||
'X-Parse-Master-Key': masterKEY,
|
'X-Parse-Master-Key': masterKEY,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return { isCompleted: a, message: 'success' };
|
return { isCompleted: t, message: 'success', AuditTrail: e };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return console.log('update doc err ', e), 'err';
|
return console.log('update doc err ', e), 'err';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function sendCompletedMail(e) {
|
async function sendCompletedMail(e) {
|
||||||
var a = e.url,
|
var t = e.url,
|
||||||
t = e.sender,
|
a = e.doc,
|
||||||
s = e.pdfName,
|
r = e.doc.ExtUserPtr,
|
||||||
r = e.receiver,
|
i = a.Name,
|
||||||
e = {
|
s = r.Email;
|
||||||
extUserId: e.extUserId,
|
let o = `Document "${i}" has been signed by all parties`,
|
||||||
url: a,
|
n =
|
||||||
from: 'OpenSign™',
|
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=https://qikinnovation.ams3.digitaloceanspaces.com/logo.png height='50' style='padding:20px'/> </div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document signed successfully</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>All parties have successfully signed the document " +
|
||||||
recipient: r,
|
`<b>"${i}"</b>` +
|
||||||
subject: `Document ${s} has been signed by all parties`,
|
'. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender ' +
|
||||||
pdfName: s,
|
r.Email +
|
||||||
html:
|
' directly. If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>';
|
||||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=https://qikinnovation.ams3.digitaloceanspaces.com/logo.png height='50' style='padding:20px'/> </div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document sign successfully</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>All parties have successfully signed the document" +
|
if (e?.isCustomMail)
|
||||||
s +
|
try {
|
||||||
'. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender ' +
|
var l,
|
||||||
t.Mail +
|
c,
|
||||||
' directly. If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>',
|
d,
|
||||||
};
|
p,
|
||||||
await axios.post(serverUrl + '/functions/sendmailv3', e, {
|
m,
|
||||||
|
g = new Parse.Query('partners_Tenant');
|
||||||
|
g.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: r.UserId.objectId });
|
||||||
|
const f = await g.first();
|
||||||
|
f &&
|
||||||
|
((l = JSON.parse(JSON.stringify(f)))?.CompletionSubject && (o = l?.CompletionSubject),
|
||||||
|
l?.CompletionBody && (n = l?.CompletionBody),
|
||||||
|
(c = a.ExpiryDate.iso),
|
||||||
|
(d = new Date(c).toLocaleDateString('en-US', {
|
||||||
|
day: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
year: 'numeric',
|
||||||
|
})),
|
||||||
|
(p = {
|
||||||
|
document_title: i,
|
||||||
|
sender_name: r.Name,
|
||||||
|
sender_mail: r.Email,
|
||||||
|
sender_phone: r.Phone,
|
||||||
|
receiver_name: r.Name,
|
||||||
|
receiver_email: r.Email,
|
||||||
|
receiver_phone: r.Phone,
|
||||||
|
expiry_date: d,
|
||||||
|
company_name: r.Company,
|
||||||
|
}),
|
||||||
|
(m = replaceMailVaribles(o, n, p)),
|
||||||
|
(o = m.subject),
|
||||||
|
(n = m.body));
|
||||||
|
} catch (e) {
|
||||||
|
console.log('error in fetch tenant in signpdf', e.message);
|
||||||
|
}
|
||||||
|
g = {
|
||||||
|
extUserId: r.objectId,
|
||||||
|
url: t,
|
||||||
|
from: 'OpenSign™',
|
||||||
|
recipient: s,
|
||||||
|
subject: o,
|
||||||
|
pdfName: i,
|
||||||
|
html: n,
|
||||||
|
mailProvider: e.mailProvider,
|
||||||
|
};
|
||||||
|
await axios.post(serverUrl + '/functions/sendmailv3', g, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'X-Parse-Application-Id': APPID,
|
'X-Parse-Application-Id': APPID,
|
||||||
@@ -71,220 +123,203 @@ async function sendCompletedMail(e) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async function sendDoctoWebhook(t, e, a, s) {
|
async function sendDoctoWebhook(a, e, t, r) {
|
||||||
let r = [];
|
let i = [];
|
||||||
(r = s
|
(i = r
|
||||||
? { name: s?.Name, email: s?.Email, phone: s?.Phone }
|
? { name: r?.Name, email: r?.Email, phone: r?.Phone }
|
||||||
: t?.data?.Signers?.map(e => ({ name: e.Name, email: e.Email, phone: e.Phone })) || [
|
: a?.Signers?.map(e => ({ name: e.Name, email: e.Email, phone: e.Phone })) || [
|
||||||
{
|
{ name: a?.ExtUserPtr?.Name, email: a?.ExtUserPtr?.Email, phone: a?.ExtUserPtr?.Phone },
|
||||||
name: t?.data?.ExtUserPtr?.Name,
|
|
||||||
email: t?.data?.ExtUserPtr?.Email,
|
|
||||||
phone: t?.data?.ExtUserPtr?.Phone,
|
|
||||||
},
|
|
||||||
]),
|
]),
|
||||||
t.data.ExtUserPtr?.Webhook &&
|
a.ExtUserPtr?.Webhook &&
|
||||||
((s =
|
((r =
|
||||||
'signed' === a
|
'signed' === t
|
||||||
? { signer: r, signedAt: new Date() }
|
? { signer: i, signedAt: new Date() }
|
||||||
: { signers: r, completedAt: new Date() }),
|
: { signers: i, completedAt: new Date() }),
|
||||||
(a = {
|
(t = {
|
||||||
event: a,
|
event: t,
|
||||||
objectId: t?.data?.objectId,
|
objectId: a?.objectId,
|
||||||
file: e || '',
|
file: e || '',
|
||||||
name: t?.data?.Name,
|
name: a?.Name,
|
||||||
note: t?.data?.Note || '',
|
note: a?.Note || '',
|
||||||
description: t?.data?.Description || '',
|
description: a?.Description || '',
|
||||||
...s,
|
...r,
|
||||||
createdAt: t?.data?.createdAt,
|
createdAt: a?.createdAt,
|
||||||
}),
|
}),
|
||||||
await axios
|
axios
|
||||||
.post(t?.data?.ExtUserPtr?.Webhook, a, { headers: { 'Content-Type': 'application/json' } })
|
.post(a?.ExtUserPtr?.Webhook, t, { headers: { 'Content-Type': 'application/json' } })
|
||||||
.then(e => {
|
.then(e => {
|
||||||
try {
|
try {
|
||||||
var a = new Parse.Object('contracts_Webhook');
|
var t = new Parse.Object('contracts_Webhook');
|
||||||
a.set('Log', e?.status),
|
t.set('Log', e?.status),
|
||||||
a.set('UserId', {
|
t.set('UserId', {
|
||||||
__type: 'Pointer',
|
__type: 'Pointer',
|
||||||
className: '_User',
|
className: '_User',
|
||||||
objectId: t.data.ExtUserPtr.UserId.objectId,
|
objectId: a.ExtUserPtr.UserId.objectId,
|
||||||
}),
|
}),
|
||||||
a.save(null, { useMasterKey: !0 });
|
t.save(null, { useMasterKey: !0 });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('err save in contracts_Webhook', e);
|
console.log('err save in contracts_Webhook', e.message);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
console.log('Err send data to webhook', e);
|
console.log('Err send data to webhook', e.message);
|
||||||
try {
|
try {
|
||||||
var a = new Parse.Object('contracts_Webhook');
|
var t = new Parse.Object('contracts_Webhook');
|
||||||
a.set('Log', e?.status),
|
t.set('Log', e?.status),
|
||||||
a.set('UserId', {
|
t.set('UserId', {
|
||||||
__type: 'Pointer',
|
__type: 'Pointer',
|
||||||
className: '_User',
|
className: '_User',
|
||||||
objectId: t.data.ExtUserPtr.UserId.objectId,
|
objectId: a.ExtUserPtr.UserId.objectId,
|
||||||
}),
|
}),
|
||||||
a.save(null, { useMasterKey: !0 });
|
t.save(null, { useMasterKey: !0 });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('err save in contracts_Webhook', e);
|
console.log('err save in contracts_Webhook', e.message);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
async function PDF(i) {
|
const sendMailsaveCertifcate = async (e, t, a, r, i, s) => {
|
||||||
|
var o = await GenerateCertificate(e),
|
||||||
|
o = await PDFDocument.load(o),
|
||||||
|
o =
|
||||||
|
(pdflibAddPlaceholder({
|
||||||
|
pdfDoc: o,
|
||||||
|
reason: 'Digitally signed by OpenSign.',
|
||||||
|
location: 'n/a',
|
||||||
|
signatureLength: 15e3,
|
||||||
|
}),
|
||||||
|
await o.save()),
|
||||||
|
o = Buffer.from(o),
|
||||||
|
t = await new SignPDF(o, t).signPDF(),
|
||||||
|
t =
|
||||||
|
(fs.writeFileSync('./exports/certificate.pdf', t),
|
||||||
|
await uploadFile('certificate.pdf', './exports/certificate.pdf')),
|
||||||
|
n = { CertificateUrl: t.imageUrl };
|
||||||
|
await axios.put(serverUrl + '/classes/contracts_Document/' + e.objectId, n, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Parse-Application-Id': APPID,
|
||||||
|
'X-Parse-Master-Key': masterKEY,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
e.IsSendMail && !1 === e.IsSendMail
|
||||||
|
? console.log("don't send mail")
|
||||||
|
: sendCompletedMail({ url: a, isCustomMail: r, doc: e, mailProvider: i }),
|
||||||
|
saveFileUsage(o.length, t.imageUrl, s),
|
||||||
|
sendDoctoWebhook(e, a, 'completed');
|
||||||
|
};
|
||||||
|
async function PDF(o) {
|
||||||
try {
|
try {
|
||||||
var e = i.params.docId,
|
if (!o?.user)
|
||||||
a = i.params.userId,
|
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
|
||||||
n = await axios.get(
|
|
||||||
serverUrl + '/classes/contracts_Document/' + e + '?include=ExtUserPtr,Signers',
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-Parse-Application-Id': APPID,
|
|
||||||
'X-Parse-Master-Key': masterKEY,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
),
|
|
||||||
d = await axios.get(serverUrl + '/users/me', {
|
|
||||||
headers: {
|
|
||||||
'X-Parse-Application-Id': APPID,
|
|
||||||
'X-Parse-Session-Token': i.headers.sessiontoken,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!d.data || !d.data.objectId) return { status: 'error', message: 'This user not allowed!' };
|
|
||||||
{
|
{
|
||||||
var t,
|
var n = o?.user?.toJSON(),
|
||||||
s,
|
e = o.params.docId;
|
||||||
l,
|
const F = o.params.userId;
|
||||||
c = JSON.stringify({ objectId: a });
|
var l = o.params.isCustomCompletionMail || !1,
|
||||||
let r, o;
|
c = o.params.mailProvider || '',
|
||||||
o = a
|
d = o.params.signature || '',
|
||||||
? (t = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + c, {
|
t = new Parse.Query('contracts_Document'),
|
||||||
headers: {
|
a =
|
||||||
'X-Parse-Application-Id': APPID,
|
(t.include('ExtUserPtr,Signers'),
|
||||||
'X-Parse-Session-Token': i.headers.sessiontoken,
|
t.equalTo('objectId', e),
|
||||||
},
|
await t.first({ useMasterKey: !0 }));
|
||||||
})).data && 0 < t.data.results.length
|
if (!a) throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Document not found.');
|
||||||
? ((r = t), 'contracts_Contactbook')
|
var r,
|
||||||
: ((r = await axios.get(serverUrl + '/classes/contracts_Users?where=' + c, {
|
p = a?.toJSON();
|
||||||
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
|
let i, s;
|
||||||
})),
|
F
|
||||||
'contracts_Users')
|
? ((r = p.Signers.find(e => e.objectId === F)),
|
||||||
: ((s = JSON.stringify({
|
console.log('_contractUser ', r),
|
||||||
UserId: { __type: 'Pointer', className: '_User', objectId: d.data.objectId },
|
r && ((i = r), (s = 'contracts_Contactbook')))
|
||||||
})),
|
: ((s = 'contracts_Users'), (i = p.ExtUserPtr));
|
||||||
(l = await axios.get(serverUrl + '/classes/contracts_Users?where=' + s, {
|
var m,
|
||||||
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
|
g = i.Name,
|
||||||
})).data && 0 < l.data.results.length
|
f = i.Email;
|
||||||
? ((r = l), 'contracts_Users')
|
if (!o.params.pdfFile) throw (((m = new Error('Pdf file not present!')).code = 400), m);
|
||||||
: ((r = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + s, {
|
|
||||||
headers: {
|
|
||||||
'X-Parse-Application-Id': APPID,
|
|
||||||
'X-Parse-Session-Token': i.headers.sessiontoken,
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
'contracts_Contactbook'));
|
|
||||||
var p = r.data.results[0].Name,
|
|
||||||
m = r.data.results[0].Email;
|
|
||||||
if (!i.params.pdfFile) return { status: 'error', message: 'pdf file not present!' };
|
|
||||||
{
|
{
|
||||||
let e = Buffer.from(i.params.pdfFile, 'base64');
|
let e = Buffer.from(o.params.pdfFile, 'base64');
|
||||||
var g = process.env.PFX_BASE64,
|
var u = process.env.PFX_BASE64,
|
||||||
u = Buffer.from(g, 'base64'),
|
h = Buffer.from(u, 'base64'),
|
||||||
h = {
|
y = {
|
||||||
UserPtr: { __type: 'Pointer', className: o, objectId: r.data.results[0].objectId },
|
UserPtr: { __type: 'Pointer', className: s, objectId: i.objectId },
|
||||||
SignedUrl: '',
|
SignedUrl: '',
|
||||||
Activity: 'Signed',
|
Activity: 'Signed',
|
||||||
ipAddress: i.headers['x-real-ip'],
|
ipAddress: o.headers['x-real-ip'],
|
||||||
};
|
};
|
||||||
let a;
|
let t;
|
||||||
var f = (a =
|
var P = (t = p.AuditTrail && 0 < p.AuditTrail.length ? [...p.AuditTrail, y] : [y]).filter(
|
||||||
n.data.AuditTrail && 0 < n.data.AuditTrail.length
|
e => 'Signed' === e.Activity
|
||||||
? [...n.data.AuditTrail, h]
|
|
||||||
: [h]).filter(e => 'Signed' === e.Activity);
|
|
||||||
let t = !1;
|
|
||||||
!(
|
|
||||||
(n.data.Signers && 0 < n.data.Signers.length && f.length !== n.data.Signers.length) ||
|
|
||||||
!(t = !0)
|
|
||||||
);
|
);
|
||||||
var P,
|
let a = !1;
|
||||||
y,
|
!((p.Signers && 0 < p.Signers.length && P.length !== p.Signers.length) || !(a = !0));
|
||||||
v,
|
var v,
|
||||||
U,
|
|
||||||
b,
|
b,
|
||||||
I,
|
S,
|
||||||
S = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`,
|
|
||||||
x = './exports/' + S;
|
|
||||||
let s = e.length;
|
|
||||||
s = (
|
|
||||||
t
|
|
||||||
? ((P = n.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')),
|
|
||||||
(e =
|
|
||||||
P && 0 < P.length
|
|
||||||
? ((y = await PDFDocument.load(e)),
|
|
||||||
pdflibAddPlaceholder({
|
|
||||||
pdfDoc: y,
|
|
||||||
reason: 'Digitally signed by OpenSign for ' + P?.join(', '),
|
|
||||||
location: 'location',
|
|
||||||
signatureLength: 15e3,
|
|
||||||
}),
|
|
||||||
(v = await y.save()),
|
|
||||||
Buffer.from(v))
|
|
||||||
: ((U = await PDFDocument.load(e)),
|
|
||||||
pdflibAddPlaceholder({
|
|
||||||
pdfDoc: U,
|
|
||||||
reason: 'Digitally signed by OpenSign for ' + p + ' <' + m + '>',
|
|
||||||
location: 'location',
|
|
||||||
signatureLength: 15e3,
|
|
||||||
}),
|
|
||||||
(b = await U.save()),
|
|
||||||
Buffer.from(b))),
|
|
||||||
(I = await new SignPDF(e, u).signPDF()),
|
|
||||||
fs.writeFileSync(x, I),
|
|
||||||
I)
|
|
||||||
: (fs.writeFileSync(x, e), e)
|
|
||||||
).length;
|
|
||||||
var A,
|
|
||||||
w,
|
w,
|
||||||
D = await uploadFile(S, x);
|
U,
|
||||||
if (D && D.imageUrl)
|
D,
|
||||||
return (
|
I = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`,
|
||||||
(A = await updateDoc(
|
_ = './exports/' + I;
|
||||||
i.params.docId,
|
let r = e.length;
|
||||||
D.imageUrl,
|
r = (
|
||||||
r.data.results[0].objectId,
|
a
|
||||||
i.headers['x-real-ip'],
|
? ((v = p.Signers?.map(e => e.Name + ' <' + e.Email + '>')),
|
||||||
n.data,
|
(e =
|
||||||
o
|
v && 0 < v.length
|
||||||
)),
|
? ((b = await PDFDocument.load(e)),
|
||||||
sendDoctoWebhook(n, D.imageUrl, 'signed', r?.data.results?.[0]),
|
pdflibAddPlaceholder({
|
||||||
saveFileUsage(s, D.imageUrl, d.data.objectId),
|
pdfDoc: b,
|
||||||
A &&
|
reason: 'Digitally signed by OpenSign for ' + v?.join(', '),
|
||||||
A.isCompleted &&
|
location: 'n/a',
|
||||||
((w = {
|
signatureLength: 15e3,
|
||||||
url: D.imageUrl,
|
}),
|
||||||
sender: { Mail: n.data.ExtUserPtr.Email, Name: 'OpenSign™' },
|
(S = await b.save()),
|
||||||
pdfName: n.data.Name,
|
Buffer.from(S))
|
||||||
receiver: n.data.ExtUserPtr.Email,
|
: ((w = await PDFDocument.load(e)),
|
||||||
extUserId: n.data.ExtUserPtr.objectId,
|
pdflibAddPlaceholder({
|
||||||
}),
|
pdfDoc: w,
|
||||||
n.data.IsSendMail && !1 === n.data.IsSendMail
|
reason: 'Digitally signed by OpenSign for ' + g + ' <' + f + '>',
|
||||||
? console.log("don't send mail")
|
location: 'n/a',
|
||||||
: sendCompletedMail(w),
|
signatureLength: 15e3,
|
||||||
sendDoctoWebhook(n, D.imageUrl, 'completed')),
|
}),
|
||||||
fs.unlinkSync(x),
|
(U = await w.save()),
|
||||||
console.log('New Signed PDF created called: ' + x),
|
Buffer.from(U))),
|
||||||
'success' === A.message
|
(D = await new SignPDF(e, h).signPDF()),
|
||||||
? { status: 'success', data: D.imageUrl }
|
fs.writeFileSync(_, D),
|
||||||
: { status: 'error', message: 'please provide required parameters!' }
|
D)
|
||||||
);
|
: (fs.writeFileSync(_, e), e)
|
||||||
|
).length;
|
||||||
|
var E = await uploadFile(I, _);
|
||||||
|
if (E && E.imageUrl) {
|
||||||
|
var x,
|
||||||
|
A,
|
||||||
|
j = await updateDoc(
|
||||||
|
o.params.docId,
|
||||||
|
E.imageUrl,
|
||||||
|
i.objectId,
|
||||||
|
o.headers['x-real-ip'],
|
||||||
|
p,
|
||||||
|
s,
|
||||||
|
d
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
(sendDoctoWebhook(p, E.imageUrl, 'signed', i),
|
||||||
|
saveFileUsage(r, E.imageUrl, n.objectId),
|
||||||
|
j &&
|
||||||
|
j.isCompleted &&
|
||||||
|
((x = { ...p, AuditTrail: j.AuditTrail }),
|
||||||
|
sendMailsaveCertifcate(x, h, E.imageUrl, l, c, n.objectId)),
|
||||||
|
fs.unlinkSync(_),
|
||||||
|
console.log('New Signed PDF created called: ' + _),
|
||||||
|
'success' === j.message)
|
||||||
|
)
|
||||||
|
return { status: 'success', data: E.imageUrl };
|
||||||
|
throw (((A = new Error('Please provide required parameters!')).code = 400), A);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return (
|
throw (console.log('Err in signpdf', e), e);
|
||||||
console.log('Err ', e),
|
|
||||||
'ERR_BAD_REQUEST' === e.code
|
|
||||||
? { status: 'error', message: 'Invalid session token!' }
|
|
||||||
: { status: 'error', message: 'Encrypted files are currently not supported!' }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default PDF;
|
export default PDF;
|
||||||
|
|||||||
@@ -164,19 +164,10 @@ export default function reportJson(id, userId) {
|
|||||||
IsDeclined: { $ne: true },
|
IsDeclined: { $ne: true },
|
||||||
IsArchive: { $ne: true },
|
IsArchive: { $ne: true },
|
||||||
Type: { $ne: 'Folder' },
|
Type: { $ne: 'Folder' },
|
||||||
$and: [
|
SignedUrl: { $ne: null },
|
||||||
{
|
ExpiryDate: {
|
||||||
$or: [
|
$lt: { __type: 'Date', iso: new Date().toISOString() },
|
||||||
{ Signers: { $ne: null }, SignedUrl: { $ne: null } },
|
},
|
||||||
{ Placeholders: { $ne: null } },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ExpiryDate: {
|
|
||||||
$lt: { __type: 'Date', iso: new Date().toISOString() },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
CreatedBy: {
|
CreatedBy: {
|
||||||
__type: 'Pointer',
|
__type: 'Pointer',
|
||||||
className: '_User',
|
className: '_User',
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
export default async function saveSubscription(request) {
|
||||||
|
const serverUrl = process.env.SERVER_URL;
|
||||||
|
const appId = process.env.APP_ID;
|
||||||
|
const subscription = request.params.subscription;
|
||||||
|
const SubscriptionId = subscription.data.subscription.subscription_id;
|
||||||
|
const body = subscription;
|
||||||
|
const Next_billing_date = subscription.data.subscription.next_billing_at;
|
||||||
|
const planCode = subscription.data.subscription.plan.plan_code;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||||
|
headers: {
|
||||||
|
'X-Parse-Application-Id': appId,
|
||||||
|
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (userRes.data && userRes.data.objectId) {
|
||||||
|
const extUserCls = new Parse.Query('contracts_Users');
|
||||||
|
extUserCls.equalTo('UserId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: '_User',
|
||||||
|
objectId: userRes.data.objectId,
|
||||||
|
});
|
||||||
|
const extUser = await extUserCls.first({ useMasterKey: true });
|
||||||
|
if (extUser) {
|
||||||
|
const subcriptionCls = new Parse.Query('contracts_Subscriptions');
|
||||||
|
subcriptionCls.equalTo('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: extUser.get('TenantId').id,
|
||||||
|
});
|
||||||
|
const subscription = await subcriptionCls.first({ useMasterKey: true });
|
||||||
|
if (subscription) {
|
||||||
|
const updateSubscription = new Parse.Object('contracts_Subscriptions');
|
||||||
|
updateSubscription.id = subscription.id;
|
||||||
|
updateSubscription.set('SubscriptionId', SubscriptionId);
|
||||||
|
updateSubscription.set('SubscriptionDetails', body);
|
||||||
|
updateSubscription.set('Next_billing_date', new Date(Next_billing_date));
|
||||||
|
updateSubscription.set('PlanCode', planCode);
|
||||||
|
await updateSubscription.save(null, { useMasterKey: true });
|
||||||
|
return { status: 'update subscription!' };
|
||||||
|
} else {
|
||||||
|
const createSubscription = new Parse.Object('contracts_Subscriptions');
|
||||||
|
createSubscription.set('SubscriptionId', SubscriptionId);
|
||||||
|
createSubscription.set('SubscriptionDetails', body);
|
||||||
|
createSubscription.set('ExtUserPtr', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'contracts_Users',
|
||||||
|
objectId: extUser.id,
|
||||||
|
});
|
||||||
|
createSubscription.set('CreatedBy', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: '_User',
|
||||||
|
objectId: extUser.get('UserId').id,
|
||||||
|
});
|
||||||
|
createSubscription.set('TenantId', {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: 'partners_Tenant',
|
||||||
|
objectId: extUser.get('TenantId').id,
|
||||||
|
});
|
||||||
|
createSubscription.set('Next_billing_date', new Date(Next_billing_date));
|
||||||
|
createSubscription.set('PlanCode', planCode);
|
||||||
|
await createSubscription.save(null, { useMasterKey: true });
|
||||||
|
return { status: 'create subscription!' };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { status: 'user not found!' };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { status: 'user not found!' };
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Err in save subscription', err);
|
||||||
|
throw new Error(err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import { google } from 'googleapis';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import https from 'https';
|
||||||
|
const clientId = process.env.GOOGLE_CLIENT_ID;
|
||||||
|
const clientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
||||||
|
// Function to create a Gmail client
|
||||||
|
const createGmailClient = accessToken => {
|
||||||
|
const oauth2Client = new google.auth.OAuth2();
|
||||||
|
oauth2Client.setCredentials({ access_token: accessToken });
|
||||||
|
return google.gmail({ version: 'v1', auth: oauth2Client });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to exchange refresh token for new access token
|
||||||
|
const refreshAccessToken = async refreshToken => {
|
||||||
|
const tokenEndpoint = 'https://oauth2.googleapis.com/token';
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.append('refresh_token', refreshToken);
|
||||||
|
params.append('client_id', clientId);
|
||||||
|
params.append('client_secret', clientSecret);
|
||||||
|
params.append('grant_type', 'refresh_token');
|
||||||
|
|
||||||
|
const response = await axios.post(tokenEndpoint, params);
|
||||||
|
return response.data.access_token;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to create a raw email message
|
||||||
|
const makeEmail = async (to, from, subject, html, url, pdfName) => {
|
||||||
|
const htmlContent = html;
|
||||||
|
const boundary = 'boundary_' + Date.now().toString(16);
|
||||||
|
let str;
|
||||||
|
if (url) {
|
||||||
|
let attachments;
|
||||||
|
let Pdf = fs.createWriteStream('test.pdf');
|
||||||
|
const writeToLocalDisk = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
https.get(url, async function (response) {
|
||||||
|
response.pipe(Pdf);
|
||||||
|
response.on('end', () => resolve('success'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// `writeToLocalDisk` is used to create pdf file from doc url
|
||||||
|
const ress = await writeToLocalDisk();
|
||||||
|
if (ress) {
|
||||||
|
const file = {
|
||||||
|
filename: `${pdfName}.pdf` || 'exported.pdf',
|
||||||
|
type: 'application/pdf',
|
||||||
|
path: Pdf.path,
|
||||||
|
};
|
||||||
|
|
||||||
|
// `certificateBuffer` used to create buffer from pdf file
|
||||||
|
try {
|
||||||
|
const certificate = {
|
||||||
|
filename: 'certificate.pdf',
|
||||||
|
type: 'application/pdf',
|
||||||
|
path: './exports/certificate.pdf',
|
||||||
|
};
|
||||||
|
attachments = [file, certificate];
|
||||||
|
} catch (err) {
|
||||||
|
attachments = [file];
|
||||||
|
console.log('Err in read certificate sendmailv3', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const attachmentParts = attachments.map(attachment => {
|
||||||
|
const content = fs.readFileSync(attachment.path);
|
||||||
|
const encodedContent = content.toString('base64');
|
||||||
|
return [
|
||||||
|
`Content-Type: ${attachment.type}\n`,
|
||||||
|
'MIME-Version: 1.0\n',
|
||||||
|
`Content-Disposition: attachment; filename="${attachment.filename}"\n`,
|
||||||
|
`Content-Transfer-Encoding: base64\n\n`,
|
||||||
|
`${encodedContent}\n`,
|
||||||
|
].join('');
|
||||||
|
});
|
||||||
|
|
||||||
|
const attachmentBody = attachmentParts.join(`\n--${boundary}\n`);
|
||||||
|
|
||||||
|
str = [
|
||||||
|
'Content-Type: multipart/mixed; boundary="' + boundary + '"\n',
|
||||||
|
'MIME-Version: 1.0\n',
|
||||||
|
`To: ${to}\n`,
|
||||||
|
`From: ${from}\n`,
|
||||||
|
`Subject: ${subject}\n\n`,
|
||||||
|
'--' + boundary + '\n',
|
||||||
|
'Content-Type: text/html; charset="UTF-8"\n',
|
||||||
|
'MIME-Version: 1.0\n\n',
|
||||||
|
`${htmlContent}\n\n`,
|
||||||
|
`\n--${boundary}\n`,
|
||||||
|
attachmentBody,
|
||||||
|
'--' + boundary + '--',
|
||||||
|
].join('');
|
||||||
|
} else {
|
||||||
|
str = [
|
||||||
|
'Content-Type: multipart/mixed; boundary="' + boundary + '"\n',
|
||||||
|
'MIME-Version: 1.0\n',
|
||||||
|
`To: ${to}\n`,
|
||||||
|
`From: ${from}\n`,
|
||||||
|
`Subject: ${subject}\n\n`,
|
||||||
|
'--' + boundary + '\n',
|
||||||
|
'Content-Type: text/html; charset="UTF-8"\n',
|
||||||
|
'MIME-Version: 1.0\n\n',
|
||||||
|
`${htmlContent}\n\n`,
|
||||||
|
'--' + boundary + '--',
|
||||||
|
].join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
const encodedMail = Buffer.from(str).toString('base64').replace(/\+/g, '-').replace(/\//g, '_');
|
||||||
|
return encodedMail;
|
||||||
|
};
|
||||||
|
export default async function sendMailGmailProvider(_extRes, template) {
|
||||||
|
const { sender, receiver, subject, html, url, pdfName } = template;
|
||||||
|
|
||||||
|
if (_extRes) {
|
||||||
|
const refresh_token = _extRes.google_refresh_token;
|
||||||
|
// generate access token
|
||||||
|
const access_token = await refreshAccessToken(refresh_token);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Construct email message
|
||||||
|
const from = sender || _extRes.Email || 'me';
|
||||||
|
const to = receiver;
|
||||||
|
const email = await makeEmail(to, from, subject, html, url, pdfName);
|
||||||
|
// Update Gmail client with new access token
|
||||||
|
const newGmail = createGmailClient(access_token);
|
||||||
|
// sending email with new client
|
||||||
|
const response = await newGmail.users.messages.send({
|
||||||
|
userId: 'me',
|
||||||
|
requestBody: {
|
||||||
|
raw: email,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// console.log('response ', response);
|
||||||
|
|
||||||
|
return { code: 200, message: 'Email sent successfully' };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error sending email:', error);
|
||||||
|
return { code: 500, message: 'Failed to send email ' + error };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,10 +2,10 @@ import fs from 'node:fs';
|
|||||||
import https from 'https';
|
import https from 'https';
|
||||||
import formData from 'form-data';
|
import formData from 'form-data';
|
||||||
import Mailgun from 'mailgun.js';
|
import Mailgun from 'mailgun.js';
|
||||||
import { createTransport } from 'nodemailer';
|
|
||||||
import { updateMailCount } from '../../Utils.js';
|
import { updateMailCount } from '../../Utils.js';
|
||||||
|
import sendMailGmailProvider from './sendMailGmailProvider.js';
|
||||||
async function sendmailv3(req) {
|
import { createTransport } from 'nodemailer';
|
||||||
|
async function sendMailProvider(req) {
|
||||||
try {
|
try {
|
||||||
let transporterSMTP;
|
let transporterSMTP;
|
||||||
let mailgunClient;
|
let mailgunClient;
|
||||||
@@ -58,8 +58,20 @@ async function sendmailv3(req) {
|
|||||||
data: process.env.SMTP_ENABLE ? undefined : PdfBuffer,
|
data: process.env.SMTP_ENABLE ? undefined : PdfBuffer,
|
||||||
};
|
};
|
||||||
|
|
||||||
// const html = "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body style='text-align: center;'> <p style='font-weight: bolder; font-size: large;'>Hello!</p> <p>This is a html checking mail</p><p><button style='background-color: lightskyblue; cursor: pointer; border-radius: 5px; padding: 10px; border-style: solid; border-width: 2px; text-decoration: none; font-weight: bolder; color:blue'>Verify email</button></p></body></html>"
|
let attachment;
|
||||||
|
// `certificateBuffer` used to create buffer from pdf file
|
||||||
|
try {
|
||||||
|
const certificateBuffer = fs.readFileSync('./exports/certificate.pdf');
|
||||||
|
const certificate = {
|
||||||
|
filename: 'certificate.pdf',
|
||||||
|
content: process.env.SMTP_ENABLE ? certificateBuffer : undefined, //fs.readFileSync('./exports/exported_file_1223.pdf'),
|
||||||
|
data: process.env.SMTP_ENABLE ? undefined : certificateBuffer,
|
||||||
|
};
|
||||||
|
attachment = [file, certificate];
|
||||||
|
} catch (err) {
|
||||||
|
attachment = [file];
|
||||||
|
console.log('Err in read certificate sendmailv3', err);
|
||||||
|
}
|
||||||
const from = req.params.from || '';
|
const from = req.params.from || '';
|
||||||
const mailsender = process.env.SMTP_ENABLE
|
const mailsender = process.env.SMTP_ENABLE
|
||||||
? process.env.SMTP_USER_EMAIL
|
? process.env.SMTP_USER_EMAIL
|
||||||
@@ -71,8 +83,8 @@ async function sendmailv3(req) {
|
|||||||
subject: req.params.subject,
|
subject: req.params.subject,
|
||||||
text: req.params.text || 'mail',
|
text: req.params.text || 'mail',
|
||||||
html: req.params.html || '',
|
html: req.params.html || '',
|
||||||
attachments: process.env.SMTP_ENABLE ? [file] : undefined,
|
attachments: process.env.SMTP_ENABLE ? attachment : undefined,
|
||||||
attachment: process.env.SMTP_ENABLE ? undefined : file,
|
attachment: process.env.SMTP_ENABLE ? undefined : attachment,
|
||||||
};
|
};
|
||||||
if (transporterSMTP) {
|
if (transporterSMTP) {
|
||||||
const res = await transporterSMTP.sendMail(messageParams);
|
const res = await transporterSMTP.sendMail(messageParams);
|
||||||
@@ -81,9 +93,12 @@ async function sendmailv3(req) {
|
|||||||
if (req.params?.extUserId) {
|
if (req.params?.extUserId) {
|
||||||
await updateMailCount(req.params.extUserId);
|
await updateMailCount(req.params.extUserId);
|
||||||
}
|
}
|
||||||
return {
|
try {
|
||||||
status: 'success',
|
fs.unlinkSync('./exports/certificate.pdf');
|
||||||
};
|
} catch (err) {
|
||||||
|
console.log('Err in unlink certificate sendmailv3');
|
||||||
|
}
|
||||||
|
return { status: 'success' };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
|
const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
|
||||||
@@ -92,6 +107,11 @@ async function sendmailv3(req) {
|
|||||||
if (req.params?.extUserId) {
|
if (req.params?.extUserId) {
|
||||||
await updateMailCount(req.params.extUserId);
|
await updateMailCount(req.params.extUserId);
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
fs.unlinkSync('./exports/certificate.pdf');
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Err in unlink certificate sendmailv3');
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
status: 'success',
|
status: 'success',
|
||||||
};
|
};
|
||||||
@@ -119,9 +139,7 @@ async function sendmailv3(req) {
|
|||||||
if (req.params?.extUserId) {
|
if (req.params?.extUserId) {
|
||||||
await updateMailCount(req.params.extUserId);
|
await updateMailCount(req.params.extUserId);
|
||||||
}
|
}
|
||||||
return {
|
return { status: 'success' };
|
||||||
status: 'success',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
|
const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
|
||||||
@@ -130,9 +148,7 @@ async function sendmailv3(req) {
|
|||||||
if (req.params?.extUserId) {
|
if (req.params?.extUserId) {
|
||||||
await updateMailCount(req.params.extUserId);
|
await updateMailCount(req.params.extUserId);
|
||||||
}
|
}
|
||||||
return {
|
return { status: 'success' };
|
||||||
status: 'success',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,5 +159,45 @@ async function sendmailv3(req) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function sendmailv3(req) {
|
||||||
|
const mailProvider = req.params.mailProvider || 'default';
|
||||||
|
if (mailProvider) {
|
||||||
|
try {
|
||||||
|
const extUserId = req.params.extUserId || '';
|
||||||
|
const pdfName = req.params.pdfName || '';
|
||||||
|
const template = {
|
||||||
|
sender: req.params.from || '',
|
||||||
|
receiver: req.params.recipient,
|
||||||
|
subject: req.params.subject,
|
||||||
|
html: req.params.html || '',
|
||||||
|
url: req.params.url ? req.params.url : '',
|
||||||
|
pdfName: pdfName,
|
||||||
|
};
|
||||||
|
const extUserQuery = new Parse.Query('contracts_Users');
|
||||||
|
const extRes = await extUserQuery.get(extUserId, { useMasterKey: true });
|
||||||
|
if (extRes) {
|
||||||
|
const _extRes = JSON.parse(JSON.stringify(extRes));
|
||||||
|
if (_extRes.google_refresh_token && mailProvider === 'google') {
|
||||||
|
const res = await sendMailGmailProvider(_extRes, template);
|
||||||
|
if (res.code === 200) {
|
||||||
|
await updateMailCount(req.params.extUserId);
|
||||||
|
return { status: 'success' };
|
||||||
|
} else {
|
||||||
|
return { status: 'error' };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const nonCustomMail = await sendMailProvider(req);
|
||||||
|
return nonCustomMail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err in send custom mail', err);
|
||||||
|
return { status: 'error' };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const nonCustomMail = await sendMailProvider(req);
|
||||||
|
return nonCustomMail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default sendmailv3;
|
export default sendmailv3;
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
const serverUrl = process.env.SERVER_URL;
|
const serverUrl = process.env.SERVER_URL;
|
||||||
const APPID = process.env.APP_ID;
|
const APPID = process.env.APP_ID;
|
||||||
const masterKEY = process.env.MASTER_KEY;
|
const masterKEY = process.env.MASTER_KEY;
|
||||||
|
|
||||||
async function saveUser(userDetails) {
|
async function saveUser(userDetails) {
|
||||||
const userQuery = new Parse.Query(Parse.User);
|
const userQuery = new Parse.Query(Parse.User);
|
||||||
userQuery.equalTo("username", userDetails.email);
|
userQuery.equalTo('username', userDetails.email);
|
||||||
const userRes = await userQuery.first({ useMasterKey: true });
|
const userRes = await userQuery.first({ useMasterKey: true });
|
||||||
|
|
||||||
if (userRes) {
|
if (userRes) {
|
||||||
const url = `${serverUrl}/loginAs`;
|
const url = `${serverUrl}/loginAs`;
|
||||||
const axiosRes = await axios({
|
const axiosRes = await axios({
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
url: url,
|
url: url,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json;charset=utf-8",
|
'Content-Type': 'application/json;charset=utf-8',
|
||||||
"X-Parse-Application-Id": APPID,
|
'X-Parse-Application-Id': APPID,
|
||||||
"X-Parse-Master-Key": masterKEY,
|
'X-Parse-Master-Key': masterKEY,
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
userId: userRes.id,
|
userId: userRes.id,
|
||||||
@@ -27,39 +27,39 @@ async function saveUser(userDetails) {
|
|||||||
return { id: login.objectId, sessionToken: login.sessionToken };
|
return { id: login.objectId, sessionToken: login.sessionToken };
|
||||||
} else {
|
} else {
|
||||||
const user = new Parse.User();
|
const user = new Parse.User();
|
||||||
user.set("username", userDetails.email);
|
user.set('username', userDetails.email);
|
||||||
user.set("password", userDetails.password);
|
user.set('password', userDetails.password);
|
||||||
user.set("email", userDetails.email);
|
user.set('email', userDetails.email);
|
||||||
user.set("phone", userDetails.phone);
|
user.set('phone', userDetails.phone);
|
||||||
user.set("name", userDetails.name);
|
user.set('name', userDetails.name);
|
||||||
|
|
||||||
const res = await user.signUp();
|
const res = await user.signUp();
|
||||||
// console.log("res ", res);
|
// console.log("res ", res);
|
||||||
return { id: res.id, sessionToken: res.getSessionToken() };
|
return { id: res.id, sessionToken: res.getSessionToken() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default async function (request) {
|
export default async function usersignup(request) {
|
||||||
const userDetails = request.params.userDetails;
|
const userDetails = request.params.userDetails;
|
||||||
const planDetails = request.params.planDetails;
|
const subscription = request.params.subscription;
|
||||||
const user = await saveUser(userDetails);
|
const user = await saveUser(userDetails);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const extClass = userDetails.role.split("_")[0];
|
const extClass = userDetails.role.split('_')[0];
|
||||||
|
|
||||||
const extQuery = new Parse.Query(extClass + "_Users");
|
const extQuery = new Parse.Query(extClass + '_Users');
|
||||||
extQuery.equalTo("UserId", {
|
extQuery.equalTo('UserId', {
|
||||||
__type: "Pointer",
|
__type: 'Pointer',
|
||||||
className: "_User",
|
className: '_User',
|
||||||
objectId: user.id,
|
objectId: user.id,
|
||||||
});
|
});
|
||||||
const extUser = await extQuery.first({ useMasterKey: true });
|
const extUser = await extQuery.first({ useMasterKey: true });
|
||||||
if (extUser) {
|
if (extUser) {
|
||||||
return { message: "User already exist" };
|
return { message: 'User already exist' };
|
||||||
} else {
|
} else {
|
||||||
const roleurl = `${serverUrl}/functions/AddUserToRole`;
|
const roleurl = `${serverUrl}/functions/AddUserToRole`;
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
"X-Parse-Application-Id": APPID,
|
'X-Parse-Application-Id': APPID,
|
||||||
sessionToken: user.sessionToken, //localStorage.getItem("accesstoken"),
|
sessionToken: user.sessionToken, //localStorage.getItem("accesstoken"),
|
||||||
};
|
};
|
||||||
let body = {
|
let body = {
|
||||||
@@ -69,74 +69,98 @@ export default async function (request) {
|
|||||||
};
|
};
|
||||||
let role = await axios.post(roleurl, body, { headers: headers });
|
let role = await axios.post(roleurl, body, { headers: headers });
|
||||||
// console.log("role ", role);
|
// console.log("role ", role);
|
||||||
const partnerCls = Parse.Object.extend("partners_Tenant");
|
const partnerCls = Parse.Object.extend('partners_Tenant');
|
||||||
const partnerQuery = new partnerCls();
|
const partnerQuery = new partnerCls();
|
||||||
partnerQuery.set("UserId", {
|
partnerQuery.set('UserId', {
|
||||||
__type: "Pointer",
|
__type: 'Pointer',
|
||||||
className: "_User",
|
className: '_User',
|
||||||
objectId: user.id,
|
objectId: user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
partnerQuery.set("ContactNumber", userDetails.phone);
|
partnerQuery.set('ContactNumber', userDetails.phone);
|
||||||
partnerQuery.set("TenantName", userDetails.name);
|
partnerQuery.set('TenantName', userDetails.name);
|
||||||
partnerQuery.set("EmailAddress", userDetails.email);
|
partnerQuery.set('EmailAddress', userDetails.email);
|
||||||
partnerQuery.set("IsActive", true);
|
partnerQuery.set('IsActive', true);
|
||||||
partnerQuery.set("CreatedBy", {
|
partnerQuery.set('CreatedBy', {
|
||||||
__type: "Pointer",
|
__type: 'Pointer',
|
||||||
className: "_User",
|
className: '_User',
|
||||||
objectId: user.id,
|
objectId: user.id,
|
||||||
});
|
});
|
||||||
if (userDetails && userDetails.pincode) {
|
if (userDetails && userDetails.pincode) {
|
||||||
partnerQuery.set("PinCode", userDetails.pincode);
|
partnerQuery.set('PinCode', userDetails.pincode);
|
||||||
}
|
}
|
||||||
if (userDetails && userDetails.country) {
|
if (userDetails && userDetails.country) {
|
||||||
partnerQuery.set("Country", userDetails.country);
|
partnerQuery.set('Country', userDetails.country);
|
||||||
}
|
}
|
||||||
if (userDetails && userDetails.state) {
|
if (userDetails && userDetails.state) {
|
||||||
partnerQuery.set("State", userDetails.state);
|
partnerQuery.set('State', userDetails.state);
|
||||||
}
|
}
|
||||||
if (userDetails && userDetails.city) {
|
if (userDetails && userDetails.city) {
|
||||||
partnerQuery.set("City", userDetails.city);
|
partnerQuery.set('City', userDetails.city);
|
||||||
}
|
}
|
||||||
if (userDetails && userDetails.address) {
|
if (userDetails && userDetails.address) {
|
||||||
partnerQuery.set("Address", userDetails.address);
|
partnerQuery.set('Address', userDetails.address);
|
||||||
}
|
}
|
||||||
const tenantRes = await partnerQuery.save(null, { useMasterKey: true });
|
const tenantRes = await partnerQuery.save(null, { useMasterKey: true });
|
||||||
// console.log("tenantRes ", tenantRes);
|
// console.log("tenantRes ", tenantRes);
|
||||||
const extCls = Parse.Object.extend(extClass + "_Users");
|
const extCls = Parse.Object.extend(extClass + '_Users');
|
||||||
const newObj = new extCls();
|
const newObj = new extCls();
|
||||||
newObj.set("UserId", {
|
newObj.set('UserId', {
|
||||||
__type: "Pointer",
|
__type: 'Pointer',
|
||||||
className: "_User",
|
className: '_User',
|
||||||
objectId: user.id,
|
objectId: user.id,
|
||||||
});
|
});
|
||||||
newObj.set("UserRole", userDetails.role);
|
newObj.set('UserRole', userDetails.role);
|
||||||
newObj.set("Email", userDetails.email);
|
newObj.set('Email', userDetails.email);
|
||||||
newObj.set("Name", userDetails.name);
|
newObj.set('Name', userDetails.name);
|
||||||
newObj.set("Phone", userDetails.phone);
|
newObj.set('Phone', userDetails.phone);
|
||||||
newObj.set("TenantId", {
|
newObj.set('TenantId', {
|
||||||
__type: "Pointer",
|
__type: 'Pointer',
|
||||||
className: "partners_Tenant",
|
className: 'partners_Tenant',
|
||||||
objectId: tenantRes.id,
|
objectId: tenantRes.id,
|
||||||
});
|
});
|
||||||
if (userDetails && userDetails.company) {
|
if (userDetails && userDetails.company) {
|
||||||
newObj.set("Company", userDetails.company);
|
newObj.set('Company', userDetails.company);
|
||||||
}
|
}
|
||||||
if (userDetails && userDetails.jobTitle) {
|
if (userDetails && userDetails.jobTitle) {
|
||||||
newObj.set("JobTitle", userDetails.jobTitle);
|
newObj.set('JobTitle', userDetails.jobTitle);
|
||||||
}
|
}
|
||||||
if (planDetails && planDetails.customer_id) {
|
|
||||||
newObj.set("Next_billing_date", new Date(planDetails.nextBillingDate));
|
|
||||||
newObj.set("Plan", planDetails.plan);
|
|
||||||
newObj.set("Customer_id", planDetails.customer_id);
|
|
||||||
newObj.set("Subscription_id", planDetails.subscription_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
const extRes = await newObj.save(null, { useMasterKey: true });
|
const extRes = await newObj.save(null, { useMasterKey: true });
|
||||||
|
await saveSubscription(extRes.id, user.id, tenantRes.id, subscription);
|
||||||
return { message: "User sign up", sessionToken: user.sessionToken };
|
return { message: 'User sign up', sessionToken: user.sessionToken };
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Parse} Parse
|
||||||
|
*/
|
||||||
|
exports.up = async Parse => {
|
||||||
|
// TODO: set className here
|
||||||
|
const className = 'contracts_Document';
|
||||||
|
const schema = new Parse.Schema(className);
|
||||||
|
schema.addString('RequestBody');
|
||||||
|
schema.addString('RequestSubject');
|
||||||
|
// TODO: Set the schema here
|
||||||
|
// Example:
|
||||||
|
// schema.addString('name').addNumber('cash');
|
||||||
|
|
||||||
|
return schema.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Parse} Parse
|
||||||
|
*/
|
||||||
|
exports.down = async Parse => {
|
||||||
|
// TODO: set className here
|
||||||
|
const className = 'contracts_Document';
|
||||||
|
const schema = new Parse.Schema(className);
|
||||||
|
schema.deleteField('RequestBody');
|
||||||
|
schema.deleteField('RequestSubject');
|
||||||
|
// TODO: Set the schema here
|
||||||
|
// Example:
|
||||||
|
// schema.deleteField('name').deleteField('cash');
|
||||||
|
|
||||||
|
return schema.update();
|
||||||
|
};
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
// Example express application adding the parse-server module to expose Parse
|
|
||||||
// compatible API routes.
|
|
||||||
|
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
import { ParseServer } from 'parse-server';
|
import { ParseServer } from 'parse-server';
|
||||||
@@ -13,7 +9,7 @@ import http from 'http';
|
|||||||
import formData from 'form-data';
|
import formData from 'form-data';
|
||||||
import Mailgun from 'mailgun.js';
|
import Mailgun from 'mailgun.js';
|
||||||
import { ApiPayloadConverter } from 'parse-server-api-mail-adapter';
|
import { ApiPayloadConverter } from 'parse-server-api-mail-adapter';
|
||||||
import S3Adapter from 'parse-server-s3-adapter';
|
import S3Adapter from '@parse/s3-files-adapter';
|
||||||
import FSFilesAdapter from 'parse-server-fs-adapter';
|
import FSFilesAdapter from 'parse-server-fs-adapter';
|
||||||
import AWS from 'aws-sdk';
|
import AWS from 'aws-sdk';
|
||||||
import { app as customRoute } from './cloud/customRoute/customApp.js';
|
import { app as customRoute } from './cloud/customRoute/customApp.js';
|
||||||
@@ -21,9 +17,10 @@ import { exec } from 'child_process';
|
|||||||
import { createTransport } from 'nodemailer';
|
import { createTransport } from 'nodemailer';
|
||||||
import { app as v1 } from './cloud/customRoute/v1/apiV1.js';
|
import { app as v1 } from './cloud/customRoute/v1/apiV1.js';
|
||||||
import { PostHog } from 'posthog-node';
|
import { PostHog } from 'posthog-node';
|
||||||
// console.log("configuration ", configuration);
|
import { useLocal } from './Utils.js';
|
||||||
|
|
||||||
let fsAdapter;
|
let fsAdapter;
|
||||||
if (process.env.USE_LOCAL !== 'TRUE') {
|
if (useLocal !== 'true') {
|
||||||
try {
|
try {
|
||||||
const spacesEndpoint = new AWS.Endpoint(process.env.DO_ENDPOINT);
|
const spacesEndpoint = new AWS.Endpoint(process.env.DO_ENDPOINT);
|
||||||
const s3Options = {
|
const s3Options = {
|
||||||
@@ -32,6 +29,8 @@ if (process.env.USE_LOCAL !== 'TRUE') {
|
|||||||
region: process.env.DO_REGION,
|
region: process.env.DO_REGION,
|
||||||
directAccess: true,
|
directAccess: true,
|
||||||
preserveFileName: true,
|
preserveFileName: true,
|
||||||
|
presignedUrl: true,
|
||||||
|
presignedUrlExpires: 900,
|
||||||
s3overrides: {
|
s3overrides: {
|
||||||
accessKeyId: process.env.DO_ACCESS_KEY_ID,
|
accessKeyId: process.env.DO_ACCESS_KEY_ID,
|
||||||
secretAccessKey: process.env.DO_SECRET_ACCESS_KEY,
|
secretAccessKey: process.env.DO_SECRET_ACCESS_KEY,
|
||||||
@@ -96,6 +95,7 @@ export const config = {
|
|||||||
import('./cloud/main.js');
|
import('./cloud/main.js');
|
||||||
},
|
},
|
||||||
appId: process.env.APP_ID || 'myAppId',
|
appId: process.env.APP_ID || 'myAppId',
|
||||||
|
logLevel: ['error'],
|
||||||
maxLimit: 500,
|
maxLimit: 500,
|
||||||
maxUploadSize: '30mb',
|
maxUploadSize: '30mb',
|
||||||
masterKey: process.env.MASTER_KEY, //Add your master key here. Keep it secret!
|
masterKey: process.env.MASTER_KEY, //Add your master key here. Keep it secret!
|
||||||
@@ -166,11 +166,6 @@ app.use(cors());
|
|||||||
app.use(express.json({ limit: '50mb' }));
|
app.use(express.json({ limit: '50mb' }));
|
||||||
app.use(express.urlencoded({ limit: '50mb', extended: true }));
|
app.use(express.urlencoded({ limit: '50mb', extended: true }));
|
||||||
app.use(function (req, res, next) {
|
app.use(function (req, res, next) {
|
||||||
// console.log("req ", req.headers);
|
|
||||||
// console.log("x-forwarded-for", req.headers["x-forwarded-for"]);
|
|
||||||
// console.log("req.ip", req.ip);
|
|
||||||
// console.log("req.socket.remoteAddress; ", req.socket.remoteAddress);
|
|
||||||
// console.log("ip", ip.address());
|
|
||||||
req.headers['x-real-ip'] = getUserIP(req);
|
req.headers['x-real-ip'] = getUserIP(req);
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
@@ -230,7 +225,7 @@ if (!process.env.TESTING) {
|
|||||||
// Set the Keep-Alive and headers timeout to 100 seconds
|
// Set the Keep-Alive and headers timeout to 100 seconds
|
||||||
httpServer.keepAliveTimeout = 100000; // in milliseconds
|
httpServer.keepAliveTimeout = 100000; // in milliseconds
|
||||||
httpServer.headersTimeout = 100000; // in milliseconds
|
httpServer.headersTimeout = 100000; // in milliseconds
|
||||||
httpServer.listen(port, function () {
|
httpServer.listen(port, '0.0.0.0', function () {
|
||||||
console.log('parse-server-example running on port ' + port + '.');
|
console.log('parse-server-example running on port ' + port + '.');
|
||||||
const isWindows = process.platform === 'win32';
|
const isWindows = process.platform === 'win32';
|
||||||
// console.log('isWindows', isWindows);
|
// console.log('isWindows', isWindows);
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
Generated
+165
-45
@@ -9,22 +9,24 @@
|
|||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@parse/s3-files-adapter": "^2.2.0",
|
||||||
"aws-sdk": "^2.1581.0",
|
"aws-sdk": "^2.1581.0",
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.18.3",
|
"express": "^4.19.2",
|
||||||
"express-sse": "^0.5.3",
|
"express-sse": "^0.5.3",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"generate-api-key": "^1.0.2",
|
"generate-api-key": "^1.0.2",
|
||||||
|
"googleapis": "^134.0.0",
|
||||||
"jsonschema": "^1.4.1",
|
"jsonschema": "^1.4.1",
|
||||||
"mailgun.js": "^10.2.1",
|
"mailgun.js": "^10.2.1",
|
||||||
"mongoose": "^8.2.2",
|
"mongoose": "^8.3.3",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"multer-s3": "^3.0.1",
|
"multer-s3": "^3.0.1",
|
||||||
"node-forge": "^1.3.1",
|
"node-forge": "^1.3.1",
|
||||||
"node-signpdf": "^1.5.1",
|
"node-signpdf": "^1.5.1",
|
||||||
"nodemailer": "^6.9.12",
|
"nodemailer": "^6.9.13",
|
||||||
"parse": "^5.0.0",
|
"parse": "^5.0.0",
|
||||||
"parse-dbtool": "^1.2.0",
|
"parse-dbtool": "^1.2.0",
|
||||||
"parse-server": "^6.5.5",
|
"parse-server": "^6.5.5",
|
||||||
@@ -42,7 +44,8 @@
|
|||||||
"mongodb-runner": "^5.5.4",
|
"mongodb-runner": "^5.5.4",
|
||||||
"nodemon": "^3.1.0",
|
"nodemon": "^3.1.0",
|
||||||
"nyc": "15.1.0",
|
"nyc": "15.1.0",
|
||||||
"prettier": "^3.2.5"
|
"prettier": "^3.2.5",
|
||||||
|
"uglify-js": "^3.17.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.22.10 <21"
|
"node": ">=12.22.10 <21"
|
||||||
@@ -2560,6 +2563,69 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@parse/s3-files-adapter": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parse/s3-files-adapter/-/s3-files-adapter-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-y+d7+AvmRUrROe4kJOF8128yUSxieM53vXQsSaG2gvY9VgPScfpfho0pE7VZ5mLumzxJjmwW6oufiGdgcjgcTA==",
|
||||||
|
"dependencies": {
|
||||||
|
"aws-sdk": "2.1363.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parse/s3-files-adapter/node_modules/aws-sdk": {
|
||||||
|
"version": "2.1363.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1363.0.tgz",
|
||||||
|
"integrity": "sha512-M2MZZXehgi/EMQv5GlzRkn3TlhoOYHg2cYdSAAqhjv67WaEG50MjaQy5vRvfN1i8XvB24aJFJ5pCrx69TaCaIg==",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer": "4.9.2",
|
||||||
|
"events": "1.1.1",
|
||||||
|
"ieee754": "1.1.13",
|
||||||
|
"jmespath": "0.16.0",
|
||||||
|
"querystring": "0.2.0",
|
||||||
|
"sax": "1.2.1",
|
||||||
|
"url": "0.10.3",
|
||||||
|
"util": "^0.12.4",
|
||||||
|
"uuid": "8.0.0",
|
||||||
|
"xml2js": "0.5.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parse/s3-files-adapter/node_modules/buffer": {
|
||||||
|
"version": "4.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
|
||||||
|
"integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.0.2",
|
||||||
|
"ieee754": "^1.1.4",
|
||||||
|
"isarray": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parse/s3-files-adapter/node_modules/ieee754": {
|
||||||
|
"version": "1.1.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
|
||||||
|
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
|
||||||
|
},
|
||||||
|
"node_modules/@parse/s3-files-adapter/node_modules/uuid": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==",
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parse/s3-files-adapter/node_modules/xml2js": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
|
||||||
|
"dependencies": {
|
||||||
|
"sax": ">=0.6.0",
|
||||||
|
"xmlbuilder": "~11.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@pdf-lib/standard-fonts": {
|
"node_modules/@pdf-lib/standard-fonts": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz",
|
||||||
@@ -3614,7 +3680,6 @@
|
|||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
|
||||||
"integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==",
|
"integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
@@ -3937,7 +4002,6 @@
|
|||||||
"version": "9.1.2",
|
"version": "9.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
|
||||||
"integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==",
|
"integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==",
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
@@ -4059,9 +4123,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/bson": {
|
"node_modules/bson": {
|
||||||
"version": "6.3.0",
|
"version": "6.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/bson/-/bson-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/bson/-/bson-6.7.0.tgz",
|
||||||
"integrity": "sha512-balJfqwwTBddxfnidJZagCBPP/f48zj9Sdp3OJswREOgsJzHiQSaOIAtApSgDQFYgHqAvFkp53AFSqjMDZoTFw==",
|
"integrity": "sha512-w2IquM5mYzYZv6rs3uN2DZTOBe2a0zXLj53TGDqwF4l6Sz/XsISrisXOJihArF9+BZ6Cq/GjVht7Sjfmri7ytQ==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.20.1"
|
"node": ">=16.20.1"
|
||||||
}
|
}
|
||||||
@@ -5391,16 +5455,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/express": {
|
"node_modules/express": {
|
||||||
"version": "4.18.3",
|
"version": "4.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz",
|
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
|
||||||
"integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==",
|
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"accepts": "~1.3.8",
|
"accepts": "~1.3.8",
|
||||||
"array-flatten": "1.1.1",
|
"array-flatten": "1.1.1",
|
||||||
"body-parser": "1.20.2",
|
"body-parser": "1.20.2",
|
||||||
"content-disposition": "0.5.4",
|
"content-disposition": "0.5.4",
|
||||||
"content-type": "~1.0.4",
|
"content-type": "~1.0.4",
|
||||||
"cookie": "0.5.0",
|
"cookie": "0.6.0",
|
||||||
"cookie-signature": "1.0.6",
|
"cookie-signature": "1.0.6",
|
||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
"depd": "2.0.0",
|
"depd": "2.0.0",
|
||||||
@@ -5447,6 +5511,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/express-sse/-/express-sse-0.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/express-sse/-/express-sse-0.5.3.tgz",
|
||||||
"integrity": "sha512-DJF0nofFGq0IXJLGq95hfrryP3ZprVAVpyZUnmAk6QhHnm7zCzsHBNFP0i4FKFo2XjOf+JiYUKjT7jQhIeljpg=="
|
"integrity": "sha512-DJF0nofFGq0IXJLGq95hfrryP3ZprVAVpyZUnmAk6QhHnm7zCzsHBNFP0i4FKFo2XjOf+JiYUKjT7jQhIeljpg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/express/node_modules/cookie": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/express/node_modules/debug": {
|
"node_modules/express/node_modules/debug": {
|
||||||
"version": "2.6.9",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
@@ -5994,7 +6066,6 @@
|
|||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.3.0.tgz",
|
||||||
"integrity": "sha512-p+ggrQw3fBwH2F5N/PAI4k/G/y1art5OxKpb2J2chwNNHM4hHuAOtivjPuirMF4KNKwTTUal/lPfL2+7h2mEcg==",
|
"integrity": "sha512-p+ggrQw3fBwH2F5N/PAI4k/G/y1art5OxKpb2J2chwNNHM4hHuAOtivjPuirMF4KNKwTTUal/lPfL2+7h2mEcg==",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"extend": "^3.0.2",
|
"extend": "^3.0.2",
|
||||||
"https-proxy-agent": "^7.0.1",
|
"https-proxy-agent": "^7.0.1",
|
||||||
@@ -6009,7 +6080,6 @@
|
|||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||||
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
},
|
},
|
||||||
@@ -6208,10 +6278,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/google-auth-library": {
|
"node_modules/google-auth-library": {
|
||||||
"version": "9.7.0",
|
"version": "9.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.8.0.tgz",
|
||||||
"integrity": "sha512-I/AvzBiUXDzLOy4iIZ2W+Zq33W4lcukQv1nl7C8WUA6SQwyQwUwu3waNmWNAvzds//FG8SZ+DnKnW/2k6mQS8A==",
|
"integrity": "sha512-TJJXFzMlVGRlIH27gYZ6XXyPf5Y3OItsKFfefsDAafNNywYRTkei83nEO29IrYj8GtdHWU78YnW+YZdaZaXIJA==",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"base64-js": "^1.3.0",
|
"base64-js": "^1.3.0",
|
||||||
"ecdsa-sig-formatter": "^1.0.11",
|
"ecdsa-sig-formatter": "^1.0.11",
|
||||||
@@ -6228,7 +6297,6 @@
|
|||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz",
|
||||||
"integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==",
|
"integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"gaxios": "^6.0.0",
|
"gaxios": "^6.0.0",
|
||||||
"json-bigint": "^1.0.0"
|
"json-bigint": "^1.0.0"
|
||||||
@@ -6273,6 +6341,46 @@
|
|||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/googleapis": {
|
||||||
|
"version": "134.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/googleapis/-/googleapis-134.0.0.tgz",
|
||||||
|
"integrity": "sha512-o8LhD1754W6MHWtpwAPeP1WUHgNxuMxCnLMDFlMKAA5kCMTNqX9/eaTXnkkAIv6YRfoKMQ6D1vyR6/biXuhE9g==",
|
||||||
|
"dependencies": {
|
||||||
|
"google-auth-library": "^9.0.0",
|
||||||
|
"googleapis-common": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/googleapis-common": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-p3KHiWDBBWJEXk6SYauBEvxw5+UmRy7k2scxGtsNv9eHsTbpopJ3/7If4OrNnzJ9XMLg3IlyQXpVp8YPQsStiw==",
|
||||||
|
"dependencies": {
|
||||||
|
"extend": "^3.0.2",
|
||||||
|
"gaxios": "^6.0.3",
|
||||||
|
"google-auth-library": "^9.7.0",
|
||||||
|
"qs": "^6.7.0",
|
||||||
|
"url-template": "^2.0.8",
|
||||||
|
"uuid": "^9.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/googleapis-common/node_modules/uuid": {
|
||||||
|
"version": "9.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||||
|
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/gopd": {
|
"node_modules/gopd": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||||
@@ -6337,7 +6445,6 @@
|
|||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
|
||||||
"integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==",
|
"integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"gaxios": "^6.0.0",
|
"gaxios": "^6.0.0",
|
||||||
"jws": "^4.0.0"
|
"jws": "^4.0.0"
|
||||||
@@ -6549,7 +6656,6 @@
|
|||||||
"version": "7.0.4",
|
"version": "7.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz",
|
||||||
"integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==",
|
"integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"agent-base": "^7.0.2",
|
"agent-base": "^7.0.2",
|
||||||
"debug": "4"
|
"debug": "4"
|
||||||
@@ -7306,7 +7412,6 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
|
||||||
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
|
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bignumber.js": "^9.0.0"
|
"bignumber.js": "^9.0.0"
|
||||||
}
|
}
|
||||||
@@ -7458,7 +7563,6 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
|
||||||
"integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
|
"integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"buffer-equal-constant-time": "1.0.1",
|
"buffer-equal-constant-time": "1.0.1",
|
||||||
"ecdsa-sig-formatter": "1.0.11",
|
"ecdsa-sig-formatter": "1.0.11",
|
||||||
@@ -7485,16 +7589,15 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
|
||||||
"integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
|
"integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jwa": "^2.0.0",
|
"jwa": "^2.0.0",
|
||||||
"safe-buffer": "^5.0.1"
|
"safe-buffer": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/kareem": {
|
"node_modules/kareem": {
|
||||||
"version": "2.5.1",
|
"version": "2.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
|
||||||
"integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==",
|
"integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.0.0"
|
"node": ">=12.0.0"
|
||||||
}
|
}
|
||||||
@@ -7858,12 +7961,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mongodb": {
|
"node_modules/mongodb": {
|
||||||
"version": "6.3.0",
|
"version": "6.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.5.0.tgz",
|
||||||
"integrity": "sha512-tt0KuGjGtLUhLoU263+xvQmPHEGTw5LbcNC73EoFRYgSHwZt5tsoJC110hDyO1kjQzpgNrpdcSza9PknWN4LrA==",
|
"integrity": "sha512-Fozq68InT+JKABGLqctgtb8P56pRrJFkbhW0ux+x1mdHeyinor8oNzJqwLjV/t5X5nJGfTlluxfyMnOXNggIUA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mongodb-js/saslprep": "^1.1.0",
|
"@mongodb-js/saslprep": "^1.1.5",
|
||||||
"bson": "^6.2.0",
|
"bson": "^6.4.0",
|
||||||
"mongodb-connection-string-url": "^3.0.0"
|
"mongodb-connection-string-url": "^3.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -8209,13 +8312,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mongoose": {
|
"node_modules/mongoose": {
|
||||||
"version": "8.2.2",
|
"version": "8.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.3.3.tgz",
|
||||||
"integrity": "sha512-6sMxe1d3k/dBjiOX4ExNTNOP0g1x0iq8eXyg+ttgIXM3HLnQ0IUyXRwVVAPFFY6O4/8uYN5dB0Ec72FrexbPpw==",
|
"integrity": "sha512-3kSk0db9DM2tLttCdS6WNRqewPleamFEa4Vz/Qldc0dB4Zow/FiZxb9GExHTJjBZQ9T2xiGleQ3GzRrES3hhsA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bson": "^6.2.0",
|
"bson": "^6.5.0",
|
||||||
"kareem": "2.5.1",
|
"kareem": "2.6.3",
|
||||||
"mongodb": "6.3.0",
|
"mongodb": "6.5.0",
|
||||||
"mpath": "0.9.0",
|
"mpath": "0.9.0",
|
||||||
"mquery": "5.0.0",
|
"mquery": "5.0.0",
|
||||||
"ms": "2.1.3",
|
"ms": "2.1.3",
|
||||||
@@ -8400,9 +8503,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nodemailer": {
|
"node_modules/nodemailer": {
|
||||||
"version": "6.9.12",
|
"version": "6.9.13",
|
||||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.12.tgz",
|
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.13.tgz",
|
||||||
"integrity": "sha512-pnLo7g37Br3jXbF0bl5DekBJihm2q+3bB3l2o/B060sWmb5l+VqeScAQCBqaQ+5ezRZFzW5SciZNGdRDEbq89w==",
|
"integrity": "sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
@@ -10975,9 +11078,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tar": {
|
"node_modules/tar": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
||||||
"integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==",
|
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chownr": "^2.0.0",
|
"chownr": "^2.0.0",
|
||||||
@@ -11301,6 +11404,18 @@
|
|||||||
"is-typedarray": "^1.0.0"
|
"is-typedarray": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/uglify-js": {
|
||||||
|
"version": "3.17.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
|
||||||
|
"integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"uglifyjs": "bin/uglifyjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/unbzip2-stream": {
|
"node_modules/unbzip2-stream": {
|
||||||
"version": "1.4.3",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
|
||||||
@@ -11412,6 +11527,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
|
||||||
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="
|
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/url-template": {
|
||||||
|
"version": "2.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
|
||||||
|
"integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw=="
|
||||||
|
},
|
||||||
"node_modules/url/node_modules/punycode": {
|
"node_modules/url/node_modules/punycode": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
|
||||||
|
|||||||
@@ -18,22 +18,24 @@
|
|||||||
"watch": "nodemon index.js"
|
"watch": "nodemon index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@parse/s3-files-adapter": "^2.2.0",
|
||||||
"aws-sdk": "^2.1581.0",
|
"aws-sdk": "^2.1581.0",
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.18.3",
|
"express": "^4.19.2",
|
||||||
"express-sse": "^0.5.3",
|
"express-sse": "^0.5.3",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"generate-api-key": "^1.0.2",
|
"generate-api-key": "^1.0.2",
|
||||||
|
"googleapis": "^134.0.0",
|
||||||
"jsonschema": "^1.4.1",
|
"jsonschema": "^1.4.1",
|
||||||
"mailgun.js": "^10.2.1",
|
"mailgun.js": "^10.2.1",
|
||||||
"mongoose": "^8.2.2",
|
"mongoose": "^8.3.3",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"multer-s3": "^3.0.1",
|
"multer-s3": "^3.0.1",
|
||||||
"node-forge": "^1.3.1",
|
"node-forge": "^1.3.1",
|
||||||
"node-signpdf": "^1.5.1",
|
"node-signpdf": "^1.5.1",
|
||||||
"nodemailer": "^6.9.12",
|
"nodemailer": "^6.9.13",
|
||||||
"parse": "^5.0.0",
|
"parse": "^5.0.0",
|
||||||
"parse-dbtool": "^1.2.0",
|
"parse-dbtool": "^1.2.0",
|
||||||
"parse-server": "^6.5.5",
|
"parse-server": "^6.5.5",
|
||||||
@@ -52,7 +54,8 @@
|
|||||||
"mongodb-runner": "^5.5.4",
|
"mongodb-runner": "^5.5.4",
|
||||||
"nodemon": "^3.1.0",
|
"nodemon": "^3.1.0",
|
||||||
"nyc": "15.1.0",
|
"nyc": "15.1.0",
|
||||||
"prettier": "^3.2.5"
|
"prettier": "^3.2.5",
|
||||||
|
"uglify-js": "^3.17.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.22.10 <21"
|
"node": ">=12.22.10 <21"
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user