mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-04 16:58:05 +02:00
Compare commits
796
Commits
1.3.2-beta
...
v2.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc398d68e4 | ||
|
|
cd4844863e | ||
|
|
6d4ebf7be5 | ||
|
|
18992e0334 | ||
|
|
0580a18b0d | ||
|
|
5a4114b786 | ||
|
|
4fdf2299f8 | ||
|
|
f15aa39588 | ||
|
|
694312812a | ||
|
|
2606b58434 | ||
|
|
943f9a0673 | ||
|
|
77622ebea9 | ||
|
|
6fb714d565 | ||
|
|
f6170e01f6 | ||
|
|
1e857b615f | ||
|
|
b982ca5218 | ||
|
|
c83817800e | ||
|
|
d1992839a8 | ||
|
|
bfb7136c89 | ||
|
|
52b2cc6af4 | ||
|
|
94d386541d | ||
|
|
d85d76c8aa | ||
|
|
ade97b972f | ||
|
|
532780629b | ||
|
|
1f2298f192 | ||
|
|
ae5d527e4f | ||
|
|
e59a7e0028 | ||
|
|
1d6655eafe | ||
|
|
09b39a467b | ||
|
|
e0e7dd5298 | ||
|
|
56d5091b96 | ||
|
|
0b28e64111 | ||
|
|
482b75c6a7 | ||
|
|
cdff7e252d | ||
|
|
a18aee0be1 | ||
|
|
89f67bfeeb | ||
|
|
e4f0e9cef3 | ||
|
|
12599c1e5a | ||
|
|
6bb3203417 | ||
|
|
0eb2c5ecc4 | ||
|
|
01ab19b235 | ||
|
|
ba6b0ce7e5 | ||
|
|
b99d3f643b | ||
|
|
fea174c48d | ||
|
|
1aa1a602b3 | ||
|
|
37b7e50b4c | ||
|
|
e9fab26ef3 | ||
|
|
3216a1d4ae | ||
|
|
eb0941f087 | ||
|
|
0a315ef9c7 | ||
|
|
134babd070 | ||
|
|
954ba13f22 | ||
|
|
66718fd416 | ||
|
|
f4358c5004 | ||
|
|
63f888b3ec | ||
|
|
e066d1d273 | ||
|
|
daddb10030 | ||
|
|
6d9090d414 | ||
|
|
795e8a8ec9 | ||
|
|
e8b0b333a1 | ||
|
|
93d9a761ca | ||
|
|
3642d4f3a3 | ||
|
|
08387fc406 | ||
|
|
d1d0f40b00 | ||
|
|
ad4a9e7141 | ||
|
|
d46cb7dc10 | ||
|
|
50b9717cb9 | ||
|
|
4e83734c5c | ||
|
|
6eeaea137a | ||
|
|
2c91499232 | ||
|
|
e6085eb2c0 | ||
|
|
6fa4c4759b | ||
|
|
f8d6547c24 | ||
|
|
ffdd952440 | ||
|
|
9594e9438e | ||
|
|
08d1e9a360 | ||
|
|
74a9d08550 | ||
|
|
6fc86e026b | ||
|
|
72da56a916 | ||
|
|
4ba7ffbb1a | ||
|
|
0d9a0b8bb1 | ||
|
|
084aa69702 | ||
|
|
597635800f | ||
|
|
8da2c7fad4 | ||
|
|
2b0276ead9 | ||
|
|
45a96ece54 | ||
|
|
729d19dfd3 | ||
|
|
29aa123669 | ||
|
|
f69caf016a | ||
|
|
48e0e0ee15 | ||
|
|
a71278f95c | ||
|
|
f7bb11ede1 | ||
|
|
6a365f7734 | ||
|
|
e4d946e519 | ||
|
|
149a16f150 | ||
|
|
d8ff3d9faa | ||
|
|
fe34001e42 | ||
|
|
fcdd7e2758 | ||
|
|
025c30b685 | ||
|
|
e742e85f0e | ||
|
|
476a99feae | ||
|
|
29464585b8 | ||
|
|
cdd078699b | ||
|
|
9ef1e22fda | ||
|
|
655401e04b | ||
|
|
b550c07ca8 | ||
|
|
fd72094b8a | ||
|
|
4d7348abc2 | ||
|
|
ec68479e98 | ||
|
|
ac05942e58 | ||
|
|
b387b6b402 | ||
|
|
e13baeb2fc | ||
|
|
52eb8e4a68 | ||
|
|
71189783a8 | ||
|
|
aec9396524 | ||
|
|
d74390b974 | ||
|
|
998fe013c8 | ||
|
|
06d4c9aeaf | ||
|
|
bc77a9b0a1 | ||
|
|
07c0390401 | ||
|
|
c50d753d74 | ||
|
|
65eef5739d | ||
|
|
01eed3664b | ||
|
|
685e09d406 | ||
|
|
7bacca1f78 | ||
|
|
3764ab5c30 | ||
|
|
2f7a1d67b6 | ||
|
|
8726efb0aa | ||
|
|
e073e83ad6 | ||
|
|
69140d2139 | ||
|
|
aeed48c0ef | ||
|
|
1f9504b9cc | ||
|
|
5518d6932e | ||
|
|
f14e301b6c | ||
|
|
901ddf35bb | ||
|
|
9aa3166528 | ||
|
|
a90e679228 | ||
|
|
90b5e3c860 | ||
|
|
74f6612271 | ||
|
|
2862a97c4e | ||
|
|
5c3f967128 | ||
|
|
6fde71e947 | ||
|
|
2900464272 | ||
|
|
10bac3c11f | ||
|
|
302f38d472 | ||
|
|
8ecdbc43a3 | ||
|
|
6721b334cf | ||
|
|
454f557d14 | ||
|
|
635693b394 | ||
|
|
0be1816046 | ||
|
|
feb162e03e | ||
|
|
c8801846fa | ||
|
|
a793fc3722 | ||
|
|
ffdabe4a00 | ||
|
|
5536c99052 | ||
|
|
ba1c3145f3 | ||
|
|
0fbe6aeb6c | ||
|
|
4898c4a851 | ||
|
|
85aa6b2947 | ||
|
|
3b02d2bcdb | ||
|
|
ed01f4a7a0 | ||
|
|
1f395cf25f | ||
|
|
cf98e73d13 | ||
|
|
10112ac20d | ||
|
|
9a0183274f | ||
|
|
6b2e16c21d | ||
|
|
3c51baf1c9 | ||
|
|
3f4be1c4f3 | ||
|
|
62b36f58f7 | ||
|
|
ba3591c7bc | ||
|
|
1ec11b8733 | ||
|
|
ab89d3b71f | ||
|
|
1811173648 | ||
|
|
b218e96107 | ||
|
|
64a0be8776 | ||
|
|
414e2d819c | ||
|
|
0769101f28 | ||
|
|
5dc86119d3 | ||
|
|
4999dc2b18 | ||
|
|
962d36c088 | ||
|
|
d071986aac | ||
|
|
afb4de9d0c | ||
|
|
bc5c8cac33 | ||
|
|
be93e6a214 | ||
|
|
37748057e3 | ||
|
|
eb3bb77692 | ||
|
|
df0ce3f086 | ||
|
|
0a99b5181e | ||
|
|
8a5d3a0368 | ||
|
|
c00406e401 | ||
|
|
aeead23c86 | ||
|
|
83fe88911f | ||
|
|
527bca32d2 | ||
|
|
9bf4940c2e | ||
|
|
a653df6935 | ||
|
|
dfc6da388c | ||
|
|
3e2c822bbc | ||
|
|
1a20841a94 | ||
|
|
c6be81923b | ||
|
|
6b47f6a27b | ||
|
|
33b0111ed0 | ||
|
|
48fd9e52b3 | ||
|
|
d85074b127 | ||
|
|
5ada9a411b | ||
|
|
6f50de1ef1 | ||
|
|
612150cf4b | ||
|
|
634db83e8e | ||
|
|
b32c8068ef | ||
|
|
ae464274b0 | ||
|
|
c5ceba8d57 | ||
|
|
903d626c27 | ||
|
|
e5b4fb123f | ||
|
|
116893c1b4 | ||
|
|
592254a9a3 | ||
|
|
f52c6e24fe | ||
|
|
70ae1e24fc | ||
|
|
c491595fc8 | ||
|
|
6875135ede | ||
|
|
662049d878 | ||
|
|
1764d7f9ba | ||
|
|
07933b56b1 | ||
|
|
f6ba4db62d | ||
|
|
5bd36f91d9 | ||
|
|
c199c3019e | ||
|
|
facbc8e76e | ||
|
|
c3c6f6bab3 | ||
|
|
f5e216fedc | ||
|
|
c40a923388 | ||
|
|
a86f4fd9b7 | ||
|
|
59f6d022cf | ||
|
|
b7beeee260 | ||
|
|
31c861cbe4 | ||
|
|
6a9408b7b4 | ||
|
|
a9fd264a01 | ||
|
|
6c77bbfe75 | ||
|
|
890c3d2b1f | ||
|
|
3ede441f54 | ||
|
|
2433ad5957 | ||
|
|
fffd907d63 | ||
|
|
51edc339cd | ||
|
|
bf307abe9a | ||
|
|
08a97707b7 | ||
|
|
d99fecd46e | ||
|
|
6c59c0ec9a | ||
|
|
32c75d1fc3 | ||
|
|
7f0f81c334 | ||
|
|
a882f07f57 | ||
|
|
74b81a5363 | ||
|
|
9b75764717 | ||
|
|
c1468112b0 | ||
|
|
950b74789c | ||
|
|
7e4f12e41a | ||
|
|
d75c1d7c0c | ||
|
|
7eacbedf59 | ||
|
|
2e5947279f | ||
|
|
ef5ac7d626 | ||
|
|
658c37cc4d | ||
|
|
ffc8e4b23e | ||
|
|
3fb96fc792 | ||
|
|
71016ba5e0 | ||
|
|
cd1a6fdaf6 | ||
|
|
c2afeed448 | ||
|
|
37fd7bbeda | ||
|
|
71fbde0099 | ||
|
|
ca6cb60d78 | ||
|
|
df1c0ea66c | ||
|
|
46279efc2c | ||
|
|
aca2848406 | ||
|
|
eaec3cf607 | ||
|
|
ad25d73f26 | ||
|
|
481b9ac1e0 | ||
|
|
4cd3791feb | ||
|
|
7de8699437 | ||
|
|
4c162676b1 | ||
|
|
ca390bdfa6 | ||
|
|
22d064fd38 | ||
|
|
444c9bbfdf | ||
|
|
b289686d42 | ||
|
|
eeb878b340 | ||
|
|
7894d69cc9 | ||
|
|
b992d7db24 | ||
|
|
50b72f4d85 | ||
|
|
44639f66b0 | ||
|
|
ae740efced | ||
|
|
66c020d903 | ||
|
|
562a7d6fc8 | ||
|
|
090c17c2c0 | ||
|
|
70637d6143 | ||
|
|
f38e8705de | ||
|
|
ba06ff72a0 | ||
|
|
82312a1e0d | ||
|
|
1a8cf11a3e | ||
|
|
3deacbabc3 | ||
|
|
c28805add9 | ||
|
|
80fb320ae4 | ||
|
|
76c9c1fa53 | ||
|
|
f38d83dbe0 | ||
|
|
ee9411729d | ||
|
|
f6f7c6cecd | ||
|
|
a45fc0dd60 | ||
|
|
348f7810b9 | ||
|
|
45bec128a9 | ||
|
|
4da307315c | ||
|
|
c87aa415a9 | ||
|
|
b1786ec16a | ||
|
|
6ad35e979e | ||
|
|
9d996d5cb7 | ||
|
|
008e3e8783 | ||
|
|
8458906b0b | ||
|
|
6933aa309b | ||
|
|
067ea68d3b | ||
|
|
e4e8a0b721 | ||
|
|
dc392adc1d | ||
|
|
741efff1fa | ||
|
|
93b0d00ab0 | ||
|
|
d731951159 | ||
|
|
24bf08c14f | ||
|
|
c03819f5a9 | ||
|
|
4521d16891 | ||
|
|
f77525cd8b | ||
|
|
38b7311e66 | ||
|
|
c934f8ccd6 | ||
|
|
4e128e5a5a | ||
|
|
e0ccf049a6 | ||
|
|
b202d78059 | ||
|
|
e15136ce51 | ||
|
|
39c9211167 | ||
|
|
64864e3f54 | ||
|
|
af0bef6d29 | ||
|
|
130704b32f | ||
|
|
5b139b66a9 | ||
|
|
f9c5041af1 | ||
|
|
1e58b35db5 | ||
|
|
245bf8046b | ||
|
|
94eb5f9efe | ||
|
|
044128f36a | ||
|
|
594383fe14 | ||
|
|
90a585367e | ||
|
|
0b8382df00 | ||
|
|
a54c7e7fd7 | ||
|
|
45a2c88e90 | ||
|
|
e4526f026b | ||
|
|
11a2f6b8ec | ||
|
|
3bf35166fc | ||
|
|
cd50c8cf20 | ||
|
|
055ef3f209 | ||
|
|
964ec0d422 | ||
|
|
ec0e291604 | ||
|
|
836e952ba0 | ||
|
|
c5f39e2a24 | ||
|
|
498bd18630 | ||
|
|
56dd060531 | ||
|
|
960fbdb0eb | ||
|
|
b530ef882a | ||
|
|
f8145feebc | ||
|
|
df38d15611 | ||
|
|
bb69518674 | ||
|
|
fee53fb020 | ||
|
|
d086e60ae5 | ||
|
|
51150d4e47 | ||
|
|
1d3cd02f9d | ||
|
|
850d14064a | ||
|
|
d03515efc4 | ||
|
|
30e6e4b3fd | ||
|
|
cbdd729e95 | ||
|
|
ac82209d52 | ||
|
|
d5cc6f6758 | ||
|
|
3aa211dc1a | ||
|
|
33d5eecbbf | ||
|
|
1d6c108ba4 | ||
|
|
79da0f285d | ||
|
|
e8eef32958 | ||
|
|
dc1fab5250 | ||
|
|
3e185ef796 | ||
|
|
8cf5adb273 | ||
|
|
803faed97b | ||
|
|
660eaeb714 | ||
|
|
273ada837b | ||
|
|
79126700c4 | ||
|
|
6355c02485 | ||
|
|
bce028877b | ||
|
|
e47211a8c0 | ||
|
|
4a4c9eaa2d | ||
|
|
0a5653f53d | ||
|
|
5a90a0f484 | ||
|
|
a3a398bd92 | ||
|
|
7d70162137 | ||
|
|
e4c62c4eeb | ||
|
|
3eadca01fa | ||
|
|
659b7fe0f4 | ||
|
|
ade6694427 | ||
|
|
f8160665a4 | ||
|
|
5778bdecae | ||
|
|
9122c71c90 | ||
|
|
2c2065aca8 | ||
|
|
b1dd4df3c0 | ||
|
|
64fd3580ac | ||
|
|
01273777b7 | ||
|
|
23eaa1ae81 | ||
|
|
3fd0613407 | ||
|
|
d45566257f | ||
|
|
e9eb59aa7a | ||
|
|
9e3ba2cf5c | ||
|
|
81afc92c14 | ||
|
|
d3bf9e9e9b | ||
|
|
18e25f6cd9 | ||
|
|
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 | ||
|
|
13e2d92ce6 | ||
|
|
4b9f22a5bc | ||
|
|
77c61c89a2 | ||
|
|
d04b79001a | ||
|
|
e14b2a2a17 | ||
|
|
6afa97a76b | ||
|
|
3a28b1cdd7 | ||
|
|
23b48838ae | ||
|
|
bddebf2758 | ||
|
|
5a68e18c48 | ||
|
|
280b812e5b | ||
|
|
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 | ||
|
|
97bd375de3 | ||
|
|
e2d450f9aa | ||
|
|
add01cb02a | ||
|
|
cea1653805 | ||
|
|
9d81fce956 | ||
|
|
79e3762b36 | ||
|
|
aa04a957ed | ||
|
|
d31910aefa | ||
|
|
96a4a2e7fa | ||
|
|
e8aaab99f9 | ||
|
|
c61be7c35b | ||
|
|
0ee85f53da | ||
|
|
748e2196da | ||
|
|
58199a934a | ||
|
|
b04d2abbab | ||
|
|
7eec822a65 | ||
|
|
6c21028523 | ||
|
|
099a3cc46d | ||
|
|
5adaffc684 | ||
|
|
d588caf6d4 | ||
|
|
5930fd940d | ||
|
|
741f66b019 | ||
|
|
0bf07c2703 | ||
|
|
de26c2d719 | ||
|
|
881ac12b03 | ||
|
|
1932dda6d6 | ||
|
|
46159b7214 | ||
|
|
c57c15a4cb | ||
|
|
724fa7c27e | ||
|
|
2762c3e170 | ||
|
|
10a0c60056 | ||
|
|
036c9b8d4a | ||
|
|
1f50368259 | ||
|
|
6d5e07dac7 | ||
|
|
3656175f11 | ||
|
|
febb50c3cd | ||
|
|
f8ba0d357b | ||
|
|
74bfd39abc | ||
|
|
5a25b2d874 | ||
|
|
3115ff3e2a | ||
|
|
d1e7b9a2ab | ||
|
|
adbf1fe1e0 | ||
|
|
60140885e0 | ||
|
|
fe2f3c5f7c | ||
|
|
a06723ff3f | ||
|
|
387154c07b | ||
|
|
12a6a84450 | ||
|
|
1f350fc459 | ||
|
|
d9fd2a5531 | ||
|
|
cd4fd6e3de | ||
|
|
49cd30de96 | ||
|
|
a24ebe25a8 | ||
|
|
3e664bf677 | ||
|
|
6161e975fb | ||
|
|
c2a45c230b | ||
|
|
a629aa0bff | ||
|
|
899678d98a | ||
|
|
076a0f54c5 | ||
|
|
a94e67cd7c | ||
|
|
e78a3991f0 | ||
|
|
593a8499f4 | ||
|
|
70d643a5e2 | ||
|
|
f2b1a54695 | ||
|
|
4353a4f732 | ||
|
|
34c99edf1a | ||
|
|
91f3bdb299 | ||
|
|
276fc974fa | ||
|
|
081e11f9af | ||
|
|
4f056cc9d3 | ||
|
|
d9da25e908 | ||
|
|
99b3436c8c | ||
|
|
452d4d7a1d | ||
|
|
ed613c3424 | ||
|
|
bf70fa0b11 | ||
|
|
8684197d49 | ||
|
|
648d1224b3 | ||
|
|
126b6ad355 | ||
|
|
0512f27e2e | ||
|
|
2c61630017 | ||
|
|
72c2b2dde6 | ||
|
|
29eb78c960 | ||
|
|
aa9ba05dde | ||
|
|
365b074f62 | ||
|
|
af6cb4c17d | ||
|
|
6bcad91b0f | ||
|
|
1aa2b003b2 | ||
|
|
1a27e9addf | ||
|
|
c2891a0858 | ||
|
|
c1b226db96 | ||
|
|
8a01efee4c | ||
|
|
eafb26d462 | ||
|
|
62e1a1bd9b | ||
|
|
58eb71c52d | ||
|
|
c1e6f2b5ab | ||
|
|
ba0c18b591 | ||
|
|
c3a902dcc7 | ||
|
|
5ece3c0694 | ||
|
|
1053540410 | ||
|
|
24773759c2 | ||
|
|
7a6de70169 | ||
|
|
04b2c7c4da | ||
|
|
d11171e91c | ||
|
|
a4a78cb96c | ||
|
|
dfdcde8fcc | ||
|
|
5e1b84d2e6 | ||
|
|
f7606bce35 | ||
|
|
f08758fd71 | ||
|
|
d3b1a37a7c | ||
|
|
4718c653f7 | ||
|
|
f9b8437981 | ||
|
|
b0c73bc63e | ||
|
|
269246659b | ||
|
|
51fe5d133e | ||
|
|
36a1123535 | ||
|
|
3c1ceb4995 | ||
|
|
53d154fa59 |
@@ -205,6 +205,33 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "ugoconsonni",
|
||||||
|
"name": "ugoconsonni",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/13661702?v=4",
|
||||||
|
"profile": "https://github.com/ugoconsonni",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "daniel-mutwiri",
|
||||||
|
"name": "Daniel Mutwiri",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/8936960?v=4",
|
||||||
|
"profile": "https://github.com/daniel-mutwiri",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Zathiel",
|
||||||
|
"name": "Zathiel",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/26553418?v=4",
|
||||||
|
"profile": "https://github.com/Zathiel",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
# Clone the repo and rename this file to .env if you want to run the frontend react app locally for some quick contributions to the project.
|
|
||||||
# When used as it is, this env config will connect to our hosted UAT backend
|
|
||||||
# Note that any data in staging will get cleared from time to time and you may have to sign up again and again
|
|
||||||
|
|
||||||
# Set it to the URL form where the app home page will be accessed
|
|
||||||
PUBLIC_URL=http://localhost:3000
|
|
||||||
# Set it to true if you want to generate the Sourcemap for debugging
|
|
||||||
GENERATE_SOURCEMAP=false
|
|
||||||
# Set it to the URL from where APIs will be accessible, for local development it should be localhost:3000/api/app (use your local port number instead)
|
|
||||||
REACT_APP_SERVERURL=https://staging-app.opensignlabs.com/api/app
|
|
||||||
# A 12 character long random app identifier. The value of this should be same as APP_ID which is a variable used by backend API.
|
|
||||||
REACT_APP_APPID=opensign
|
|
||||||
+2
-2
@@ -20,7 +20,7 @@ appName=open_sign_server
|
|||||||
# A 12 character long random secret key that allows access to all the data. It is used in Parse dashboard config to view all the data in the database.
|
# A 12 character long random secret key that allows access to all the data. It is used in Parse dashboard config to view all the data in the database.
|
||||||
MASTER_KEY=XnAadwKxxByMr
|
MASTER_KEY=XnAadwKxxByMr
|
||||||
# Mongodb URI to connect to
|
# Mongodb URI to connect to
|
||||||
MONGODB_URI=mongodb://localhost:27017/OpenSignDB
|
MONGODB_URI=mongodb://mongo:27017/OpenSignDB
|
||||||
# Path on which APIs should be mounted. Do not change this. This variable shall be removed & value hardcoded in the source code in coming versions.
|
# Path on which APIs should be mounted. Do not change this. This variable shall be removed & value hardcoded in the source code in coming versions.
|
||||||
PARSE_MOUNT=/app
|
PARSE_MOUNT=/app
|
||||||
# Set it to the URL from where APIs will be accessible to the NodeJS functions, for local development it should be localhost:3000/api/app (use your local port number instead)
|
# Set it to the URL from where APIs will be accessible to the NodeJS functions, for local development it should be localhost:3000/api/app (use your local port number instead)
|
||||||
@@ -40,7 +40,7 @@ DO_SECRET_ACCESS_KEY=
|
|||||||
# Digital ocean spaces region or AWS s3 region
|
# Digital ocean spaces region or AWS s3 region
|
||||||
DO_REGION=us-west
|
DO_REGION=us-west
|
||||||
# local storage
|
# local storage
|
||||||
USE_LOCAL=TRUE
|
USE_LOCAL=true
|
||||||
|
|
||||||
# Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
|
# Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
|
||||||
MAILGUN_API_KEY=
|
MAILGUN_API_KEY=
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ name: ci
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'staging'
|
- 'main'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
build:
|
build:
|
||||||
cp .env.local_dev .env
|
cp .env.local_dev .env
|
||||||
cd apps/OpenSign && npm install && npm run build
|
cd apps/OpenSign && cp ../../.env.local_dev .env && npm install && npm run build
|
||||||
docker compose up --build --force-recreate
|
docker compose up --build --force-recreate
|
||||||
|
|
||||||
run:
|
run:
|
||||||
|
|||||||
@@ -42,24 +42,24 @@ Please star ⭐ the repo to support us! 😀
|
|||||||
|
|
||||||
### Introduction
|
### Introduction
|
||||||
|
|
||||||
Welcome to OpenSign, the premier open-source docusign alternative - document e-signing solution designed to provide a secure, reliable, and free alternative to commercial platforms like DocuSign, PandaDoc, SignNow, Adobe Sign, Smartwaiver, SignRequest, HelloSign & Zoho sign. Developed under the OpenSignLabs organization, our mission is to democratize the e-signing process, making it accessible and straightforward for everyone.
|
Welcome to OpenSign, the premier open source docusign alternative - document e-signing solution designed to provide a secure, reliable and free alternative to commercial esign platforms like DocuSign, PandaDoc, SignNow, Adobe Sign, Smartwaiver, SignRequest, HelloSign & Zoho sign. Our mission is to democratize the e-signing process, making it accessible and straightforward for everyone.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- **Secure PDF E-Signing:** With the help of Robust encryption algorithms, OpenSign™ ensures maximum security, privacy & compatibility.
|
- **Secure PDF E-Signing:** With the help of robust encryption algorithms, OpenSign™ ensures maximum security, privacy & compatibility.
|
||||||
- **Annotate Documents:** OpenSign™ allows you to annotate PDF documents with an advanced signing pad that comes with hand drawn signatures support as well as uploaded images & saved signatures for the simplest signing experience.
|
- **Annotate Documents:** OpenSign™ allows you to annotate PDF documents with an advanced signing pad that allows hand drawn signatures, uploaded images, typed signatures & saved signatures for the simplest signing experience ever.
|
||||||
- **User-Friendly Interface:** OpenSign™ was built while keeping Intuitive design in mind for ease of use. Features like "Sign yourself", "One click signatures" and "OpenSign Drive" makes it stand out of the crowd and even makes it better than a lot of so-called industry leaders.
|
- **User-Friendly Interface:** OpenSign™ was built while keeping Intuitive design in mind for ease of use. Features like "Sign yourself", "Templates", "One click signatures" and "OpenSign™ Drive" makes it stand out of the crowd and even makes it better than a lot of so-called industry leaders.
|
||||||
- **Multi-signer Support:** OpenSign's ability to invite multiple signers for signing along with the ability to invite witnesses & being able to enforce signing in a sequence makes it the only open source solution that is fully loaded and allows it to compete head-to-head with established players.
|
- **Multi-signer Support:** OpenSign's ability to invite multiple signers for signing along with the ability to invite witnesses & being able to enforce signing in a sequence makes it the only open source solution that is fully loaded and allows it to compete head-to-head with established players in e-signature space.
|
||||||
- **Email Unique Code(OTP) verification support for guest signers:** With OpenSign™, your documents are fully secure even when being signed by guest users. Guest signers can only sign the document after entering a unique code sent to their email address.
|
- **Email Unique Code(OTP) verification support for guest signers:** With OpenSign™, your documents are fully secure even when being signed by guest users. Guest signers can only sign the document after entering a unique code sent to their email address.
|
||||||
- **"Expiring Docs" & "Rejection":** You can set documents to expire after certain number of days after which nobody will be able to sign it. Not just this, OpenSign also allows signers to reject signing a document.
|
- **"Expiring Docs" & "Rejection":** You can set documents to expire after certain number of days after which nobody will be able to sign. Not just this, OpenSign™ also allows signers to reject signing a document.
|
||||||
- **Beautiful email templates:** All document signing invitations, completion notifications & reminders are formatted using great looking email templates.
|
- **Beautiful email templates:** All document signing invitations, completion notifications & reminders are formatted using great looking email templates.
|
||||||
- **PDF Template Creation(coming soon):** OpenSign™ allows you to create and store PDF document templates for repeated use thereby saving you a lot of time.
|
- **PDF Template Creation:** OpenSign™ allows you to create and store PDF document templates for repeated use thereby saving you a lot of time & collect e-signatures seamlessly.
|
||||||
- **OpenSign™ Drive:** It is a centralised secure vault for your signed documents that makes storing, signing, organizing, sharing & achieving your docs a breeze.
|
- **OpenSign™ Drive:** It is a centralised secure vault for your digital documents that makes storing, signing, organizing, sharing & achieving your docs a breeze.
|
||||||
- **Audit Trails & completion certificate:** Being a security focused solution, OpenSign™ makes it a top priority to save detailed logs for tracking document activities along with time-stamps, IP addresses, email IDs & phone numbers. A completion certificate is generated as soon as document is completed which contains all the document related logs for added safety.
|
- **Audit Trails & completion certificate:** Being a security focused solution, OpenSign™ makes it a top priority to save detailed logs for tracking document activities along with time-stamps, IP addresses, email IDs & phone numbers. A completion certificate is generated as soon as document is completed which contains all the document related logs for added safety.
|
||||||
- **API Support(coming soon):** OpenSign™ API allows seamless integration into existing systems and software. APIs will soon be available as a cloud hosted solution.
|
- **API Support:** OpenSign™ API allows seamless integration into existing systems and software. You can generate an API key from the app and refer the [docs](https://docs.opensignlabs.com) to start integrating it in your existing applications.
|
||||||
- **Integrations:** Seamless integrations with various Cloud storage systems, CRMs & enterprise platforms is coming soon.
|
- **Integrations:** Seamless integrations with various Cloud storage systems, CRMs & enterprise platforms is available. We also have a Zapier integration that allows you to integrate it with virtually any application.
|
||||||
|
|
||||||
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/b37ff443-7099-4273-9aeb-21c46d7154cf height='200'>
|
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/b37ff443-7099-4273-9aeb-21c46d7154cf height='200'>
|
||||||
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/86db91b7-6c2f-4885-a33c-58f4fd35ec89 height='200'>
|
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/86db91b7-6c2f-4885-a33c-58f4fd35ec89 height='200'>
|
||||||
@@ -76,7 +76,7 @@ Please refer to the [Installation Guide](INSTALLATION.md) for detailed instructi
|
|||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
For comprehensive guidelines on how to use OpenSign, please consult our [User Manual](USAGE.md).
|
For comprehensive guidelines on how to use OpenSign™, please consult our [User Manual](USAGE.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -134,6 +134,9 @@ We would like to thank all our contributors and users for their support and feed
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/VikramNagwal"><img src="https://avatars.githubusercontent.com/u/123088024?v=4?s=100" width="100px;" alt="Vikram"/><br /><sub><b>Vikram</b></sub></a><br /><a href="#code-VikramNagwal" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/VikramNagwal"><img src="https://avatars.githubusercontent.com/u/123088024?v=4?s=100" width="100px;" alt="Vikram"/><br /><sub><b>Vikram</b></sub></a><br /><a href="#code-VikramNagwal" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ugoconsonni"><img src="https://avatars.githubusercontent.com/u/13661702?v=4?s=100" width="100px;" alt="ugoconsonni"/><br /><sub><b>ugoconsonni</b></sub></a><br /><a href="#code-ugoconsonni" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/daniel-mutwiri"><img src="https://avatars.githubusercontent.com/u/8936960?v=4?s=100" width="100px;" alt="Daniel Mutwiri"/><br /><sub><b>Daniel Mutwiri</b></sub></a><br /><a href="#code-daniel-mutwiri" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Zathiel"><img src="https://avatars.githubusercontent.com/u/26553418?v=4?s=100" width="100px;" alt="Zathiel"/><br /><sub><b>Zathiel</b></sub></a><br /><a href="#code-Zathiel" title="Code">💻</a><a href="#security-Zathiel" title="Security">🛡️</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -21,5 +21,5 @@ EXPOSE 3000
|
|||||||
# ENV NODE_ENV production
|
# ENV NODE_ENV production
|
||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
ENTRYPOINT npm run start-dev
|
ENTRYPOINT npm run start
|
||||||
|
|
||||||
|
|||||||
Generated
+5178
-4569
File diff suppressed because it is too large
Load Diff
+40
-32
@@ -3,49 +3,52 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/themes": "^2.0.3",
|
"@formkit/auto-animate": "^0.8.2",
|
||||||
"@react-pdf/renderer": "^3.3.8",
|
"@lottiefiles/dotlottie-react": "^0.6.4",
|
||||||
"@reduxjs/toolkit": "^2.2.1",
|
"@radix-ui/themes": "^3.0.5",
|
||||||
"axios": "^1.6.0",
|
"@react-pdf/renderer": "^3.4.4",
|
||||||
"daisyui": "^3.9.2",
|
"@reduxjs/toolkit": "^2.2.5",
|
||||||
|
"axios": "^1.7.2",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"html-react-parser": "^4.2.2",
|
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.30.1",
|
||||||
"parse": "^4.3.1",
|
"nth-check": "^2.1.1",
|
||||||
|
"parse": "^5.1.0",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
"radix-ui": "^1.0.1",
|
"radix-ui": "^1.0.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-bootstrap": "^2.10.1",
|
"react-bootstrap": "^2.10.2",
|
||||||
"react-datepicker": "^6.2.0",
|
"react-confetti": "^6.1.0",
|
||||||
|
"react-cookie": "^7.1.4",
|
||||||
|
"react-datepicker": "^6.9.0",
|
||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
"react-dnd-html5-backend": "^16.0.1",
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
"react-dnd-multi-backend": "^8.0.3",
|
"react-dnd-multi-backend": "^8.0.3",
|
||||||
"react-dnd-touch-backend": "^16.0.1",
|
"react-dnd-touch-backend": "^16.0.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-drag-listview": "^2.0.0",
|
|
||||||
"react-draggable": "^4.4.6",
|
|
||||||
"react-gtm-module": "^2.0.11",
|
"react-gtm-module": "^2.0.11",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
"react-konva": "^18.2.10",
|
"react-konva": "^18.2.10",
|
||||||
"react-modal": "^3.16.1",
|
"react-pdf": "^9.0.0",
|
||||||
"react-pdf": "^7.7.1",
|
"react-quill": "^2.0.0",
|
||||||
"react-redux": "^8.1.3",
|
"react-redux": "^9.1.2",
|
||||||
"react-rnd": "^10.4.1",
|
"react-rnd": "^10.4.11",
|
||||||
"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.4",
|
||||||
"reactour": "^1.19.2",
|
"react-web-share": "^2.0.2",
|
||||||
"redux": "^4.2.1",
|
"reactour": "^1.19.4",
|
||||||
"redux-thunk": "^2.4.2",
|
"redux": "^5.0.1",
|
||||||
|
"redux-thunk": "^3.1.0",
|
||||||
"regex-parser": "^2.3.0",
|
"regex-parser": "^2.3.0",
|
||||||
"serve": "^14.2.1",
|
"serve": "^14.2.3",
|
||||||
"styled-components": "^4.4.1",
|
"styled-components": "^4.4.1",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^4.0.1",
|
||||||
|
"ws": "^8.17.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "serve -s build",
|
"start": "serve -s build",
|
||||||
@@ -83,16 +86,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/runtime-corejs2": "^7.23.9",
|
"@babel/runtime-corejs2": "^7.24.7",
|
||||||
"autoprefixer": "^10.4.18",
|
"autoprefixer": "^10.4.19",
|
||||||
"commitizen": "^4.3.0",
|
"commitizen": "^4.3.0",
|
||||||
"eslint": "^8.51.0",
|
"daisyui": "^4.12.2",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"lint-staged": "^15.2.2",
|
"eslint-plugin-react": "^7.34.3",
|
||||||
"postcss": "^8.4.35",
|
"lint-staged": "^15.2.7",
|
||||||
"prettier": "^2.8.0",
|
"postcss": "^8.4.38",
|
||||||
"pretty-quick": "^3.1.3",
|
"prettier": "^3.3.2",
|
||||||
"tailwindcss": "^3.3.3"
|
"pretty-quick": "^4.0.0",
|
||||||
|
"tailwindcss": "^3.4.4"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"nth-check": "$nth-check",
|
||||||
|
"ws":"$ws"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,53 +1,20 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en" data-theme="opensigncss">
|
||||||
|
|
||||||
<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"
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||||
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC"
|
|
||||||
sizes="40x40" /> -->
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta name="description" content="The fastest way to sign PDFs & request signatures from others" />
|
<meta name="description" content="The fastest way to sign PDFs & request signatures from others" />
|
||||||
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> -->
|
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> -->
|
||||||
<!--
|
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
|
||||||
-->
|
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
|
||||||
<!--
|
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
|
||||||
Only files inside the `public` folder can be referenced from the HTML.
|
|
||||||
|
|
||||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
<link rel="manifest" href="/manifest.json" />
|
||||||
work correctly both with client-side routing and a non-root public URL.
|
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
|
||||||
-->
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"
|
|
||||||
integrity="sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn+CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA=="
|
|
||||||
crossorigin="anonymous" referrerpolicy="no-referrer" />
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
|
||||||
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" />
|
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" />
|
||||||
|
<link rel="stylesheet" href="/css/fonts.css" />
|
||||||
<title>OpenSign™</title>
|
<title>OpenSign™</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|
||||||
<!--
|
|
||||||
This HTML file is a template.
|
|
||||||
If you open it directly in the browser, you will see an empty page.
|
|
||||||
|
|
||||||
You can add webfonts, meta tags, or analytics to this file.
|
|
||||||
The build step will place the bundled scripts into the <body> tag.
|
|
||||||
|
|
||||||
To begin the development, run `npm start` or `yarn start`.
|
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
|
||||||
-->
|
|
||||||
</body>
|
</body>
|
||||||
|
</html>
|
||||||
</html>
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+109
-91
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, Suspense, lazy } from "react";
|
import React, { useState, useEffect, lazy } from "react";
|
||||||
import { Routes, Route, BrowserRouter } from "react-router-dom";
|
import { Routes, Route, BrowserRouter } from "react-router-dom";
|
||||||
import { pdfjs } from "react-pdf";
|
import { pdfjs } from "react-pdf";
|
||||||
import Login from "./pages/Login";
|
import Login from "./pages/Login";
|
||||||
@@ -9,12 +9,15 @@ import HomeLayout from "./layout/HomeLayout";
|
|||||||
import PageNotFound from "./pages/PageNotFound";
|
import PageNotFound from "./pages/PageNotFound";
|
||||||
import ValidateRoute from "./primitives/ValidateRoute";
|
import ValidateRoute from "./primitives/ValidateRoute";
|
||||||
import Validate from "./primitives/Validate";
|
import Validate from "./primitives/Validate";
|
||||||
import ManageSign from "./pages/Managesign";
|
|
||||||
import TemplatePlaceholder from "./pages/TemplatePlaceholder";
|
import TemplatePlaceholder from "./pages/TemplatePlaceholder";
|
||||||
import SignYourSelf from "./pages/SignyourselfPdf";
|
import SignYourSelf from "./pages/SignyourselfPdf";
|
||||||
import DraftDocument from "./components/pdf/DraftDocument";
|
import DraftDocument from "./components/pdf/DraftDocument";
|
||||||
import PlaceHolderSign from "./pages/PlaceHolderSign";
|
import PlaceHolderSign from "./pages/PlaceHolderSign";
|
||||||
import PdfRequestFiles from "./pages/PdfRequestFiles";
|
import PdfRequestFiles from "./pages/PdfRequestFiles";
|
||||||
|
import LazyPage from "./primitives/LazyPage";
|
||||||
|
import { isEnableSubscription } from "./constant/const";
|
||||||
|
import SSOVerify from "./pages/SSOVerify";
|
||||||
|
import Loader from "./primitives/Loader";
|
||||||
const DebugPdf = lazy(() => import("./pages/DebugPdf"));
|
const DebugPdf = lazy(() => import("./pages/DebugPdf"));
|
||||||
const ForgetPassword = lazy(() => import("./pages/ForgetPassword"));
|
const ForgetPassword = lazy(() => import("./pages/ForgetPassword"));
|
||||||
const GuestLogin = lazy(() => import("./pages/GuestLogin"));
|
const GuestLogin = lazy(() => import("./pages/GuestLogin"));
|
||||||
@@ -23,28 +26,16 @@ const Subscriptions = lazy(() => import("./pages/PlanSubscriptions"));
|
|||||||
const ChangePassword = lazy(() => import("./pages/ChangePassword"));
|
const ChangePassword = lazy(() => import("./pages/ChangePassword"));
|
||||||
const UserProfile = lazy(() => import("./pages/UserProfile"));
|
const UserProfile = lazy(() => import("./pages/UserProfile"));
|
||||||
const Signup = lazy(() => import("./pages/Signup"));
|
const Signup = lazy(() => import("./pages/Signup"));
|
||||||
|
const Opensigndrive = lazy(() => import("./pages/Opensigndrive"));
|
||||||
|
const ManageSign = lazy(() => import("./pages/Managesign"));
|
||||||
const GenerateToken = lazy(() => import("./pages/GenerateToken"));
|
const GenerateToken = lazy(() => import("./pages/GenerateToken"));
|
||||||
const Webhook = lazy(() => import("./pages/Webhook"));
|
const Webhook = lazy(() => import("./pages/Webhook"));
|
||||||
const Opensigndrive = lazy(() => import("./pages/Opensigndrive"));
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
|
|
||||||
|
|
||||||
const Loader = () => {
|
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
|
||||||
|
const AppLoader = () => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="flex justify-center items-center h-[100vh]">
|
||||||
style={{
|
<Loader />
|
||||||
height: "100vh",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -73,88 +64,115 @@ function App() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-[#eef1f5]">
|
<div className="bg-base-200">
|
||||||
{isloading ? (
|
{isloading ? (
|
||||||
<Loader />
|
<AppLoader />
|
||||||
) : (
|
) : (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Suspense fallback={<Loader />}>
|
<Routes>
|
||||||
<Routes>
|
<Route element={<ValidateRoute />}>
|
||||||
<Route element={<ValidateRoute />}>
|
<Route exact path="/" element={<Login />} />
|
||||||
<Route exact path="/" element={<Login />} />
|
<Route path="/signup" element={<LazyPage Page={Signup} />} />
|
||||||
<Route exact path="/signup" element={<Signup />} />
|
</Route>
|
||||||
</Route>
|
<Route element={<Validate />}>
|
||||||
<Route element={<Validate />}>
|
|
||||||
<Route
|
|
||||||
path="/load/template/:templateId"
|
|
||||||
element={<TemplatePlaceholder />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
exact
|
|
||||||
path="/load/placeholdersign/:docId"
|
|
||||||
element={<PlaceHolderSign />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
exact
|
|
||||||
path="/load/recipientSignPdf/:docId/:contactBookId"
|
|
||||||
element={<PdfRequestFiles />}
|
|
||||||
/>
|
|
||||||
</Route>
|
|
||||||
<Route
|
<Route
|
||||||
path="/loadmf/signmicroapp/login/:id/:userMail/:contactBookId/:serverUrl"
|
path="/load/template/:templateId"
|
||||||
element={<GuestLogin />}
|
element={<TemplatePlaceholder />}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="/login/:id/:userMail/:contactBookId/:serverUrl"
|
exact
|
||||||
element={<GuestLogin />}
|
path="/load/placeholdersign/:docId"
|
||||||
|
element={<PlaceHolderSign />}
|
||||||
/>
|
/>
|
||||||
<Route path="/debugpdf" element={<DebugPdf />} />
|
<Route
|
||||||
<Route path="/forgetpassword" element={<ForgetPassword />} />
|
exact
|
||||||
{process.env.REACT_APP_ENABLE_SUBSCRIPTION && (
|
path="/load/recipientSignPdf/:docId/:contactBookId"
|
||||||
<>
|
element={<PdfRequestFiles />}
|
||||||
<Route exact path="/pgsignup" element={<Pgsignup />} />
|
/>
|
||||||
<Route path="/subscription" element={<Subscriptions />} />
|
</Route>
|
||||||
</>
|
<Route
|
||||||
)}
|
path="/loadmf/signmicroapp/login/:id/:userMail/:contactBookId/:serverUrl"
|
||||||
<Route element={<HomeLayout />}>
|
element={<LazyPage Page={GuestLogin} />}
|
||||||
<Route path="/changepassword" element={<ChangePassword />} />
|
/>
|
||||||
<Route path="/form/:id" element={<Form />} />
|
<Route
|
||||||
<Route path="/report/:id" element={<Report />} />
|
path="/login/:id/:userMail/:contactBookId/:serverUrl"
|
||||||
<Route path="/dashboard/:id" element={<Dashboard />} />
|
element={<LazyPage Page={GuestLogin} />}
|
||||||
<Route path="/profile" element={<UserProfile />} />
|
/>
|
||||||
<Route path="/generatetoken" element={<GenerateToken />} />
|
<Route
|
||||||
<Route path="/webhook" element={<Webhook />} />
|
path="/login/:base64url"
|
||||||
<Route path="/managesign" element={<ManageSign />} />
|
element={<LazyPage Page={GuestLogin} />}
|
||||||
<Route path="/opensigndrive" element={<Opensigndrive />} />
|
/>
|
||||||
|
<Route path="/debugpdf" element={<LazyPage Page={DebugPdf} />} />
|
||||||
|
<Route
|
||||||
|
path="/forgetpassword"
|
||||||
|
element={<LazyPage Page={ForgetPassword} />}
|
||||||
|
/>
|
||||||
|
{isEnableSubscription && (
|
||||||
|
<>
|
||||||
<Route
|
<Route
|
||||||
path="/template/:templateId"
|
path="/pgsignup"
|
||||||
element={<TemplatePlaceholder />}
|
element={<LazyPage Page={Pgsignup} />}
|
||||||
/>
|
/>
|
||||||
{/* signyouself route with no rowlevel data using docId from url */}
|
|
||||||
<Route path="/signaturePdf/:docId" element={<SignYourSelf />} />
|
|
||||||
{/* draft document route to handle and navigate route page accordiing to document status */}
|
|
||||||
<Route path="/draftDocument" element={<DraftDocument />} />
|
|
||||||
{/* recipient placeholder set route with no rowlevel data using docId from url*/}
|
|
||||||
<Route
|
<Route
|
||||||
path="/placeHolderSign/:docId"
|
path="/subscription"
|
||||||
element={<PlaceHolderSign />}
|
element={<LazyPage Page={Subscriptions} />}
|
||||||
/>
|
/>
|
||||||
{/* for user signature (need your sign route) with row level data */}
|
</>
|
||||||
<Route path="/pdfRequestFiles" element={<PdfRequestFiles />} />
|
)}
|
||||||
{/* for user signature (need your sign route) with no row level data */}
|
<Route element={<HomeLayout />}>
|
||||||
<Route
|
<Route
|
||||||
path="/pdfRequestFiles/:docId"
|
path="/changepassword"
|
||||||
element={<PdfRequestFiles />}
|
element={<LazyPage Page={ChangePassword} />}
|
||||||
/>
|
/>
|
||||||
{/* recipient signature route with no rowlevel data using docId from url */}
|
<Route path="/form/:id" element={<Form />} />
|
||||||
<Route
|
<Route path="/report/:id" element={<Report />} />
|
||||||
path="/recipientSignPdf/:docId/:contactBookId"
|
<Route path="/dashboard/:id" element={<Dashboard />} />
|
||||||
element={<PdfRequestFiles />}
|
<Route
|
||||||
/>
|
path="/profile"
|
||||||
</Route>
|
element={<LazyPage Page={UserProfile} />}
|
||||||
<Route path="*" element={<PageNotFound />} />
|
/>
|
||||||
</Routes>
|
<Route
|
||||||
</Suspense>
|
path="/opensigndrive"
|
||||||
|
element={<LazyPage Page={Opensigndrive} />}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="/managesign"
|
||||||
|
element={<LazyPage Page={ManageSign} />}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="/generatetoken"
|
||||||
|
element={<LazyPage Page={GenerateToken} />}
|
||||||
|
/>
|
||||||
|
<Route path="/webhook" element={<LazyPage Page={Webhook} />} />
|
||||||
|
<Route
|
||||||
|
path="/template/:templateId"
|
||||||
|
element={<TemplatePlaceholder />}
|
||||||
|
/>
|
||||||
|
{/* signyouself route with no rowlevel data using docId from url */}
|
||||||
|
<Route path="/signaturePdf/:docId" element={<SignYourSelf />} />
|
||||||
|
{/* draft document route to handle and navigate route page accordiing to document status */}
|
||||||
|
<Route path="/draftDocument" element={<DraftDocument />} />
|
||||||
|
{/* recipient placeholder set route with no rowlevel data using docId from url*/}
|
||||||
|
<Route
|
||||||
|
path="/placeHolderSign/:docId"
|
||||||
|
element={<PlaceHolderSign />}
|
||||||
|
/>
|
||||||
|
{/* for user signature (need your sign route) with row level data */}
|
||||||
|
<Route path="/pdfRequestFiles" element={<PdfRequestFiles />} />
|
||||||
|
{/* for user signature (need your sign route) with no row level data */}
|
||||||
|
<Route
|
||||||
|
path="/pdfRequestFiles/:docId"
|
||||||
|
element={<PdfRequestFiles />}
|
||||||
|
/>
|
||||||
|
{/* recipient signature route with no rowlevel data using docId from url */}
|
||||||
|
<Route
|
||||||
|
path="/recipientSignPdf/:docId/:contactBookId"
|
||||||
|
element={<PdfRequestFiles />}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
<Route path="/sso" element={<SSOVerify />} />
|
||||||
|
<Route path="*" element={<PageNotFound />} />
|
||||||
|
</Routes>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 61 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 234 KiB |
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const";
|
import Loader from "../primitives/Loader";
|
||||||
|
|
||||||
const AddSigner = (props) => {
|
const AddSigner = (props) => {
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
@@ -23,7 +23,7 @@ const AddSigner = (props) => {
|
|||||||
);
|
);
|
||||||
if (savedUserDetails && addYourself) {
|
if (savedUserDetails && addYourself) {
|
||||||
setName(savedUserDetails.name);
|
setName(savedUserDetails.name);
|
||||||
setPhone(savedUserDetails.phone);
|
setPhone(savedUserDetails?.phone || "");
|
||||||
setEmail(savedUserDetails.email);
|
setEmail(savedUserDetails.email);
|
||||||
}
|
}
|
||||||
}, [addYourself]);
|
}, [addYourself]);
|
||||||
@@ -49,144 +49,162 @@ const AddSigner = (props) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIsLoader(true);
|
setIsLoader(true);
|
||||||
try {
|
if (localStorage.getItem("TenantId")) {
|
||||||
const contactQuery = new Parse.Object("contracts_Contactbook");
|
|
||||||
contactQuery.set("Name", name);
|
|
||||||
contactQuery.set("Phone", phone);
|
|
||||||
contactQuery.set("Email", email);
|
|
||||||
contactQuery.set("UserRole", "contracts_Guest");
|
|
||||||
|
|
||||||
if (localStorage.getItem("TenetId")) {
|
|
||||||
contactQuery.set("TenantId", {
|
|
||||||
__type: "Pointer",
|
|
||||||
className: "partners_Tenant",
|
|
||||||
objectId: localStorage.getItem("TenetId")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const _users = Parse.Object.extend("User");
|
const user = Parse.User.current();
|
||||||
const _user = new _users();
|
const query = new Parse.Query("contracts_Contactbook");
|
||||||
_user.set("name", name);
|
query.equalTo("CreatedBy", user);
|
||||||
_user.set("username", email);
|
query.notEqualTo("IsDeleted", true);
|
||||||
_user.set("email", email);
|
query.equalTo("Email", email);
|
||||||
_user.set("phone", phone);
|
const res = await query.first();
|
||||||
_user.set("password", phone);
|
// console.log(res);
|
||||||
|
if (!res) {
|
||||||
const user = await _user.save();
|
const contactQuery = new Parse.Object("contracts_Contactbook");
|
||||||
if (user) {
|
contactQuery.set("Name", name);
|
||||||
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
|
if (phone) {
|
||||||
const headers = {
|
contactQuery.set("Phone", phone);
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId,
|
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
|
||||||
};
|
|
||||||
const body = {
|
|
||||||
appName: localStorage.getItem("_appName"),
|
|
||||||
roleName: "contracts_Guest",
|
|
||||||
userId: user.id
|
|
||||||
};
|
|
||||||
await axios.post(roleurl, body, { headers: headers });
|
|
||||||
const currentUser = Parse.User.current();
|
|
||||||
contactQuery.set(
|
|
||||||
"CreatedBy",
|
|
||||||
Parse.User.createWithoutData(currentUser.id)
|
|
||||||
);
|
|
||||||
|
|
||||||
contactQuery.set("UserId", user);
|
|
||||||
const acl = new Parse.ACL();
|
|
||||||
acl.setPublicReadAccess(true);
|
|
||||||
acl.setPublicWriteAccess(true);
|
|
||||||
acl.setReadAccess(currentUser.id, true);
|
|
||||||
acl.setWriteAccess(currentUser.id, true);
|
|
||||||
|
|
||||||
contactQuery.setACL(acl);
|
|
||||||
|
|
||||||
const res = await contactQuery.save();
|
|
||||||
|
|
||||||
const parseData = JSON.parse(JSON.stringify(res));
|
|
||||||
if (props.details) {
|
|
||||||
props.details({
|
|
||||||
value: parseData[props.valueKey],
|
|
||||||
label: parseData[props.displayKey]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (props.closePopup) {
|
|
||||||
props.closePopup();
|
|
||||||
}
|
|
||||||
if (props.handleUserData) {
|
|
||||||
props.handleUserData(parseData);
|
|
||||||
}
|
}
|
||||||
|
contactQuery.set("Email", email);
|
||||||
|
contactQuery.set("UserRole", "contracts_Guest");
|
||||||
|
|
||||||
|
contactQuery.set("TenantId", {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: "partners_Tenant",
|
||||||
|
objectId: localStorage.getItem("TenantId")
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const _users = Parse.Object.extend("User");
|
||||||
|
const _user = new _users();
|
||||||
|
_user.set("name", name);
|
||||||
|
_user.set("username", email);
|
||||||
|
_user.set("email", email);
|
||||||
|
_user.set("password", email);
|
||||||
|
if (phone) {
|
||||||
|
_user.set("phone", phone);
|
||||||
|
}
|
||||||
|
const user = await _user.save();
|
||||||
|
if (user) {
|
||||||
|
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
|
||||||
|
const headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Parse-Application-Id": parseAppId,
|
||||||
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
|
};
|
||||||
|
const body = {
|
||||||
|
appName: localStorage.getItem("_appName"),
|
||||||
|
roleName: "contracts_Guest",
|
||||||
|
userId: user.id
|
||||||
|
};
|
||||||
|
await axios.post(roleurl, body, { headers: headers });
|
||||||
|
const currentUser = Parse.User.current();
|
||||||
|
contactQuery.set(
|
||||||
|
"CreatedBy",
|
||||||
|
Parse.User.createWithoutData(currentUser.id)
|
||||||
|
);
|
||||||
|
|
||||||
|
contactQuery.set("UserId", user);
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
acl.setPublicWriteAccess(true);
|
||||||
|
acl.setReadAccess(currentUser.id, true);
|
||||||
|
acl.setWriteAccess(currentUser.id, true);
|
||||||
|
|
||||||
|
contactQuery.setACL(acl);
|
||||||
|
|
||||||
|
const res = await contactQuery.save();
|
||||||
|
|
||||||
|
const parseData = JSON.parse(JSON.stringify(res));
|
||||||
|
if (props.details) {
|
||||||
|
props.details({
|
||||||
|
value: parseData[props.valueKey],
|
||||||
|
label: parseData[props.displayKey]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (props.closePopup) {
|
||||||
|
props.closePopup();
|
||||||
|
}
|
||||||
|
if (props.handleUserData) {
|
||||||
|
props.handleUserData(parseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsLoader(false);
|
||||||
|
// Reset the form fields
|
||||||
|
setAddYourself(false);
|
||||||
|
setName("");
|
||||||
|
setPhone("");
|
||||||
|
setEmail("");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err ", err);
|
||||||
|
if (err.code === 202) {
|
||||||
|
const params = { email: email };
|
||||||
|
const userRes = await Parse.Cloud.run("getUserId", params);
|
||||||
|
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
|
||||||
|
const headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Parse-Application-Id": parseAppId,
|
||||||
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
|
};
|
||||||
|
const body = {
|
||||||
|
appName: localStorage.getItem("_appName"),
|
||||||
|
roleName: "contracts_Guest",
|
||||||
|
userId: userRes.id
|
||||||
|
};
|
||||||
|
await axios.post(roleurl, body, { headers: headers });
|
||||||
|
const currentUser = Parse.User.current();
|
||||||
|
contactQuery.set(
|
||||||
|
"CreatedBy",
|
||||||
|
Parse.User.createWithoutData(currentUser.id)
|
||||||
|
);
|
||||||
|
|
||||||
|
contactQuery.set("UserId", {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: "_User",
|
||||||
|
objectId: userRes.id
|
||||||
|
});
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
acl.setPublicWriteAccess(true);
|
||||||
|
acl.setReadAccess(currentUser.id, true);
|
||||||
|
acl.setWriteAccess(currentUser.id, true);
|
||||||
|
|
||||||
|
contactQuery.setACL(acl);
|
||||||
|
const res = await contactQuery.save();
|
||||||
|
|
||||||
|
const parseData = JSON.parse(JSON.stringify(res));
|
||||||
|
if (props.details) {
|
||||||
|
props.details({
|
||||||
|
value: parseData[props.valueKey],
|
||||||
|
label: parseData[props.displayKey]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (props.closePopup) {
|
||||||
|
props.closePopup();
|
||||||
|
}
|
||||||
|
if (props.handleUserData) {
|
||||||
|
props.handleUserData(parseData);
|
||||||
|
}
|
||||||
|
setIsLoader(false);
|
||||||
|
// Reset the form fields
|
||||||
|
setAddYourself(false);
|
||||||
|
setName("");
|
||||||
|
setPhone("");
|
||||||
|
setEmail("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert("Contact already exist!");
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
// Reset the form fields
|
|
||||||
setAddYourself(false);
|
|
||||||
setName("");
|
|
||||||
setPhone("");
|
|
||||||
setEmail("");
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err ", err);
|
console.log("err in fetch contact", err);
|
||||||
if (err.code === 202) {
|
setIsLoader(false);
|
||||||
const params = { email: email };
|
alert("something went wrong, please try again later");
|
||||||
const userRes = await Parse.Cloud.run("getUserId", params);
|
|
||||||
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
|
|
||||||
const headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId,
|
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
|
||||||
};
|
|
||||||
const body = {
|
|
||||||
appName: localStorage.getItem("_appName"),
|
|
||||||
roleName: "contracts_Guest",
|
|
||||||
userId: userRes.id
|
|
||||||
};
|
|
||||||
await axios.post(roleurl, body, { headers: headers });
|
|
||||||
const currentUser = Parse.User.current();
|
|
||||||
contactQuery.set(
|
|
||||||
"CreatedBy",
|
|
||||||
Parse.User.createWithoutData(currentUser.id)
|
|
||||||
);
|
|
||||||
|
|
||||||
contactQuery.set("UserId", {
|
|
||||||
__type: "Pointer",
|
|
||||||
className: "_User",
|
|
||||||
objectId: userRes.id
|
|
||||||
});
|
|
||||||
const acl = new Parse.ACL();
|
|
||||||
acl.setPublicReadAccess(true);
|
|
||||||
acl.setPublicWriteAccess(true);
|
|
||||||
acl.setReadAccess(currentUser.id, true);
|
|
||||||
acl.setWriteAccess(currentUser.id, true);
|
|
||||||
|
|
||||||
contactQuery.setACL(acl);
|
|
||||||
const res = await contactQuery.save();
|
|
||||||
|
|
||||||
const parseData = JSON.parse(JSON.stringify(res));
|
|
||||||
if (props.details) {
|
|
||||||
props.details({
|
|
||||||
value: parseData[props.valueKey],
|
|
||||||
label: parseData[props.displayKey]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (props.closePopup) {
|
|
||||||
props.closePopup();
|
|
||||||
}
|
|
||||||
if (props.handleUserData) {
|
|
||||||
props.handleUserData(parseData);
|
|
||||||
}
|
|
||||||
setIsLoader(false);
|
|
||||||
// Reset the form fields
|
|
||||||
setAddYourself(false);
|
|
||||||
setName("");
|
|
||||||
setPhone("");
|
|
||||||
setEmail("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} else {
|
||||||
// console.log("err", err);
|
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
alert("something went wrong!");
|
alert("something went wrong, please try again later");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -209,38 +227,29 @@ const AddSigner = (props) => {
|
|||||||
<div className="h-full p-[20px]">
|
<div className="h-full p-[20px]">
|
||||||
{isLoader && (
|
{isLoader && (
|
||||||
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30">
|
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30">
|
||||||
<div
|
<Loader />
|
||||||
style={{
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="w-full mx-auto p-2">
|
<div className="w-full mx-auto p-2 text-base-content">
|
||||||
{isUserExist && (
|
{isUserExist && (
|
||||||
<div className="mb-3">
|
<div className="mb-3 flex items-center">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="addYourself"
|
id="addYourself"
|
||||||
checked={addYourself}
|
checked={addYourself}
|
||||||
onChange={handleAddYourselfChange}
|
onChange={handleAddYourselfChange}
|
||||||
className="form-checkbox"
|
className="op-checkbox op-checkbox-sm"
|
||||||
/>
|
/>
|
||||||
<label htmlFor="addYourself" className="ml-2 text-gray-700">
|
<label htmlFor="addYourself" className="ml-2 mb-0">
|
||||||
Add Yourself
|
Add Yourself
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label
|
<label htmlFor="name" className="block text-xs font-semibold">
|
||||||
htmlFor="name"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Name
|
Name
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -249,59 +258,45 @@ const AddSigner = (props) => {
|
|||||||
onChange={(e) => setName(e.target.value)}
|
onChange={(e) => setName(e.target.value)}
|
||||||
required
|
required
|
||||||
disabled={addYourself}
|
disabled={addYourself}
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label
|
<label htmlFor="email" className="block text-xs font-semibold">
|
||||||
htmlFor="email"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Email
|
Email
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
id="email"
|
id="email"
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value?.toLowerCase())}
|
||||||
required
|
required
|
||||||
disabled={addYourself}
|
disabled={addYourself}
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label
|
<label htmlFor="phone" className="block text-xs font-semibold">
|
||||||
htmlFor="phone"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Phone
|
Phone
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="phone"
|
id="phone"
|
||||||
value={phone}
|
value={phone}
|
||||||
onChange={(e) => setPhone(e.target.value)}
|
onChange={(e) => setPhone(e.target.value)}
|
||||||
required
|
|
||||||
disabled={addYourself}
|
disabled={addYourself}
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-4 flex gap-x-2 justify-start">
|
||||||
<div className="mt-4 flex justify-start">
|
<button type="submit" className="op-btn op-btn-primary">
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
style={{ backgroundColor: modalSubmitBtnColor }}
|
|
||||||
className="mr-2 px-[20px] py-1.5 text-white rounded shadow-md text-center focus:outline-none "
|
|
||||||
>
|
|
||||||
Submit
|
Submit
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleReset()}
|
onClick={() => handleReset()}
|
||||||
style={{ backgroundColor: modalCancelBtnColor }}
|
className="op-btn op-btn-secondary"
|
||||||
className="px-4 py-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none"
|
|
||||||
>
|
>
|
||||||
Reset
|
Reset
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Parse from "parse";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Title from "./Title";
|
import Title from "./Title";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
|
||||||
const AddUser = (props) => {
|
const AddUser = (props) => {
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
@@ -48,11 +49,11 @@ const AddUser = (props) => {
|
|||||||
contactQuery.set("Email", email);
|
contactQuery.set("Email", email);
|
||||||
contactQuery.set("UserRole", "contracts_User");
|
contactQuery.set("UserRole", "contracts_User");
|
||||||
|
|
||||||
if (localStorage.getItem("TenetId")) {
|
if (localStorage.getItem("TenantId")) {
|
||||||
contactQuery.set("TenantId", {
|
contactQuery.set("TenantId", {
|
||||||
__type: "Pointer",
|
__type: "Pointer",
|
||||||
className: "partners_Tenant",
|
className: "partners_Tenant",
|
||||||
objectId: localStorage.getItem("TenetId")
|
objectId: localStorage.getItem("TenantId")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,8 +63,10 @@ const AddUser = (props) => {
|
|||||||
_user.set("name", name);
|
_user.set("name", name);
|
||||||
_user.set("username", email);
|
_user.set("username", email);
|
||||||
_user.set("email", email);
|
_user.set("email", email);
|
||||||
_user.set("phone", phone);
|
_user.set("password", email);
|
||||||
_user.set("password", phone);
|
if (phone) {
|
||||||
|
_user.set("phone", phone);
|
||||||
|
}
|
||||||
|
|
||||||
const user = await _user.save();
|
const user = await _user.save();
|
||||||
if (user) {
|
if (user) {
|
||||||
@@ -193,13 +196,7 @@ const AddUser = (props) => {
|
|||||||
{isUserExist && <Alert type="danger">User already exists!</Alert>}
|
{isUserExist && <Alert type="danger">User already exists!</Alert>}
|
||||||
{isLoader && (
|
{isLoader && (
|
||||||
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30 z-50">
|
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30 z-50">
|
||||||
<div
|
<Loader />
|
||||||
style={{
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="w-full mx-auto">
|
<div className="w-full mx-auto">
|
||||||
@@ -211,7 +208,7 @@ const AddUser = (props) => {
|
|||||||
className="block text-xs text-gray-700 font-semibold"
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
>
|
>
|
||||||
Name
|
Name
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -219,7 +216,7 @@ const AddUser = (props) => {
|
|||||||
value={name}
|
value={name}
|
||||||
onChange={(e) => setName(e.target.value)}
|
onChange={(e) => setName(e.target.value)}
|
||||||
required
|
required
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
@@ -228,7 +225,7 @@ const AddUser = (props) => {
|
|||||||
className="block text-xs text-gray-700 font-semibold"
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
>
|
>
|
||||||
Email
|
Email
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
@@ -236,7 +233,7 @@ const AddUser = (props) => {
|
|||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
required
|
required
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
@@ -245,7 +242,7 @@ const AddUser = (props) => {
|
|||||||
className="block text-xs text-gray-700 font-semibold"
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
>
|
>
|
||||||
Phone
|
Phone
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -253,7 +250,7 @@ const AddUser = (props) => {
|
|||||||
value={phone}
|
value={phone}
|
||||||
onChange={(e) => setPhone(e.target.value)}
|
onChange={(e) => setPhone(e.target.value)}
|
||||||
required
|
required
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,283 @@
|
|||||||
|
import React, { useState, useEffect, useRef } from "react";
|
||||||
|
import axios from "axios";
|
||||||
|
import SuggestionInput from "./shared/fields/SuggestionInput";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
|
||||||
|
const BulkSendUi = (props) => {
|
||||||
|
const [forms, setForms] = useState([]);
|
||||||
|
const [formId, setFormId] = useState(2);
|
||||||
|
const formRef = useRef(null);
|
||||||
|
const [scrollOnNextUpdate, setScrollOnNextUpdate] = useState(false);
|
||||||
|
const [isSubmit, setIsSubmit] = useState(false);
|
||||||
|
const [allowedForm, setAllowedForm] = useState(0);
|
||||||
|
const [isSignatureExist, setIsSignatureExist] = useState();
|
||||||
|
const allowedSigners = 50;
|
||||||
|
useEffect(() => {
|
||||||
|
signatureExist();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
//function to check atleast one signature field exist
|
||||||
|
const signatureExist = () => {
|
||||||
|
const getPlaceholder = props.item?.Placeholders;
|
||||||
|
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
|
||||||
|
placeholderObj?.placeHolder?.some((holder) =>
|
||||||
|
holder?.pos?.some((posItem) => posItem?.type === "signature")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
setIsSignatureExist(checkIsSignatureExistt);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
if (scrollOnNextUpdate && formRef.current) {
|
||||||
|
formRef.current.scrollIntoView({
|
||||||
|
behavior: "smooth",
|
||||||
|
block: "end",
|
||||||
|
inline: "nearest"
|
||||||
|
});
|
||||||
|
setScrollOnNextUpdate(false);
|
||||||
|
}
|
||||||
|
}, [forms, scrollOnNextUpdate]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(() => {
|
||||||
|
if (props?.Placeholders?.length > 0) {
|
||||||
|
let users = [];
|
||||||
|
props?.Placeholders?.forEach((element) => {
|
||||||
|
if (!element.signerObjId) {
|
||||||
|
users = [
|
||||||
|
...users,
|
||||||
|
{
|
||||||
|
fieldId: element.Id,
|
||||||
|
email: "",
|
||||||
|
label: element.Role,
|
||||||
|
signer: {}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setForms((prevForms) => [...prevForms, { Id: 1, fields: users }]);
|
||||||
|
const totalForms = Math.floor(allowedSigners / users?.length);
|
||||||
|
setAllowedForm(totalForms);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
// eslint-disable-next-line
|
||||||
|
}, []);
|
||||||
|
const handleInputChange = (index, signer, fieldIndex) => {
|
||||||
|
const newForms = [...forms];
|
||||||
|
newForms[index].fields[fieldIndex].email = signer?.Email
|
||||||
|
? signer?.Email
|
||||||
|
: signer || "";
|
||||||
|
newForms[index].fields[fieldIndex].signer = signer?.objectId ? signer : "";
|
||||||
|
setForms(newForms);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddForm = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
// Check if the quick send limit has been reached
|
||||||
|
if (forms?.length < allowedForm) {
|
||||||
|
if (props?.Placeholders.length > 0) {
|
||||||
|
let newForm = [];
|
||||||
|
props?.Placeholders?.forEach((element) => {
|
||||||
|
if (!element.signerObjId) {
|
||||||
|
newForm = [
|
||||||
|
...newForm,
|
||||||
|
{
|
||||||
|
fieldId: element.Id,
|
||||||
|
email: "",
|
||||||
|
label: element.Role,
|
||||||
|
signer: {}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setForms([...forms, { Id: formId, fields: newForm }]);
|
||||||
|
}
|
||||||
|
setFormId(formId + 1);
|
||||||
|
setScrollOnNextUpdate(true);
|
||||||
|
} else {
|
||||||
|
// If the limit has been reached, throw an error with the appropriate message
|
||||||
|
alert("Quick send reached limit.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemoveForm = (index) => {
|
||||||
|
const updatedForms = forms.filter((_, i) => i !== index);
|
||||||
|
setForms(updatedForms);
|
||||||
|
};
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setIsSubmit(true);
|
||||||
|
|
||||||
|
// Create a copy of Placeholders array from props.item
|
||||||
|
let Placeholders = [...props.item.Placeholders];
|
||||||
|
// Initialize an empty array to store updated documents
|
||||||
|
let Documents = [];
|
||||||
|
// Loop through each form
|
||||||
|
forms.forEach((form) => {
|
||||||
|
//checking if user enter email which already exist as a signer then add user in a signers array
|
||||||
|
let existSigner = [];
|
||||||
|
form.fields.map((data) => {
|
||||||
|
if (data.signer) {
|
||||||
|
existSigner.push(data.signer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Map through the copied Placeholders array to update email values
|
||||||
|
const updatedPlaceholders = Placeholders.map((placeholder) => {
|
||||||
|
// Find the field in the current form that matches the placeholder Id
|
||||||
|
const field = form.fields.find(
|
||||||
|
(element) => parseInt(element.fieldId) === placeholder.Id
|
||||||
|
);
|
||||||
|
// If a matching field is found, update the email value in the placeholder
|
||||||
|
const signer = field?.signer?.objectId ? field.signer : "";
|
||||||
|
if (field) {
|
||||||
|
if (signer) {
|
||||||
|
return {
|
||||||
|
...placeholder,
|
||||||
|
signerObjId: field?.signer?.objectId || "",
|
||||||
|
signerPtr: signer
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
...placeholder,
|
||||||
|
email: field.email,
|
||||||
|
signerObjId: field?.signer?.objectId || "",
|
||||||
|
signerPtr: signer
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If no matching field is found, keep the placeholder as is
|
||||||
|
return placeholder;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Push a new document object with updated Placeholders into the Documents array
|
||||||
|
if (existSigner?.length > 0) {
|
||||||
|
Documents.push({
|
||||||
|
...props.item,
|
||||||
|
Placeholders: updatedPlaceholders,
|
||||||
|
Signers: props.item.Signers
|
||||||
|
? [...props.item.Signers, ...existSigner]
|
||||||
|
: [...existSigner]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Documents.push({
|
||||||
|
...props.item,
|
||||||
|
Placeholders: updatedPlaceholders
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//console.log("Documents ", Documents);
|
||||||
|
await batchQuery(Documents);
|
||||||
|
};
|
||||||
|
|
||||||
|
const batchQuery = async (Documents) => {
|
||||||
|
const serverUrl = localStorage.getItem("baseUrl");
|
||||||
|
const functionsUrl = `${serverUrl}functions/batchdocuments`;
|
||||||
|
const headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
|
};
|
||||||
|
const params = {
|
||||||
|
Documents: JSON.stringify(Documents)
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const res = await axios.post(functionsUrl, params, { headers: headers });
|
||||||
|
// console.log("res ", res);
|
||||||
|
if (res.data && res.data.result) {
|
||||||
|
props.handleClose("success", Documents?.length);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err ", err);
|
||||||
|
props.handleClose("error", 0);
|
||||||
|
} finally {
|
||||||
|
setIsSubmit(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{isSubmit && (
|
||||||
|
<div className="absolute z-[999] h-full w-full flex justify-center items-center bg-black bg-opacity-30">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{props.Placeholders?.length > 0 ? (
|
||||||
|
isSignatureExist ? (
|
||||||
|
<>
|
||||||
|
{props.Placeholders?.some((x) => !x.signerObjId) ? (
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<div className="min-h-max max-h-[250px] overflow-y-auto">
|
||||||
|
{forms?.map((form, index) => (
|
||||||
|
<div
|
||||||
|
key={form.Id}
|
||||||
|
className="p-3 op-card border-[1px] border-gray-400 mt-3 mx-4 mb-4 bg-base-200 text-base-content grid grid-cols-1 md:grid-cols-2 gap-2 relative"
|
||||||
|
>
|
||||||
|
{form?.fields?.map((field, fieldIndex) => (
|
||||||
|
<div className="flex flex-col" key={field.fieldId}>
|
||||||
|
<label>{field.label}</label>
|
||||||
|
<SuggestionInput
|
||||||
|
required
|
||||||
|
type="email"
|
||||||
|
value={field.value}
|
||||||
|
index={fieldIndex}
|
||||||
|
onChange={(signer) =>
|
||||||
|
handleInputChange(index, signer, fieldIndex)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{forms?.length > 1 && (
|
||||||
|
<button
|
||||||
|
onClick={() => handleRemoveForm(index)}
|
||||||
|
className="absolute right-3 top-1 text-[red] border-[1px] border-[red] rounded-lg w-[1.7rem] h-[1.7rem]"
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<div ref={formRef}></div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col mx-4 mb-4 gap-3">
|
||||||
|
<button
|
||||||
|
onClick={handleAddForm}
|
||||||
|
className="op-btn op-btn-primary focus:outline-none"
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-plus"></i> <span>Add new</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="op-btn op-btn-secondary focus:outline-none"
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-paper-plane"></i>{" "}
|
||||||
|
<span>Send</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
) : (
|
||||||
|
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
|
||||||
|
All roles in this document are currently linked to contacts. To
|
||||||
|
'quick send' copies of this template to multiple
|
||||||
|
signers, please ensure that at least one role is not linked to
|
||||||
|
any contact.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
|
||||||
|
Please ensure there's at least one signature widget added for
|
||||||
|
all recipients.
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
|
||||||
|
Please add at least one role to this template in order to 'quick
|
||||||
|
send' copies of it to multiple signers.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BulkSendUi;
|
||||||
@@ -45,19 +45,23 @@ const Footer = () => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="bg-[#222c3c] text-[#98a6ba] text-center text-[13px] py-3">
|
<footer className="op-footer op-footer-center py-3 bg-base-300 text-base-content text-center text-[13px]">
|
||||||
All Rights Reserved © {new Date().getFullYear()}
|
<aside>
|
||||||
<span onClick={openUrl} className="hover:underline cursor-pointer">
|
<p>
|
||||||
{appName} ( version: {version ? version : `${Package.version} `})
|
All Rights Reserved © {new Date().getFullYear()}
|
||||||
</span>
|
<span onClick={openUrl} className="hover:underline cursor-pointer">
|
||||||
</div>
|
{appName} ( version: {version ? version : `${Package.version} `})
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</aside>
|
||||||
|
</footer>
|
||||||
<button
|
<button
|
||||||
className={`${
|
className={`${
|
||||||
showButton ? "block" : "hidden"
|
showButton ? "block" : "hidden"
|
||||||
} fixed bottom-4 right-4 px-3 p-2 text-xl bg-blue-500 text-white rounded focus:outline-none`}
|
} fixed bottom-4 right-4 px-3 p-2 text-xl op-bg-secondary text-white rounded focus:outline-none`}
|
||||||
onClick={scrollToTop}
|
onClick={scrollToTop}
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-angle-up"></i>
|
<i className="fa-light fa-angle-up"></i>
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -67,12 +67,12 @@ const FullScreenButton = () => {
|
|||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<button
|
<button
|
||||||
onClick={toggleFullScreen}
|
onClick={toggleFullScreen}
|
||||||
className="text-black p-2 text-sm focus:outline-none"
|
className="text-base-content p-2 text-sm focus:outline-none"
|
||||||
>
|
>
|
||||||
{isFullScreen ? (
|
{isFullScreen ? (
|
||||||
<i className="fa-solid fa-compress"></i>
|
<i className="fa-light fa-compress"></i>
|
||||||
) : (
|
) : (
|
||||||
<i className="fa fa-maximize"></i>
|
<i className="fa-light fa-maximize"></i>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,23 +4,53 @@ 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 { openInNewTab } from "../constant/Utils";
|
import { checkIsSubscribed, getAppLogo, openInNewTab } from "../constant/Utils";
|
||||||
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
|
||||||
const Header = ({ showSidebar }) => {
|
const Header = ({ showSidebar }) => {
|
||||||
const navigation = 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 [isPro, setIsPro] = useState(false);
|
||||||
|
const [applogo, setAppLogo] = useState(
|
||||||
|
localStorage.getItem("appLogo") || " "
|
||||||
|
);
|
||||||
|
|
||||||
const toggleDropdown = () => {
|
const toggleDropdown = () => {
|
||||||
setIsOpen(!isOpen);
|
setIsOpen(!isOpen);
|
||||||
};
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
checkSubscription();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
async function checkSubscription() {
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const getIsSubscribe = await checkIsSubscribed();
|
||||||
|
if (getIsSubscribe) {
|
||||||
|
const applogo = await getAppLogo();
|
||||||
|
if (applogo) {
|
||||||
|
setAppLogo(applogo);
|
||||||
|
} else {
|
||||||
|
setAppLogo(localStorage.getItem("appLogo") || "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setIsPro(getIsSubscribe);
|
||||||
|
setIsSubscribe(getIsSubscribe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const closeDropdown = () => {
|
const closeDropdown = () => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
Parse.User.logOut();
|
if (Parse?.User?.current()) {
|
||||||
|
try {
|
||||||
|
Parse.User.logOut();
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
let appdata = localStorage.getItem("userSettings");
|
let appdata = localStorage.getItem("userSettings");
|
||||||
let applogo = localStorage.getItem("appLogo");
|
let applogo = localStorage.getItem("appLogo");
|
||||||
let appName = localStorage.getItem("appName");
|
let appName = localStorage.getItem("appName");
|
||||||
@@ -43,7 +73,7 @@ const Header = ({ showSidebar }) => {
|
|||||||
localStorage.setItem("baseUrl", baseUrl);
|
localStorage.setItem("baseUrl", baseUrl);
|
||||||
localStorage.setItem("parseAppId", appid);
|
localStorage.setItem("parseAppId", appid);
|
||||||
|
|
||||||
navigation("/");
|
navigate("/");
|
||||||
};
|
};
|
||||||
|
|
||||||
//handle to close profile drop down menu onclick screen
|
//handle to close profile drop down menu onclick screen
|
||||||
@@ -63,14 +93,16 @@ const Header = ({ showSidebar }) => {
|
|||||||
}, [isOpen]);
|
}, [isOpen]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-row justify-between items-center gap-x-3 md:gap-x-4 bg-white md:px-4 px-2 shadow h-[50px] md:w-full ">
|
<div className="op-navbar bg-base-100 shadow">
|
||||||
<button
|
<div className="flex-none">
|
||||||
className="cursor-pointer focus:outline-none"
|
<button
|
||||||
onClick={showSidebar}
|
className="op-btn op-btn-square op-btn-ghost focus:outline-none hover:bg-transparent op-btn-sm no-animation"
|
||||||
>
|
onClick={showSidebar}
|
||||||
<i className={`fa-solid fa-bars text-xl `}></i>
|
>
|
||||||
</button>
|
<i className="fa-light fa-bars text-xl text-base-content"></i>
|
||||||
<div className="flex-1">
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 ml-2">
|
||||||
<div className="h-[25px] md:h-[40px] w-auto overflow-hidden">
|
<div className="h-[25px] md:h-[40px] w-auto overflow-hidden">
|
||||||
<img
|
<img
|
||||||
className="object-contain h-full w-auto"
|
className="object-contain h-full w-auto"
|
||||||
@@ -79,10 +111,22 @@ const Header = ({ showSidebar }) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div id="profile-menu" className="flex-none gap-2">
|
||||||
id="profile-menu"
|
{!isSubscribe && (
|
||||||
className="flex justify-between items-center gap-x-3"
|
<div>
|
||||||
>
|
<button
|
||||||
|
className="text-xs md:text-sm shadow op-btn op-btn-outline op-btn-sm md:op-btn-md op-btn-accent"
|
||||||
|
onClick={() => navigate("/subscription")}
|
||||||
|
>
|
||||||
|
Upgrade Now
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isPro && (
|
||||||
|
<div className="w-[35px] h-[35px] bg-white rounded-full ring-[1px] ring-offset-2 ring-[#002862] text-[#002862] overflow-hidden font-semibold flex items-center justify-center">
|
||||||
|
PRO
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div>
|
<div>
|
||||||
<FullScreenButton />
|
<FullScreenButton />
|
||||||
</div>
|
</div>
|
||||||
@@ -99,52 +143,70 @@ const Header = ({ showSidebar }) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{width >= 768 && (
|
{width >= 768 && (
|
||||||
<div onClick={toggleDropdown} className="cursor-pointer text-sm">
|
<div
|
||||||
|
onClick={toggleDropdown}
|
||||||
|
className="cursor-pointer text-base-content text-sm"
|
||||||
|
>
|
||||||
{username && username}
|
{username && username}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="relative">
|
<div className="op-dropdown op-dropdown-end" id="profile-menu">
|
||||||
<div className="cursor-pointer">
|
|
||||||
<i onClick={toggleDropdown} className="fa-solid fa-angle-down"></i>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
className={`dropdown absolute text-sm text-gray-700 font-light right-0 mt-4 p-1 w-48 bg-white border rounded-lg shadow-lg z-10 ${
|
tabIndex={0}
|
||||||
isOpen ? "block" : "hidden"
|
role="button"
|
||||||
}`}
|
className="op-btn op-btn-ghost op-btn-xs w-[10px] h-[20px] hover:bg-transparent"
|
||||||
>
|
>
|
||||||
<ul>
|
<i
|
||||||
<li
|
tabIndex={0}
|
||||||
className="hover:bg-gray-100 rounded-t-lg py-1 px-2 cursor-pointer font-normal"
|
role="button"
|
||||||
onClick={() => openInNewTab("https://docs.opensignlabs.com")}
|
onClick={toggleDropdown}
|
||||||
>
|
className="fa-light fa-angle-down text-base-content"
|
||||||
<i className="fa-solid fa-book"></i> Docs
|
></i>
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
|
|
||||||
onClick={() => {
|
|
||||||
setIsOpen(false);
|
|
||||||
navigation("/profile");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i className="fa-regular fa-user"></i> Profile
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
|
|
||||||
onClick={() => {
|
|
||||||
setIsOpen(false);
|
|
||||||
navigation("/changepassword");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-lock"></i> Change Password
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
className="hover:bg-gray-100 rounded-b-lg py-1 px-2 cursor-pointer font-normal"
|
|
||||||
onClick={closeDropdown}
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-arrow-right-from-bracket"></i> Log Out
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
<ul
|
||||||
|
tabIndex={0}
|
||||||
|
className="mt-3 z-[1] p-2 shadow op-menu op-menu-sm op-dropdown-content text-base-content bg-base-100 rounded-box w-52"
|
||||||
|
>
|
||||||
|
<li onClick={() => openInNewTab("https://docs.opensignlabs.com")}>
|
||||||
|
<span>
|
||||||
|
<i className="fa-light fa-book"></i> Docs
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
onClick={() => {
|
||||||
|
setIsOpen(false);
|
||||||
|
navigate("/profile");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<i className="fa-light fa-user"></i> Profile
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
onClick={() => {
|
||||||
|
setIsOpen(false);
|
||||||
|
navigate("/changepassword");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<i className="fa-light fa-lock"></i> Change Password
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
onClick={() => {
|
||||||
|
window.open("https://console.opensignlabs.com/");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<i className="fa-light fa-id-card"></i> Console
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li onClick={closeDropdown}>
|
||||||
|
<span>
|
||||||
|
<i className="fa-light fa-arrow-right-from-bracket"></i> Log Out
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
// import FacebookLogin from "react-facebook-login";
|
// import FacebookLogin from "react-facebook-login";
|
||||||
|
|
||||||
const LoginFacebook = ({
|
const LoginFacebook = ({
|
||||||
@@ -49,7 +50,7 @@ const LoginFacebook = ({
|
|||||||
const extRes = await Parse.Cloud.run("getUserDetails", params);
|
const extRes = await Parse.Cloud.run("getUserDetails", params);
|
||||||
// console.log("extRes ", extRes);
|
// console.log("extRes ", extRes);
|
||||||
if (extRes) {
|
if (extRes) {
|
||||||
const params = { ...details, Phone: extRes.get("Phone") };
|
const params = { ...details, Phone: extRes?.get("Phone") || "" };
|
||||||
const payload = await Parse.Cloud.run("facebooksign", params);
|
const payload = await Parse.Cloud.run("facebooksign", params);
|
||||||
// console.log("payload ", payload);
|
// console.log("payload ", payload);
|
||||||
if (payload && payload.sessiontoken) {
|
if (payload && payload.sessiontoken) {
|
||||||
@@ -59,7 +60,7 @@ const LoginFacebook = ({
|
|||||||
const LocalUserDetails = {
|
const LocalUserDetails = {
|
||||||
name: details.Name,
|
name: details.Name,
|
||||||
email: details.Email,
|
email: details.Email,
|
||||||
phone: extRes.get("Phone"),
|
phone: extRes?.get("Phone") || "",
|
||||||
company: extRes.get("Company")
|
company: extRes.get("Company")
|
||||||
};
|
};
|
||||||
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
||||||
@@ -75,7 +76,7 @@ const LoginFacebook = ({
|
|||||||
const handleSubmitbtn = async () => {
|
const handleSubmitbtn = async () => {
|
||||||
if (userDetails.Phone && userDetails.Company) {
|
if (userDetails.Phone && userDetails.Company) {
|
||||||
setThirdpartyLoader(true);
|
setThirdpartyLoader(true);
|
||||||
const params = { ...fBDetails, Phone: userDetails.Phone };
|
const params = { ...fBDetails, Phone: userDetails?.Phone || "" };
|
||||||
const payload = await Parse.Cloud.run("facebooksign", params);
|
const payload = await Parse.Cloud.run("facebooksign", params);
|
||||||
// console.log("payload ", payload);
|
// console.log("payload ", payload);
|
||||||
|
|
||||||
@@ -85,7 +86,7 @@ const LoginFacebook = ({
|
|||||||
name: userDetails.Name,
|
name: userDetails.Name,
|
||||||
email: userDetails.Email,
|
email: userDetails.Email,
|
||||||
// "passsword":userDetails.Phone,
|
// "passsword":userDetails.Phone,
|
||||||
phone: userDetails.Phone,
|
phone: userDetails?.Phone || "",
|
||||||
role: "contracts_User",
|
role: "contracts_User",
|
||||||
company: userDetails.Company
|
company: userDetails.Company
|
||||||
}
|
}
|
||||||
@@ -96,7 +97,7 @@ const LoginFacebook = ({
|
|||||||
const LocalUserDetails = {
|
const LocalUserDetails = {
|
||||||
name: userDetails.Name,
|
name: userDetails.Name,
|
||||||
email: userDetails.Email,
|
email: userDetails.Email,
|
||||||
phone: userDetails.Phone,
|
phone: userDetails?.Phone || "",
|
||||||
company: userDetails.Company
|
company: userDetails.Company
|
||||||
};
|
};
|
||||||
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
||||||
@@ -112,29 +113,10 @@ const LoginFacebook = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div style={{ position: "relative" }}>
|
<div className="relative">
|
||||||
{thirdpartyLoader && (
|
{thirdpartyLoader && (
|
||||||
<div
|
<div className="fixed flex justify-center items-center inset-0 bg-black bg-opacity-25 z-20 ">
|
||||||
style={{
|
<Loader />
|
||||||
position: "fixed",
|
|
||||||
width: "100vw",
|
|
||||||
height: "100vh",
|
|
||||||
backgroundColor: "rgba(0,0,0,0.2)",
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
zIndex: 2
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "fixed",
|
|
||||||
fontSize: "50px",
|
|
||||||
color: "#3ac9d6",
|
|
||||||
top: "50%",
|
|
||||||
left: "45%"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{/* <FacebookLogin
|
{/* <FacebookLogin
|
||||||
@@ -146,11 +128,10 @@ const LoginFacebook = ({
|
|||||||
/> */}
|
/> */}
|
||||||
{isModal && (
|
{isModal && (
|
||||||
<div
|
<div
|
||||||
className="modal fade show"
|
className="modal fade show block z-[1]"
|
||||||
id="exampleModal"
|
id="exampleModal"
|
||||||
tabIndex="-1"
|
tabIndex="-1"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
style={{ display: "block", zIndex: 1 }}
|
|
||||||
>
|
>
|
||||||
<div className="modal-dialog" role="document">
|
<div className="modal-dialog" role="document">
|
||||||
<div className="modal-content">
|
<div className="modal-content">
|
||||||
@@ -163,13 +144,8 @@ const LoginFacebook = ({
|
|||||||
<div className="modal-body">
|
<div className="modal-body">
|
||||||
<form>
|
<form>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label
|
<label htmlFor="Phone" className="col-form-label">
|
||||||
htmlFor="Phone"
|
Phone <span className="text-[red] text-[13px]">*</span>
|
||||||
style={{ display: "flex" }}
|
|
||||||
className="col-form-label"
|
|
||||||
>
|
|
||||||
Phone{" "}
|
|
||||||
<span style={{ fontSize: 13, color: "red" }}>*</span>
|
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="tel"
|
type="tel"
|
||||||
@@ -186,13 +162,8 @@ const LoginFacebook = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label
|
<label htmlFor="Company" className="col-form-label">
|
||||||
htmlFor="Company"
|
Company <span className="text-[red] text-[13px]">*</span>
|
||||||
style={{ display: "flex" }}
|
|
||||||
className="col-form-label"
|
|
||||||
>
|
|
||||||
Company{" "}
|
|
||||||
<span style={{ fontSize: 13, color: "red" }}>*</span>
|
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -212,16 +183,14 @@ const LoginFacebook = ({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleSubmitbtn()}
|
onClick={() => handleSubmitbtn()}
|
||||||
className="btn btn-info"
|
className="btn btn-info mr-[10px]"
|
||||||
style={{ marginRight: 10 }}
|
|
||||||
>
|
>
|
||||||
Sign up
|
Sign up
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-secondary"
|
className="btn btn-secondary w-[90px]"
|
||||||
onClick={() => setIsModal(false)}
|
onClick={() => setIsModal(false)}
|
||||||
style={{ width: 90 }}
|
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import Parse from "parse";
|
|||||||
import { jwtDecode } from "jwt-decode";
|
import { jwtDecode } from "jwt-decode";
|
||||||
import { useScript } from "../hook/useScript";
|
import { useScript } from "../hook/useScript";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const";
|
import Loader from "../primitives/Loader";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* `GoogleSignInBtn`as it's name indicates it render google sign in button
|
* `GoogleSignInBtn`as it's name indicates it render google sign in button
|
||||||
@@ -110,22 +110,22 @@ const GoogleSignInBtn = ({
|
|||||||
const extRes = await Parse.Cloud.run("getUserDetails", params);
|
const extRes = await Parse.Cloud.run("getUserDetails", params);
|
||||||
// console.log("extRes ", extRes);
|
// console.log("extRes ", extRes);
|
||||||
if (extRes) {
|
if (extRes) {
|
||||||
const params = { ...details, Phone: extRes.get("Phone") };
|
const params = { ...details, Phone: extRes?.get("Phone") || "" };
|
||||||
const payload = await Parse.Cloud.run("googlesign", params);
|
const payload = await Parse.Cloud.run("googlesign", params);
|
||||||
// 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,
|
||||||
email: details.Gmail,
|
email: details.Gmail,
|
||||||
phone: extRes.get("Phone"),
|
phone: extRes?.get("Phone") || "",
|
||||||
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 {
|
||||||
@@ -139,7 +139,7 @@ const GoogleSignInBtn = ({
|
|||||||
setThirdpartyLoader(true);
|
setThirdpartyLoader(true);
|
||||||
// e.preventDefault()
|
// e.preventDefault()
|
||||||
// console.log("handelSubmit", userDetails);
|
// console.log("handelSubmit", userDetails);
|
||||||
const params = { ...googleDetails, Phone: userDetails.Phone };
|
const params = { ...googleDetails, Phone: userDetails?.Phone };
|
||||||
const payload = await Parse.Cloud.run("googlesign", params);
|
const payload = await Parse.Cloud.run("googlesign", params);
|
||||||
|
|
||||||
// console.log("payload ", payload);
|
// console.log("payload ", payload);
|
||||||
@@ -149,7 +149,7 @@ const GoogleSignInBtn = ({
|
|||||||
name: userDetails.Name,
|
name: userDetails.Name,
|
||||||
email: userDetails.Email,
|
email: userDetails.Email,
|
||||||
// "passsword":userDetails.Phone,
|
// "passsword":userDetails.Phone,
|
||||||
phone: userDetails.Phone,
|
phone: userDetails?.Phone || "",
|
||||||
role: "contracts_User",
|
role: "contracts_User",
|
||||||
company: userDetails.Company,
|
company: userDetails.Company,
|
||||||
jobTitle: userDetails.Destination
|
jobTitle: userDetails.Destination
|
||||||
@@ -161,7 +161,7 @@ const GoogleSignInBtn = ({
|
|||||||
const LocalUserDetails = {
|
const LocalUserDetails = {
|
||||||
name: userDetails.Name,
|
name: userDetails.Name,
|
||||||
email: userDetails.Email,
|
email: userDetails.Email,
|
||||||
phone: userDetails.Phone,
|
phone: userDetails?.Phone || "",
|
||||||
company: userDetails.Company
|
company: userDetails.Company
|
||||||
// jobTitle: userDetails.JobTitle
|
// jobTitle: userDetails.JobTitle
|
||||||
};
|
};
|
||||||
@@ -207,45 +207,22 @@ const GoogleSignInBtn = ({
|
|||||||
localStorage.setItem("parseAppId", appid);
|
localStorage.setItem("parseAppId", appid);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div style={{ position: "relative" }}>
|
<div className="relative">
|
||||||
{thirdpartyLoader && (
|
{thirdpartyLoader && (
|
||||||
<div
|
<div className="fixed flex justify-center items-center inset-0 bg-black bg-opacity-25 z-20 ">
|
||||||
style={{
|
<Loader />
|
||||||
position: "fixed",
|
|
||||||
width: "100vw",
|
|
||||||
height: "100vh",
|
|
||||||
backgroundColor: "rgba(0,0,0,0.2)",
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
zIndex: 2
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "fixed",
|
|
||||||
fontSize: "50px",
|
|
||||||
color: "#3ac9d6",
|
|
||||||
top: "50%",
|
|
||||||
left: "45%"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div ref={googleBtn} className="text-sm"></div>
|
<div ref={googleBtn} className="text-sm"></div>
|
||||||
<ModalUi showClose={false} isOpen={isModal} title="Sign up form">
|
<ModalUi showClose={false} isOpen={isModal} title="Sign up form">
|
||||||
<form className="px-4 py-3">
|
<form className="px-4 py-3 text-base-content">
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label
|
<label htmlFor="Phone" className="block text-xs font-semibold">
|
||||||
htmlFor="Phone"
|
Phone <span className="text-[13px] text-[red]">*</span>
|
||||||
style={{ display: "flex" }}
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Phone <span style={{ fontSize: 13, color: "red" }}>*</span>
|
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="tel"
|
type="tel"
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
id="Phone"
|
id="Phone"
|
||||||
value={userDetails.Phone}
|
value={userDetails.Phone}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
@@ -258,16 +235,12 @@ const GoogleSignInBtn = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label
|
<label htmlFor="Company" className="block text-xs font-semibold">
|
||||||
htmlFor="Company"
|
Company <span className="text-[13px] text-[red]">*</span>
|
||||||
style={{ display: "flex" }}
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Company <span style={{ fontSize: 13, color: "red" }}>*</span>
|
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
id="Company"
|
id="Company"
|
||||||
value={userDetails.Company}
|
value={userDetails.Company}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
@@ -280,16 +253,12 @@ const GoogleSignInBtn = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label
|
<label htmlFor="JobTitle" className="block text-xs font-semibold">
|
||||||
htmlFor="JobTitle"
|
Job Title <span className="text-[13px] text-[red]">*</span>
|
||||||
style={{ display: "flex" }}
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Job Title <span style={{ fontSize: 13, color: "red" }}>*</span>
|
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
id="JobTitle"
|
id="JobTitle"
|
||||||
value={userDetails.Destination}
|
value={userDetails.Destination}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
@@ -301,20 +270,18 @@ const GoogleSignInBtn = ({
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex flex-row gap-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="px-3 py-1.5 text-white rounded shadow-md text-center focus:outline-none "
|
className="op-btn op-btn-primary"
|
||||||
onClick={() => handleSubmitbtn()}
|
onClick={() => handleSubmitbtn()}
|
||||||
style={{ marginRight: 10, backgroundColor: modalSubmitBtnColor }}
|
|
||||||
>
|
>
|
||||||
Sign up
|
Sign up
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="p-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none"
|
className="op-btn op-btn-ghost"
|
||||||
onClick={handleCloseModal}
|
onClick={handleCloseModal}
|
||||||
style={{ width: 90, backgroundColor: modalCancelBtnColor }}
|
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,38 +1,19 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Document, Page } from "react-pdf";
|
import { Document, Page } from "react-pdf";
|
||||||
import { Stage, Layer, Rect } from "react-konva";
|
import { Stage, Layer, Rect, Text } from "react-konva";
|
||||||
const RenderDebugPdf = (props) => {
|
const RenderDebugPdf = (props) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div className="sticky top-0 p-[10px] z-10 bg-white border-[1px] border-[gray] my-[5px]">
|
||||||
style={{
|
|
||||||
position: "sticky",
|
|
||||||
top: 0,
|
|
||||||
padding: 10,
|
|
||||||
zIndex: 1,
|
|
||||||
backgroundColor: "white",
|
|
||||||
border: "1px solid grey",
|
|
||||||
margin: "5px 0"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{`Co-ordinates: X - ${props.hoverCoordinates.x}, Y - ${props.hoverCoordinates.y}`}
|
{`Co-ordinates: X - ${props.hoverCoordinates.x}, Y - ${props.hoverCoordinates.y}`}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
className="relative flex-1 cursor-crosshair border-[1px] border-[gray] overflow-auto"
|
||||||
flex: 1,
|
|
||||||
position: "relative",
|
|
||||||
border: "1px solid grey",
|
|
||||||
overflow: "auto"
|
|
||||||
}}
|
|
||||||
onMouseMove={props.handleMouseMoveDiv}
|
onMouseMove={props.handleMouseMoveDiv}
|
||||||
>
|
>
|
||||||
<Document
|
<Document
|
||||||
onLoadError={() => {
|
onLoadError={() => {
|
||||||
const load = {
|
props.setPdfLoadFail(false);
|
||||||
status: false,
|
|
||||||
type: "failed"
|
|
||||||
};
|
|
||||||
props.setPdfLoadFail(load);
|
|
||||||
}}
|
}}
|
||||||
loading={"Loading Document.."}
|
loading={"Loading Document.."}
|
||||||
onLoadSuccess={props.pageDetails}
|
onLoadSuccess={props.pageDetails}
|
||||||
@@ -56,22 +37,36 @@ const RenderDebugPdf = (props) => {
|
|||||||
onMouseUp={props.handleMouseUp}
|
onMouseUp={props.handleMouseUp}
|
||||||
width={props.pdfDimension.width}
|
width={props.pdfDimension.width}
|
||||||
height={props.pdfDimension.height}
|
height={props.pdfDimension.height}
|
||||||
style={{ position: "absolute", top: 0, left: 0 }}
|
className="absolute top-0 right-0"
|
||||||
>
|
>
|
||||||
<Layer>
|
<Layer>
|
||||||
{props.annotations
|
{props.annotations
|
||||||
.filter((value) => value.page === props.pageNumber)
|
.filter((value) => value.page === props.pageNumber)
|
||||||
.map((value) => {
|
.map((value) => {
|
||||||
|
const textX = value.x + value.width / 3;
|
||||||
|
const textY = value.y + value.height / 2.5;
|
||||||
return (
|
return (
|
||||||
<Rect
|
<React.Fragment key={value.key}>
|
||||||
key={value.key}
|
<Rect
|
||||||
x={value.x}
|
x={value.x}
|
||||||
y={value.y}
|
y={value.y}
|
||||||
width={value.width}
|
width={value.width}
|
||||||
height={value.height}
|
height={value.height}
|
||||||
fill="transparent"
|
fill="#cbe9ed"
|
||||||
stroke="black"
|
stroke="black"
|
||||||
/>
|
/>
|
||||||
|
<Text
|
||||||
|
x={textX}
|
||||||
|
y={textY}
|
||||||
|
text={
|
||||||
|
value?.key > 0 ? "box " + value.key.toString() : "box"
|
||||||
|
}
|
||||||
|
fontSize={16}
|
||||||
|
fill="black"
|
||||||
|
align="center"
|
||||||
|
verticalAlign="middle"
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Layer>
|
</Layer>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import "../../styles/loader.css";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { openInNewTab } from "../../constant/Utils";
|
import { openInNewTab } from "../../constant/Utils";
|
||||||
|
|
||||||
@@ -26,19 +25,17 @@ const DashboardButton = (props) => {
|
|||||||
props.Data && props.Data.Redirect_type
|
props.Data && props.Data.Redirect_type
|
||||||
? "cursor-pointer"
|
? "cursor-pointer"
|
||||||
: "cursor-default"
|
: "cursor-default"
|
||||||
} w-full px-3 py-2 flex text-white rounded-md shadow overflow-hidden`}
|
} w-full shadow-md px-3 py-2 op-card bg-base-100`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-start gap-5">
|
<div className="flex flex-row items-center">
|
||||||
<span className="rounded-full bg-black bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
|
<span className="rounded-full bg-base-content bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
|
||||||
<i
|
<i
|
||||||
className={`${
|
className={`${
|
||||||
props.Icon ? props.Icon : "fa fa-solid fa-info"
|
props.Icon ? props.Icon : "fa-light fa-info"
|
||||||
} text-[25px] lg:text-[30px]`}
|
} text-[25px] lg:text-[30px]`}
|
||||||
></i>
|
></i>
|
||||||
</span>
|
</span>
|
||||||
<div className="">
|
<div className=" text-lg ml-3 text-base-content">{props.Label}</div>
|
||||||
<div className="text-base lg:text-lg text-black"> {props.Label}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import React, { useState, useEffect } from "react";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import getReplacedHashQuery from "../../constant/getReplacedHashQuery";
|
import getReplacedHashQuery from "../../constant/getReplacedHashQuery";
|
||||||
import "../../styles/loader.css";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import Tooltip from "../../primitives/Tooltip";
|
||||||
|
|
||||||
const DashboardCard = (props) => {
|
const DashboardCard = (props) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -148,7 +148,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 = [];
|
||||||
@@ -261,21 +261,14 @@ const DashboardCard = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
body = str;
|
body = str;
|
||||||
await axios
|
const response = await axios.post(url, body, { headers: headers });
|
||||||
.post(url, body, { headers: headers })
|
if (response.data.result.length > 0) {
|
||||||
.then((response) => {
|
setresponse(response.data.result[0][props.FilterData.key]);
|
||||||
try {
|
setLoading(false);
|
||||||
if (response.data.result.length > 0) {
|
} else {
|
||||||
setresponse(response.data.result[0][props.FilterData.key]);
|
setresponse("0");
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
} else {
|
}
|
||||||
setresponse("0");
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -335,23 +328,30 @@ const DashboardCard = (props) => {
|
|||||||
props.Data && props.Data.Redirect_type
|
props.Data && props.Data.Redirect_type
|
||||||
? "cursor-pointer"
|
? "cursor-pointer"
|
||||||
: "cursor-default"
|
: "cursor-default"
|
||||||
} w-full h-[140px] px-3 pt-4 pb-10 text-white rounded-md shadow overflow-hidden`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-start gap-5">
|
<div className="flex items-center justify-start gap-5 text-white">
|
||||||
<span className="rounded-full bg-black bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
|
<span className="rounded-full bg-base-300 bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
|
||||||
<i
|
<i
|
||||||
className={`${
|
className={`${
|
||||||
props.Icon ? props.Icon : "fa fa-solid fa-info"
|
props.Icon ? props.Icon : "fa-light fa-info"
|
||||||
} text-[25px] lg:text-[30px]`}
|
} text-[25px] lg:text-[30px]`}
|
||||||
></i>
|
></i>
|
||||||
</span>
|
</span>
|
||||||
<div className="">
|
<div className="font-medium">
|
||||||
<div className="text-base lg:text-lg"> {props.Label}</div>
|
<div className="text-base lg:text-lg"> {props.Label}</div>
|
||||||
<div className="text-2xl font-light">
|
<div className="text-2xl font-light">
|
||||||
{loading ? <div className="loader-01"></div> : setFormat(response)}
|
{loading ? <div className="loader-01"></div> : setFormat(response)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="text-xs absolute top-3 right-2">
|
||||||
|
<Tooltip
|
||||||
|
id={props.Label}
|
||||||
|
iconColor={"white"}
|
||||||
|
message={props?.Data?.tourMessage}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Parse from "parse";
|
|||||||
import ReportTable from "../../primitives/GetReportDisplay";
|
import ReportTable from "../../primitives/GetReportDisplay";
|
||||||
import reportJson from "../../json/ReportJson";
|
import reportJson from "../../json/ReportJson";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import Loader from "../../primitives/Loader";
|
||||||
function DashboardReport(props) {
|
function DashboardReport(props) {
|
||||||
// console.log("props ", props)
|
// console.log("props ", props)
|
||||||
const [List, setList] = useState([]);
|
const [List, setList] = useState([]);
|
||||||
@@ -97,11 +98,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 +113,7 @@ function DashboardReport(props) {
|
|||||||
console.log("err ", err);
|
console.log("err ", err);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
}
|
}
|
||||||
|
setIsLoader(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
@@ -118,21 +122,8 @@ function DashboardReport(props) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isLoader ? (
|
{isLoader ? (
|
||||||
<div
|
<div className="h-[250px] flex justify-center items-center">
|
||||||
style={{
|
<Loader />
|
||||||
height: "100vh",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -6,61 +6,38 @@ const buttonList = [
|
|||||||
{
|
{
|
||||||
label: "Sign yourself",
|
label: "Sign yourself",
|
||||||
redirectId: "sHAnZphf69",
|
redirectId: "sHAnZphf69",
|
||||||
redirectType: "Form"
|
redirectType: "Form",
|
||||||
|
icon: "fa-light fa-pen-nib"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Request signature",
|
label: "Request signature",
|
||||||
redirectId: "8mZzFxbG1z",
|
redirectId: "8mZzFxbG1z",
|
||||||
redirectType: "Form"
|
redirectType: "Form",
|
||||||
|
icon: "fa-light fa-paper-plane"
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
const GetDashboard = (props) => {
|
const GetDashboard = (props) => {
|
||||||
const Button = ({ label, redirectId, redirectType }) => (
|
const Button = ({ label, redirectId, redirectType, icon }) => (
|
||||||
<div className={"bg-white rounded-md shadow w-full"}>
|
<DashboardButton
|
||||||
<Suspense
|
Icon={icon}
|
||||||
fallback={
|
Label={label}
|
||||||
<div style={{ height: "300px" }}>
|
Data={{ Redirect_type: redirectType, Redirect_id: redirectId }}
|
||||||
<div
|
/>
|
||||||
style={{
|
|
||||||
marginLeft: "45%",
|
|
||||||
marginTop: "150px",
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<DashboardButton
|
|
||||||
Icon={"fa-solid fa-plus"}
|
|
||||||
Label={label}
|
|
||||||
Data={{ Redirect_type: redirectType, Redirect_id: redirectId }}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
const renderSwitchWithTour = (col) => {
|
const renderSwitchWithTour = (col) => {
|
||||||
switch (col.widget.type) {
|
switch (col.widget.type) {
|
||||||
case "Card":
|
case "Card":
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={"bg-[#2ed8b6] rounded-md shadow mb-3 md:mb-0"}
|
className={`${
|
||||||
|
col?.widget?.bgColor ? col.widget.bgColor : "bg-[#2ed8b6]"
|
||||||
|
} op-card w-full h-[140px] px-3 pt-4 mb-3 shadow-md"`}
|
||||||
data-tut={col.widget.data.tourSection}
|
data-tut={col.widget.data.tourSection}
|
||||||
style={{ background: col.widget.bgColor }}
|
|
||||||
>
|
>
|
||||||
<Suspense
|
<Suspense
|
||||||
fallback={
|
fallback={
|
||||||
<div style={{ height: "300px" }}>
|
<div className="h-[150px] w-full flex justify-center items-center">
|
||||||
<div
|
loading...
|
||||||
style={{
|
|
||||||
marginLeft: "45%",
|
|
||||||
marginTop: "150px",
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -70,7 +47,6 @@ const GetDashboard = (props) => {
|
|||||||
Format={col.widget.format && col.widget.format}
|
Format={col.widget.format && col.widget.format}
|
||||||
Data={col.widget.data}
|
Data={col.widget.data}
|
||||||
FilterData={col.widget.filter}
|
FilterData={col.widget.filter}
|
||||||
DefaultQuery={props.DefaultQuery}
|
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
@@ -87,7 +63,7 @@ const GetDashboard = (props) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return null;
|
return <></>;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const renderSwitch = (col) => {
|
const renderSwitch = (col) => {
|
||||||
@@ -95,8 +71,9 @@ const GetDashboard = (props) => {
|
|||||||
case "Card":
|
case "Card":
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={"bg-[#2ed8b6] rounded-md shadow mb-3 md:mb-0"}
|
className={`${
|
||||||
style={{ background: col.widget.bgColor }}
|
col?.widget?.bgColor ? col.widget.bgColor : "bg-[#2ed8b6]"
|
||||||
|
} op-card w-full h-[140px] px-3 pt-4 mb-3 shadow-md"`}
|
||||||
>
|
>
|
||||||
<Suspense fallback={<div>please wait</div>}>
|
<Suspense fallback={<div>please wait</div>}>
|
||||||
<DashboardCard
|
<DashboardCard
|
||||||
@@ -105,7 +82,6 @@ const GetDashboard = (props) => {
|
|||||||
Format={col.widget.format && col.widget.format}
|
Format={col.widget.format && col.widget.format}
|
||||||
Data={col.widget.data}
|
Data={col.widget.data}
|
||||||
FilterData={col.widget.filter}
|
FilterData={col.widget.filter}
|
||||||
DefaultQuery={props.DefaultQuery}
|
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
@@ -120,7 +96,7 @@ const GetDashboard = (props) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return null;
|
return <></>;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
@@ -128,7 +104,7 @@ const GetDashboard = (props) => {
|
|||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<div
|
<div
|
||||||
data-tut={"tourbutton"}
|
data-tut={"tourbutton"}
|
||||||
className="flex flex-col md:flex-row gap-6 md:gap-8"
|
className="flex flex-col md:flex-row gap-4"
|
||||||
>
|
>
|
||||||
{buttonList.map((btn) => (
|
{buttonList.map((btn) => (
|
||||||
<Button
|
<Button
|
||||||
@@ -136,25 +112,24 @@ const GetDashboard = (props) => {
|
|||||||
label={btn.label}
|
label={btn.label}
|
||||||
redirectType={btn.redirectType}
|
redirectType={btn.redirectType}
|
||||||
redirectId={btn.redirectId}
|
redirectId={btn.redirectId}
|
||||||
|
icon={btn.icon}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{props.dashboard.map((val, key) => (
|
<div className="grid grid-cols-12 w-full gap-x-4">
|
||||||
<div key={"a" + key} className="row">
|
{props?.dashboard?.columns?.map((col, i) =>
|
||||||
{val.columns.map((col, i) =>
|
col.widget.data && col.widget.data.tourSection ? (
|
||||||
col.widget.data && col.widget.data.tourSection ? (
|
<div key={i} className={col?.colsize}>
|
||||||
<div key={i} className={props.classnameArray[key][i]}>
|
{renderSwitchWithTour(col)}
|
||||||
{renderSwitchWithTour(col)}
|
</div>
|
||||||
</div>
|
) : (
|
||||||
) : (
|
<div key={i} className={col?.colsize}>
|
||||||
<div key={i} className={props.classnameArray[key][i]}>
|
{renderSwitch(col)}
|
||||||
{renderSwitch(col)}
|
</div>
|
||||||
</div>
|
)
|
||||||
)
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,26 +1,15 @@
|
|||||||
import React, { useState, useEffect, useRef } from "react";
|
import React, { useState, useEffect, useRef } from "react";
|
||||||
import folder from "../../assets/images/folder.png";
|
|
||||||
import "../../styles/opensigndrive.css";
|
import "../../styles/opensigndrive.css";
|
||||||
import pdfLogo from "../../assets/images/pdf3.png";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import * as ContextMenu from "@radix-ui/react-context-menu";
|
import * as ContextMenu from "@radix-ui/react-context-menu";
|
||||||
import { saveAs } from "file-saver";
|
import { saveAs } from "file-saver";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import Table from "react-bootstrap/Table";
|
import Table from "react-bootstrap/Table";
|
||||||
import * as HoverCard from "@radix-ui/react-hover-card";
|
import * as HoverCard from "@radix-ui/react-hover-card";
|
||||||
import SelectFolder from "../shared/fields/SelectFolder"; //check this one
|
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
import { themeColor } from "../../constant/const";
|
import FolderModal from "../shared/fields/FolderModal";
|
||||||
|
|
||||||
function DriveBody({
|
function DriveBody(props) {
|
||||||
pdfData,
|
|
||||||
setFolderName,
|
|
||||||
setDocId,
|
|
||||||
setIsLoading,
|
|
||||||
setPdfData,
|
|
||||||
isList,
|
|
||||||
setIsAlert
|
|
||||||
}) {
|
|
||||||
const [rename, setRename] = useState("");
|
const [rename, setRename] = useState("");
|
||||||
const [renameValue, setRenameValue] = useState("");
|
const [renameValue, setRenameValue] = useState("");
|
||||||
const inputRef = useRef(null);
|
const inputRef = useRef(null);
|
||||||
@@ -28,10 +17,10 @@ function DriveBody({
|
|||||||
const [selectDoc, setSelectDoc] = useState();
|
const [selectDoc, setSelectDoc] = useState();
|
||||||
const [isDeleteDoc, setIsDeleteDoc] = useState(false);
|
const [isDeleteDoc, setIsDeleteDoc] = useState(false);
|
||||||
const contextMenu = [
|
const contextMenu = [
|
||||||
{ type: "Download", icon: "fa-solid fa-arrow-down" },
|
{ type: "Download", icon: "fa-light fa-arrow-down" },
|
||||||
{ type: "Rename", icon: "fa-solid fa-font" },
|
{ type: "Rename", icon: "fa-light fa-font" },
|
||||||
{ type: "Move", icon: "fa-solid fa-file-export" },
|
{ type: "Move", icon: "fa-light fa-file-export" },
|
||||||
{ type: "Delete", icon: "fa-solid fa-trash" }
|
{ type: "Delete", icon: "fa-light fa-trash" }
|
||||||
];
|
];
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
@@ -50,28 +39,25 @@ function DriveBody({
|
|||||||
name: data.Name,
|
name: data.Name,
|
||||||
objectId: data.objectId
|
objectId: data.objectId
|
||||||
};
|
};
|
||||||
setFolderName((prev) => [...prev, folderData]);
|
props.setFolderName((prev) => [...prev, folderData]);
|
||||||
const loadObj = {
|
props.setIsLoading({
|
||||||
isLoad: true,
|
isLoad: true,
|
||||||
message: "This might take some time"
|
message: "This might take some time"
|
||||||
};
|
});
|
||||||
|
props.setDocId(data.objectId);
|
||||||
setIsLoading(loadObj);
|
props.setPdfData([]);
|
||||||
setDocId(data.objectId);
|
props.setSkip(0);
|
||||||
};
|
};
|
||||||
//function for change doc name and update doc name in _document class
|
//function for change doc name and update doc name in _document class
|
||||||
const handledRenameDoc = async (data) => {
|
const handledRenameDoc = async (data) => {
|
||||||
setRename("");
|
setRename("");
|
||||||
const trimmedValue = renameValue.trim();
|
const trimmedValue = renameValue.trim();
|
||||||
|
|
||||||
if (trimmedValue.length > 0) {
|
if (trimmedValue.length > 0) {
|
||||||
const updateName = {
|
const updateName = {
|
||||||
Name: renameValue
|
Name: renameValue
|
||||||
};
|
};
|
||||||
const docId = data.objectId;
|
const docId = data.objectId;
|
||||||
|
const docData = props.pdfData;
|
||||||
const docData = pdfData;
|
|
||||||
|
|
||||||
const updatedData = docData.map((item) => {
|
const updatedData = docData.map((item) => {
|
||||||
if (item.objectId === docId) {
|
if (item.objectId === docId) {
|
||||||
// If the item's ID matches the target ID, update the name
|
// If the item's ID matches the target ID, update the name
|
||||||
@@ -80,8 +66,8 @@ function DriveBody({
|
|||||||
// If the item's ID doesn't match, keep it unchanged
|
// If the item's ID doesn't match, keep it unchanged
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
|
props.setPdfData(updatedData);
|
||||||
setPdfData(updatedData);
|
props.sortingData(null, null, updatedData);
|
||||||
await axios
|
await axios
|
||||||
.put(
|
.put(
|
||||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||||
@@ -102,7 +88,7 @@ function DriveBody({
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log("Err ", err);
|
console.log("Err ", err);
|
||||||
setIsAlert({
|
props.setIsAlert({
|
||||||
isShow: true,
|
isShow: true,
|
||||||
alertMessage: "something went wrong"
|
alertMessage: "something went wrong"
|
||||||
});
|
});
|
||||||
@@ -199,13 +185,13 @@ function DriveBody({
|
|||||||
.then((result) => {
|
.then((result) => {
|
||||||
const res = result.data;
|
const res = result.data;
|
||||||
if (res) {
|
if (res) {
|
||||||
const updatedData = pdfData.filter((x) => x.objectId !== docId);
|
const updatedData = props.pdfData.filter((x) => x.objectId !== docId);
|
||||||
setPdfData(updatedData);
|
props.setPdfData(updatedData);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log("Err ", err);
|
console.log("Err ", err);
|
||||||
setIsAlert({
|
props.setIsAlert({
|
||||||
isShow: true,
|
isShow: true,
|
||||||
alertMessage: "something went wrong"
|
alertMessage: "something went wrong"
|
||||||
});
|
});
|
||||||
@@ -262,10 +248,10 @@ function DriveBody({
|
|||||||
// console.log("Listdata ", Listdata);
|
// console.log("Listdata ", Listdata);
|
||||||
const res = Listdata.data;
|
const res = Listdata.data;
|
||||||
if (res) {
|
if (res) {
|
||||||
const updatedData = pdfData.filter(
|
const updatedData = props.pdfData.filter(
|
||||||
(x) => x.objectId !== updateDocId
|
(x) => x.objectId !== updateDocId
|
||||||
);
|
);
|
||||||
setPdfData(updatedData);
|
props.setPdfData(updatedData);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@@ -292,14 +278,13 @@ function DriveBody({
|
|||||||
|
|
||||||
//component to handle type of document and render according to type
|
//component to handle type of document and render according to type
|
||||||
const handleFolderData = (data, ind, listType) => {
|
const handleFolderData = (data, ind, listType) => {
|
||||||
let createddate, status, isDecline, signerExist, isComplete, isPlaceholder;
|
let createddate, status, isDecline, signerExist, isComplete;
|
||||||
if (data.Type !== "Folder") {
|
if (data.Type !== "Folder") {
|
||||||
const expireDate = data.ExpiryDate && data.ExpiryDate.iso;
|
const expireDate = data.ExpiryDate && data.ExpiryDate.iso;
|
||||||
const createdDate = data.createdAt && data.createdAt;
|
const createdDate = data.createdAt && data.createdAt;
|
||||||
createddate = new Date(createdDate).toLocaleDateString();
|
createddate = new Date(createdDate).toLocaleDateString();
|
||||||
isComplete = data.IsCompleted && data.IsCompleted ? true : false;
|
isComplete = data.IsCompleted && data.IsCompleted ? true : false;
|
||||||
isDecline = data.IsDeclined && data.IsDeclined;
|
isDecline = data.IsDeclined && data.IsDeclined;
|
||||||
isPlaceholder = data.Placeholders && data.Placeholders;
|
|
||||||
signerExist = data.Signers && data.Signers;
|
signerExist = data.Signers && data.Signers;
|
||||||
const signedUrl = data.SignedUrl;
|
const signedUrl = data.SignedUrl;
|
||||||
|
|
||||||
@@ -314,18 +299,7 @@ function DriveBody({
|
|||||||
status = "Completed";
|
status = "Completed";
|
||||||
} else if (isDecline) {
|
} else if (isDecline) {
|
||||||
status = "Declined";
|
status = "Declined";
|
||||||
} else if (!signerExist || signerExist?.length === 0) {
|
} else if (!signedUrl) {
|
||||||
status = "Draft";
|
|
||||||
} else if (
|
|
||||||
signerExist?.length > 0 &&
|
|
||||||
(!isPlaceholder || isPlaceholder?.length === 0)
|
|
||||||
) {
|
|
||||||
status = "Draft";
|
|
||||||
} else if (
|
|
||||||
signerExist?.length > 0 &&
|
|
||||||
isPlaceholder?.length > 0 &&
|
|
||||||
!signedUrl
|
|
||||||
) {
|
|
||||||
status = "Draft";
|
status = "Draft";
|
||||||
} else if (isExpire) {
|
} else if (isExpire) {
|
||||||
status = "Expired";
|
status = "Expired";
|
||||||
@@ -336,32 +310,26 @@ function DriveBody({
|
|||||||
|
|
||||||
const signersName = () => {
|
const signersName = () => {
|
||||||
const getSignersName = signerExist.map((data) => data.Name);
|
const getSignersName = signerExist.map((data) => data.Name);
|
||||||
const signerName = getSignersName.join(",");
|
const signerName = getSignersName.join(", ");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span className="text-[12px] font-medium w-[90%] break-words">
|
||||||
className="statusSpan"
|
{signerName}
|
||||||
style={{ width: "90%", wordWrap: "break-word" }}
|
|
||||||
>
|
|
||||||
{signerName}{" "}
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return listType === "table" ? (
|
return listType === "table" ? (
|
||||||
data.Type === "Folder" ? (
|
data.Type === "Folder" ? (
|
||||||
<tr onClick={() => handleOnclikFolder(data)}>
|
<tr onClick={() => handleOnclikFolder(data)}>
|
||||||
<td
|
<td className="cursor-pointer flex items-center gap-2">
|
||||||
style={{ cursor: "pointer", display: "flex", alignItems: "center" }}
|
<svg
|
||||||
>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<i
|
viewBox="0 0 512 512"
|
||||||
className="fa fa-folder"
|
className="w-[26px] h-[26px] fill-current op-text-secondary"
|
||||||
aria-hidden="true"
|
>
|
||||||
style={{ color: "#f0ad26", marginRight: "8px", fontSize: "26px" }}
|
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
|
||||||
></i>
|
</svg>
|
||||||
|
<span className="text-[12px] font-medium">{data.Name}</span>
|
||||||
<span style={{ fontSize: "12px", fontWeight: "500" }}>
|
|
||||||
{data.Name}
|
|
||||||
</span>
|
|
||||||
</td>
|
</td>
|
||||||
<td>_</td>
|
<td>_</td>
|
||||||
<td>Folder</td>
|
<td>Folder</td>
|
||||||
@@ -370,17 +338,15 @@ function DriveBody({
|
|||||||
</tr>
|
</tr>
|
||||||
) : (
|
) : (
|
||||||
<tr onClick={() => checkPdfStatus(data)}>
|
<tr onClick={() => checkPdfStatus(data)}>
|
||||||
<td
|
<td className="cursor-pointer flex items-center gap-2">
|
||||||
style={{ cursor: "pointer", display: "flex", alignItems: "center" }}
|
<svg
|
||||||
>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<i
|
viewBox="0 0 384 512"
|
||||||
className="fa fa-file-pdf"
|
className="w-[26px] h-[26px] fill-current op-text-primary"
|
||||||
style={{ color: "#ed4d0e", marginRight: "8px", fontSize: "26px" }}
|
>
|
||||||
></i>
|
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
|
||||||
|
</svg>
|
||||||
<span style={{ fontSize: "12px", fontWeight: "500" }}>
|
<span className="text-[12px] font-medium">{data.Name}</span>
|
||||||
{data.Name}
|
|
||||||
</span>
|
|
||||||
</td>
|
</td>
|
||||||
<td>{createddate}</td>
|
<td>{createddate}</td>
|
||||||
<td>Pdf</td>
|
<td>Pdf</td>
|
||||||
@@ -391,31 +357,29 @@ function DriveBody({
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
handleMenuItemClick("Download", data);
|
handleMenuItemClick("Download", data);
|
||||||
}}
|
}}
|
||||||
className="fa fa-download"
|
className="fa-light fa-download mr-[8px] op-text-primary"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
style={{ color: "#ed280e", marginRight: "8px" }}
|
|
||||||
></i>
|
></i>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)
|
)
|
||||||
) : listType === "list" && data.Type === "Folder" ? (
|
) : listType === "list" && data.Type === "Folder" ? (
|
||||||
<div key={ind} className="folderBox">
|
<div key={ind} className="relative w-[100px] h-[100px] mx-2 my-3">
|
||||||
<ContextMenu.Root>
|
<ContextMenu.Root>
|
||||||
<ContextMenu.Trigger className="ContextMenuTrigger">
|
<ContextMenu.Trigger className="flex flex-col justify-center items-center">
|
||||||
|
{/* folder */}
|
||||||
<div
|
<div
|
||||||
style={{
|
data-tut={props.dataTutSeventh}
|
||||||
display: "flex",
|
onClick={() => handleOnclikFolder(data)}
|
||||||
flexDirection: "column",
|
className="cursor-pointer"
|
||||||
cursor: "pointer"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<img
|
<svg
|
||||||
alt="no img"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
onClick={() => handleOnclikFolder(data)}
|
viewBox="0 0 512 512"
|
||||||
src={folder}
|
className="w-[100px] h-[100px] fill-current op-text-secondary"
|
||||||
width={100}
|
>
|
||||||
height={103}
|
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
|
||||||
/>
|
</svg>
|
||||||
{rename === data.objectId ? (
|
{rename === data.objectId ? (
|
||||||
<input
|
<input
|
||||||
onFocus={() => {
|
onFocus={() => {
|
||||||
@@ -433,15 +397,10 @@ function DriveBody({
|
|||||||
defaultValue={renameValue}
|
defaultValue={renameValue}
|
||||||
// value={renameValue}
|
// value={renameValue}
|
||||||
onChange={(e) => setRenameValue(e.target.value)}
|
onChange={(e) => setRenameValue(e.target.value)}
|
||||||
style={{
|
className="w-[100px] border-[1.5px] border-black rounded-sm text-[10px]"
|
||||||
width: "100px",
|
|
||||||
border: "1.5px solid black",
|
|
||||||
borderRadius: "2px",
|
|
||||||
fontSize: "10px"
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span className="foldName">{data.Name}</span>
|
<span className="fileName">{data.Name}</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</ContextMenu.Trigger>
|
</ContextMenu.Trigger>
|
||||||
@@ -456,8 +415,8 @@ function DriveBody({
|
|||||||
onClick={() => handleMenuItemClick("Rename", data)}
|
onClick={() => handleMenuItemClick("Rename", data)}
|
||||||
className="ContextMenuItem"
|
className="ContextMenuItem"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-font"></i>
|
<i className="fa-light fa-font mr-[8px]"></i>
|
||||||
<span style={{ marginLeft: "8px" }}>Rename</span>
|
<span>Rename</span>
|
||||||
</ContextMenu.Item>
|
</ContextMenu.Item>
|
||||||
</ContextMenu.Content>
|
</ContextMenu.Content>
|
||||||
</ContextMenu.Portal>
|
</ContextMenu.Portal>
|
||||||
@@ -468,62 +427,65 @@ function DriveBody({
|
|||||||
<HoverCard.Trigger asChild>
|
<HoverCard.Trigger asChild>
|
||||||
<div>
|
<div>
|
||||||
<ContextMenu.Root>
|
<ContextMenu.Root>
|
||||||
<div className="icon-container">
|
<div className="relative w-[100px] h-[100px] mx-2 my-3">
|
||||||
<ContextMenu.Trigger className="ContextMenuTrigger">
|
<ContextMenu.Trigger className="flex flex-col justify-center items-center">
|
||||||
<img
|
{/* pdf */}
|
||||||
alt="PDF"
|
<div
|
||||||
className="pdf-icon"
|
data-tut={props.dataTutSixth}
|
||||||
src={pdfLogo}
|
|
||||||
onClick={() => checkPdfStatus(data)}
|
onClick={() => checkPdfStatus(data)}
|
||||||
/>
|
className="cursor-pointer"
|
||||||
{rename === data.objectId ? (
|
>
|
||||||
<input
|
<svg
|
||||||
autoFocus={true}
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
type="text"
|
viewBox="0 0 384 512"
|
||||||
onFocus={() => {
|
className="w-[100px] h-[100px] fill-current op-text-primary"
|
||||||
inputRef.current.setSelectionRange(0, 0);
|
>
|
||||||
const input = inputRef.current;
|
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
|
||||||
if (input) {
|
</svg>
|
||||||
input.select();
|
{rename === data.objectId ? (
|
||||||
}
|
<input
|
||||||
}}
|
autoFocus={true}
|
||||||
onBlur={() => handledRenameDoc(data)}
|
type="text"
|
||||||
onKeyDown={(e) => handleEnterPress(e, data)}
|
onFocus={() => {
|
||||||
ref={inputRef}
|
inputRef.current.setSelectionRange(0, 0);
|
||||||
defaultValue={renameValue}
|
const input = inputRef.current;
|
||||||
// value={renameValue}
|
if (input) {
|
||||||
onChange={(e) => setRenameValue(e.target.value)}
|
input.select();
|
||||||
style={{
|
}
|
||||||
width: "100px",
|
}}
|
||||||
border: "1.5px solid black",
|
onBlur={() => handledRenameDoc(data)}
|
||||||
borderRadius: "2px",
|
onKeyDown={(e) => handleEnterPress(e, data)}
|
||||||
fontSize: "10px"
|
ref={inputRef}
|
||||||
}}
|
defaultValue={renameValue}
|
||||||
/>
|
// value={renameValue}
|
||||||
) : (
|
onChange={(e) => setRenameValue(e.target.value)}
|
||||||
<span className="fileName">{data.Name}</span>
|
className="w-[100px] border-[1.5px] border-black rounded-sm text-[10px]"
|
||||||
)}
|
/>
|
||||||
|
) : (
|
||||||
|
<span className="fileName">{data.Name}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</ContextMenu.Trigger>
|
</ContextMenu.Trigger>
|
||||||
{status === "Completed" ? (
|
{status === "Completed" ? (
|
||||||
<div className="status-badge completed">
|
<div className="status-badge completed">
|
||||||
<i className="fas fa-check-circle"></i>
|
<i className="fa-light fa-check-circle"></i>
|
||||||
</div>
|
</div>
|
||||||
) : status === "Declined" ? (
|
) : status === "Declined" ? (
|
||||||
<div className="status-badge declined">
|
<div className="status-badge declined">
|
||||||
<i className="fa fa-thumbs-down"></i>
|
<i className="fa-light fa-thumbs-down"></i>
|
||||||
</div>
|
</div>
|
||||||
) : status === "Expired" ? (
|
) : status === "Expired" ? (
|
||||||
<div className="status-badge expired">
|
<div className="status-badge expired">
|
||||||
<i className="fa fa-hourglass-end"></i>
|
<i className="fa-light fa-hourglass-end"></i>
|
||||||
</div>
|
</div>
|
||||||
) : status === "Draft" ? (
|
) : status === "Draft" ? (
|
||||||
<div className="status-badge draft">
|
<div className="status-badge draft">
|
||||||
<i className="fa fa-file"></i>
|
<i className="fa-light fa-file"></i>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
status === "In Progress" && (
|
status === "In Progress" && (
|
||||||
<div className="status-badge in-progress">
|
<div className="status-badge in-progress">
|
||||||
<i className="fa fa-paper-plane"></i>
|
<i className="fa-light fa-paper-plane"></i>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
@@ -543,7 +505,7 @@ function DriveBody({
|
|||||||
className="ContextMenuItem"
|
className="ContextMenuItem"
|
||||||
>
|
>
|
||||||
<i className={menu.icon}></i>
|
<i className={menu.icon}></i>
|
||||||
<span style={{ marginLeft: "8px" }}>{menu.type}</span>
|
<span className="ml-[8px]">{menu.type}</span>
|
||||||
</ContextMenu.Item>
|
</ContextMenu.Item>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -554,22 +516,18 @@ function DriveBody({
|
|||||||
</HoverCard.Trigger>
|
</HoverCard.Trigger>
|
||||||
<HoverCard.Portal>
|
<HoverCard.Portal>
|
||||||
<HoverCard.Content className="HoverCardContent" sideOffset={5}>
|
<HoverCard.Content className="HoverCardContent" sideOffset={5}>
|
||||||
<strong style={{ fontSize: "13px" }}>Title: </strong>
|
<strong className="text-[13px]">Title: </strong>
|
||||||
<span className="statusSpan" style={{ marginBottom: "0px" }}>
|
<span className="text-[12px] font-medium mb-0"> {data.Name}</span>
|
||||||
{" "}
|
|
||||||
{data.Name}
|
|
||||||
</span>
|
|
||||||
<br />
|
<br />
|
||||||
<strong style={{ fontSize: "13px" }}>Status: </strong>
|
<strong className="text-[13px]">Status: </strong>
|
||||||
<span className="statusSpan"> {status}</span>
|
<span className="text-[12px] font-medium"> {status}</span>
|
||||||
<br />
|
<br />
|
||||||
<strong style={{ fontSize: "13px" }}>Created Date: </strong>
|
<strong className="text-[13px]">Created Date: </strong>
|
||||||
<span className="statusSpan">{createddate}</span>
|
<span className="text-[12px] font-medium">{createddate}</span>
|
||||||
<br />
|
<br />
|
||||||
{signerExist && (
|
{signerExist && (
|
||||||
<>
|
<>
|
||||||
<strong style={{ fontSize: "13px" }}>Signers: </strong>
|
<strong className="text-[13px]">Signers: </strong>
|
||||||
{/* <span className="statusSpan">kjefjjnejkfnkbjs bbfjkdsbjbfjkbjk kscbjkbjkb</span> */}
|
|
||||||
{signersName()}
|
{signersName()}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -584,7 +542,7 @@ function DriveBody({
|
|||||||
//component to handle type of document and render according to type
|
//component to handle type of document and render according to type
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isList ? (
|
{props.isList ? (
|
||||||
<div className="container" style={{ overflowX: "auto" }}>
|
<div className="container" style={{ overflowX: "auto" }}>
|
||||||
<Table striped bordered hover>
|
<Table striped bordered hover>
|
||||||
<thead>
|
<thead>
|
||||||
@@ -597,7 +555,7 @@ function DriveBody({
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{pdfData.map((data, ind) => {
|
{props.pdfData.map((data, ind) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={ind}>
|
<React.Fragment key={ind}>
|
||||||
{handleFolderData(data, ind, "table")}
|
{handleFolderData(data, ind, "table")}
|
||||||
@@ -608,65 +566,41 @@ function DriveBody({
|
|||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="pdfContainer">
|
<div className="flex flex-row flex-wrap items-center mt-1 pb-[20px] mx-[5px]">
|
||||||
{pdfData.map((data, ind) => {
|
{props.pdfData.map((data, ind) => {
|
||||||
return (
|
return <div key={ind}>{handleFolderData(data, ind, "list")}</div>;
|
||||||
<div className="box" key={ind}>
|
|
||||||
{handleFolderData(data, ind, "list")}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isOpenMoveModal && (
|
{isOpenMoveModal && (
|
||||||
<SelectFolder
|
<FolderModal
|
||||||
onSuccess={handleMoveFolder}
|
onSuccess={handleMoveFolder}
|
||||||
isOpenModal={isOpenMoveModal}
|
isOpenModal={isOpenMoveModal}
|
||||||
folderCls={"contracts_Document"}
|
folderCls={"contracts_Document"}
|
||||||
setIsOpenMoveModal={setIsOpenMoveModal}
|
setIsOpenMoveModal={setIsOpenMoveModal}
|
||||||
setPdfData={setPdfData}
|
setPdfData={props.setPdfData}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen={isDeleteDoc}
|
isOpen={isDeleteDoc}
|
||||||
headerColor={themeColor}
|
|
||||||
title={"Delete Document"}
|
title={"Delete Document"}
|
||||||
handleClose={() => {
|
handleClose={() => setIsDeleteDoc(false)}
|
||||||
setIsDeleteDoc(false);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div style={{ height: "100%", padding: 20 }}>
|
<div className="h-full p-[20px] text-base-content">
|
||||||
<p>Are you sure you want to delete this document?</p>
|
<p>Are you sure you want to delete this document?</p>
|
||||||
|
<div className="h-[1px] w-full bg-[#9f9f9f] my-[15px]"></div>
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: "1px",
|
|
||||||
backgroundColor: "#9f9f9f",
|
|
||||||
width: "100%",
|
|
||||||
marginTop: "15px",
|
|
||||||
marginBottom: "15px"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => handleDeleteDocument(selectDoc)}
|
||||||
handleDeleteDocument(selectDoc);
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
type="button"
|
type="button"
|
||||||
className="finishBtn"
|
className="op-btn op-btn-primary mr-2"
|
||||||
>
|
>
|
||||||
Yes
|
Yes
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => setIsDeleteDoc(false)}
|
||||||
setIsDeleteDoc(false);
|
|
||||||
}}
|
|
||||||
type="button"
|
type="button"
|
||||||
className="finishBtn cancelBtn"
|
className="op-btn op-btn-neutral"
|
||||||
>
|
>
|
||||||
No
|
No
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -8,11 +8,8 @@ const AddRoleModal = (props) => {
|
|||||||
isOpen={props.isModalRole}
|
isOpen={props.isModalRole}
|
||||||
handleClose={props.handleCloseRoleModal}
|
handleClose={props.handleCloseRoleModal}
|
||||||
>
|
>
|
||||||
<div className="addusercontainer">
|
<div className="h-full py-[10px] px-[20px]">
|
||||||
<form
|
<form className="flex flex-col" onSubmit={props.handleAddRole}>
|
||||||
style={{ display: "flex", flexDirection: "column" }}
|
|
||||||
onSubmit={props.handleAddRole}
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
value={props.roleName}
|
value={props.roleName}
|
||||||
onChange={(e) => props.setRoleName(e.target.value)}
|
onChange={(e) => props.setRoleName(e.target.value)}
|
||||||
@@ -21,39 +18,20 @@ const AddRoleModal = (props) => {
|
|||||||
? "User " + (props.signersdata.length + 1)
|
? "User " + (props.signersdata.length + 1)
|
||||||
: "User 1"
|
: "User 1"
|
||||||
}
|
}
|
||||||
className="addUserInput"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs mt-1"
|
||||||
/>
|
/>
|
||||||
<p
|
<p className="text-[gray] text-[11px] mt-[5px] mb-[10px] ml-[10px]">
|
||||||
style={{
|
e.g: Customer, Hr, Director, Manager, Student, etc...
|
||||||
color: "grey",
|
|
||||||
fontSize: 11,
|
|
||||||
margin: "10px 0 10px 5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
e.g: Hr, Director, Manager, New joinee, Accountant, etc...
|
|
||||||
</p>
|
</p>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div className="h-[1px] w-full bg-[#9f9f9f] mb-[10px]"></div>
|
||||||
style={{
|
<button type="submit" className="op-btn op-btn-primary">
|
||||||
height: "1px",
|
|
||||||
backgroundColor: "#9f9f9f",
|
|
||||||
width: "100%",
|
|
||||||
marginBottom: "15px"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
style={{
|
|
||||||
background: "#00a2b7"
|
|
||||||
}}
|
|
||||||
className="finishBtn"
|
|
||||||
>
|
|
||||||
Add
|
Add
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={props.handleCloseRoleModal}
|
onClick={props.handleCloseRoleModal}
|
||||||
type="button"
|
type="button"
|
||||||
className="finishBtn cancelBtn"
|
className="op-btn op-btn-ghost ml-2"
|
||||||
>
|
>
|
||||||
Close
|
Close
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -3,13 +3,9 @@ import React from "react";
|
|||||||
function BorderResize({ right, top }) {
|
function BorderResize({ right, top }) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="borderResize"
|
className={`${right ? `-right-[12px]` : "-right-[1px]"} ${
|
||||||
style={{
|
top ? `-bottom-[11px]` : "-bottom-[1px]"
|
||||||
right: right ? right + "px" : "-1px",
|
} absolute inline-block w-[14px] h-[14px] hover:cursor-sw-resize border-r-[3px] border-b-[3px] border-[#188ae2]`}
|
||||||
bottom: top ? top + "px" : "-1px",
|
|
||||||
borderRight: "3px solid #188ae2",
|
|
||||||
borderBottom: "3px solid #188ae2"
|
|
||||||
}}
|
|
||||||
></div>
|
></div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
function DefaultSignature({ defaultSignImg, xyPostion, setDefaultSignAlert }) {
|
function DefaultSignature({ defaultSignImg, xyPostion, setDefaultSignAlert }) {
|
||||||
const confirmToaddDefaultSign = () => {
|
const confirmToaddDefaultSign = () => {
|
||||||
if (xyPostion.length > 0) {
|
if (xyPostion.length > 0) {
|
||||||
@@ -17,55 +16,26 @@ function DefaultSignature({ defaultSignImg, xyPostion, setDefaultSignAlert }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div data-tut="reactourThird">
|
||||||
<div
|
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white",
|
|
||||||
padding: "5px",
|
|
||||||
fontFamily: "sans-serif",
|
|
||||||
marginTop: "5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Signature
|
Signature
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="flex flex-col items-center mt-[10px] font-semibold">
|
||||||
style={{
|
<p className="text-base-content">Your Signature</p>
|
||||||
display: "flex",
|
<div className="op-card shadow-md h-[111px] w-[90%] p-2">
|
||||||
flexDirection: "column",
|
<img
|
||||||
alignItems: "center",
|
alt="signature"
|
||||||
marginTop: "10px",
|
className="w-full h-full object-contain"
|
||||||
fontWeight: "600"
|
src={defaultSignImg}
|
||||||
}}
|
/>
|
||||||
>
|
</div>
|
||||||
<>
|
<button
|
||||||
<p>Your Signature</p>
|
type="button"
|
||||||
<div className="defaultSignBox">
|
className="op-btn op-btn-primary op-btn-sm mt-[10px]"
|
||||||
<img
|
onClick={() => confirmToaddDefaultSign()}
|
||||||
alt="default img"
|
>
|
||||||
style={{
|
Auto Sign All
|
||||||
width: "100%",
|
</button>
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
src={defaultSignImg}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white",
|
|
||||||
marginTop: "20px",
|
|
||||||
cursor: "pointer",
|
|
||||||
marginBottom: "10px"
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className="finishBtn finishnHover"
|
|
||||||
onClick={() => confirmToaddDefaultSign()}
|
|
||||||
>
|
|
||||||
Auto Sign All
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import Loader from "../../primitives/LoaderWithMsg";
|
import LoaderWithMsg from "../../primitives/LoaderWithMsg";
|
||||||
import { contractDocument } from "../../constant/Utils";
|
import { contractDocument } from "../../constant/Utils";
|
||||||
import HandleError from "../../primitives/HandleError";
|
import HandleError from "../../primitives/HandleError";
|
||||||
function DraftDocument() {
|
function DraftDocument() {
|
||||||
@@ -86,7 +86,7 @@ function DraftDocument() {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{isLoading.isLoader ? (
|
{isLoading.isLoader ? (
|
||||||
<Loader isLoading={isLoading} />
|
<LoaderWithMsg isLoading={isLoading} />
|
||||||
) : (
|
) : (
|
||||||
<HandleError handleError={isLoading.message} />
|
<HandleError handleError={isLoading.message} />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { themeColor } from "../../constant/const";
|
import { isEnableSubscription } from "../../constant/const";
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
import { radioButtonWidget } from "../../constant/Utils";
|
import { radioButtonWidget } from "../../constant/Utils";
|
||||||
|
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
||||||
|
import Upgrade from "../../primitives/Upgrade";
|
||||||
function DropdownWidgetOption(props) {
|
function DropdownWidgetOption(props) {
|
||||||
const [dropdownOptionList, setDropdownOptionList] = useState([
|
const [dropdownOptionList, setDropdownOptionList] = useState([
|
||||||
"option-1",
|
"option-1",
|
||||||
@@ -144,53 +146,34 @@ function DropdownWidgetOption(props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
//props.showDropdown
|
<ModalUi isOpen={props.showDropdown} title={props.title} showClose={false}>
|
||||||
<ModalUi
|
<div className="h-full p-[15px] text-base-content">
|
||||||
// styleClass={"dropdownModal"}
|
|
||||||
isOpen={props.showDropdown}
|
|
||||||
title={props.title}
|
|
||||||
showClose={false}
|
|
||||||
>
|
|
||||||
<div style={{ height: "100%", padding: 20 }}>
|
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
onSubmit={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handleSaveOption();
|
handleSaveOption();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="dropdownContainer">
|
<div>
|
||||||
<label style={{ fontSize: "13px", fontWeight: "600" }}>
|
<label className="text-[13px] font-semibold">
|
||||||
Name<span style={{ color: "red", fontSize: 13 }}> *</span>
|
Name<span className="text-[red] text-[13px]"> *</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
required
|
required
|
||||||
defaultValue={dropdownName}
|
defaultValue={dropdownName}
|
||||||
value={dropdownName}
|
value={dropdownName}
|
||||||
onChange={(e) => setDropdownName(e.target.value)}
|
onChange={(e) => setDropdownName(e.target.value)}
|
||||||
className="drodown-input"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<label
|
<label className="text-[13px] font-semibold mt-[5px]">
|
||||||
style={{ fontSize: "13px", fontWeight: "600", marginTop: "5px" }}
|
|
||||||
>
|
|
||||||
Options
|
Options
|
||||||
</label>
|
</label>
|
||||||
|
<div className="flex flex-col">
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{dropdownOptionList.map((option, index) => (
|
{dropdownOptionList.map((option, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
style={{
|
className="flex flex-row mb-[5px] items-center"
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
marginBottom: "5px",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{props.type === "checkbox" && !props.isSignYourself && (
|
{props.type === "checkbox" && !props.isSignYourself && (
|
||||||
<input
|
<input
|
||||||
@@ -210,101 +193,95 @@ function DropdownWidgetOption(props) {
|
|||||||
setDefaultCheckbox(removeOption);
|
setDefaultCheckbox(removeOption);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
style={{
|
className="op-checkbox focus:outline-none hover:border-base-content mr-[5px]"
|
||||||
width: "23px",
|
|
||||||
height: "19px",
|
|
||||||
marginRight: "5px"
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<input
|
<input
|
||||||
required
|
required
|
||||||
className="drodown-input"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
type="text"
|
type="text"
|
||||||
value={option}
|
value={option}
|
||||||
onChange={(e) => handleInputChange(index, e.target.value)}
|
onChange={(e) => handleInputChange(index, e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<i
|
<i
|
||||||
className="fa-solid fa-rectangle-xmark"
|
className="fa-light fa-rectangle-xmark text-[25px] ml-[10px] text-accent cursor-pointer"
|
||||||
onClick={() => handleDeleteInput(index)}
|
onClick={() => handleDeleteInput(index)}
|
||||||
style={{
|
|
||||||
color: "red",
|
|
||||||
fontSize: "25px",
|
|
||||||
marginLeft: "10px"
|
|
||||||
}}
|
|
||||||
></i>
|
></i>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<i
|
<i
|
||||||
onClick={handleAddInput}
|
onClick={handleAddInput}
|
||||||
style={{
|
className="fa-light fa-square-plus text-[25px] ml-[10px] op-text-primary cursor-pointer"
|
||||||
cursor: "pointer",
|
|
||||||
color: themeColor,
|
|
||||||
fontSize: "25px",
|
|
||||||
marginLeft: "10px"
|
|
||||||
}}
|
|
||||||
className="fa-solid fa-square-plus"
|
|
||||||
></i>
|
></i>
|
||||||
{props.type === "checkbox" && !props.isSignYourself && (
|
<div>
|
||||||
<>
|
{props.type === "checkbox" && !props.isSignYourself && (
|
||||||
<label style={{ fontSize: "13px", fontWeight: "600" }}>
|
<>
|
||||||
Minimun check
|
<label
|
||||||
</label>
|
className={`${
|
||||||
<input
|
!props.isSubscribe ? "text-[gray]" : ""
|
||||||
required
|
} text-[13px] font-semibold`}
|
||||||
defaultValue={0}
|
>
|
||||||
value={minCount}
|
Minimun check
|
||||||
onChange={(e) => {
|
</label>
|
||||||
const count = handleSetMinMax(e);
|
{!props.isSubscribe && isEnableSubscription && <Upgrade />}
|
||||||
setMinCount(count);
|
<input
|
||||||
}}
|
required
|
||||||
className="drodown-input"
|
defaultValue={0}
|
||||||
/>
|
value={minCount}
|
||||||
<label style={{ fontSize: "13px", fontWeight: "600" }}>
|
onChange={(e) => {
|
||||||
Maximum check
|
const count = handleSetMinMax(e);
|
||||||
</label>
|
setMinCount(count);
|
||||||
<input
|
}}
|
||||||
required
|
className={`${
|
||||||
defaultValue={0}
|
props.isSubscribe || !isEnableSubscription
|
||||||
value={maxCount}
|
? ""
|
||||||
onChange={(e) => {
|
: "pointer-events-none bg-opacity-50"
|
||||||
const count = handleSetMinMax(e);
|
} op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs`}
|
||||||
setMaxCount(count);
|
/>
|
||||||
}}
|
<label
|
||||||
className="drodown-input"
|
className={`${
|
||||||
/>
|
!props.isSubscribe ? "text-[gray]" : ""
|
||||||
</>
|
} text-[13px] font-semibold`}
|
||||||
)}
|
>
|
||||||
|
Maximum check
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
required
|
||||||
|
defaultValue={0}
|
||||||
|
value={maxCount}
|
||||||
|
onChange={(e) => {
|
||||||
|
const count = handleSetMinMax(e);
|
||||||
|
setMaxCount(count);
|
||||||
|
}}
|
||||||
|
className={`${
|
||||||
|
props.isSubscribe || !isEnableSubscription
|
||||||
|
? ""
|
||||||
|
: "pointer-events-none bg-opacity-50"
|
||||||
|
} op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs`}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{["dropdown", radioButtonWidget].includes(props.type) && (
|
{["dropdown", radioButtonWidget].includes(props.type) && (
|
||||||
<>
|
<>
|
||||||
<label
|
<label className="text-[13px] font-semibold mt-[5px]">
|
||||||
style={{
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: "600",
|
|
||||||
marginTop: "5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Default value
|
Default value
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
onChange={(e) => setDefaultValue(e.target.value)}
|
onChange={(e) => setDefaultValue(e.target.value)}
|
||||||
className="drodown-input"
|
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
name="defaultvalue"
|
name="defaultvalue"
|
||||||
value={defaultValue}
|
value={defaultValue}
|
||||||
placeholder="select default value"
|
placeholder="select default value"
|
||||||
>
|
>
|
||||||
<option value="" disabled hidden style={{ fontSize: "13px" }}>
|
<option value="" disabled hidden className="text-[13px]">
|
||||||
Select...
|
Select...
|
||||||
</option>
|
</option>
|
||||||
{dropdownOptionList.map((data, ind) => {
|
{dropdownOptionList.map((data, ind) => {
|
||||||
return (
|
return (
|
||||||
<option
|
<option className="text-[13px]" key={ind} value={data}>
|
||||||
style={{ fontSize: "13px" }}
|
|
||||||
key={ind}
|
|
||||||
value={data}
|
|
||||||
>
|
|
||||||
{data}
|
{data}
|
||||||
</option>
|
</option>
|
||||||
);
|
);
|
||||||
@@ -314,35 +291,21 @@ function DropdownWidgetOption(props) {
|
|||||||
)}
|
)}
|
||||||
{props.type !== "checkbox" && props.type !== radioButtonWidget && (
|
{props.type !== "checkbox" && props.type !== radioButtonWidget && (
|
||||||
<>
|
<>
|
||||||
<div
|
<div className="flex flex-row gap-[10px] mt-[0.5rem]">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
gap: 10,
|
|
||||||
marginTop: "0.5rem"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{statusArr.map((data, ind) => {
|
{statusArr.map((data, ind) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={ind}
|
key={ind}
|
||||||
style={{
|
className="flex flex-row gap-[5px] items-center"
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
gap: 5,
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
style={{ accentColor: "red" }}
|
className="op-radio op-radio-xs my-1"
|
||||||
type="radio"
|
type="radio"
|
||||||
name="status"
|
name="status"
|
||||||
onChange={() => setStatus(data.toLowerCase())}
|
onChange={() => setStatus(data.toLowerCase())}
|
||||||
checked={status.toLowerCase() === data.toLowerCase()}
|
checked={status.toLowerCase() === data.toLowerCase()}
|
||||||
/>
|
/>
|
||||||
<div style={{ fontSize: "13px", fontWeight: "500" }}>
|
<div className="text-[13px] font-500">{data}</div>
|
||||||
{data}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -350,64 +313,65 @@ function DropdownWidgetOption(props) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{["checkbox", radioButtonWidget].includes(props.type) && (
|
{["checkbox", radioButtonWidget].includes(props.type) && (
|
||||||
<div className="flex flex-row gap-5 mt-2 items-center text-center">
|
<div className="flex flex-row gap-5 my-2 items-center text-center">
|
||||||
{!props.isSignYourself && (
|
{!props.isSignYourself && (
|
||||||
<div>
|
<div className="flex items-center">
|
||||||
<input
|
<input
|
||||||
id="isreadonly"
|
id="isreadonly"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={isReadOnly}
|
checked={isReadOnly}
|
||||||
onChange={(e) => {
|
className="op-checkbox op-checkbox-sm"
|
||||||
setIsReadOnly(e.target.checked);
|
onChange={(e) => setIsReadOnly(e.target.checked)}
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<label className="ml-1" htmlFor="isreadonly">
|
<label className="ml-1 mb-0" htmlFor="isreadonly">
|
||||||
Is read only
|
Is read only
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div>
|
<div className="flex items-center">
|
||||||
<input
|
<input
|
||||||
id="ishidelabel"
|
id="ishidelabel"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={isHideLabel}
|
checked={isHideLabel}
|
||||||
onChange={(e) => {
|
className="op-checkbox op-checkbox-sm"
|
||||||
setIsHideLabel(e.target.checked);
|
onChange={(e) => setIsHideLabel(e.target.checked)}
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<label className="ml-1" htmlFor="ishidelabel">
|
<label className="ml-1 mb-0" htmlFor="ishidelabel">
|
||||||
Hide labels
|
Hide labels
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{props.type === "checkbox" &&
|
||||||
|
!props.isSignYourself &&
|
||||||
|
!isEnableSubscription && (
|
||||||
|
<PremiumAlertHeader
|
||||||
|
message={
|
||||||
|
"Field validations are free in beta, this feature will incur a fee later."
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
style={{
|
className={`${
|
||||||
height: "1px",
|
props.type === "checkbox" && !props.isSignYourself
|
||||||
backgroundColor: "#9f9f9f",
|
? "mb-[15px]"
|
||||||
width: "100%",
|
: "my-[15px]"
|
||||||
marginTop: "15px",
|
} w-full h-[1px] bg-[#9f9f9f]`}
|
||||||
marginBottom: "15px"
|
|
||||||
}}
|
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
// onClick={() => handleSaveOption()}
|
|
||||||
disabled={dropdownOptionList.length === 0 && true}
|
disabled={dropdownOptionList.length === 0 && true}
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
type="submit"
|
type="submit"
|
||||||
className={"finishBtn"}
|
className="op-btn op-btn-primary"
|
||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
{props.currWidgetsDetails?.options?.values?.length > 0 && (
|
{props.currWidgetsDetails?.options?.values?.length > 0 && (
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="finishBtn cancelBtn"
|
className="op-btn op-btn-ghost ml-1"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
props.handleClose && props.handleClose();
|
props.handleClose && props.handleClose();
|
||||||
resetState();
|
resetState();
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import "../../styles/AddUser.css";
|
import { checkIsSubscribed, getFileName } from "../../constant/Utils";
|
||||||
|
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
||||||
|
import Upgrade from "../../primitives/Upgrade";
|
||||||
|
import { isEnableSubscription } from "../../constant/const";
|
||||||
// import SelectFolder from "../../premitives/SelectFolder";
|
// import SelectFolder from "../../premitives/SelectFolder";
|
||||||
|
|
||||||
const EditTemplate = ({ template, onSuccess }) => {
|
const EditTemplate = ({ template, onSuccess }) => {
|
||||||
@@ -8,9 +11,21 @@ const EditTemplate = ({ template, onSuccess }) => {
|
|||||||
Name: template?.Name || "",
|
Name: template?.Name || "",
|
||||||
Note: template?.Note || "",
|
Note: template?.Note || "",
|
||||||
Description: template?.Description || "",
|
Description: template?.Description || "",
|
||||||
SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false"
|
SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false",
|
||||||
|
AutomaticReminders: template?.AutomaticReminders || false,
|
||||||
|
RemindOnceInEvery: template?.RemindOnceInEvery || 5
|
||||||
});
|
});
|
||||||
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSubscription();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
const fetchSubscription = async () => {
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const getIsSubscribe = await checkIsSubscribed();
|
||||||
|
setIsSubscribe(getIsSubscribe);
|
||||||
|
}
|
||||||
|
};
|
||||||
const handleStrInput = (e) => {
|
const handleStrInput = (e) => {
|
||||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||||
};
|
};
|
||||||
@@ -24,34 +39,40 @@ const EditTemplate = ({ template, onSuccess }) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const isChecked = formData.SendinOrder === "true" ? true : false;
|
const isChecked = formData.SendinOrder === "true" ? true : false;
|
||||||
const data = { ...formData, SendinOrder: isChecked };
|
const AutoReminder = formData?.AutomaticReminders || false;
|
||||||
|
|
||||||
|
let reminderDate = {};
|
||||||
|
if (AutoReminder) {
|
||||||
|
const RemindOnceInEvery = parseInt(formData?.RemindOnceInEvery);
|
||||||
|
const ReminderDate = new Date(template?.createdAt);
|
||||||
|
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
|
||||||
|
reminderDate = { NextReminderDate: ReminderDate };
|
||||||
|
}
|
||||||
|
const data = { ...formData, SendinOrder: isChecked, ...reminderDate };
|
||||||
onSuccess(data);
|
onSuccess(data);
|
||||||
};
|
};
|
||||||
|
const handleAutoReminder = () => {
|
||||||
|
setFormData((prev) => ({
|
||||||
|
...prev,
|
||||||
|
AutomaticReminders: !formData.AutomaticReminders
|
||||||
|
}));
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="addusercontainer">
|
<div className="max-h-[300px] md:max-h-[400px] overflow-y-scroll p-[10px]">
|
||||||
<div className="form-wrapper">
|
<div className="text-base-content">
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<div>
|
<div className="mb-[0.35rem]">
|
||||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
<label htmlFor="name" className="text-[13px]">
|
||||||
File
|
File
|
||||||
</label>
|
</label>
|
||||||
<div
|
<div className="op-input op-input-bordered op-input-sm focus:outline-none py-2 font-semibold w-full text-xs">
|
||||||
style={{
|
{getFileName(template.URL)}
|
||||||
padding: "0.5rem 0.75rem",
|
|
||||||
border: "1px solid #d1d5db",
|
|
||||||
borderRadius: "0.375rem",
|
|
||||||
fontSize: "0.75rem",
|
|
||||||
fontWeight: "700"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{template.URL?.split("/")?.pop()?.split("_")[1]}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-section">
|
<div className="mb-[0.35rem]">
|
||||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
<label htmlFor="name" className="text-[13px]">
|
||||||
Name
|
Name
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
<span className="text-[13px] text-[red]"> *</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -59,11 +80,11 @@ const EditTemplate = ({ template, onSuccess }) => {
|
|||||||
value={formData.Name}
|
value={formData.Name}
|
||||||
onChange={(e) => handleStrInput(e)}
|
onChange={(e) => handleStrInput(e)}
|
||||||
required
|
required
|
||||||
className="addUserInput"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-section">
|
<div className="mb-[0.35rem]">
|
||||||
<label htmlFor="Note" style={{ fontSize: 13 }}>
|
<label htmlFor="Note" className="text-[13px]">
|
||||||
Note
|
Note
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -72,11 +93,11 @@ const EditTemplate = ({ template, onSuccess }) => {
|
|||||||
id="Note"
|
id="Note"
|
||||||
value={formData.Note}
|
value={formData.Note}
|
||||||
onChange={(e) => handleStrInput(e)}
|
onChange={(e) => handleStrInput(e)}
|
||||||
className="addUserInput"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-section">
|
<div className="mb-[0.35rem]">
|
||||||
<label htmlFor="Description" style={{ fontSize: 13 }}>
|
<label htmlFor="Description" className="text-[13px]">
|
||||||
Description
|
Description
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -85,51 +106,85 @@ const EditTemplate = ({ template, onSuccess }) => {
|
|||||||
id="Description"
|
id="Description"
|
||||||
value={formData.Description}
|
value={formData.Description}
|
||||||
onChange={(e) => handleStrInput(e)}
|
onChange={(e) => handleStrInput(e)}
|
||||||
className="addUserInput"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-section">
|
<div className="mb-[0.35rem]">
|
||||||
<label style={{ fontSize: 13 }}>Send In Order</label>
|
<label className="text-[13px]">Send In Order</label>
|
||||||
<div
|
<div className="flex items-center gap-[8px] ml-[8px] mb-[5px]">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: 8,
|
|
||||||
marginLeft: 8,
|
|
||||||
marginBottom: 5
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
value={"true"}
|
value={"true"}
|
||||||
|
className="op-radio op-radio-xs"
|
||||||
name="SendinOrder"
|
name="SendinOrder"
|
||||||
checked={formData.SendinOrder === "true"}
|
checked={formData.SendinOrder === "true"}
|
||||||
onChange={handleStrInput}
|
onChange={handleStrInput}
|
||||||
/>
|
/>
|
||||||
<div style={{ fontSize: 12 }}>Yes</div>
|
<div className="text-[12px]">Yes</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="flex items-center gap-[8px] ml-[8px] mb-[5px]">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: 8,
|
|
||||||
marginLeft: 8,
|
|
||||||
marginBottom: 5
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
value={"false"}
|
value={"false"}
|
||||||
name="SendinOrder"
|
name="SendinOrder"
|
||||||
|
className="op-radio op-radio-xs"
|
||||||
checked={formData.SendinOrder === "false"}
|
checked={formData.SendinOrder === "false"}
|
||||||
onChange={handleStrInput}
|
onChange={handleStrInput}
|
||||||
/>
|
/>
|
||||||
<div style={{ fontSize: 12 }}>No</div>
|
<div className="text-[12px]">No</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* <SelectFolder onSuccess={handleFolder} folderCls={"contracts_Template"} /> */}
|
<div className="text-xs mt-2">
|
||||||
<div className="buttoncontainer">
|
{!isEnableSubscription && (
|
||||||
<button type="submit" className="submitbutton">
|
<PremiumAlertHeader
|
||||||
|
message={
|
||||||
|
"Auto reminder is free in beta, this feature will incur a fee later."
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<span
|
||||||
|
className={
|
||||||
|
isSubscribe || !isEnableSubscription
|
||||||
|
? "font-semibold"
|
||||||
|
: "font-semibold text-gray-300"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Auto reminder{" "}
|
||||||
|
{!isSubscribe && isEnableSubscription && <Upgrade />}
|
||||||
|
</span>
|
||||||
|
<label
|
||||||
|
className={`${
|
||||||
|
isSubscribe || !isEnableSubscription
|
||||||
|
? "cursor-pointer "
|
||||||
|
: "pointer-events-none opacity-50"
|
||||||
|
} relative block items-center mb-0`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
checked={formData.AutomaticReminders}
|
||||||
|
onChange={handleAutoReminder}
|
||||||
|
type="checkbox"
|
||||||
|
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white mt-2"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{isSubscribe && formData?.AutomaticReminders === true && (
|
||||||
|
<div className="text-xs mt-2">
|
||||||
|
<label className="block">
|
||||||
|
Remind once in every (Days)
|
||||||
|
<span className="text-red-500 text-[13px]">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={formData.RemindOnceInEvery}
|
||||||
|
name="RemindOnceInEvery"
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
onChange={handleStrInput}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="mt-[1rem] flex justify-start">
|
||||||
|
<button type="submit" className="op-btn op-btn-primary">
|
||||||
Submit
|
Submit
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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,42 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Tooltip from "../../primitives/Tooltip";
|
||||||
|
import ReactQuill from "react-quill";
|
||||||
|
import "react-quill/dist/quill.snow.css";
|
||||||
|
import EditorToolbar, { module1, formats } from "./EditorToolbar";
|
||||||
|
|
||||||
|
export function EmailBody(props) {
|
||||||
|
return (
|
||||||
|
<form className="flex flex-col text-base-content text-lg font-normal">
|
||||||
|
<div className="m-2 md:m-10 p-3 md:p-10 shadow-md hover:shadow-lg border-[1px] border-indigo-800 rounded-md">
|
||||||
|
<label className="text-sm ml-2">
|
||||||
|
Subject <Tooltip message={"email subject"} />
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
required
|
||||||
|
value={props.requestSubject}
|
||||||
|
onChange={(e) => props.setRequestSubject(e.target.value)}
|
||||||
|
placeholder='${senderName} has requested you to sign "${documentName}"'
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
/>
|
||||||
|
<label className="text-sm ml-2 mt-3">
|
||||||
|
Body <Tooltip message={"email body"} />
|
||||||
|
</label>
|
||||||
|
<div className="px-3 py-2 w-full focus:outline-none text-xs">
|
||||||
|
<EditorToolbar containerId="toolbar1" />
|
||||||
|
<ReactQuill
|
||||||
|
theme="snow"
|
||||||
|
value={props.requestBody}
|
||||||
|
// value={typedText}
|
||||||
|
placeholder="add body of email "
|
||||||
|
// readOnly={loading}
|
||||||
|
// onChangeSelection={handleTextSelection} // Listen for text selection
|
||||||
|
ref={props.editorRef}
|
||||||
|
modules={module1}
|
||||||
|
formats={formats}
|
||||||
|
onChange={props.handleOnchangeRequest}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,21 +1,22 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { saveAs } from "file-saver";
|
import { saveAs } from "file-saver";
|
||||||
import celebration from "../../assets/images/newCeleb.gif";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { getBase64FromUrl } from "../../constant/Utils";
|
import { getBase64FromUrl } from "../../constant/Utils";
|
||||||
import { themeColor } from "../../constant/const";
|
import { themeColor } from "../../constant/const";
|
||||||
import printModule from "print-js";
|
import printModule from "print-js";
|
||||||
import loader from "../../assets/images/loader2.gif";
|
import Loader from "../../primitives/Loader";
|
||||||
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
|
|
||||||
function EmailComponent({
|
function EmailComponent({
|
||||||
isEmail,
|
isEmail,
|
||||||
pdfUrl,
|
pdfUrl,
|
||||||
isCeleb,
|
|
||||||
setIsEmail,
|
setIsEmail,
|
||||||
setSuccessEmail,
|
setSuccessEmail,
|
||||||
pdfName,
|
pdfName,
|
||||||
sender,
|
sender,
|
||||||
setIsAlert
|
setIsAlert,
|
||||||
|
extUserId,
|
||||||
|
activeMailAdapter
|
||||||
}) {
|
}) {
|
||||||
const [emailList, setEmailList] = useState([]);
|
const [emailList, setEmailList] = useState([]);
|
||||||
const [emailValue, setEmailValue] = useState();
|
const [emailValue, setEmailValue] = useState();
|
||||||
@@ -23,6 +24,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 {
|
||||||
@@ -38,6 +40,8 @@ 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,
|
||||||
pdfName: pdfName,
|
pdfName: pdfName,
|
||||||
url: pdfUrl,
|
url: pdfUrl,
|
||||||
recipient: emailList[i],
|
recipient: emailList[i],
|
||||||
@@ -161,266 +165,141 @@ function EmailComponent({
|
|||||||
<div>
|
<div>
|
||||||
{/* isEmail */}
|
{/* isEmail */}
|
||||||
{isEmail && (
|
{isEmail && (
|
||||||
<div className="modaloverlay">
|
<ModalUi isOpen showHeader={false}>
|
||||||
<div className="modalcontainer">
|
{isLoading && (
|
||||||
{isLoading && (
|
<div className="absolute w-full h-full flex flex-col justify-center items-center z-[20] bg-[#e6f2f2]/70">
|
||||||
<div
|
<Loader />
|
||||||
style={{
|
<span className="text-[12px] text-base-content">
|
||||||
position: "absolute",
|
This might take some time
|
||||||
height: "100%",
|
|
||||||
width: "100%",
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
|
||||||
zIndex: "20",
|
|
||||||
backgroundColor: "#e6f2f2",
|
|
||||||
opacity: 0.8
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="no img"
|
|
||||||
src={loader}
|
|
||||||
style={{ width: "70px", height: "70px" }}
|
|
||||||
/>
|
|
||||||
<span style={{ fontSize: "12px", fontWeight: "bold" }}>
|
|
||||||
This might take some time
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div style={{ background: "#32a3ac" }} className="modalheader">
|
|
||||||
<span style={{ color: "white" }}>Successfully signed!</span>
|
|
||||||
|
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
|
||||||
<div></div>
|
|
||||||
{!isAndroid && (
|
|
||||||
<button
|
|
||||||
onClick={handleToPrint}
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
className="btn btn-primary btn-sm"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-print"
|
|
||||||
style={{
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px",
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Print
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<button
|
|
||||||
className="btn btn-danger btn-sm"
|
|
||||||
onClick={() => handleDownloadPdf()}
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
marginLeft: "10px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-download"
|
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Download
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ height: "100%", padding: 20 }}>
|
|
||||||
{isCeleb && (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "absolute",
|
|
||||||
marginLeft: "50px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="print img"
|
|
||||||
width={300}
|
|
||||||
height={250}
|
|
||||||
// style={styles.gifCeleb}
|
|
||||||
src={celebration}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
fontFamily: "system-ui",
|
|
||||||
verticalAlign: "baseline",
|
|
||||||
fontWeight: "500",
|
|
||||||
color: "#403f3e",
|
|
||||||
fontSize: "15px",
|
|
||||||
marginBottom: "5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Recipients added here will get a copy of the signed document.
|
|
||||||
</p>
|
|
||||||
{emailList.length > 0 ? (
|
|
||||||
<>
|
|
||||||
<div className="addEmail">
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
|
|
||||||
flexWrap: "wrap"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{emailList.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="emailChip"
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
key={ind}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: "13px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{data}
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: 13,
|
|
||||||
fontWeight: 600,
|
|
||||||
marginLeft: 7,
|
|
||||||
cursor: "pointer"
|
|
||||||
}}
|
|
||||||
onClick={() => removeChip(ind)}
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-xmark"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
{emailList.length <= 9 && (
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={emailValue}
|
|
||||||
className="addEmailInput"
|
|
||||||
onChange={handleEmailValue}
|
|
||||||
onKeyDown={handleEnterPress}
|
|
||||||
onBlur={() => {
|
|
||||||
if (emailValue) {
|
|
||||||
handleEnterPress("add");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={emailValue}
|
|
||||||
className="emailInput"
|
|
||||||
onChange={handleEmailValue}
|
|
||||||
onKeyDown={handleEnterPress}
|
|
||||||
placeholder="Add the email addresses"
|
|
||||||
onBlur={() => {
|
|
||||||
if (emailValue) {
|
|
||||||
handleEnterPress("add");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
cursor: emailValue && "pointer"
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
if (emailValue) {
|
|
||||||
handleEnterPress("add");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
style={{
|
|
||||||
backgroundColor: themeColor,
|
|
||||||
padding: "5px 7px",
|
|
||||||
marginTop: "10px",
|
|
||||||
color: "white",
|
|
||||||
borderRadius: "2px"
|
|
||||||
}}
|
|
||||||
className="fa fa-plus"
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
<div
|
)}
|
||||||
style={{
|
<div className="flex justify-between items-center py-[10px] px-[20px] border-b-[1px] border-base-content">
|
||||||
background: "#e3e2e1",
|
<span className="text-base-content font-semibold">
|
||||||
marginTop: "10px",
|
Successfully signed!
|
||||||
padding: "5px",
|
</span>
|
||||||
borderRadius: "3px"
|
<div className="flex flex-row">
|
||||||
}}
|
<div></div>
|
||||||
>
|
{!isAndroid && (
|
||||||
<span style={{ fontWeight: "700" }}>Note:</span>
|
<button
|
||||||
<span style={{ fontSize: "15px" }}>
|
onClick={handleToPrint}
|
||||||
{" "}
|
className="op-btn op-btn-neutral op-btn-sm text-[15px]"
|
||||||
You can only send to ten recipients at a time.
|
>
|
||||||
</span>
|
<i className="fa-light fa-print" aria-hidden="true"></i>
|
||||||
</div>
|
Print
|
||||||
<div
|
</button>
|
||||||
style={{
|
)}
|
||||||
height: "1px",
|
|
||||||
backgroundColor: "#9f9f9f",
|
|
||||||
width: "100%",
|
|
||||||
marginTop: "15px",
|
|
||||||
marginBottom: "15px"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
<button
|
<button
|
||||||
disabled={emailList.length === 0 && true}
|
className="op-btn op-btn-primary op-btn-sm text-[15px] ml-2"
|
||||||
style={{
|
onClick={() => handleDownloadPdf()}
|
||||||
background: themeColor,
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className={emailList.length === 0 ? "defaultBtn" : "finishBtn"}
|
|
||||||
onClick={() => sendEmail()}
|
|
||||||
>
|
>
|
||||||
Send
|
<i className="fa-light fa-download" aria-hidden="true"></i>
|
||||||
</button>
|
Download
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="finishBtn cancelBtn"
|
|
||||||
onClick={() => {
|
|
||||||
setIsEmail(false);
|
|
||||||
setEmailValue("");
|
|
||||||
setEmailList([]);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Close
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="h-full p-[20px]">
|
||||||
|
<p className="font-medium text-[15px] mb-[5px] text-base-content align-baseline">
|
||||||
|
Recipients added here will get a copy of the signed document.
|
||||||
|
</p>
|
||||||
|
{emailList.length > 0 ? (
|
||||||
|
<>
|
||||||
|
<div className="p-0 border-[1.5px] op-border-primary rounded w-full text-[15px]">
|
||||||
|
<div className="flex flex-row flex-wrap">
|
||||||
|
{emailList.map((data, ind) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex flex-row items-center op-bg-primary m-[4px] rounded-md py-[5px] px-[10px]"
|
||||||
|
key={ind}
|
||||||
|
>
|
||||||
|
<span className="text-base-100 text-[13px]">
|
||||||
|
{data}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="text-base-100 text-[13px] font-semibold ml-[7px] cursor-pointer"
|
||||||
|
onClick={() => removeChip(ind)}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-xmark"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
{emailList.length <= 9 && (
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={emailValue}
|
||||||
|
className="p-[10px] pb-[20px] rounded w-full text-[15px] bg-transparent outline-none"
|
||||||
|
onChange={handleEmailValue}
|
||||||
|
onKeyDown={handleEnterPress}
|
||||||
|
onBlur={() => {
|
||||||
|
if (emailValue) {
|
||||||
|
handleEnterPress("add");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={emailValue}
|
||||||
|
className="p-[10px] pb-[20px] rounded w-full text-[15px] outline-none bg-transparent border-[1.5px] op-border-primary"
|
||||||
|
onChange={handleEmailValue}
|
||||||
|
onKeyDown={handleEnterPress}
|
||||||
|
placeholder="Add the email addresses"
|
||||||
|
onBlur={() => {
|
||||||
|
if (emailValue) {
|
||||||
|
handleEnterPress("add");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
className={`${
|
||||||
|
emailValue ? "cursor-pointer" : "cursor-default"
|
||||||
|
} op-btn op-btn-primary op-btn-sm m-2 shadow-md`}
|
||||||
|
onClick={() => {
|
||||||
|
if (emailValue) {
|
||||||
|
handleEnterPress("add");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-plus" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div className="bg-[#e3e2e1] mt-[10px] p-[5px] rounded">
|
||||||
|
<span className="font-bold">Note: </span>
|
||||||
|
<span className="text-[15px]">
|
||||||
|
You can only send to ten recipients at a time.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<hr className="w-full my-[15px] bg-base-content" />
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-secondary"
|
||||||
|
onClick={() => emailList.length > 0 && sendEmail()}
|
||||||
|
>
|
||||||
|
Send
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-ghost ml-2"
|
||||||
|
onClick={() => {
|
||||||
|
setIsEmail(false);
|
||||||
|
setEmailValue("");
|
||||||
|
setEmailList([]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,26 +1,24 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import PrevNext from "./PrevNext";
|
import PrevNext from "./PrevNext";
|
||||||
import { PDFDownloadLink } from "@react-pdf/renderer";
|
import {
|
||||||
import Certificate from "./Certificate";
|
handleDownloadCertificate,
|
||||||
import printModule from "print-js";
|
handleDownloadPdf,
|
||||||
import { getBase64FromUrl } from "../../constant/Utils";
|
handleToPrint
|
||||||
import { saveAs } from "file-saver";
|
} from "../../constant/Utils";
|
||||||
import "../../styles/signature.css";
|
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 ModalUi from "../../primitives/ModalUi";
|
||||||
|
import Loader from "../../primitives/Loader";
|
||||||
|
|
||||||
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,
|
||||||
@@ -31,7 +29,6 @@ function Header({
|
|||||||
isShowHeader,
|
isShowHeader,
|
||||||
decline,
|
decline,
|
||||||
currentSigner,
|
currentSigner,
|
||||||
dataTut4,
|
|
||||||
alreadySign,
|
alreadySign,
|
||||||
isSignYourself,
|
isSignYourself,
|
||||||
setIsEmail,
|
setIsEmail,
|
||||||
@@ -42,15 +39,9 @@ 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 [isDownloading, setIsDownloading] = useState("");
|
||||||
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
||||||
//for go to previous page
|
|
||||||
function previousPage() {
|
|
||||||
changePage(-1);
|
|
||||||
}
|
|
||||||
//for go to next page
|
|
||||||
function nextPage() {
|
|
||||||
changePage(1);
|
|
||||||
}
|
|
||||||
//function for show decline alert
|
//function for show decline alert
|
||||||
const handleDeclinePdfAlert = async () => {
|
const handleDeclinePdfAlert = async () => {
|
||||||
const currentDecline = {
|
const currentDecline = {
|
||||||
@@ -60,145 +51,8 @@ function Header({
|
|||||||
setIsDecline(currentDecline);
|
setIsDecline(currentDecline);
|
||||||
};
|
};
|
||||||
|
|
||||||
//function for print digital sign pdf
|
|
||||||
const handleToPrint = async (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
const pdf = await getBase64FromUrl(pdfUrl);
|
|
||||||
const isAndroidDevice = navigator.userAgent.match(/Android/i);
|
|
||||||
const isAppleDevice =
|
|
||||||
(/iPad|iPhone|iPod/.test(navigator.platform) ||
|
|
||||||
(navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1)) &&
|
|
||||||
!window.MSStream;
|
|
||||||
if (isAndroidDevice || isAppleDevice) {
|
|
||||||
const byteArray = Uint8Array.from(
|
|
||||||
atob(pdf)
|
|
||||||
.split("")
|
|
||||||
.map((char) => char.charCodeAt(0))
|
|
||||||
);
|
|
||||||
const blob = new Blob([byteArray], { type: "application/pdf" });
|
|
||||||
const blobUrl = URL.createObjectURL(blob);
|
|
||||||
window.open(blobUrl, "_blank");
|
|
||||||
} else {
|
|
||||||
printModule({ printable: pdf, type: "pdf", base64: true });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//handle download signed pdf
|
|
||||||
const handleDownloadPdf = () => {
|
|
||||||
const pdfName = pdfDetails[0] && pdfDetails[0].Name;
|
|
||||||
saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
|
|
||||||
};
|
|
||||||
|
|
||||||
const sanitizeFileName = (pdfName) => {
|
|
||||||
// Replace spaces with underscore
|
|
||||||
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 (
|
|
||||||
<PDFDownloadLink
|
|
||||||
onClick={(e) => e.preventDefault()}
|
|
||||||
style={{ textDecoration: "none", zIndex: "35" }}
|
|
||||||
document={<Certificate pdfData={pdfDetails} />}
|
|
||||||
>
|
|
||||||
{({ blob, loading }) => (
|
|
||||||
<>
|
|
||||||
{loading ? (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border: "none",
|
|
||||||
backgroundColor: "#fff"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa-solid fa-award"
|
|
||||||
style={{ marginRight: "2px" }}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Certificate
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{ border: "none", backgroundColor: "#fff" }}
|
|
||||||
onClick={() =>
|
|
||||||
handleDownload(
|
|
||||||
blob,
|
|
||||||
`completion certificate-${
|
|
||||||
pdfDetails[0] && pdfDetails[0].Name
|
|
||||||
}.pdf`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa-solid fa-award"
|
|
||||||
style={{ marginRight: "2px" }}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Certificate
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</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 className="flex py-[5px]">
|
||||||
{isMobile && isShowHeader ? (
|
{isMobile && isShowHeader ? (
|
||||||
<div
|
<div
|
||||||
id="navbar"
|
id="navbar"
|
||||||
@@ -209,64 +63,28 @@ function Header({
|
|||||||
: window.innerWidth - 30 + "px"
|
: window.innerWidth - 30 + "px"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="preBtn2">
|
<div className="flex justify-between items-center py-[5px] px-[10px] ">
|
||||||
<div
|
<div onClick={() => navigate(-1)}>
|
||||||
onClick={() => {
|
|
||||||
navigate(-1);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
<i
|
||||||
className="fa fa-arrow-left"
|
className="fa-light fa-arrow-left text-base-content"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
style={{ color: themeColor, cursor: "pointer" }}
|
|
||||||
></i>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<i
|
|
||||||
onClick={() => {
|
|
||||||
if (pageNumber > 1) {
|
|
||||||
previousPage();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="fa fa-backward"
|
|
||||||
style={{ color: "gray", cursor: "pointer" }}
|
|
||||||
></i>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: "600",
|
|
||||||
marginLeft: "10px",
|
|
||||||
marginRight: "10px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
|
|
||||||
</span>
|
|
||||||
<i
|
|
||||||
onClick={() => {
|
|
||||||
if (pageNumber < allPages) {
|
|
||||||
nextPage();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="fa fa-forward"
|
|
||||||
style={{ color: "gray", cursor: "pointer" }}
|
|
||||||
></i>
|
></i>
|
||||||
</div>
|
</div>
|
||||||
|
<PrevNext
|
||||||
|
pageNumber={pageNumber}
|
||||||
|
allPages={allPages}
|
||||||
|
changePage={changePage}
|
||||||
|
/>
|
||||||
{pdfUrl && alreadySign ? (
|
{pdfUrl && alreadySign ? (
|
||||||
<DropdownMenu.Root>
|
<DropdownMenu.Root>
|
||||||
<DropdownMenu.Trigger asChild>
|
<DropdownMenu.Trigger asChild>
|
||||||
<div
|
<div className="op-link op-link-primary no-underline text-[16px] font-semibold pr-[3px] pl-[5px]">
|
||||||
style={{
|
<i
|
||||||
color: themeColor,
|
className="fa-light fa-ellipsis-v"
|
||||||
border: "none",
|
aria-hidden="true"
|
||||||
fontWeight: "650",
|
></i>
|
||||||
fontSize: "16px",
|
|
||||||
padding: "0px 3px 0px 5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<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"
|
||||||
@@ -274,74 +92,61 @@ function Header({
|
|||||||
>
|
>
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Item
|
||||||
className="DropdownMenuItem"
|
className="DropdownMenuItem"
|
||||||
onClick={() => handleDownloadPdf()}
|
onClick={() =>
|
||||||
|
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div
|
<div className="flex flex-row">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
<i
|
||||||
className="fa fa-arrow-down"
|
className="fa-light fa-arrow-down mr-[3px]"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
style={{ marginRight: "2px" }}
|
|
||||||
></i>
|
></i>
|
||||||
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(
|
||||||
|
pdfDetails,
|
||||||
|
setIsDownloading
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="border-none bg-[#fff]">
|
||||||
|
<i
|
||||||
|
className="fa-light fa-award mr-[3px]"
|
||||||
|
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 className="flex flex-row">
|
||||||
|
<i
|
||||||
|
className="fa-light fa-envelope mr-[3px]"
|
||||||
|
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"
|
||||||
onClick={handleToPrint}
|
onClick={(e) =>
|
||||||
|
handleToPrint(e, pdfUrl, setIsDownloading)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div
|
<div className="flex flex-row">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{" "}
|
|
||||||
<i
|
<i
|
||||||
className="fa fa-print"
|
className="fa-light fa-print mr-[3px]"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
style={{ marginRight: "2px" }}
|
|
||||||
></i>
|
></i>
|
||||||
Print
|
Print
|
||||||
</div>
|
</div>
|
||||||
@@ -350,24 +155,16 @@ function Header({
|
|||||||
</DropdownMenu.Portal>
|
</DropdownMenu.Portal>
|
||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ display: "flex", justifyContent: "space-around" }}>
|
<div className="flex justify-around items-center">
|
||||||
{/* current signer is checking user send request and check status of pdf sign than if current
|
{/* current signer is checking user send request and check status of pdf sign than if current
|
||||||
user exist than show finish button else no
|
user exist than show finish button else no
|
||||||
*/}
|
*/}
|
||||||
{currentSigner && (
|
{currentSigner && (
|
||||||
<>
|
<div className="flex items-center" data-tut="reactourFifth">
|
||||||
{decline && (
|
{decline && (
|
||||||
<div
|
<div
|
||||||
onClick={() => {
|
onClick={() => handleDeclinePdfAlert()}
|
||||||
handleDeclinePdfAlert();
|
className="text-[red] border-none font-[650] text-[14px] mr-2"
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
color: "red",
|
|
||||||
border: "none",
|
|
||||||
fontWeight: "650",
|
|
||||||
fontSize: "16px",
|
|
||||||
marginRight: "10px"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Decline
|
Decline
|
||||||
</div>
|
</div>
|
||||||
@@ -379,13 +176,10 @@ function Header({
|
|||||||
alertSendEmail();
|
alertSendEmail();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
style={{
|
className={`${
|
||||||
color: isMailSend ? "gray" : themeColor,
|
isMailSend ? "" : "op-link-primary"
|
||||||
border: "none",
|
} op-link no-underline font-[650] text-[14px]`}
|
||||||
fontWeight: "650",
|
data-tut="headerArea"
|
||||||
fontSize: "16px"
|
|
||||||
}}
|
|
||||||
data-tut={dataTut4}
|
|
||||||
>
|
>
|
||||||
{completeBtnTitle ? completeBtnTitle : "Send"}
|
{completeBtnTitle ? completeBtnTitle : "Send"}
|
||||||
</div>
|
</div>
|
||||||
@@ -399,343 +193,268 @@ function Header({
|
|||||||
embedWidgetsData();
|
embedWidgetsData();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
style={{
|
className="border-none font-[650] text-[14px] op-link op-link-primary no-underline"
|
||||||
color: themeColor,
|
|
||||||
border: "none",
|
|
||||||
fontWeight: "650",
|
|
||||||
fontSize: "16px"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Finish
|
Finish
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
<DropdownMenu.Root>
|
||||||
|
<DropdownMenu.Trigger asChild>
|
||||||
|
<div className="font-[650] text-[18px] px-2 ml-[4px] text-base-content no-underline">
|
||||||
|
<i
|
||||||
|
className="fa-light fa-ellipsis-v"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
</DropdownMenu.Trigger>
|
||||||
|
<DropdownMenu.Portal>
|
||||||
|
<DropdownMenu.Content
|
||||||
|
className="bg-white shadow-md rounded px-2 py-1"
|
||||||
|
sideOffset={5}
|
||||||
|
>
|
||||||
|
<DropdownMenu.Item
|
||||||
|
className="flex flex-row justify-center items-center text-[13px] focus:outline-none cursor-pointer"
|
||||||
|
onClick={() =>
|
||||||
|
handleDownloadPdf(
|
||||||
|
pdfDetails,
|
||||||
|
pdfUrl,
|
||||||
|
setIsDownloading
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="fa-light fa-arrow-down mr-[3px]"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
<span className="font-[500]">Download</span>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu.Portal>
|
||||||
|
</DropdownMenu.Root>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="signatureHeader headerBtn">
|
<div className="flex flex-wrap justify-between items-center w-full gap-y-1 ml-1">
|
||||||
<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 className="text-[13px] text-[#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 className="text-[13px] text-[#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-[3px]"
|
||||||
border: "none",
|
|
||||||
outline: "none",
|
|
||||||
textAlign: "center"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-gear fa-lg"></i>
|
<i className="fa-light fa-gear fa-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => navigate(-1)}
|
||||||
navigate(-1);
|
|
||||||
}}
|
|
||||||
type="button"
|
type="button"
|
||||||
className="defaultBtn backBtn"
|
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||||
>
|
>
|
||||||
Back
|
Back
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
disabled={isMailSend && true}
|
disabled={isMailSend && true}
|
||||||
data-tut="reactourFour"
|
data-tut="headerArea"
|
||||||
style={{
|
className="op-btn op-btn-primary op-btn-sm mr-[3px]"
|
||||||
background: isMailSend ? "rgb(203, 203, 203)" : "#188ae2",
|
onClick={() => alertSendEmail()}
|
||||||
color: isMailSend && "rgb(77, 75, 75)"
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
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 className="flex flex-row">
|
||||||
{isCompleted.isCertificate && <CertificateComponent />}
|
{isCompleted && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() =>
|
||||||
|
handleDownloadCertificate(pdfDetails, setIsDownloading)
|
||||||
|
}
|
||||||
|
className="op-btn op-btn-secondary op-btn-sm mr-[3px] shadow"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="fa-light fa-award py-[3px]"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
<span className="hidden lg:block">Certificate</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={handleToPrint}
|
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
|
||||||
type="button"
|
type="button"
|
||||||
className="defaultBtn printBtn"
|
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
className="fa fa-print"
|
className="fa-light fa-print py-[3px]"
|
||||||
style={{
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px",
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
Print
|
<span className="hidden lg:block">Print</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="defaultBtn downloadBtn"
|
className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow"
|
||||||
style={{
|
onClick={() =>
|
||||||
display: "flex",
|
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
|
||||||
flexDirection: "row",
|
}
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
onClick={() => handleDownloadPdf()}
|
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
className="fa fa-download"
|
className="fa-light fa-download py-[3px]"
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
Download
|
<span className="hidden lg:block">Download</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div className="flex" data-tut="reactourFifth">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => navigate(-1)}
|
||||||
navigate(-1);
|
|
||||||
}}
|
|
||||||
type="button"
|
type="button"
|
||||||
className="defaultBtn backBtn"
|
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||||
>
|
>
|
||||||
Back
|
Back
|
||||||
</button>
|
</button>
|
||||||
{currentSigner && (
|
{currentSigner && (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
style={{
|
className="op-btn op-btn-secondary op-btn-sm mr-[3px] shadow"
|
||||||
background: "#de4337"
|
onClick={() => handleDeclinePdfAlert()}
|
||||||
}}
|
|
||||||
className="finishBtn hoverCss"
|
|
||||||
onClick={() => {
|
|
||||||
handleDeclinePdfAlert();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Decline
|
Decline
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
style={{
|
|
||||||
background: "#188ae2"
|
|
||||||
}}
|
|
||||||
type="button"
|
type="button"
|
||||||
className="finishBtn sendHover"
|
className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow"
|
||||||
onClick={() => {
|
onClick={() => embedWidgetsData()}
|
||||||
embedWidgetsData();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Finish
|
Finish
|
||||||
</button>
|
</button>
|
||||||
|
<div className="op-dropdown op-dropdown-end">
|
||||||
|
<div
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
className="op-btn op-btn-info op-btn-sm shadow"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="fa-light fa-ellipsis-v"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
<ul
|
||||||
|
tabIndex={0}
|
||||||
|
className="op-dropdown-content z-[1] op-menu op-menu-sm p-1 shadow bg-base-100 rounded-box mt-1"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
onClick={() =>
|
||||||
|
handleDownloadPdf(
|
||||||
|
pdfDetails,
|
||||||
|
pdfUrl,
|
||||||
|
setIsDownloading
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="font-semibold text-[12px]">
|
||||||
|
<i
|
||||||
|
className="fa-light fa-arrow-down"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>{" "}
|
||||||
|
Download
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
) : pdfUrl || (documentStatus && documentStatus.isCompleted) ? (
|
) : isCompleted ? (
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
<div className="flex flex-row">
|
||||||
<CertificateComponent />
|
{isCompleted && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() =>
|
||||||
|
handleDownloadCertificate(pdfDetails, setIsDownloading)
|
||||||
|
}
|
||||||
|
className="op-btn op-btn-secondary op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-award" aria-hidden="true"></i>
|
||||||
|
<span className="hidden lg:block ml-1">Certificate</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={handleToPrint}
|
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
|
||||||
type="button"
|
type="button"
|
||||||
style={{
|
className="op-btn op-btn-neutral op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
className="defaultBtn printBtn"
|
|
||||||
>
|
>
|
||||||
<i
|
<i className="fa-light fa-print" 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="op-btn op-btn-primary op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
|
||||||
style={{
|
onClick={() =>
|
||||||
display: "flex",
|
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
|
||||||
flexDirection: "row",
|
}
|
||||||
alignItems: "center",
|
|
||||||
marginLeft: "10px"
|
|
||||||
}}
|
|
||||||
onClick={() => handleDownloadPdf()}
|
|
||||||
>
|
>
|
||||||
<i
|
<i className="fa-light fa-download" 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="op-btn op-btn-info op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
marginLeft: "10px"
|
|
||||||
}}
|
|
||||||
onClick={() => setIsEmail(true)}
|
onClick={() => setIsEmail(true)}
|
||||||
>
|
>
|
||||||
<i
|
<i className="fa-light fa-envelope" 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="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||||
>
|
>
|
||||||
Back
|
Back
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
style={{
|
|
||||||
background: "#188ae2"
|
|
||||||
}}
|
|
||||||
type="button"
|
type="button"
|
||||||
className="finishBtn sendHover"
|
className="op-btn op-btn-primary op-btn-sm mr-[3px]"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!pdfUrl) {
|
if (!pdfUrl) {
|
||||||
embedWidgetsData();
|
embedWidgetsData();
|
||||||
@@ -748,6 +467,29 @@ function Header({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{isDownloading === "pdf" && (
|
||||||
|
<div className="fixed z-[200] inset-0 flex justify-center items-center bg-black bg-opacity-30">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<ModalUi
|
||||||
|
isOpen={isDownloading === "certificate"}
|
||||||
|
title={
|
||||||
|
isDownloading === "certificate"
|
||||||
|
? "Generating certificate"
|
||||||
|
: "PDF Download"
|
||||||
|
}
|
||||||
|
handleClose={() => setIsDownloading("")}
|
||||||
|
>
|
||||||
|
<div className="p-3 md:p-5 text-[13px] md:text-base text-center text-base-content">
|
||||||
|
{isDownloading === "certificate"}{" "}
|
||||||
|
<p>
|
||||||
|
Your completion certificate is being generated. Please wait
|
||||||
|
momentarily. If the download doesn't start shortly, click the
|
||||||
|
button again.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
function PdfZoom(props) {
|
||||||
|
const onClickZoomIn = () => {
|
||||||
|
props.setScale(props.scale + 0.1 * props.scale);
|
||||||
|
props.setZoomPercent(props.zoomPercent + 10);
|
||||||
|
};
|
||||||
|
const onClickZoomOut = () => {
|
||||||
|
if (props.zoomPercent > 0) {
|
||||||
|
if (props.zoomPercent === 10) {
|
||||||
|
props.setScale(1);
|
||||||
|
} else {
|
||||||
|
props.setScale(props.scale - 0.1 * props.scale);
|
||||||
|
}
|
||||||
|
props.setZoomPercent(props.zoomPercent - 10);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleReset = () => {
|
||||||
|
props.setScale(1);
|
||||||
|
props.setZoomPercent(0);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
// md:mt-[41px] xl:mt-[63px]mt=[]
|
||||||
|
<span className="hidden md:flex flex-col gap-1 text-center md:w-[5%] mt-[50px] 2xl:mt-[63px]">
|
||||||
|
<span
|
||||||
|
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
|
||||||
|
onClick={onClickZoomIn}
|
||||||
|
title="Zoom in"
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-magnifying-glass-plus text-gray-500 2xl:text-[30px]"></i>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
|
||||||
|
onClick={handleReset}
|
||||||
|
title="Reset"
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-magnifying-glass-arrows-rotate text-gray-500 2xl:text-[30px]"></i>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px]"
|
||||||
|
onClick={onClickZoomOut}
|
||||||
|
style={{
|
||||||
|
cursor: props.zoomPercent > 0 ? "pointer" : "default"
|
||||||
|
}}
|
||||||
|
title="Zoom out"
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-magnifying-glass-minus text-gray-500 2xl:text-[30px]"></i>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PdfZoom;
|
||||||
@@ -4,7 +4,8 @@ import PlaceholderBorder from "./PlaceholderBorder";
|
|||||||
import { Rnd } from "react-rnd";
|
import { Rnd } from "react-rnd";
|
||||||
import {
|
import {
|
||||||
defaultWidthHeight,
|
defaultWidthHeight,
|
||||||
isMobile,
|
handleCopyNextToWidget,
|
||||||
|
isTabAndMobile,
|
||||||
onChangeInput,
|
onChangeInput,
|
||||||
radioButtonWidget,
|
radioButtonWidget,
|
||||||
textInputWidget,
|
textInputWidget,
|
||||||
@@ -87,8 +88,10 @@ const getDefaultdate = (selectedDate, format = "dd-MM-yyyy") => {
|
|||||||
const getDefaultFormat = (dateFormat) => dateFormat || "MM/dd/yyyy";
|
const getDefaultFormat = (dateFormat) => dateFormat || "MM/dd/yyyy";
|
||||||
|
|
||||||
function Placeholder(props) {
|
function Placeholder(props) {
|
||||||
|
const [placeholderBorder, setPlaceholderBorder] = useState({ w: 0, h: 0 });
|
||||||
const [isDraggingEnabled, setDraggingEnabled] = useState(true);
|
const [isDraggingEnabled, setDraggingEnabled] = useState(true);
|
||||||
const [isShowDateFormat, setIsShowDateFormat] = useState(false);
|
const [isShowDateFormat, setIsShowDateFormat] = useState(false);
|
||||||
|
const [containerScale, setContainerScale] = useState();
|
||||||
const [selectDate, setSelectDate] = useState({
|
const [selectDate, setSelectDate] = useState({
|
||||||
date:
|
date:
|
||||||
props.pos.type === "date"
|
props.pos.type === "date"
|
||||||
@@ -118,6 +121,14 @@ function Placeholder(props) {
|
|||||||
width: null,
|
width: null,
|
||||||
height: null
|
height: null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const getPdfPageWidth = props.pdfOriginalWH.find(
|
||||||
|
(data) => data.pageNumber === props.pageNumber
|
||||||
|
);
|
||||||
|
setContainerScale(props.containerWH.width / getPdfPageWidth.width);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [props.containerWH.width, props.pdfOriginalWH]);
|
||||||
const dateFormatArr = [
|
const dateFormatArr = [
|
||||||
"L",
|
"L",
|
||||||
"DD-MM-YYYY",
|
"DD-MM-YYYY",
|
||||||
@@ -274,6 +285,7 @@ function Placeholder(props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleOnClickPlaceholder = () => {
|
const handleOnClickPlaceholder = () => {
|
||||||
|
props.setCurrWidgetsDetails && props.setCurrWidgetsDetails(props.pos);
|
||||||
if (!props.isNeedSign) {
|
if (!props.isNeedSign) {
|
||||||
props.setWidgetType(props.pos.type);
|
props.setWidgetType(props.pos.type);
|
||||||
}
|
}
|
||||||
@@ -291,19 +303,40 @@ function Placeholder(props) {
|
|||||||
props?.setShowDropdown(true);
|
props?.setShowDropdown(true);
|
||||||
} else if (props.pos.type === "checkbox") {
|
} else if (props.pos.type === "checkbox") {
|
||||||
props?.setIsCheckbox(true);
|
props?.setIsCheckbox(true);
|
||||||
|
} else if (
|
||||||
|
[
|
||||||
|
textInputWidget,
|
||||||
|
textWidget,
|
||||||
|
"name",
|
||||||
|
"company",
|
||||||
|
"job title",
|
||||||
|
"email"
|
||||||
|
].includes(props.pos.type)
|
||||||
|
) {
|
||||||
|
props.handleTextSettingModal(true);
|
||||||
} else {
|
} else {
|
||||||
props?.handleNameModal(true);
|
props?.handleNameModal && props?.handleNameModal(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.isPlaceholder && props.type !== textWidget) {
|
if (props.data && props?.pos?.type !== textWidget) {
|
||||||
props.setUniqueId(props.data.Id);
|
props.setSignerObjId(props?.data?.signerObjId);
|
||||||
|
props.setUniqueId(props?.data?.Id);
|
||||||
|
} else if (props.data && props.pos.type === textWidget) {
|
||||||
|
props.setTempSignerId(props.uniqueId);
|
||||||
|
props.setUniqueId(props?.data?.Id);
|
||||||
}
|
}
|
||||||
props.setSignKey(props.pos.key);
|
props.setSignKey(props.pos.key);
|
||||||
props.setWidgetType(props.pos.type);
|
props.setWidgetType(props.pos.type);
|
||||||
props.setCurrWidgetsDetails(props.pos);
|
props.setCurrWidgetsDetails(props.pos);
|
||||||
};
|
};
|
||||||
//function ro set state value of onclick on widget's copy icon
|
//function to set required state value onclick on widget's copy icon
|
||||||
const handleCopyPlaceholder = (e) => {
|
const handleCopyPlaceholder = (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
//condition to handle text widget signer obj id and unique id
|
||||||
|
//when user click on copy icon of text widget in that condition text widget does not have any signerObjId
|
||||||
|
//in that case i have to save in tempSignerId as a unique id of previous select signer's unique id
|
||||||
|
//and on save or cancel button of copy all page popup i have set this temp signer Id in unique id
|
||||||
|
|
||||||
if (props.data && props?.pos?.type !== textWidget) {
|
if (props.data && props?.pos?.type !== textWidget) {
|
||||||
props.setSignerObjId(props?.data?.signerObjId);
|
props.setSignerObjId(props?.data?.signerObjId);
|
||||||
props.setUniqueId(props?.data?.Id);
|
props.setUniqueId(props?.data?.Id);
|
||||||
@@ -312,9 +345,24 @@ function Placeholder(props) {
|
|||||||
props.setSignerObjId(props?.data?.signerObjId);
|
props.setSignerObjId(props?.data?.signerObjId);
|
||||||
props.setUniqueId(props?.data?.Id);
|
props.setUniqueId(props?.data?.Id);
|
||||||
}
|
}
|
||||||
e.stopPropagation();
|
|
||||||
props.setIsPageCopy(true);
|
//checking widget's type and open widget copy modal for required widgets
|
||||||
props.setSignKey(props.pos.key);
|
if (
|
||||||
|
["signature", textWidget, "stamp", "initial"].includes(props.pos.type)
|
||||||
|
) {
|
||||||
|
props.setIsPageCopy(true);
|
||||||
|
props.setSignKey(props.pos.key);
|
||||||
|
} else {
|
||||||
|
//function to create new widget next to just widget
|
||||||
|
handleCopyNextToWidget(
|
||||||
|
props.pos,
|
||||||
|
props.pos.type,
|
||||||
|
props.xyPostion,
|
||||||
|
props.index,
|
||||||
|
props.setXyPostion,
|
||||||
|
props.data && props.data?.Id
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//function to save date and format on local array onchange date and onclick format
|
//function to save date and format on local array onchange date and onclick format
|
||||||
@@ -352,7 +400,15 @@ function Placeholder(props) {
|
|||||||
<>
|
<>
|
||||||
{(props.isPlaceholder || props.isSignYourself) && (
|
{(props.isPlaceholder || props.isSignYourself) && (
|
||||||
<>
|
<>
|
||||||
{props.pos.type === "checkbox" && props.isSignYourself ? (
|
{[
|
||||||
|
"checkbox",
|
||||||
|
textInputWidget,
|
||||||
|
textWidget,
|
||||||
|
"name",
|
||||||
|
"company",
|
||||||
|
"job title",
|
||||||
|
"email"
|
||||||
|
].includes(props.pos.type) && props.isSignYourself ? (
|
||||||
<i
|
<i
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -362,7 +418,7 @@ function Placeholder(props) {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
handleOnClickSettingIcon();
|
handleOnClickSettingIcon();
|
||||||
}}
|
}}
|
||||||
className="fa-solid fa-gear settingIcon"
|
className="fa-light fa-gear icon"
|
||||||
style={{
|
style={{
|
||||||
color: "#188ae2",
|
color: "#188ae2",
|
||||||
right: "29px",
|
right: "29px",
|
||||||
@@ -372,9 +428,7 @@ function Placeholder(props) {
|
|||||||
) : (
|
) : (
|
||||||
((!props?.pos?.type && props.pos.isStamp) ||
|
((!props?.pos?.type && props.pos.isStamp) ||
|
||||||
(props?.pos?.type &&
|
(props?.pos?.type &&
|
||||||
!["date", textWidget, "signature"].includes(
|
!["date", "signature"].includes(props.pos.type) &&
|
||||||
props.pos.type
|
|
||||||
) &&
|
|
||||||
!props.isSignYourself)) && (
|
!props.isSignYourself)) && (
|
||||||
<i
|
<i
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
@@ -385,16 +439,20 @@ function Placeholder(props) {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
handleOnClickSettingIcon();
|
handleOnClickSettingIcon();
|
||||||
}}
|
}}
|
||||||
className="fa-solid fa-gear settingIcon"
|
className="fa-light fa-gear icon"
|
||||||
style={{ color: "#188ae2", right: "47px", top: "-19px" }}
|
style={{
|
||||||
|
color: "#188ae2",
|
||||||
|
right: props?.pos?.type === textWidget ? "32px" : "47px",
|
||||||
|
top: "-19px"
|
||||||
|
}}
|
||||||
></i>
|
></i>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{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-light fa-user icon"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
props.handleLinkUser(props.data.Id);
|
props.handleLinkUser(props.data.Id);
|
||||||
@@ -418,11 +476,7 @@ function Placeholder(props) {
|
|||||||
top: "-19px",
|
top: "-19px",
|
||||||
right: props.isPlaceholder ? "60px" : "44px"
|
right: props.isPlaceholder ? "60px" : "44px"
|
||||||
}}
|
}}
|
||||||
className={
|
className={`${isShowDateFormat ? "show" : ""} dropdown icon`}
|
||||||
isShowDateFormat
|
|
||||||
? "dropdown signUserIcon show"
|
|
||||||
: "dropdown signUserIcon"
|
|
||||||
}
|
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
setIsShowDateFormat(!isShowDateFormat);
|
setIsShowDateFormat(!isShowDateFormat);
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -441,7 +495,7 @@ function Placeholder(props) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
className="fa-solid fa-gear settingIcon"
|
className="fa-light fa-gear icon"
|
||||||
style={{
|
style={{
|
||||||
color: "#188ae2",
|
color: "#188ae2",
|
||||||
fontSize: "14px"
|
fontSize: "14px"
|
||||||
@@ -469,8 +523,7 @@ function Placeholder(props) {
|
|||||||
setSelectDate(data);
|
setSelectDate(data);
|
||||||
handleSaveDate(data);
|
handleSaveDate(data);
|
||||||
}}
|
}}
|
||||||
className="dropdown-item itemColor"
|
className="dropdown-item text-[13px]"
|
||||||
style={{ fontSize: "12px" }}
|
|
||||||
>
|
>
|
||||||
{data?.date ? data?.date : "nodata"}
|
{data?.date ? data?.date : "nodata"}
|
||||||
</span>
|
</span>
|
||||||
@@ -480,13 +533,13 @@ function Placeholder(props) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<i
|
<i
|
||||||
className="fa-regular fa-copy signCopy"
|
className="fa-light fa-copy icon"
|
||||||
onClick={(e) => handleCopyPlaceholder(e)}
|
onClick={(e) => handleCopyPlaceholder(e)}
|
||||||
onTouchEnd={(e) => handleCopyPlaceholder(e)}
|
onTouchEnd={(e) => handleCopyPlaceholder(e)}
|
||||||
style={{ color: "#188ae2", right: "12px", top: "-18px" }}
|
style={{ color: "#188ae2", right: "12px", top: "-18px" }}
|
||||||
></i>
|
></i>
|
||||||
<i
|
<i
|
||||||
className="fa-regular fa-circle-xmark signCloseBtn"
|
className="fa-light fa-circle-xmark icon"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
@@ -512,6 +565,61 @@ function Placeholder(props) {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
const xPos = (pos, signYourself) => {
|
||||||
|
const getPdfPageWidth = props.pdfOriginalWH.find(
|
||||||
|
(data) => data.pageNumber === props.pageNumber
|
||||||
|
);
|
||||||
|
const containerScale = props.containerWH.width / getPdfPageWidth?.width;
|
||||||
|
const resizePos = pos.xPosition;
|
||||||
|
if (signYourself) {
|
||||||
|
return resizePos * containerScale * props.scale;
|
||||||
|
} else {
|
||||||
|
//checking both condition mobile and desktop view
|
||||||
|
if (pos.isMobile && pos.scale) {
|
||||||
|
if (props.scale > 1) {
|
||||||
|
return resizePos * pos.scale * containerScale * props.scale;
|
||||||
|
} else {
|
||||||
|
return resizePos * pos.scale * containerScale;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if (pos.scale === containerScale) {
|
||||||
|
// return resizePos * pos.scale * props.scale;
|
||||||
|
// } else {
|
||||||
|
return resizePos * containerScale * props.scale;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const yPos = (pos, signYourself) => {
|
||||||
|
const getPdfPageWidth = props.pdfOriginalWH.find(
|
||||||
|
(data) => data.pageNumber === props.pageNumber
|
||||||
|
);
|
||||||
|
const containerScale = props.containerWH.width / getPdfPageWidth.width;
|
||||||
|
const resizePos = pos.yPosition;
|
||||||
|
|
||||||
|
if (signYourself) {
|
||||||
|
return resizePos * containerScale * props.scale;
|
||||||
|
} else {
|
||||||
|
//checking both condition mobile and desktop view
|
||||||
|
if (pos.isMobile && pos.scale) {
|
||||||
|
if (props.scale > 1) {
|
||||||
|
return resizePos * pos.scale * containerScale * props.scale;
|
||||||
|
} else {
|
||||||
|
return resizePos * pos.scale * containerScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else if (pos.scale === containerScale) {
|
||||||
|
// if (props.scale > 1) {
|
||||||
|
// return resizePos * pos.scale * props.scale;
|
||||||
|
// } else {
|
||||||
|
// return resizePos * pos.scale;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
else {
|
||||||
|
return resizePos * containerScale * props.scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Rnd
|
<Rnd
|
||||||
@@ -519,7 +627,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 /
|
||||||
@@ -589,8 +705,20 @@ function Placeholder(props) {
|
|||||||
setDraggingEnabled(true);
|
setDraggingEnabled(true);
|
||||||
props.setIsResize && props.setIsResize(true);
|
props.setIsResize && props.setIsResize(true);
|
||||||
}}
|
}}
|
||||||
onResizeStop={() => {
|
onResizeStop={(e, direction, ref) => {
|
||||||
props.setIsResize && props.setIsResize(false);
|
props.setIsResize && props.setIsResize(false);
|
||||||
|
props.handleSignYourselfImageResize &&
|
||||||
|
props.handleSignYourselfImageResize(
|
||||||
|
ref,
|
||||||
|
props.pos.key,
|
||||||
|
props.xyPostion,
|
||||||
|
props.setXyPostion,
|
||||||
|
props.index,
|
||||||
|
containerScale,
|
||||||
|
props.scale,
|
||||||
|
props.data && props.data.Id,
|
||||||
|
props.isResize
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
disableDragging={
|
disableDragging={
|
||||||
props.isNeedSign
|
props.isNeedSign
|
||||||
@@ -603,21 +731,15 @@ function Placeholder(props) {
|
|||||||
props.handleStop &&
|
props.handleStop &&
|
||||||
props.handleStop(event, dragElement, props.data?.Id, props.pos?.key)
|
props.handleStop(event, dragElement, props.data?.Id, props.pos?.key)
|
||||||
}
|
}
|
||||||
default={{
|
position={{
|
||||||
x: props.xPos(props.pos, props.isSignYourself),
|
x: xPos(props.pos, props.isSignYourself),
|
||||||
y: props.yPos(props.pos, props.isSignYourself)
|
y: yPos(props.pos, props.isSignYourself)
|
||||||
}}
|
}}
|
||||||
onResize={(e, direction, ref) => {
|
onResize={(e, direction, ref) => {
|
||||||
props.handleSignYourselfImageResize &&
|
setPlaceholderBorder({
|
||||||
props.handleSignYourselfImageResize(
|
w: ref.offsetWidth / (props.scale * containerScale),
|
||||||
ref,
|
h: ref.offsetHeight / (props.scale * containerScale)
|
||||||
props.pos.key,
|
});
|
||||||
props.xyPostion,
|
|
||||||
props.setXyPostion,
|
|
||||||
props.index,
|
|
||||||
props.data && props.data.Id,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
onClick={() => handleOnClickPlaceholder()}
|
onClick={() => handleOnClickPlaceholder()}
|
||||||
>
|
>
|
||||||
@@ -646,20 +768,23 @@ function Placeholder(props) {
|
|||||||
pos={props.pos}
|
pos={props.pos}
|
||||||
isPlaceholder={props.isPlaceholder}
|
isPlaceholder={props.isPlaceholder}
|
||||||
getCheckboxRenderWidth={getCheckboxRenderWidth}
|
getCheckboxRenderWidth={getCheckboxRenderWidth}
|
||||||
|
scale={props.scale}
|
||||||
|
containerScale={containerScale}
|
||||||
|
placeholderBorder={placeholderBorder}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isMobile ? (
|
{isTabAndMobile ? (
|
||||||
<div
|
<div
|
||||||
|
// className="sm:inline-block md:inline-block lg:hidden "
|
||||||
|
className="flex items-stretch"
|
||||||
style={{
|
style={{
|
||||||
left: props.xPos(props.pos, props.isSignYourself),
|
left: xPos(props.pos, props.isSignYourself),
|
||||||
top: props.yPos(props.pos, props.isSignYourself),
|
top: yPos(props.pos, props.isSignYourself),
|
||||||
width:
|
width:
|
||||||
props.pos.type === radioButtonWidget ||
|
props.pos.type === radioButtonWidget ||
|
||||||
props.pos.type === "checkbox"
|
props.pos.type === "checkbox"
|
||||||
? "auto"
|
? "auto"
|
||||||
: props.posWidth(props.pos, props.isSignYourself),
|
: props.posWidth(props.pos, props.isSignYourself),
|
||||||
// "auto", //props.posWidth(props.pos, props.isSignYourself),
|
|
||||||
// height: props.posHeight(props.pos, props.isSignYourself),
|
|
||||||
height:
|
height:
|
||||||
props.pos.type === radioButtonWidget ||
|
props.pos.type === radioButtonWidget ||
|
||||||
props.pos.type === "checkbox"
|
props.pos.type === "checkbox"
|
||||||
@@ -668,6 +793,7 @@ function Placeholder(props) {
|
|||||||
zIndex: "10"
|
zIndex: "10"
|
||||||
}}
|
}}
|
||||||
onTouchEnd={() => handleOnClickPlaceholder()}
|
onTouchEnd={() => handleOnClickPlaceholder()}
|
||||||
|
onClick={() => handleOnClickPlaceholder()}
|
||||||
>
|
>
|
||||||
{props.pos.key === props.selectWidgetId && <PlaceholderIcon />}
|
{props.pos.key === props.selectWidgetId && <PlaceholderIcon />}
|
||||||
|
|
||||||
@@ -692,6 +818,7 @@ function Placeholder(props) {
|
|||||||
setStartDate={setStartDate}
|
setStartDate={setStartDate}
|
||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
handleSaveDate={handleSaveDate}
|
handleSaveDate={handleSaveDate}
|
||||||
|
xPos={props.xPos}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -718,6 +845,7 @@ function Placeholder(props) {
|
|||||||
setStartDate={setStartDate}
|
setStartDate={setStartDate}
|
||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
handleSaveDate={handleSaveDate}
|
handleSaveDate={handleSaveDate}
|
||||||
|
xPos={props.xPos}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -11,23 +11,34 @@ function PlaceholderBorder(props) {
|
|||||||
const getResizeBorderExtraWidth = resizeBorderExtraWidth();
|
const getResizeBorderExtraWidth = resizeBorderExtraWidth();
|
||||||
const defaultWidth = defaultWidthHeight(props.pos.type).width;
|
const defaultWidth = defaultWidthHeight(props.pos.type).width;
|
||||||
const defaultHeight = defaultWidthHeight(props.pos.type).height;
|
const defaultHeight = defaultWidthHeight(props.pos.type).height;
|
||||||
|
const width = () => {
|
||||||
|
const getWidth =
|
||||||
|
props.placeholderBorder.w || props.pos.Width || defaultWidth;
|
||||||
|
return (
|
||||||
|
getWidth * props.scale * props.containerScale + getResizeBorderExtraWidth
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const height = () => {
|
||||||
|
const getHeight =
|
||||||
|
props.placeholderBorder.h || props.pos.Height || defaultHeight;
|
||||||
|
|
||||||
|
return (
|
||||||
|
getHeight * props.scale * props.containerScale + getResizeBorderExtraWidth
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const handleMinWidth = () => {
|
const handleMinWidth = () => {
|
||||||
if (props.pos.type === "checkbox" || props.pos.type === radioButtonWidget) {
|
if (props.pos.type === "checkbox" || props.pos.type === radioButtonWidget) {
|
||||||
return props.getCheckboxRenderWidth.width + getResizeBorderExtraWidth;
|
return props.getCheckboxRenderWidth.width + getResizeBorderExtraWidth;
|
||||||
} else {
|
} else {
|
||||||
return props.pos.Width
|
return width();
|
||||||
? props.pos.Width + getResizeBorderExtraWidth
|
|
||||||
: defaultWidth + getResizeBorderExtraWidth;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleMinHeight = () => {
|
const handleMinHeight = () => {
|
||||||
if (props.pos.type === "checkbox" || props.pos.type === radioButtonWidget) {
|
if (props.pos.type === "checkbox" || props.pos.type === radioButtonWidget) {
|
||||||
return props.getCheckboxRenderWidth.height + getResizeBorderExtraWidth;
|
return props.getCheckboxRenderWidth.height + getResizeBorderExtraWidth;
|
||||||
} else {
|
} else {
|
||||||
return props.pos.Height
|
return height();
|
||||||
? props.pos.Height + getResizeBorderExtraWidth
|
|
||||||
: defaultHeight + getResizeBorderExtraWidth;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
@@ -36,7 +47,7 @@ function PlaceholderBorder(props) {
|
|||||||
onTouchEnd={() =>
|
onTouchEnd={() =>
|
||||||
props.pos.type === textWidget && props?.setDraggingEnabled(true)
|
props.pos.type === textWidget && props?.setDraggingEnabled(true)
|
||||||
}
|
}
|
||||||
className="borderResize"
|
className="absolute inline-block w-[14px] h-[14px] hover:cursor-sw-resize"
|
||||||
style={{
|
style={{
|
||||||
borderColor: themeColor,
|
borderColor: themeColor,
|
||||||
borderStyle: "dashed",
|
borderStyle: "dashed",
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
import { randomId, textWidget } from "../../constant/Utils";
|
import { randomId, textWidget } from "../../constant/Utils";
|
||||||
|
|
||||||
function PlaceholderCopy(props) {
|
function PlaceholderCopy(props) {
|
||||||
const copyType = ["All pages", "All pages but last", "All pages but first"];
|
const copyType = ["All pages", "All pages but last", "All pages but first"];
|
||||||
const [selectCopyType, setSelectCopyType] = useState("");
|
const [selectCopyType, setSelectCopyType] = useState("");
|
||||||
|
|
||||||
//function for get copy placeholder position
|
//function for get copy placeholder position
|
||||||
const getCopyPlaceholderPosition = (
|
const getCopyPlaceholderPosition = (
|
||||||
type,
|
type,
|
||||||
@@ -195,13 +193,13 @@ function PlaceholderCopy(props) {
|
|||||||
props.setIsPageCopy(false);
|
props.setIsPageCopy(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ height: "100%", padding: 20 }}>
|
<div className="h-full p-[20px] text-base-content">
|
||||||
{copyType.map((data, key) => {
|
{copyType.map((data, key) => {
|
||||||
return (
|
return (
|
||||||
<div key={key} style={{ display: "flex", flexDirection: "column" }}>
|
<div key={key} className="flex flex-col">
|
||||||
<label key={key} style={{ fontSize: "16px", fontWeight: "500" }}>
|
<label className="text-[16px] font-medium">
|
||||||
<input
|
<input
|
||||||
style={{ accentColor: "red", marginRight: "10px" }}
|
className="mr-[8px] op-radio op-radio-xs"
|
||||||
type="radio"
|
type="radio"
|
||||||
value={data}
|
value={data}
|
||||||
onChange={() => setSelectCopyType(data)}
|
onChange={() => setSelectCopyType(data)}
|
||||||
@@ -214,33 +212,22 @@ function PlaceholderCopy(props) {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
<div
|
<div className="flex bg-[#9f9f9f] w-full my-[15px]"></div>
|
||||||
style={{
|
|
||||||
height: "1px",
|
|
||||||
backgroundColor: "#9f9f9f",
|
|
||||||
width: "100%",
|
|
||||||
marginTop: "15px",
|
|
||||||
marginBottom: "15px"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleApplyCopy();
|
handleApplyCopy();
|
||||||
handleUniqueId();
|
handleUniqueId();
|
||||||
}}
|
}}
|
||||||
style={{ background: themeColor }}
|
|
||||||
type="button"
|
type="button"
|
||||||
disabled={!selectCopyType}
|
disabled={!selectCopyType}
|
||||||
className="finishBtn"
|
className="op-btn op-btn-primary"
|
||||||
>
|
>
|
||||||
Apply
|
Apply
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="finishBtn cancelBtn"
|
className="op-btn op-btn-ghost"
|
||||||
onClick={() => {
|
onClick={() => handleUniqueId()}
|
||||||
handleUniqueId();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { useEffect, useState, forwardRef, useRef } from "react";
|
|||||||
import {
|
import {
|
||||||
getMonth,
|
getMonth,
|
||||||
getYear,
|
getYear,
|
||||||
isMobile,
|
onChangeHeightOfTextArea,
|
||||||
onChangeInput,
|
onChangeInput,
|
||||||
radioButtonWidget,
|
radioButtonWidget,
|
||||||
range,
|
range,
|
||||||
@@ -13,7 +13,10 @@ import DatePicker from "react-datepicker";
|
|||||||
import "react-datepicker/dist/react-datepicker.css";
|
import "react-datepicker/dist/react-datepicker.css";
|
||||||
import "../../styles/signature.css";
|
import "../../styles/signature.css";
|
||||||
import RegexParser from "regex-parser";
|
import RegexParser from "regex-parser";
|
||||||
|
const textWidgetCls =
|
||||||
|
"w-full h-full md:min-w-full md:min-h-full z-[999] text-[12px] rounded-[2px] border-[1px] border-[#007bff] overflow-hidden resize-none outline-none text-base-content item-center bg-base-100 whitespace-pre-wrap";
|
||||||
|
const selectWidgetCls =
|
||||||
|
"w-full h-full absolute left-0 top-0 border-[1px] border-[#007bff] rounded-[2px] focus:outline-none bg-base-100 text-base-content";
|
||||||
function PlaceholderType(props) {
|
function PlaceholderType(props) {
|
||||||
const type = props?.pos?.type;
|
const type = props?.pos?.type;
|
||||||
const [selectOption, setSelectOption] = useState("");
|
const [selectOption, setSelectOption] = useState("");
|
||||||
@@ -37,15 +40,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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,22 +58,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,11 +87,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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,17 +135,17 @@ 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
|
||||||
className="inputPlaceholder"
|
className={`${selectWidgetCls} overflow-hidden`}
|
||||||
style={{ overflow: "hidden", fontSize: calculateFontSize() }}
|
style={{ fontSize: calculateFontSize() }}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
<i className="fa-regular fa-calendar" style={{ marginLeft: "5px" }}></i>
|
<i className="fa-light fa-calendar ml-[5px]"></i>
|
||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
ExampleCustomInput.displayName = "ExampleCustomInput";
|
ExampleCustomInput.displayName = "ExampleCustomInput";
|
||||||
@@ -285,20 +286,33 @@ function PlaceholderType(props) {
|
|||||||
};
|
};
|
||||||
props.handleSaveDate(dateObj, isDateChange);
|
props.handleSaveDate(dateObj, isDateChange);
|
||||||
};
|
};
|
||||||
|
//handle height on enter press in text area
|
||||||
|
const handleEnterPress = (e) => {
|
||||||
|
const height = 18;
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
//function to save height of text area
|
||||||
|
onChangeHeightOfTextArea(
|
||||||
|
height,
|
||||||
|
props.pos.type,
|
||||||
|
props.pos.key,
|
||||||
|
props.xyPostion,
|
||||||
|
props.index,
|
||||||
|
props.setXyPostion,
|
||||||
|
props.data && props.data?.Id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "signature":
|
case "signature":
|
||||||
return props.pos.SignUrl ? (
|
return props.pos.SignUrl ? (
|
||||||
<img
|
<img
|
||||||
alt="signimg"
|
alt="signature"
|
||||||
|
draggable="false"
|
||||||
src={props.pos.SignUrl}
|
src={props.pos.SignUrl}
|
||||||
style={{
|
className="w-full h-full "
|
||||||
width: "99%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
|
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
|
||||||
{props?.handleUserName &&
|
{props?.handleUserName &&
|
||||||
props?.handleUserName(
|
props?.handleUserName(
|
||||||
props?.data?.Id,
|
props?.data?.Id,
|
||||||
@@ -310,16 +324,13 @@ function PlaceholderType(props) {
|
|||||||
case "stamp":
|
case "stamp":
|
||||||
return props.pos.SignUrl ? (
|
return props.pos.SignUrl ? (
|
||||||
<img
|
<img
|
||||||
alt="signimg"
|
alt="stamp"
|
||||||
|
draggable="false"
|
||||||
src={props.pos.SignUrl}
|
src={props.pos.SignUrl}
|
||||||
style={{
|
className="w-full h-full"
|
||||||
width: "99%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
|
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
|
||||||
{props?.handleUserName &&
|
{props?.handleUserName &&
|
||||||
props?.handleUserName(
|
props?.handleUserName(
|
||||||
props?.data?.Id,
|
props?.data?.Id,
|
||||||
@@ -335,12 +346,9 @@ function PlaceholderType(props) {
|
|||||||
return (
|
return (
|
||||||
<div key={ind} className="flex items-center text-center gap-0.5">
|
<div key={ind} className="flex items-center text-center gap-0.5">
|
||||||
<input
|
<input
|
||||||
style={{
|
className={`${
|
||||||
width: props.pos.Width,
|
ind === 0 ? "mt-0" : "mt-[5px]"
|
||||||
display: "flex",
|
} flex justify-center op-checkbox op-checkbox-xs rounded-[0.350rem]`}
|
||||||
justifyContent: "center",
|
|
||||||
marginTop: ind === 0 ? 0 : "5px"
|
|
||||||
}}
|
|
||||||
onBlur={handleInputBlur}
|
onBlur={handleInputBlur}
|
||||||
disabled={
|
disabled={
|
||||||
props.isNeedSign &&
|
props.isNeedSign &&
|
||||||
@@ -384,19 +392,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);
|
||||||
@@ -410,12 +411,20 @@ function PlaceholderType(props) {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
className={textWidgetCls}
|
||||||
|
style={{
|
||||||
|
fontSize: props.pos.options?.fontSize
|
||||||
|
? props.pos.options?.fontSize + "px"
|
||||||
|
: "12px",
|
||||||
|
color: props.pos.options?.fontColor || "black"
|
||||||
|
}}
|
||||||
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
color: "black",
|
color: "black",
|
||||||
fontSize: calculateFontSize()
|
fontSize: "12px"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>{type}</span>
|
<span>{type}</span>
|
||||||
@@ -424,9 +433,8 @@ function PlaceholderType(props) {
|
|||||||
case "dropdown":
|
case "dropdown":
|
||||||
return props.data?.signerObjId === props.signerObjId ? (
|
return props.data?.signerObjId === props.signerObjId ? (
|
||||||
<select
|
<select
|
||||||
className="inputPlaceholder"
|
className={`${selectWidgetCls} text-[12px]`}
|
||||||
id="myDropdown"
|
id="myDropdown"
|
||||||
style={{ fontSize: "12px" }}
|
|
||||||
value={selectOption}
|
value={selectOption}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setSelectOption(e.target.value);
|
setSelectOption(e.target.value);
|
||||||
@@ -443,10 +451,10 @@ function PlaceholderType(props) {
|
|||||||
>
|
>
|
||||||
{/* Default/Title option */}
|
{/* Default/Title option */}
|
||||||
<option value="" disabled hidden>
|
<option value="" disabled hidden>
|
||||||
{props.pos.options.name}
|
{props?.pos?.options?.name}
|
||||||
</option>
|
</option>
|
||||||
|
|
||||||
{props.pos?.options?.values.map((data, ind) => {
|
{props.pos?.options?.values?.map((data, ind) => {
|
||||||
return (
|
return (
|
||||||
<option key={ind} value={data}>
|
<option key={ind} value={data}>
|
||||||
{data}
|
{data}
|
||||||
@@ -456,7 +464,7 @@ function PlaceholderType(props) {
|
|||||||
</select>
|
</select>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
className="inputPlaceholder"
|
className={selectWidgetCls}
|
||||||
style={{ fontSize: calculateFontSize() }}
|
style={{ fontSize: calculateFontSize() }}
|
||||||
>
|
>
|
||||||
{props.pos?.options?.name ? props.pos.options.name : type}
|
{props.pos?.options?.name ? props.pos.options.name : type}
|
||||||
@@ -465,16 +473,13 @@ function PlaceholderType(props) {
|
|||||||
case "initials":
|
case "initials":
|
||||||
return props.pos.SignUrl ? (
|
return props.pos.SignUrl ? (
|
||||||
<img
|
<img
|
||||||
alt="signimg"
|
alt="initials"
|
||||||
|
draggable="false"
|
||||||
src={props.pos.SignUrl}
|
src={props.pos.SignUrl}
|
||||||
style={{
|
className="w-full h-full"
|
||||||
width: "99%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
|
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
|
||||||
{props?.handleUserName &&
|
{props?.handleUserName &&
|
||||||
props?.handleUserName(
|
props?.handleUserName(
|
||||||
props?.data?.Id,
|
props?.data?.Id,
|
||||||
@@ -486,15 +491,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);
|
||||||
@@ -508,12 +510,20 @@ function PlaceholderType(props) {
|
|||||||
isDefault
|
isDefault
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
className={textWidgetCls}
|
||||||
|
style={{
|
||||||
|
fontSize: props.pos.options?.fontSize
|
||||||
|
? props.pos.options?.fontSize + "px"
|
||||||
|
: "12px",
|
||||||
|
color: props.pos.options?.fontColor || "black"
|
||||||
|
}}
|
||||||
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
color: "black",
|
color: "black",
|
||||||
fontSize: calculateFontSize()
|
fontSize: "12px"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>{type}</span>
|
<span>{type}</span>
|
||||||
@@ -522,14 +532,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(
|
||||||
@@ -542,12 +550,20 @@ function PlaceholderType(props) {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
className={textWidgetCls}
|
||||||
|
style={{
|
||||||
|
fontSize: props.pos.options?.fontSize
|
||||||
|
? props.pos.options?.fontSize + "px"
|
||||||
|
: "12px",
|
||||||
|
color: props.pos.options?.fontColor || "black"
|
||||||
|
}}
|
||||||
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
color: "black",
|
color: "black",
|
||||||
fontSize: calculateFontSize()
|
fontSize: "12px"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>{type}</span>
|
<span>{type}</span>
|
||||||
@@ -556,14 +572,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(
|
||||||
@@ -576,12 +590,20 @@ function PlaceholderType(props) {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
className={textWidgetCls}
|
||||||
|
style={{
|
||||||
|
fontSize: props.pos.options?.fontSize
|
||||||
|
? props.pos.options?.fontSize + "px"
|
||||||
|
: "12px",
|
||||||
|
color: props.pos.options?.fontColor || "black"
|
||||||
|
}}
|
||||||
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
color: "black",
|
color: "black",
|
||||||
fontSize: calculateFontSize()
|
fontSize: "12px"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>{type}</span>
|
<span>{type}</span>
|
||||||
@@ -626,8 +648,7 @@ function PlaceholderType(props) {
|
|||||||
}
|
}
|
||||||
onBlur={handleInputBlur}
|
onBlur={handleInputBlur}
|
||||||
closeOnScroll={true}
|
closeOnScroll={true}
|
||||||
className="inputPlaceholder"
|
className={`${selectWidgetCls} outline-[#007bff]`}
|
||||||
style={{ outlineColor: "#007bff" }}
|
|
||||||
selected={
|
selected={
|
||||||
props?.startDate
|
props?.startDate
|
||||||
? props?.startDate
|
? props?.startDate
|
||||||
@@ -650,16 +671,13 @@ function PlaceholderType(props) {
|
|||||||
case "image":
|
case "image":
|
||||||
return props.pos.SignUrl ? (
|
return props.pos.SignUrl ? (
|
||||||
<img
|
<img
|
||||||
alt="signimg"
|
alt="image"
|
||||||
|
draggable="false"
|
||||||
src={props.pos.SignUrl}
|
src={props.pos.SignUrl}
|
||||||
style={{
|
className="w-full h-full"
|
||||||
width: "99%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
|
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
|
||||||
{props?.handleUserName &&
|
{props?.handleUserName &&
|
||||||
props?.handleUserName(
|
props?.handleUserName(
|
||||||
props?.data?.Id,
|
props?.data?.Id,
|
||||||
@@ -671,12 +689,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) => {
|
||||||
@@ -691,12 +708,20 @@ function PlaceholderType(props) {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
className={textWidgetCls}
|
||||||
|
style={{
|
||||||
|
fontSize: props.pos.options?.fontSize
|
||||||
|
? props.pos.options?.fontSize + "px"
|
||||||
|
: "12px",
|
||||||
|
color: props.pos.options?.fontColor || "black"
|
||||||
|
}}
|
||||||
|
cols="50"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
color: "black",
|
color: "black",
|
||||||
fontSize: calculateFontSize()
|
fontSize: "12px"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>{type}</span>
|
<span>{type}</span>
|
||||||
@@ -709,12 +734,9 @@ function PlaceholderType(props) {
|
|||||||
return (
|
return (
|
||||||
<div key={ind} className="flex items-center text-center gap-0.5">
|
<div key={ind} className="flex items-center text-center gap-0.5">
|
||||||
<input
|
<input
|
||||||
style={{
|
className={`${
|
||||||
width: props.pos.Width,
|
ind === 0 ? "mt-0" : "mt-[5px]"
|
||||||
display: "flex",
|
} ${"w-[15px] h-[15px]"} flex justify-center op-radio`}
|
||||||
justifyContent: "center",
|
|
||||||
marginTop: ind === 0 ? 0 : "5px"
|
|
||||||
}}
|
|
||||||
type="radio"
|
type="radio"
|
||||||
disabled={
|
disabled={
|
||||||
props.isNeedSign &&
|
props.isNeedSign &&
|
||||||
@@ -739,8 +761,9 @@ function PlaceholderType(props) {
|
|||||||
case textWidget:
|
case textWidget:
|
||||||
return (
|
return (
|
||||||
<textarea
|
<textarea
|
||||||
placeholder="Enter label"
|
placeholder="Enter text"
|
||||||
rows={1}
|
rows={1}
|
||||||
|
onKeyDown={handleEnterPress}
|
||||||
value={textValue}
|
value={textValue}
|
||||||
onBlur={handleInputBlur}
|
onBlur={handleInputBlur}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
@@ -755,36 +778,28 @@ function PlaceholderType(props) {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
className={
|
className={textWidgetCls}
|
||||||
isMobile
|
style={{
|
||||||
? "labelTextArea labelWidthMobile"
|
fontSize: props.pos.options?.fontSize
|
||||||
: "labelTextArea labelWidthDesktop"
|
? props.pos.options?.fontSize + "px"
|
||||||
}
|
: "12px",
|
||||||
style={{ whiteSpace: "pre-wrap" }}
|
color: props.pos.options?.fontColor || "black"
|
||||||
|
}}
|
||||||
cols="50"
|
cols="50"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
return props.pos.SignUrl ? (
|
return props.pos.SignUrl ? (
|
||||||
<div style={{ pointerEvents: "none" }}>
|
<div className="pointer-events-none">
|
||||||
<img
|
<img
|
||||||
alt="signimg"
|
alt="image"
|
||||||
|
draggable="false"
|
||||||
src={props.pos.SignUrl}
|
src={props.pos.SignUrl}
|
||||||
style={{
|
className="w-full h-full"
|
||||||
width: "99%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
|
||||||
style={{
|
|
||||||
fontSize: "10px",
|
|
||||||
color: "black",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.pos.isStamp ? <div>stamp</div> : <div>signature</div>}
|
{props.pos.isStamp ? <div>stamp</div> : <div>signature</div>}
|
||||||
{props?.handleUserName &&
|
{props?.handleUserName &&
|
||||||
props?.handleUserName(props?.data?.Id, props?.data?.Role)}
|
props?.handleUserName(props?.data?.Id, props?.data?.Role)}
|
||||||
|
|||||||
@@ -11,46 +11,30 @@ function PrevNext({ pageNumber, allPages, changePage }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="flex items-center">
|
||||||
<div className="preBtn1">
|
<button
|
||||||
<button
|
className="op-btn op-btn-neutral op-btn-xs md:op-btn-sm font-semibold text-xs"
|
||||||
style={{
|
disabled={pageNumber <= 1}
|
||||||
padding: "3px 20px ",
|
onClick={previousPage}
|
||||||
fontSize: "10px",
|
>
|
||||||
background: "#d3edeb",
|
<span className="block lg:hidden">
|
||||||
fontWeight: "600",
|
<i className="fa-light fa-backward" aria-hidden="true"></i>
|
||||||
|
|
||||||
border: "0px",
|
|
||||||
marginRight: "5px"
|
|
||||||
}}
|
|
||||||
disabled={pageNumber <= 1}
|
|
||||||
onClick={previousPage}
|
|
||||||
>
|
|
||||||
Prev
|
|
||||||
</button>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: "600"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
|
|
||||||
</span>
|
</span>
|
||||||
<button
|
<span className="lg:block hidden 2xl:text-[30px]">Prev</span>
|
||||||
style={{
|
</button>
|
||||||
padding: "3px 20px ",
|
<span className="text-xs text-base-content font-medium mx-2 2xl:text-[30px]">
|
||||||
fontSize: "10px",
|
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
|
||||||
background: "#d3edeb",
|
</span>
|
||||||
fontWeight: "600",
|
<button
|
||||||
marginLeft: "5px",
|
className="op-btn op-btn-neutral op-btn-xs md:op-btn-sm font-semibold text-xs"
|
||||||
border: "0px"
|
disabled={pageNumber >= allPages}
|
||||||
}}
|
onClick={nextPage}
|
||||||
disabled={pageNumber >= allPages}
|
>
|
||||||
onClick={nextPage}
|
<span className="block lg:hidden">
|
||||||
>
|
<i className="fa-light fa-forward" aria-hidden="true"></i>
|
||||||
Next
|
</span>
|
||||||
</button>
|
<span className="lg:block hidden 2xl:text-[30px]">Next</span>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,128 +1,137 @@
|
|||||||
import React, { useRef, useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import { darkenColor, getFirstLetter } from "../../constant/Utils";
|
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||||
|
import {
|
||||||
|
color,
|
||||||
|
darkenColor,
|
||||||
|
getFirstLetter,
|
||||||
|
isMobile,
|
||||||
|
nameColor
|
||||||
|
} from "../../constant/Utils";
|
||||||
|
const cursor =
|
||||||
|
"cursor-[url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAASElEQVR4nGNgwAMkJSUbpKSkOvCpIaT5PxSTbogUQjMYMwxeIIXmVFIxA8UGDDyQGg0DnIDi6JKUlCxHMqCeZAOghjSAMD5FAKfeaURdUFxCAAAAAElFTkSuQmCC'),_pointer]";
|
||||||
const RecipientList = (props) => {
|
const RecipientList = (props) => {
|
||||||
const color = [
|
const [animationParent] = useAutoAnimate();
|
||||||
"#93a3db",
|
|
||||||
"#e6c3db",
|
|
||||||
"#c0e3bc",
|
|
||||||
"#bce3db",
|
|
||||||
"#b8ccdb",
|
|
||||||
"#ceb8db",
|
|
||||||
"#ffccff",
|
|
||||||
"#99ffcc",
|
|
||||||
"#cc99ff",
|
|
||||||
"#ffcc99",
|
|
||||||
"#66ccff",
|
|
||||||
"#ffffcc"
|
|
||||||
];
|
|
||||||
|
|
||||||
const nameColor = [
|
|
||||||
"#304fbf",
|
|
||||||
"#7d5270",
|
|
||||||
"#5f825b",
|
|
||||||
"#578077",
|
|
||||||
"#576e80",
|
|
||||||
"#6d527d",
|
|
||||||
"#cc00cc",
|
|
||||||
"#006666",
|
|
||||||
"#cc00ff",
|
|
||||||
"#ff9900",
|
|
||||||
"#336699",
|
|
||||||
"#cc9900"
|
|
||||||
];
|
|
||||||
const [isHover, setIsHover] = useState();
|
const [isHover, setIsHover] = useState();
|
||||||
const [isEdit, setIsEdit] = useState(false);
|
const [isEdit, setIsEdit] = useState(false);
|
||||||
//function for onhover signer name change background color
|
//function for onhover signer name change background color
|
||||||
const inputRef = useRef(null);
|
const inputRef = useRef(null);
|
||||||
const onHoverStyle = (ind, blockColor) => {
|
|
||||||
const style = {
|
|
||||||
background: blockColor ? blockColor : color[ind % color.length],
|
|
||||||
padding: "10px",
|
|
||||||
marginTop: "2px",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
borderBottom: "1px solid #e3e1e1",
|
|
||||||
alignItems: "center"
|
|
||||||
};
|
|
||||||
return style;
|
|
||||||
};
|
|
||||||
//function for onhover signer name remove background color
|
|
||||||
const nonHoverStyle = () => {
|
|
||||||
const style = {
|
|
||||||
padding: "10px",
|
|
||||||
marginTop: "2px",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
borderBottom: "1px solid #e3e1e1",
|
|
||||||
alignItems: "center"
|
|
||||||
};
|
|
||||||
return style;
|
|
||||||
};
|
|
||||||
const isWidgetExist = (Id) => {
|
const isWidgetExist = (Id) => {
|
||||||
return props.signerPos.some((x) => x.Id === Id);
|
return props.signerPos.some((x) => x.Id === Id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//handle drag start
|
||||||
|
const handleDragStart = (e, id) => {
|
||||||
|
// `e.dataTransfer.setData('text/plain')`is used to set the data to be transferred during a drag operation.
|
||||||
|
// The first argument specifies the type of data being set, and the second argument is the actual data you want to transfer.
|
||||||
|
e.dataTransfer.setData("text/plain", id);
|
||||||
|
};
|
||||||
|
|
||||||
|
//handleDragOver prevents the default behavior of the dragover event, which is necessary for the drop event to be triggered.
|
||||||
|
const handleDragOver = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
//handle draggable element drop and also used in mobile view on up and down key to chnage sequence of recipient's list
|
||||||
|
const handleChangeSequence = (e, ind, isUp, isDown) => {
|
||||||
|
e.preventDefault();
|
||||||
|
let draggedItemId;
|
||||||
|
let index = ind;
|
||||||
|
|
||||||
|
//if isUp true then set item's id and index in mobile view
|
||||||
|
if (isUp) {
|
||||||
|
draggedItemId = index;
|
||||||
|
index = index - 1;
|
||||||
|
}
|
||||||
|
//if isDown true then set item's id and index in mobile view
|
||||||
|
else if (isDown) {
|
||||||
|
draggedItemId = index;
|
||||||
|
index = index + 1;
|
||||||
|
} //else set id on drag element in desktop viiew
|
||||||
|
else {
|
||||||
|
//`e.dataTransfer.getData('text/plain')` is used to get data that you have saved.
|
||||||
|
draggedItemId = e.dataTransfer.getData("text/plain");
|
||||||
|
}
|
||||||
|
|
||||||
|
//convert string to number
|
||||||
|
const intDragId = parseInt(draggedItemId);
|
||||||
|
//get that item to change position
|
||||||
|
const draggedItem = props.signersdata.filter((_, ind) => ind === intDragId);
|
||||||
|
const remainingItems = props.signersdata.filter(
|
||||||
|
(_, ind) => ind !== intDragId
|
||||||
|
);
|
||||||
|
//splice method is used to replace or add new value in array at specific index
|
||||||
|
remainingItems.splice(index, 0, ...draggedItem);
|
||||||
|
|
||||||
|
//set current draggable recipient details,objectId,index,contract_className ... after replace recipient list
|
||||||
|
props.setSignersData(remainingItems);
|
||||||
|
props.setSignerObjId(remainingItems[index]?.objectId || "");
|
||||||
|
props.setIsSelectId(index);
|
||||||
|
props.setContractName(remainingItems[index]?.className || "");
|
||||||
|
props.setUniqueId(remainingItems[index]?.Id);
|
||||||
|
props.setRoleName(remainingItems[index]?.Role);
|
||||||
|
props.setBlockColor(remainingItems[index]?.blockColor);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{props.signersdata.length > 0 &&
|
{props.signersdata.length > 0 &&
|
||||||
props.signersdata.map((obj, ind) => {
|
props.signersdata.map((obj, ind) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-tut="reactourFirst"
|
ref={animationParent}
|
||||||
|
key={ind}
|
||||||
|
draggable={props.sendInOrder && !isMobile ? true : false}
|
||||||
|
onDragStart={(e) =>
|
||||||
|
props.sendInOrder && !isMobile && handleDragStart(e, ind)
|
||||||
|
}
|
||||||
|
onDragOver={(e) =>
|
||||||
|
props.sendInOrder && !isMobile && handleDragOver(e)
|
||||||
|
}
|
||||||
|
onDrop={(e) =>
|
||||||
|
props.sendInOrder && !isMobile && handleChangeSequence(e, ind)
|
||||||
|
}
|
||||||
|
data-tut="recipientArea"
|
||||||
onMouseEnter={() => setIsHover(ind)}
|
onMouseEnter={() => setIsHover(ind)}
|
||||||
onMouseLeave={() => setIsHover(null)}
|
onMouseLeave={() => setIsHover(null)}
|
||||||
key={ind}
|
className={`${
|
||||||
style={
|
props.sendInOrder
|
||||||
isHover === ind || props.isSelectListId === ind
|
? props.isMailSend
|
||||||
? onHoverStyle(ind, obj.blockColor)
|
? "pointer-events-none bg-opacity-80"
|
||||||
: nonHoverStyle(ind)
|
: `text-[12px] font-bold ${cursor}`
|
||||||
}
|
: props.isMailSend && "pointer-events-none bg-opacity-80"
|
||||||
onClick={() => {
|
} flex flex-row rounded-xl px-2 py-[10px] mt-1 mx-1 items-center last:mb-0.5`}
|
||||||
|
style={{
|
||||||
|
background:
|
||||||
|
(!isMobile && isHover === ind) || props.isSelectListId === ind
|
||||||
|
? obj?.blockColor
|
||||||
|
? obj?.blockColor
|
||||||
|
: color[ind % color.length]
|
||||||
|
: "transparent"
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
props.setSignerObjId(obj?.objectId || "");
|
props.setSignerObjId(obj?.objectId || "");
|
||||||
props.setIsSelectId(ind);
|
props.setIsSelectId(ind);
|
||||||
props.setContractName(obj?.className || "");
|
props.setContractName(obj?.className || "");
|
||||||
props.setUniqueId(obj.Id);
|
props.setUniqueId(obj.Id);
|
||||||
props.setRoleName(obj.Role);
|
props.setRoleName(obj.Role);
|
||||||
|
props.setBlockColor(obj?.blockColor);
|
||||||
if (props.handleModal) {
|
if (props.handleModal) {
|
||||||
props.handleModal();
|
props.handleModal();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div className="flex flex-row items-center w-full">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
width: "100%"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
className="signerStyle"
|
className="flex w-[30px] h-[30px] rounded-full items-center justify-center mr-2"
|
||||||
style={{
|
style={{
|
||||||
background: obj.blockColor
|
background: obj?.blockColor
|
||||||
? darkenColor(obj.blockColor, 0.4)
|
? darkenColor(obj?.blockColor, 0.4)
|
||||||
: nameColor[ind % nameColor.length],
|
: nameColor[ind % nameColor.length]
|
||||||
width: 30,
|
|
||||||
height: 30,
|
|
||||||
display: "flex",
|
|
||||||
borderRadius: 30 / 2,
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
marginRight: "12px"
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span className="text-white uppercase font-bold text-center text-[12px]">
|
||||||
style={{
|
|
||||||
fontSize: "12px",
|
|
||||||
textAlign: "center",
|
|
||||||
fontWeight: "bold",
|
|
||||||
color: "white",
|
|
||||||
textTransform: "uppercase"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isWidgetExist(obj.Id) ? (
|
{isWidgetExist(obj.Id) ? (
|
||||||
<i className="fa-solid fa-check"></i>
|
<i className="fa-light fa-check"></i>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{obj.Name
|
{obj.Name
|
||||||
@@ -133,67 +142,116 @@ const RecipientList = (props) => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
className={`${
|
||||||
display: "flex",
|
obj.Name ? "flex-col" : "flex-row"
|
||||||
flexDirection: obj.Name ? "column" : "row",
|
} flex items-center`}
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{obj.Name ? (
|
{obj.Name ? (
|
||||||
<span className="userName" style={{ cursor: "default" }}>
|
<span
|
||||||
|
className={`${
|
||||||
|
(!isMobile && isHover === ind) ||
|
||||||
|
props.isSelectListId === ind
|
||||||
|
? "text-[#424242]"
|
||||||
|
: "text-base-content"
|
||||||
|
} text-[12px] font-bold w-[100px] whitespace-nowrap overflow-hidden text-ellipsis`}
|
||||||
|
>
|
||||||
{obj.Name}
|
{obj.Name}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<span
|
||||||
<span
|
className={`${
|
||||||
className="userName"
|
(!isMobile && isHover === ind) ||
|
||||||
onClick={() => {
|
props.isSelectListId === ind
|
||||||
setIsEdit({ [obj.Id]: true });
|
? "text-[#424242]"
|
||||||
props.setRoleName(obj.Role);
|
: "text-base-content"
|
||||||
}}
|
} text-[12px] font-bold w-[100px] whitespace-nowrap overflow-hidden text-ellipsis cursor-pointer`}
|
||||||
>
|
onClick={() => {
|
||||||
{isEdit?.[obj.Id] && props.handleRoleChange ? (
|
setIsEdit({ [obj.Id]: true });
|
||||||
<input
|
props.setRoleName(obj.Role);
|
||||||
ref={inputRef}
|
}}
|
||||||
style={{
|
>
|
||||||
backgroundColor: "transparent",
|
{isEdit?.[obj.Id] && props.handleRoleChange ? (
|
||||||
width: "inherit"
|
<input
|
||||||
}}
|
ref={inputRef}
|
||||||
value={obj.Role}
|
className="bg-transparent p-[3px]"
|
||||||
onChange={(e) => props.handleRoleChange(e, obj.Id)}
|
value={obj.Role}
|
||||||
onBlur={() => {
|
onChange={(e) => props.handleRoleChange(e, obj.Id)}
|
||||||
setIsEdit({});
|
onBlur={() => {
|
||||||
props.handleOnBlur(obj.Role, obj.Id);
|
setIsEdit({});
|
||||||
}}
|
props.handleOnBlur(obj.Role, obj.Id);
|
||||||
onKeyDown={(e) => {
|
}}
|
||||||
if (e.key === "Enter") {
|
onKeyDown={(e) => {
|
||||||
e.preventDefault();
|
if (e.key === "Enter") {
|
||||||
inputRef.current.blur();
|
e.preventDefault();
|
||||||
}
|
inputRef.current.blur();
|
||||||
}}
|
}
|
||||||
/>
|
}}
|
||||||
) : (
|
/>
|
||||||
obj.Role
|
) : (
|
||||||
)}
|
<span className="text-[13px] 2xl:text-[25px]">
|
||||||
</span>
|
{obj.Role}
|
||||||
</>
|
</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
{obj.Name && (
|
{obj.Name && (
|
||||||
<span className="useEmail" style={{ cursor: "default" }}>
|
<span
|
||||||
{obj.Role}
|
className={` ${
|
||||||
|
(!isMobile && isHover === ind) ||
|
||||||
|
props.isSelectListId === ind
|
||||||
|
? "text-[#424242]"
|
||||||
|
: "text-base-content"
|
||||||
|
} text-[10px] font-medium w-[100px] whitespace-nowrap overflow-hidden text-ellipsis`}
|
||||||
|
>
|
||||||
|
{obj?.Role || obj?.Email}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{isMobile && props.sendInOrder && (
|
||||||
|
<div className="flex flex-row items-center gap-[5px] mr-2">
|
||||||
|
<div
|
||||||
|
onClick={(e) => {
|
||||||
|
if (ind !== 0) {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleChangeSequence(e, ind, "up");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className={ind === 0 ? "text-[gray]" : "text-black"}
|
||||||
|
>
|
||||||
|
▲
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
onClick={(e) => {
|
||||||
|
if (ind !== props.signersdata.length - 1) {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleChangeSequence(e, ind, null, "down");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className={
|
||||||
|
ind === props.signersdata.length - 1
|
||||||
|
? "text-[gray]"
|
||||||
|
: "text-black"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
▼
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{props.handleDeleteUser && (
|
{props.handleDeleteUser && (
|
||||||
<div
|
<div
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
props.handleDeleteUser(obj.Id);
|
props.handleDeleteUser(obj.Id);
|
||||||
}}
|
}}
|
||||||
style={{ cursor: "pointer" }}
|
className={`${
|
||||||
|
(!isMobile && isHover === ind) ||
|
||||||
|
props.isSelectListId === ind
|
||||||
|
? "text-[#424242]"
|
||||||
|
: "text-base-content"
|
||||||
|
} cursor-pointer`}
|
||||||
>
|
>
|
||||||
<i className="fa-regular fa-trash-can"></i>
|
<i className="fa-light fa-trash-can 2xl:text-[30px]"></i>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<hr />
|
<hr />
|
||||||
|
|||||||
@@ -1,98 +1,111 @@
|
|||||||
import React from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import RSC from "react-scrollbars-custom";
|
|
||||||
import { Document, Page } from "react-pdf";
|
import { Document, Page } from "react-pdf";
|
||||||
import { themeColor } from "../../constant/const";
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
function RenderAllPdfPage({
|
function RenderAllPdfPage({
|
||||||
pdfUrl,
|
|
||||||
signPdfUrl,
|
signPdfUrl,
|
||||||
allPages,
|
allPages,
|
||||||
setAllPages,
|
setAllPages,
|
||||||
setPageNumber,
|
setPageNumber,
|
||||||
setSignBtnPosition,
|
setSignBtnPosition,
|
||||||
pageNumber
|
pageNumber,
|
||||||
|
signerPos,
|
||||||
|
signerObjectId
|
||||||
}) {
|
}) {
|
||||||
|
const [signPageNumber, setSignPageNumber] = useState([]);
|
||||||
|
const [bookmarkColor, setBookmarkColor] = useState("");
|
||||||
//set all number of pages after load pdf
|
//set all number of pages after load pdf
|
||||||
function onDocumentLoad({ numPages }) {
|
function onDocumentLoad({ numPages }) {
|
||||||
setAllPages(numPages);
|
setAllPages(numPages);
|
||||||
|
//check if signerPos array exist then save page number exist in signerPos array to show bookmark icon
|
||||||
|
if (signerPos) {
|
||||||
|
const checkUser = signerPos.filter(
|
||||||
|
(data) => data.signerObjId === signerObjectId
|
||||||
|
);
|
||||||
|
setBookmarkColor(checkUser[0]?.blockColor);
|
||||||
|
let pageNumberArr = [];
|
||||||
|
if (checkUser?.length > 0) {
|
||||||
|
checkUser[0]?.placeHolder?.map((data) => {
|
||||||
|
pageNumberArr.push(data?.pageNumber);
|
||||||
|
});
|
||||||
|
|
||||||
|
setSignPageNumber(pageNumberArr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
const pageContainer = useRef();
|
||||||
|
const isHeader = useSelector((state) => state.showHeader);
|
||||||
|
const [pageWidth, setPageWidth] = useState("");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const updateSize = () => {
|
||||||
|
if (pageContainer.current) {
|
||||||
|
setPageWidth(pageContainer.current.offsetWidth);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use setTimeout to wait for the transition to complete
|
||||||
|
const timer = setTimeout(updateSize, 100); // match the transition duration
|
||||||
|
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [isHeader, pageContainer]);
|
||||||
|
//'function `addSignatureBookmark` is used to display the page where the user's signature is located.
|
||||||
|
const addSignatureBookmark = (index) => {
|
||||||
|
const ispageNumber = signPageNumber.includes(index + 1);
|
||||||
|
return (
|
||||||
|
ispageNumber && (
|
||||||
|
<div className="absolute z-20 top-[1px] -right-[13px] -translate-x-1/2 -translate-y-1/2">
|
||||||
|
<i
|
||||||
|
style={{ color: bookmarkColor || "red" }}
|
||||||
|
className="fa-light fa-bookmark"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="showPages">
|
<div ref={pageContainer} className="hidden w-[20%] bg-base-100 md:block">
|
||||||
|
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
|
||||||
|
Pages
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
className={`flex h-[90%] flex-col items-center m-2
|
||||||
display: "flex",
|
autoSignScroll hide-scrollbar max-h-[100vh] `}
|
||||||
flexDirection: "row",
|
|
||||||
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
|
|
||||||
backgroundColor: "white",
|
|
||||||
height: "100%"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div style={{ width: "140px" }}>
|
<Document
|
||||||
<div
|
loading={"Loading Document.."}
|
||||||
style={{
|
onLoadSuccess={onDocumentLoad}
|
||||||
background: themeColor
|
file={signPdfUrl}
|
||||||
// color:"white"
|
>
|
||||||
}}
|
{Array.from(new Array(allPages), (el, index) => (
|
||||||
className="signedStyle"
|
<div
|
||||||
>
|
key={index}
|
||||||
Pages
|
className={`${
|
||||||
</div>
|
pageNumber - 1 === index ? "border-[red]" : "border-[#878787]"
|
||||||
|
} border-2 m-[10px] flex justify-center items-center relative`}
|
||||||
<div>
|
onClick={() => {
|
||||||
<RSC
|
setPageNumber(index + 1);
|
||||||
id="RSC-Example"
|
if (setSignBtnPosition) {
|
||||||
style={{
|
setSignBtnPosition([]);
|
||||||
width: "135px",
|
}
|
||||||
height: window.innerHeight - 130 + "px"
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Document
|
{signerPos && addSignatureBookmark(index)}
|
||||||
loading={"Loading Document.."}
|
|
||||||
onLoadSuccess={onDocumentLoad}
|
|
||||||
file={pdfUrl ? pdfUrl : signPdfUrl}
|
|
||||||
// file="https://api.printnode.com/static/test/pdf/multipage.pdf"
|
|
||||||
>
|
|
||||||
{Array.from(new Array(allPages), (el, index) => (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
style={{
|
|
||||||
width: "100px",
|
|
||||||
border:
|
|
||||||
pageNumber - 1 === index
|
|
||||||
? "2px solid red"
|
|
||||||
: "2px solid #878787",
|
|
||||||
// padding: "5px",
|
|
||||||
margin: "10px",
|
|
||||||
|
|
||||||
display: "flex",
|
<div className="relative z-[1] overflow-hidden">
|
||||||
justifyContent: "center",
|
<Page
|
||||||
alignItems: "center",
|
key={`page_${index + 1}`}
|
||||||
contain: "content"
|
pageNumber={index + 1}
|
||||||
}}
|
width={pageWidth - 60}
|
||||||
onClick={() => {
|
scale={1}
|
||||||
setPageNumber(index + 1);
|
renderAnnotationLayer={false}
|
||||||
if (setSignBtnPosition) {
|
renderTextLayer={false}
|
||||||
setSignBtnPosition([]);
|
/>
|
||||||
}
|
</div>
|
||||||
}}
|
</div>
|
||||||
>
|
))}
|
||||||
<Page
|
</Document>
|
||||||
key={`page_${index + 1}`}
|
|
||||||
pageNumber={index + 1}
|
|
||||||
width={100}
|
|
||||||
height={100}
|
|
||||||
scale={1}
|
|
||||||
renderAnnotationLayer={false}
|
|
||||||
renderTextLayer={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</Document>
|
|
||||||
</RSC>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ import Alert from "../../primitives/Alert";
|
|||||||
|
|
||||||
function RenderPdf({
|
function RenderPdf({
|
||||||
pageNumber,
|
pageNumber,
|
||||||
pdfOriginalWidth,
|
|
||||||
pdfNewWidth,
|
|
||||||
drop,
|
drop,
|
||||||
signerPos,
|
signerPos,
|
||||||
successEmail,
|
successEmail,
|
||||||
@@ -26,15 +24,13 @@ function RenderPdf({
|
|||||||
pdfDetails,
|
pdfDetails,
|
||||||
xyPostion,
|
xyPostion,
|
||||||
pdfUrl,
|
pdfUrl,
|
||||||
numPages,
|
|
||||||
pageDetails,
|
pageDetails,
|
||||||
pdfRequest,
|
pdfRequest,
|
||||||
setCurrentSigner,
|
|
||||||
signerObjectId,
|
signerObjectId,
|
||||||
signedSigners,
|
signedSigners,
|
||||||
setPdfLoadFail,
|
pdfLoad,
|
||||||
|
setPdfLoad,
|
||||||
placeholder,
|
placeholder,
|
||||||
pdfLoadFail,
|
|
||||||
setSignerPos,
|
setSignerPos,
|
||||||
setXyPostion,
|
setXyPostion,
|
||||||
index,
|
index,
|
||||||
@@ -57,183 +53,105 @@ function RenderPdf({
|
|||||||
unSignedWidgetId,
|
unSignedWidgetId,
|
||||||
setIsCheckbox,
|
setIsCheckbox,
|
||||||
handleNameModal,
|
handleNameModal,
|
||||||
|
handleTextSettingModal,
|
||||||
setTempSignerId,
|
setTempSignerId,
|
||||||
uniqueId
|
uniqueId,
|
||||||
|
pdfOriginalWH,
|
||||||
|
scale
|
||||||
}) {
|
}) {
|
||||||
const isMobile = window.innerWidth < 767;
|
const isMobile = window.innerWidth < 767;
|
||||||
const newWidth = containerWH.width;
|
|
||||||
const scale = isMobile ? pdfOriginalWidth / newWidth : 1;
|
|
||||||
//check isGuestSigner is present in local if yes than handle login flow header in mobile view
|
//check isGuestSigner is present in local if yes than handle login flow header in mobile view
|
||||||
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
||||||
|
|
||||||
// handle signature block width and height according to screen
|
// handle signature block width and height according to screen
|
||||||
const posWidth = (pos, signYourself) => {
|
const posWidth = (pos, signYourself) => {
|
||||||
|
const getPdfPageWidth = pdfOriginalWH.find(
|
||||||
|
(data) => data.pageNumber === pageNumber
|
||||||
|
);
|
||||||
|
const containerScale = containerWH.width / getPdfPageWidth.width || 1;
|
||||||
const defaultWidth = defaultWidthHeight(pos.type).width;
|
const defaultWidth = defaultWidthHeight(pos.type).width;
|
||||||
const posWidth = pos.Width ? pos.Width : defaultWidth;
|
const posWidth = pos.Width ? pos.Width : defaultWidth;
|
||||||
let width;
|
|
||||||
if (signYourself) {
|
if (signYourself) {
|
||||||
width = posWidth;
|
return posWidth * scale * containerScale;
|
||||||
return width;
|
|
||||||
} else {
|
} else {
|
||||||
if (isMobile) {
|
if (pos.isMobile && pos.scale) {
|
||||||
if (!pos.isMobile) {
|
if (pos.IsResize) {
|
||||||
if (pos.IsResize) {
|
if (scale > 1) {
|
||||||
width = posWidth ? posWidth : defaultWidth;
|
return posWidth * pos.scale * containerScale * scale;
|
||||||
return width;
|
|
||||||
} else {
|
} else {
|
||||||
width = (posWidth || defaultWidth) / scale;
|
return posWidth * containerScale;
|
||||||
|
|
||||||
return width;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
width = posWidth;
|
if (scale > 1) {
|
||||||
return width;
|
return posWidth * pos.scale * containerScale * scale;
|
||||||
|
} else {
|
||||||
|
return posWidth * pos.scale * containerScale;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (pos.isMobile) {
|
return posWidth * scale * containerScale;
|
||||||
if (pos.IsResize) {
|
|
||||||
width = posWidth ? posWidth : defaultWidth;
|
|
||||||
return width;
|
|
||||||
} else {
|
|
||||||
width = (posWidth || defaultWidth) * pos.scale;
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
width = posWidth ? posWidth : defaultWidth;
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const posHeight = (pos, signYourself) => {
|
const posHeight = (pos, signYourself) => {
|
||||||
let height;
|
const getPdfPageWidth = pdfOriginalWH.find(
|
||||||
const posHeight = pos.Height;
|
(data) => data.pageNumber === pageNumber
|
||||||
const defaultHeight = defaultWidthHeight(pos.type).height;
|
|
||||||
|
|
||||||
if (signYourself) {
|
|
||||||
height = posHeight ? posHeight : defaultHeight;
|
|
||||||
|
|
||||||
return height;
|
|
||||||
} else {
|
|
||||||
if (isMobile) {
|
|
||||||
if (!pos.isMobile) {
|
|
||||||
if (pos.IsResize) {
|
|
||||||
height = posHeight ? posHeight : defaultHeight;
|
|
||||||
return height;
|
|
||||||
} else {
|
|
||||||
height = (posHeight || defaultHeight) / scale;
|
|
||||||
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
height = posHeight ? posHeight : defaultHeight;
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (pos.isMobile) {
|
|
||||||
if (pos.IsResize) {
|
|
||||||
height = posHeight ? posHeight : defaultHeight;
|
|
||||||
return height;
|
|
||||||
} else {
|
|
||||||
height = (posHeight || defaultHeight) * pos.scale;
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
height = posHeight ? posHeight : defaultHeight;
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const xPos = (pos, signYourself) => {
|
|
||||||
const resizePos = pos.xPosition;
|
|
||||||
if (signYourself) {
|
|
||||||
return resizePos;
|
|
||||||
} else {
|
|
||||||
//checking both condition mobile and desktop view
|
|
||||||
if (isMobile) {
|
|
||||||
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
|
|
||||||
if (!pos.isMobile) {
|
|
||||||
return resizePos / scale;
|
|
||||||
}
|
|
||||||
//pos.isMobile true -- placeholder save from mobile view(small device) handle position in mobile view(small screen) view divided by scale
|
|
||||||
else {
|
|
||||||
return resizePos * (pos.scale / scale);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale
|
|
||||||
|
|
||||||
if (pos.isMobile) {
|
|
||||||
return pos.scale && resizePos * pos.scale;
|
|
||||||
}
|
|
||||||
//else placeholder save from desktop(bigscreen) and show in desktop(bigscreen)
|
|
||||||
else {
|
|
||||||
return resizePos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const yPos = (pos, signYourself) => {
|
|
||||||
const resizePos = pos.yPosition;
|
|
||||||
if (signYourself) {
|
|
||||||
return resizePos;
|
|
||||||
} else {
|
|
||||||
//checking both condition mobile and desktop view
|
|
||||||
if (isMobile) {
|
|
||||||
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
|
|
||||||
if (!pos.isMobile) {
|
|
||||||
return resizePos / scale;
|
|
||||||
}
|
|
||||||
//pos.isMobile true -- placeholder save from mobile view(small device) handle position in mobile view(small screen) view divided by scale
|
|
||||||
else {
|
|
||||||
return resizePos * (pos.scale / scale);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale
|
|
||||||
|
|
||||||
if (pos.isMobile) {
|
|
||||||
return pos.scale && resizePos * pos.scale;
|
|
||||||
}
|
|
||||||
//else placeholder save from desktop(bigscreen) and show in desktop(bigscreen)
|
|
||||||
else {
|
|
||||||
return resizePos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//function for render placeholder block over pdf document
|
|
||||||
const checkSignedSignes = (data) => {
|
|
||||||
const checkSign = signedSigners.filter(
|
|
||||||
(sign) => sign.objectId === data.signerObjId
|
|
||||||
);
|
);
|
||||||
if (data.signerObjId === signerObjectId) {
|
const containerScale = containerWH.width / getPdfPageWidth?.width || 1;
|
||||||
setCurrentSigner(true);
|
|
||||||
}
|
|
||||||
const handleAllUserName = (Id, Role, type) => {
|
|
||||||
return pdfDetails[0].Signers.map((signerData, key) => {
|
|
||||||
return (
|
|
||||||
signerData.objectId === data.signerObjId && (
|
|
||||||
<React.Fragment key={key}>
|
|
||||||
{signerData?.Name && (
|
|
||||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
|
||||||
{signerData.Name}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{type && (
|
|
||||||
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
|
||||||
)}
|
|
||||||
{Role && (
|
|
||||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
|
||||||
{`(${Role})`}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const posHeight = pos.Height || defaultWidthHeight(pos.type).height;
|
||||||
|
if (signYourself) {
|
||||||
|
return posHeight * scale * containerScale;
|
||||||
|
} else {
|
||||||
|
if (pos.isMobile && pos.scale) {
|
||||||
|
if (pos.IsResize) {
|
||||||
|
if (scale > 1) {
|
||||||
|
return posHeight * pos.scale * containerScale * scale;
|
||||||
|
} else {
|
||||||
|
return posHeight * containerScale;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (scale > 1) {
|
||||||
|
return posHeight * pos.scale * containerScale * scale;
|
||||||
|
} else {
|
||||||
|
return posHeight * pos.scale * containerScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return posHeight * scale * containerScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//function for render placeholder block over pdf document
|
||||||
|
const checkSignedSigners = (data) => {
|
||||||
|
let checkSign = [];
|
||||||
|
//condition to handle quick send flow and using normal request sign flow
|
||||||
|
checkSign = signedSigners
|
||||||
|
? signedSigners?.filter(
|
||||||
|
(sign) =>
|
||||||
|
sign?.Id === data?.Id || sign?.objectId === data?.signerObjId
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
const handleAllUserName = (Id, Role, type) => {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<div className="text-black text-[8px] font-bold">
|
||||||
|
{
|
||||||
|
pdfDetails[0].Signers?.find(
|
||||||
|
(signer) => signer.objectId === data.signerObjId
|
||||||
|
)?.Name
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
{type && <div className="text-[11px] font-bold">{type}</div>}
|
||||||
|
{Role && (
|
||||||
|
<div className="text-black text-[8px] font-medium">
|
||||||
|
{`(${Role})`}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
checkSign.length === 0 &&
|
checkSign.length === 0 &&
|
||||||
data.placeHolder.map((placeData, key) => {
|
data.placeHolder.map((placeData, key) => {
|
||||||
@@ -260,8 +178,6 @@ function RenderPdf({
|
|||||||
isShowDropdown={true}
|
isShowDropdown={true}
|
||||||
isNeedSign={true}
|
isNeedSign={true}
|
||||||
isSignYourself={false}
|
isSignYourself={false}
|
||||||
xPos={xPos}
|
|
||||||
yPos={yPos}
|
|
||||||
posWidth={posWidth}
|
posWidth={posWidth}
|
||||||
posHeight={posHeight}
|
posHeight={posHeight}
|
||||||
handleUserName={handleAllUserName}
|
handleUserName={handleAllUserName}
|
||||||
@@ -272,6 +188,12 @@ function RenderPdf({
|
|||||||
unSignedWidgetId={unSignedWidgetId}
|
unSignedWidgetId={unSignedWidgetId}
|
||||||
setSelectWidgetId={setSelectWidgetId}
|
setSelectWidgetId={setSelectWidgetId}
|
||||||
selectWidgetId={selectWidgetId}
|
selectWidgetId={selectWidgetId}
|
||||||
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
|
uniqueId={uniqueId}
|
||||||
|
scale={scale}
|
||||||
|
containerWH={containerWH}
|
||||||
|
pdfOriginalWH={pdfOriginalWH}
|
||||||
|
pageNumber={pageNumber}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
@@ -282,6 +204,7 @@ function RenderPdf({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
//function for render placeholder block over pdf document
|
||||||
|
|
||||||
const handleUserName = (Id, Role, type) => {
|
const handleUserName = (Id, Role, type) => {
|
||||||
if (Id) {
|
if (Id) {
|
||||||
@@ -289,61 +212,53 @@ function RenderPdf({
|
|||||||
if (checkSign?.Name) {
|
if (checkSign?.Name) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
<div className="text-black text-[8px] font-medium">
|
||||||
{checkSign?.Name}
|
{checkSign?.Name}
|
||||||
</div>
|
</div>
|
||||||
{type && (
|
{type && <div className="text-[11px] font-bold">{type}</div>}
|
||||||
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
{Role && (
|
||||||
|
<div className="text-black text-[8px] font-medium">
|
||||||
|
{`(${Role})`}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
|
||||||
{`(${Role})`}
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{type && (
|
{type && <div className="text-[11px] font-bold">{type}</div>}
|
||||||
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
<div className="text-black text-[8px] font-medium">{Role}</div>
|
||||||
)}
|
|
||||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
|
||||||
{Role}
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{type && (
|
{type && <div className="text-[11px] font-bold">{type}</div>}
|
||||||
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
<div className="text-black text-[8px] font-medium">{Role}</div>
|
||||||
)}
|
|
||||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
|
||||||
{Role}
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{successEmail && <Alert type={"success"}>Email sent successfully!</Alert>}
|
{successEmail && <Alert type={"success"}>Email sent successfully!</Alert>}
|
||||||
{isMobile && scale ? (
|
{isMobile ? (
|
||||||
<div
|
<div
|
||||||
style={{
|
data-tut="reactourForth"
|
||||||
border: "0.1px solid #ebe8e8",
|
className={`${
|
||||||
marginTop: isGuestSigner && "30px"
|
isGuestSigner ? "30px" : ""
|
||||||
}}
|
} border-[0.1px] border-[#ebe8e8]`}
|
||||||
ref={drop}
|
ref={drop}
|
||||||
id="container"
|
id="container"
|
||||||
>
|
>
|
||||||
{pdfLoadFail.status &&
|
{containerWH?.width &&
|
||||||
|
pdfOriginalWH.length > 0 &&
|
||||||
(pdfRequest
|
(pdfRequest
|
||||||
? signerPos.map((data, key) => {
|
? signerPos.map((data, key) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={key}>
|
<React.Fragment key={key}>
|
||||||
{checkSignedSignes(data)}
|
{checkSignedSigners(data)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -382,8 +297,6 @@ function RenderPdf({
|
|||||||
handleLinkUser={handleLinkUser}
|
handleLinkUser={handleLinkUser}
|
||||||
handleUserName={handleUserName}
|
handleUserName={handleUserName}
|
||||||
isSignYourself={false}
|
isSignYourself={false}
|
||||||
xPos={xPos}
|
|
||||||
yPos={yPos}
|
|
||||||
posWidth={posWidth}
|
posWidth={posWidth}
|
||||||
posHeight={posHeight}
|
posHeight={posHeight}
|
||||||
isDragging={isDragging}
|
isDragging={isDragging}
|
||||||
@@ -399,6 +312,13 @@ function RenderPdf({
|
|||||||
handleNameModal={handleNameModal}
|
handleNameModal={handleNameModal}
|
||||||
setTempSignerId={setTempSignerId}
|
setTempSignerId={setTempSignerId}
|
||||||
uniqueId={uniqueId}
|
uniqueId={uniqueId}
|
||||||
|
handleTextSettingModal={
|
||||||
|
handleTextSettingModal
|
||||||
|
}
|
||||||
|
scale={scale}
|
||||||
|
containerWH={containerWH}
|
||||||
|
pdfOriginalWH={pdfOriginalWH}
|
||||||
|
pageNumber={pageNumber}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
@@ -430,13 +350,10 @@ function RenderPdf({
|
|||||||
index={index}
|
index={index}
|
||||||
xyPostion={xyPostion}
|
xyPostion={xyPostion}
|
||||||
setXyPostion={setXyPostion}
|
setXyPostion={setXyPostion}
|
||||||
pdfOriginalWidth={pdfOriginalWidth}
|
|
||||||
containerWH={containerWH}
|
containerWH={containerWH}
|
||||||
setIsSignPad={setIsSignPad}
|
setIsSignPad={setIsSignPad}
|
||||||
isShowBorder={true}
|
isShowBorder={true}
|
||||||
isSignYourself={true}
|
isSignYourself={true}
|
||||||
xPos={xPos}
|
|
||||||
yPos={yPos}
|
|
||||||
posWidth={posWidth}
|
posWidth={posWidth}
|
||||||
posHeight={posHeight}
|
posHeight={posHeight}
|
||||||
pdfDetails={pdfDetails[0]}
|
pdfDetails={pdfDetails[0]}
|
||||||
@@ -449,6 +366,12 @@ function RenderPdf({
|
|||||||
setIsCheckbox={setIsCheckbox}
|
setIsCheckbox={setIsCheckbox}
|
||||||
setValidateAlert={setValidateAlert}
|
setValidateAlert={setValidateAlert}
|
||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
||||||
|
handleTextSettingModal={
|
||||||
|
handleTextSettingModal
|
||||||
|
}
|
||||||
|
scale={scale}
|
||||||
|
pdfOriginalWH={pdfOriginalWH}
|
||||||
|
pageNumber={pageNumber}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -458,16 +381,10 @@ function RenderPdf({
|
|||||||
}))}
|
}))}
|
||||||
|
|
||||||
{/* this component for render pdf document is in middle of the component */}
|
{/* this component for render pdf document is in middle of the component */}
|
||||||
<div
|
<div className="flex items-center justify-center">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Document
|
<Document
|
||||||
onLoadError={() => {
|
onLoadError={() => {
|
||||||
setPdfLoadFail(true);
|
setPdfLoad(false);
|
||||||
}}
|
}}
|
||||||
loading={"Loading Document.."}
|
loading={"Loading Document.."}
|
||||||
onLoadSuccess={pageDetails}
|
onLoadSuccess={pageDetails}
|
||||||
@@ -485,19 +402,16 @@ function RenderPdf({
|
|||||||
: pdfDetails[0].URL
|
: pdfDetails[0].URL
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{Array.from(new Array(numPages), (el, index) => (
|
<Page
|
||||||
<Page
|
key={index}
|
||||||
key={index}
|
pageNumber={pageNumber}
|
||||||
pageNumber={pageNumber}
|
width={containerWH.width}
|
||||||
width={containerWH.width}
|
renderAnnotationLayer={false}
|
||||||
height={containerWH.height}
|
renderTextLayer={false}
|
||||||
renderAnnotationLayer={false}
|
onGetAnnotationsError={(error) => {
|
||||||
renderTextLayer={false}
|
console.log("annotation error", error);
|
||||||
onGetAnnotationsError={(error) => {
|
}}
|
||||||
console.log("annotation error", error);
|
/>
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Document>
|
</Document>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -506,31 +420,31 @@ function RenderPdf({
|
|||||||
style={{
|
style={{
|
||||||
position: "relative",
|
position: "relative",
|
||||||
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
|
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
|
||||||
width:
|
height: window.innerHeight + "px",
|
||||||
pdfOriginalWidth > pdfNewWidth ? pdfNewWidth : pdfOriginalWidth,
|
zIndex: 0
|
||||||
height: window.innerHeight - 110 + "px"
|
|
||||||
}}
|
}}
|
||||||
noScrollY={false}
|
noScrollY={false}
|
||||||
noScrollX={pdfNewWidth < pdfOriginalWidth ? false : true}
|
noScrollX={scale === 1 ? true : false}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
border: "0.1px solid #ebe8e8",
|
width: containerWH.width * scale
|
||||||
width: pdfOriginalWidth
|
|
||||||
}}
|
}}
|
||||||
ref={drop}
|
ref={drop}
|
||||||
id="container"
|
id="container"
|
||||||
>
|
>
|
||||||
{pdfLoadFail.status &&
|
{pdfLoad &&
|
||||||
(pdfRequest
|
containerWH?.width &&
|
||||||
? signerPos.map((data, key) => {
|
pdfOriginalWH.length > 0 &&
|
||||||
|
(pdfRequest //pdf request sign flow
|
||||||
|
? signerPos?.map((data, key) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={key}>
|
<React.Fragment key={key}>
|
||||||
{checkSignedSignes(data)}
|
{checkSignedSigners(data)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
: placeholder
|
: placeholder //placeholder and template flow
|
||||||
? signerPos.map((data, ind) => {
|
? signerPos.map((data, ind) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={ind}>
|
<React.Fragment key={ind}>
|
||||||
@@ -565,8 +479,6 @@ function RenderPdf({
|
|||||||
handleLinkUser={handleLinkUser}
|
handleLinkUser={handleLinkUser}
|
||||||
handleUserName={handleUserName}
|
handleUserName={handleUserName}
|
||||||
isSignYourself={false}
|
isSignYourself={false}
|
||||||
xPos={xPos}
|
|
||||||
yPos={yPos}
|
|
||||||
posWidth={posWidth}
|
posWidth={posWidth}
|
||||||
posHeight={posHeight}
|
posHeight={posHeight}
|
||||||
isDragging={isDragging}
|
isDragging={isDragging}
|
||||||
@@ -582,6 +494,13 @@ function RenderPdf({
|
|||||||
handleNameModal={handleNameModal}
|
handleNameModal={handleNameModal}
|
||||||
setTempSignerId={setTempSignerId}
|
setTempSignerId={setTempSignerId}
|
||||||
uniqueId={uniqueId}
|
uniqueId={uniqueId}
|
||||||
|
handleTextSettingModal={
|
||||||
|
handleTextSettingModal
|
||||||
|
}
|
||||||
|
scale={scale}
|
||||||
|
containerWH={containerWH}
|
||||||
|
pdfOriginalWH={pdfOriginalWH}
|
||||||
|
pageNumber={pageNumber}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
@@ -593,53 +512,55 @@ function RenderPdf({
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
: xyPostion.map((data, ind) => {
|
: xyPostion.map((data, ind) => {
|
||||||
|
// signyourself flow
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={ind}>
|
<React.Fragment key={ind}>
|
||||||
{data.pageNumber === pageNumber &&
|
{data.pageNumber === pageNumber &&
|
||||||
data.pos.map((pos) => {
|
data.pos.map((pos) => {
|
||||||
return (
|
return (
|
||||||
pos && (
|
<React.Fragment key={pos.key}>
|
||||||
<React.Fragment key={pos.key}>
|
<Placeholder
|
||||||
<Placeholder
|
pos={pos}
|
||||||
pos={pos}
|
setIsPageCopy={setIsPageCopy}
|
||||||
setIsPageCopy={setIsPageCopy}
|
setSignKey={setSignKey}
|
||||||
setSignKey={setSignKey}
|
handleDeleteSign={handleDeleteSign}
|
||||||
handleDeleteSign={handleDeleteSign}
|
setIsStamp={setIsStamp}
|
||||||
setIsStamp={setIsStamp}
|
handleTabDrag={handleTabDrag}
|
||||||
handleTabDrag={handleTabDrag}
|
handleStop={(event, dragElement) =>
|
||||||
handleStop={(event, dragElement) =>
|
handleStop(event, dragElement, pos.type)
|
||||||
handleStop(event, dragElement, pos.type)
|
}
|
||||||
}
|
handleSignYourselfImageResize={
|
||||||
handleSignYourselfImageResize={
|
handleSignYourselfImageResize
|
||||||
handleSignYourselfImageResize
|
}
|
||||||
}
|
index={index}
|
||||||
index={index}
|
xyPostion={xyPostion}
|
||||||
xyPostion={xyPostion}
|
setXyPostion={setXyPostion}
|
||||||
setXyPostion={setXyPostion}
|
setIsSignPad={setIsSignPad}
|
||||||
pdfOriginalWidth={pdfOriginalWidth}
|
isShowBorder={true}
|
||||||
containerWH={containerWH}
|
isSignYourself={true}
|
||||||
setIsSignPad={setIsSignPad}
|
posWidth={posWidth}
|
||||||
isShowBorder={true}
|
posHeight={posHeight}
|
||||||
isSignYourself={true}
|
pdfDetails={pdfDetails[0]}
|
||||||
xPos={xPos}
|
isDragging={isDragging}
|
||||||
yPos={yPos}
|
setIsInitial={setIsInitial}
|
||||||
posWidth={posWidth}
|
setWidgetType={setWidgetType}
|
||||||
posHeight={posHeight}
|
setSelectWidgetId={setSelectWidgetId}
|
||||||
pdfDetails={pdfDetails[0]}
|
selectWidgetId={selectWidgetId}
|
||||||
isDragging={isDragging}
|
handleUserName={handleUserName}
|
||||||
setIsInitial={setIsInitial}
|
setIsCheckbox={setIsCheckbox}
|
||||||
setWidgetType={setWidgetType}
|
setValidateAlert={setValidateAlert}
|
||||||
setSelectWidgetId={setSelectWidgetId}
|
setCurrWidgetsDetails={
|
||||||
selectWidgetId={selectWidgetId}
|
setCurrWidgetsDetails
|
||||||
handleUserName={handleUserName}
|
}
|
||||||
setIsCheckbox={setIsCheckbox}
|
handleTextSettingModal={
|
||||||
setValidateAlert={setValidateAlert}
|
handleTextSettingModal
|
||||||
setCurrWidgetsDetails={
|
}
|
||||||
setCurrWidgetsDetails
|
scale={scale}
|
||||||
}
|
containerWH={containerWH}
|
||||||
/>
|
pdfOriginalWH={pdfOriginalWH}
|
||||||
</React.Fragment>
|
pageNumber={pageNumber}
|
||||||
)
|
/>
|
||||||
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
@@ -649,11 +570,7 @@ function RenderPdf({
|
|||||||
{/* this component for render pdf document is in middle of the component */}
|
{/* this component for render pdf document is in middle of the component */}
|
||||||
<Document
|
<Document
|
||||||
onLoadError={() => {
|
onLoadError={() => {
|
||||||
const load = {
|
pdfLoad(false);
|
||||||
status: false,
|
|
||||||
type: "failed"
|
|
||||||
};
|
|
||||||
setPdfLoadFail(load);
|
|
||||||
}}
|
}}
|
||||||
loading={"Loading Document.."}
|
loading={"Loading Document.."}
|
||||||
onLoadSuccess={pageDetails}
|
onLoadSuccess={pageDetails}
|
||||||
@@ -671,17 +588,18 @@ function RenderPdf({
|
|||||||
: pdfDetails[0].URL
|
: pdfDetails[0].URL
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{Array.from(new Array(numPages), (el, index) => (
|
<Page
|
||||||
<Page
|
key={index}
|
||||||
key={index}
|
width={containerWH.width}
|
||||||
pageNumber={pageNumber}
|
scale={scale || 1}
|
||||||
renderAnnotationLayer={false}
|
className={"-z-[1]"} // when user zoom-in in tablet widgets move backward that's why pass -z-[1]
|
||||||
renderTextLayer={false}
|
pageNumber={pageNumber}
|
||||||
onGetAnnotationsError={(error) => {
|
renderAnnotationLayer={false}
|
||||||
console.log("annotation error", error);
|
renderTextLayer={false}
|
||||||
}}
|
onGetAnnotationsError={(error) => {
|
||||||
/>
|
console.log("annotation error", error);
|
||||||
))}
|
}}
|
||||||
|
/>
|
||||||
</Document>
|
</Document>
|
||||||
</div>
|
</div>
|
||||||
</RSC>
|
</RSC>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import React, { useRef, useState, useEffect } from "react";
|
import React, { useRef, useState, useEffect } from "react";
|
||||||
import SignatureCanvas from "react-signature-canvas";
|
import SignatureCanvas from "react-signature-canvas";
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
|
|
||||||
function SignPad({
|
function SignPad({
|
||||||
isSignPad,
|
isSignPad,
|
||||||
@@ -20,7 +19,9 @@ function SignPad({
|
|||||||
isInitial,
|
isInitial,
|
||||||
setIsInitial,
|
setIsInitial,
|
||||||
setIsStamp,
|
setIsStamp,
|
||||||
widgetType
|
widgetType,
|
||||||
|
currWidgetsDetails,
|
||||||
|
setCurrWidgetsDetails
|
||||||
}) {
|
}) {
|
||||||
const [penColor, setPenColor] = useState("blue");
|
const [penColor, setPenColor] = useState("blue");
|
||||||
const allColor = ["blue", "red", "black"];
|
const allColor = ["blue", "red", "black"];
|
||||||
@@ -31,6 +32,7 @@ function SignPad({
|
|||||||
const [signValue, setSignValue] = useState("");
|
const [signValue, setSignValue] = useState("");
|
||||||
const [textWidth, setTextWidth] = useState(null);
|
const [textWidth, setTextWidth] = useState(null);
|
||||||
const [textHeight, setTextHeight] = useState(null);
|
const [textHeight, setTextHeight] = useState(null);
|
||||||
|
const [signatureType, setSignatureType] = useState("draw");
|
||||||
const fontOptions = [
|
const fontOptions = [
|
||||||
{ value: "Fasthand" },
|
{ value: "Fasthand" },
|
||||||
{ value: "Dancing Script" },
|
{ value: "Dancing Script" },
|
||||||
@@ -48,81 +50,67 @@ function SignPad({
|
|||||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
);
|
);
|
||||||
const jsonSender = JSON.parse(senderUser);
|
const jsonSender = JSON.parse(senderUser);
|
||||||
|
|
||||||
const currentUserName = jsonSender && jsonSender.name;
|
const currentUserName = jsonSender && jsonSender.name;
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const trimmedName = currentUserName.trim();
|
|
||||||
const firstCharacter = trimmedName.charAt(0);
|
|
||||||
const userName = isInitial ? firstCharacter : currentUserName;
|
|
||||||
setSignValue(userName);
|
|
||||||
setFontSelect("Fasthand");
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
//function for clear signature image
|
//function for clear signature image
|
||||||
const handleClear = () => {
|
const handleClear = () => {
|
||||||
|
setCurrWidgetsDetails({});
|
||||||
if (isTab === "draw") {
|
if (isTab === "draw") {
|
||||||
if (canvasRef.current) {
|
if (canvasRef.current) {
|
||||||
canvasRef.current.clear();
|
canvasRef.current.clear();
|
||||||
} else if (isStamp) {
|
} else if (isStamp) {
|
||||||
setImage("");
|
setImage("");
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsSignImg("");
|
setIsSignImg("");
|
||||||
} else if (isTab === "uploadImage") {
|
} else if (isTab === "uploadImage") {
|
||||||
setImage("");
|
setImage("");
|
||||||
}
|
}
|
||||||
setIsInitial(false);
|
// setIsInitial(false);
|
||||||
};
|
};
|
||||||
//function for set signature url
|
//function for set signature url
|
||||||
const handleSignatureChange = () => {
|
const handleSignatureChange = (data) => {
|
||||||
// canvasRef.current.backgroundColor = 'rgb(165, 26, 26)'
|
setSignature(data);
|
||||||
setSignature(canvasRef.current.toDataURL());
|
setIsSignImg(data);
|
||||||
setIsSignImg(canvasRef.current.toDataURL());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//save button component
|
//save button component
|
||||||
const SaveBtn = () => {
|
const SaveBtn = () => {
|
||||||
return (
|
return (
|
||||||
<div style={{ marginTop: "2px" }}>
|
<div>
|
||||||
{(isTab === "draw" || isTab === "uploadImage") && (
|
{(isTab === "draw" || isTab === "uploadImage") && (
|
||||||
<button
|
<button
|
||||||
style={{
|
|
||||||
color: "black",
|
|
||||||
border: "1px solid #ccc"
|
|
||||||
}}
|
|
||||||
type="button"
|
type="button"
|
||||||
className="finishBtn saveBtn"
|
className="op-btn op-btn-ghost mr-1 mt-[2px]"
|
||||||
onClick={() => handleClear()}
|
onClick={() => handleClear()}
|
||||||
>
|
>
|
||||||
Clear
|
Clear
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
setCurrWidgetsDetails({});
|
||||||
if (!image) {
|
if (!image) {
|
||||||
if (isTab === "mysignature") {
|
if (isTab === "mysignature") {
|
||||||
setIsSignImg("");
|
setIsSignImg("");
|
||||||
if (isInitial) {
|
if (isInitial) {
|
||||||
onSaveSign("initials");
|
onSaveSign(signatureType, "initials");
|
||||||
} else {
|
} else {
|
||||||
onSaveSign("default");
|
onSaveSign(null, "default");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isTab === "type") {
|
if (isTab === "type") {
|
||||||
setIsSignImg("");
|
setIsSignImg("");
|
||||||
onSaveSign(false, textWidth, textHeight);
|
onSaveSign(null, false, textWidth, textHeight);
|
||||||
} else {
|
} else {
|
||||||
setIsSignImg("");
|
setIsSignImg("");
|
||||||
onSaveSign();
|
canvasRef.current.clear();
|
||||||
|
onSaveSign(signatureType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setPenColor("blue");
|
setPenColor("blue");
|
||||||
} else {
|
} else {
|
||||||
setIsSignImg("");
|
setIsSignImg("");
|
||||||
onSaveImage();
|
onSaveImage(signatureType);
|
||||||
}
|
}
|
||||||
setIsSignPad(false);
|
setIsSignPad(false);
|
||||||
setIsInitial(false);
|
setIsInitial(false);
|
||||||
@@ -133,18 +121,21 @@ function SignPad({
|
|||||||
setSignValue("");
|
setSignValue("");
|
||||||
setIsStamp(false);
|
setIsStamp(false);
|
||||||
}}
|
}}
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
disabled={
|
|
||||||
isSignImg || image || isDefaultSign || textWidth ? false : true
|
|
||||||
}
|
|
||||||
type="button"
|
type="button"
|
||||||
className={
|
className={`${
|
||||||
isSignImg || image || isDefaultSign || textWidth
|
isSignImg || image || isDefaultSign || textWidth
|
||||||
? "finishBtn saveBtn"
|
? ""
|
||||||
: "disabledFinish saveBtn"
|
: "pointer-events-none"
|
||||||
|
} op-btn op-btn-primary shadow-lg`}
|
||||||
|
disabled={
|
||||||
|
(isTab === "draw" && isSignImg) ||
|
||||||
|
(isTab === "image" && image) ||
|
||||||
|
(isTab === "mysignature" && isDefaultSign) ||
|
||||||
|
(isTab === "type" && textWidth)
|
||||||
|
? false
|
||||||
|
: image
|
||||||
|
? false
|
||||||
|
: true
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
@@ -152,7 +143,35 @@ function SignPad({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
//useEffect for set already draw or save signature url/text url of signature text type and draw type for initial type and signature type widgets
|
||||||
|
useEffect(() => {
|
||||||
|
if (currWidgetsDetails && canvasRef.current) {
|
||||||
|
const isWidgetType = currWidgetsDetails?.type;
|
||||||
|
const signatureType = currWidgetsDetails?.signatureType;
|
||||||
|
const url = currWidgetsDetails?.SignUrl;
|
||||||
|
|
||||||
|
//checking widget type and draw type signature url
|
||||||
|
if (isInitial) {
|
||||||
|
if (isWidgetType === "initials" && signatureType === "draw" && url) {
|
||||||
|
canvasRef.current.fromDataURL(url);
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
isWidgetType === "signature" &&
|
||||||
|
signatureType === "draw" &&
|
||||||
|
url
|
||||||
|
) {
|
||||||
|
canvasRef.current.fromDataURL(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimmedName = currentUserName.trim();
|
||||||
|
const firstCharacter = trimmedName.charAt(0);
|
||||||
|
const userName = isInitial ? firstCharacter : currentUserName;
|
||||||
|
setSignValue(userName);
|
||||||
|
setFontSelect("Fasthand");
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [isSignPad]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadFont = async () => {
|
const loadFont = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -184,9 +203,8 @@ function SignPad({
|
|||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [isTab]);
|
}, [isTab]);
|
||||||
|
|
||||||
//function for convert input text value in image
|
//function for convert input text value in image
|
||||||
const convertToImg = async (fontStyle, text) => {
|
const convertToImg = async (fontStyle, text, color) => {
|
||||||
//get text content to convert in image
|
//get text content to convert in image
|
||||||
const textContent = text;
|
const textContent = text;
|
||||||
const fontfamily = fontStyle
|
const fontfamily = fontStyle
|
||||||
@@ -199,6 +217,7 @@ function SignPad({
|
|||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.textContent = textContent;
|
span.textContent = textContent;
|
||||||
span.style.font = `20px ${fontfamily}`; // here put your text size and font family
|
span.style.font = `20px ${fontfamily}`; // here put your text size and font family
|
||||||
|
span.style.color = color ? color : penColor;
|
||||||
span.style.display = "hidden";
|
span.style.display = "hidden";
|
||||||
document.body.appendChild(span); // Replace 'container' with the ID of the container element
|
document.body.appendChild(span); // Replace 'container' with the ID of the container element
|
||||||
|
|
||||||
@@ -216,13 +235,9 @@ function SignPad({
|
|||||||
canvasElement.width = width * pixelRatio;
|
canvasElement.width = width * pixelRatio;
|
||||||
canvasElement.height = height * pixelRatio;
|
canvasElement.height = height * pixelRatio;
|
||||||
|
|
||||||
// Render the content of the span onto the canvas
|
|
||||||
// ctx.fillStyle = "white"; // Set the background color of the canvas
|
|
||||||
// ctx.fillRect(0, 0, width*pixelRatio, height*pixelRatio);
|
|
||||||
|
|
||||||
// You can customize text styles if needed
|
// You can customize text styles if needed
|
||||||
ctx.font = font;
|
ctx.font = font;
|
||||||
ctx.fillStyle = "black"; // Set the text color
|
ctx.fillStyle = color ? color : penColor; // Set the text color
|
||||||
ctx.textAlign = "center";
|
ctx.textAlign = "center";
|
||||||
ctx.textBaseline = "middle";
|
ctx.textBaseline = "middle";
|
||||||
ctx.scale(pixelRatio, pixelRatio);
|
ctx.scale(pixelRatio, pixelRatio);
|
||||||
@@ -235,36 +250,56 @@ function SignPad({
|
|||||||
setSignature(dataUrl);
|
setSignature(dataUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PenColorComponent = (props) => {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-row items-start">
|
||||||
|
{allColor.map((data, key) => {
|
||||||
|
return (
|
||||||
|
<i
|
||||||
|
style={{
|
||||||
|
margin: "5px",
|
||||||
|
color: data,
|
||||||
|
borderBottom:
|
||||||
|
key === 0 && penColor === "blue"
|
||||||
|
? "2px solid blue"
|
||||||
|
: key === 1 && penColor === "red"
|
||||||
|
? "2px solid red"
|
||||||
|
: key === 2 && penColor === "black"
|
||||||
|
? "2px solid black"
|
||||||
|
: "2px solid white"
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
props?.convertToImg &&
|
||||||
|
props?.convertToImg(fontSelect, signValue, data);
|
||||||
|
if (key === 0) {
|
||||||
|
setPenColor("blue");
|
||||||
|
} else if (key === 1) {
|
||||||
|
setPenColor("red");
|
||||||
|
} else if (key === 2) {
|
||||||
|
setPenColor("black");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
key={key}
|
||||||
|
className="fa-light fa-pen-nib"
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
></i>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{isSignPad && (
|
{isSignPad && (
|
||||||
<div className="modaloverlay">
|
<div className="op-modal op-modal-open">
|
||||||
<div className="modalcontainer">
|
<div className="op-modal-box px-[13px] pt-2 pb-0">
|
||||||
<div
|
<div className="flex justify-between text-base-content items-center">
|
||||||
className="modalheader"
|
<div className="text-[1.2rem]">
|
||||||
style={{ padding: "0 13px", marginTop: "5px" }}
|
<div className="flex flex-row justify-between mt-[3px]">
|
||||||
>
|
<div className="flex flex-row justify-between gap-[5px] md:gap-[8px] text-[11px] md:text-base">
|
||||||
<div className="modaltitle">
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
background: "white",
|
|
||||||
marginTop: "3px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-around",
|
|
||||||
alignItems: "end",
|
|
||||||
gap: 10
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isStamp ? (
|
{isStamp ? (
|
||||||
<span style={{ color: themeColor }} className="signTab">
|
<span className="op-link-primary op-link">
|
||||||
{widgetType === "image"
|
{widgetType === "image"
|
||||||
? "Upload image"
|
? "Upload image"
|
||||||
: "Upload stamp image"}
|
: "Upload stamp image"}
|
||||||
@@ -278,24 +313,18 @@ function SignPad({
|
|||||||
setIsImageSelect(false);
|
setIsImageSelect(false);
|
||||||
setIsTab("draw");
|
setIsTab("draw");
|
||||||
setImage();
|
setImage();
|
||||||
|
if (isSignImg) {
|
||||||
|
setSignature(isSignImg);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
style={{
|
className={`${
|
||||||
color: isTab === "draw" ? themeColor : "#515252",
|
isTab === "draw"
|
||||||
marginLeft: "2px"
|
? "op-link-primary"
|
||||||
}}
|
: "no-underline"
|
||||||
className="signTab"
|
} op-link underline-offset-8 ml-[2px]`}
|
||||||
>
|
>
|
||||||
Draw
|
Draw
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border:
|
|
||||||
isTab === "draw"
|
|
||||||
? "1.5px solid #108783"
|
|
||||||
: "1.5px solid #ffffff"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
@@ -303,23 +332,16 @@ function SignPad({
|
|||||||
setIsDefaultSign(false);
|
setIsDefaultSign(false);
|
||||||
setIsImageSelect(true);
|
setIsImageSelect(true);
|
||||||
setIsTab("uploadImage");
|
setIsTab("uploadImage");
|
||||||
|
setSignatureType("");
|
||||||
}}
|
}}
|
||||||
style={{
|
className={`${
|
||||||
color:
|
isTab === "uploadImage"
|
||||||
isTab === "uploadImage" ? themeColor : "#515252"
|
? "op-link-primary"
|
||||||
}}
|
: "no-underline"
|
||||||
className="signTab"
|
} op-link underline-offset-8 ml-[2px]`}
|
||||||
>
|
>
|
||||||
Upload Image
|
Upload Image
|
||||||
</span>
|
</span>
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border:
|
|
||||||
isTab === "uploadImage"
|
|
||||||
? "1.5px solid #108783"
|
|
||||||
: "1.5px solid #ffffff"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
@@ -327,25 +349,17 @@ function SignPad({
|
|||||||
setIsDefaultSign(false);
|
setIsDefaultSign(false);
|
||||||
setIsImageSelect(false);
|
setIsImageSelect(false);
|
||||||
setIsTab("type");
|
setIsTab("type");
|
||||||
|
setSignatureType("");
|
||||||
setImage();
|
setImage();
|
||||||
}}
|
}}
|
||||||
style={{
|
className={`${
|
||||||
color: isTab === "type" ? themeColor : "#515252",
|
isTab === "type"
|
||||||
marginLeft: "2px"
|
? "op-link-primary"
|
||||||
}}
|
: "no-underline"
|
||||||
className="signTab"
|
} op-link underline-offset-8 ml-[2px]`}
|
||||||
>
|
>
|
||||||
Type
|
Type
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border:
|
|
||||||
isTab === "type"
|
|
||||||
? "1.5px solid #108783"
|
|
||||||
: "1.5px solid #ffffff"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
{!isInitial && defaultSign ? (
|
{!isInitial && defaultSign ? (
|
||||||
<div>
|
<div>
|
||||||
@@ -354,26 +368,17 @@ function SignPad({
|
|||||||
setIsDefaultSign(true);
|
setIsDefaultSign(true);
|
||||||
setIsImageSelect(true);
|
setIsImageSelect(true);
|
||||||
setIsTab("mysignature");
|
setIsTab("mysignature");
|
||||||
|
setSignatureType("");
|
||||||
setImage();
|
setImage();
|
||||||
}}
|
}}
|
||||||
style={{
|
className={`${
|
||||||
color:
|
isTab === "mysignature"
|
||||||
isTab === "mysignature"
|
? "op-link-primary"
|
||||||
? themeColor
|
: "no-underline"
|
||||||
: "#515252"
|
} op-link underline-offset-8 ml-[2px]`}
|
||||||
}}
|
|
||||||
className="signTab"
|
|
||||||
>
|
>
|
||||||
My Signature
|
My Signature
|
||||||
</span>
|
</span>
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border:
|
|
||||||
isTab === "mysignature"
|
|
||||||
? "1.5px solid #108783"
|
|
||||||
: "1.5px solid #ffffff"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
isInitial &&
|
isInitial &&
|
||||||
@@ -384,26 +389,17 @@ function SignPad({
|
|||||||
setIsDefaultSign(true);
|
setIsDefaultSign(true);
|
||||||
setIsImageSelect(true);
|
setIsImageSelect(true);
|
||||||
setIsTab("mysignature");
|
setIsTab("mysignature");
|
||||||
|
setSignatureType("");
|
||||||
setImage();
|
setImage();
|
||||||
}}
|
}}
|
||||||
style={{
|
className={`${
|
||||||
color:
|
isTab === "mysignature"
|
||||||
isTab === "mysignature"
|
? "op-link-primary"
|
||||||
? themeColor
|
: "no-underline"
|
||||||
: "#515252"
|
} op-link underline-offset-8 ml-[2px]`}
|
||||||
}}
|
|
||||||
className="signTab"
|
|
||||||
>
|
>
|
||||||
My Initials
|
My Initials
|
||||||
</span>
|
</span>
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border:
|
|
||||||
isTab === "mysignature"
|
|
||||||
? "1.5px solid #108783"
|
|
||||||
: "1.5px solid #ffffff"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
@@ -413,8 +409,7 @@ function SignPad({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="closebtn"
|
className="text-[1.5rem] cursor-pointer"
|
||||||
style={{ color: "black" }}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setPenColor("blue");
|
setPenColor("blue");
|
||||||
setIsSignPad(false);
|
setIsSignPad(false);
|
||||||
@@ -423,6 +418,7 @@ function SignPad({
|
|||||||
setIsDefaultSign(false);
|
setIsDefaultSign(false);
|
||||||
setImage();
|
setImage();
|
||||||
setIsTab("draw");
|
setIsTab("draw");
|
||||||
|
setSignatureType("draw");
|
||||||
setSignValue("");
|
setSignValue("");
|
||||||
setIsStamp(false);
|
setIsStamp(false);
|
||||||
}}
|
}}
|
||||||
@@ -430,10 +426,10 @@ function SignPad({
|
|||||||
×
|
×
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ height: "100%", padding: 20 }}>
|
<div className="p-[20px] h-full">
|
||||||
{isDefaultSign ? (
|
{isDefaultSign ? (
|
||||||
<>
|
<>
|
||||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
<div className="flex justify-center">
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
border: "1.3px solid #007bff",
|
border: "1.3px solid #007bff",
|
||||||
@@ -451,28 +447,23 @@ function SignPad({
|
|||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="stamp img"
|
alt="stamp img"
|
||||||
style={{
|
className="w-full h-full object-contain bg-white"
|
||||||
width: "100%",
|
draggable="false"
|
||||||
height: "100%",
|
|
||||||
background: "rgb(255, 255, 255)",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
src={isInitial ? myInitial : defaultSign}
|
src={isInitial ? myInitial : defaultSign}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", justifyContent: "flex-end" }}>
|
<div className="flex justify-end">
|
||||||
<SaveBtn />
|
<SaveBtn />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : isImageSelect || isStamp ? (
|
) : isImageSelect || isStamp ? (
|
||||||
!image ? (
|
!image ? (
|
||||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
<div className="flex justify-center">
|
||||||
<div
|
<div
|
||||||
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",
|
||||||
@@ -489,17 +480,17 @@ 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
|
||||||
/>
|
/>
|
||||||
<i className="fas fa-cloud-upload-alt uploadImgLogo"></i>
|
<i className="fa-light fa-cloud-upload-alt uploadImgLogo"></i>
|
||||||
<div className="uploadImg">Upload</div>
|
<div className="text-[10px]">Upload</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
<div className="flex justify-center">
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
border: "1.3px solid #007bff",
|
border: "1.3px solid #007bff",
|
||||||
@@ -517,39 +508,27 @@ function SignPad({
|
|||||||
alt="print img"
|
alt="print img"
|
||||||
ref={imageRef}
|
ref={imageRef}
|
||||||
src={image.src}
|
src={image.src}
|
||||||
style={{
|
draggable="false"
|
||||||
objectFit: "contain",
|
className=" object-contain h-full w-full"
|
||||||
height: "100%",
|
|
||||||
width: "100%"
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="flex justify-end">
|
||||||
style={{ display: "flex", justifyContent: "flex-end" }}
|
|
||||||
>
|
|
||||||
<SaveBtn />
|
<SaveBtn />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
) : isTab === "type" ? (
|
) : isTab === "type" ? (
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div className="flex justify-between items-center">
|
||||||
style={{
|
<span className="mr-[5px] text-[12px]">
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="signatureText">
|
|
||||||
{isInitial ? "Initials" : "Signature"}:
|
{isInitial ? "Initials" : "Signature"}:
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
maxLength={isInitial ? 3 : 30}
|
maxLength={isInitial ? 3 : 30}
|
||||||
style={{ fontFamily: fontSelect }}
|
style={{ fontFamily: fontSelect, color: penColor }}
|
||||||
type="text"
|
type="text"
|
||||||
className="signatureInput"
|
className="ml-1 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-[20px]"
|
||||||
placeholder="Your signature"
|
placeholder="Your signature"
|
||||||
value={signValue}
|
value={signValue}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
@@ -558,8 +537,7 @@ function SignPad({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="border-[1px] border-[#d6d3d3] mt-[10px] ml-[5px]">
|
||||||
<div className="fontOptionContainer">
|
|
||||||
{fontOptions.map((font, ind) => {
|
{fontOptions.map((font, ind) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -578,7 +556,8 @@ function SignPad({
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
padding: "5px 10px 5px 10px",
|
padding: "5px 10px 5px 10px",
|
||||||
fontSize: "20px"
|
fontSize: "20px",
|
||||||
|
color: penColor
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{signValue ? signValue : "Your signature"}
|
{signValue ? signValue : "Your signature"}
|
||||||
@@ -588,13 +567,14 @@ function SignPad({
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: "flex", justifyContent: "flex-end" }}>
|
<div className="flex flex-row justify-between mt-[10px]">
|
||||||
|
<PenColorComponent convertToImg={convertToImg} />
|
||||||
<SaveBtn />
|
<SaveBtn />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
<div className="flex justify-center">
|
||||||
<SignatureCanvas
|
<SignatureCanvas
|
||||||
ref={canvasRef}
|
ref={canvasRef}
|
||||||
penColor={penColor}
|
penColor={penColor}
|
||||||
@@ -609,52 +589,13 @@ function SignPad({
|
|||||||
}}
|
}}
|
||||||
backgroundColor="rgb(255, 255, 255)"
|
backgroundColor="rgb(255, 255, 255)"
|
||||||
onEnd={() =>
|
onEnd={() =>
|
||||||
handleSignatureChange(canvasRef.current.toDataURL())
|
handleSignatureChange(canvasRef.current?.toDataURL())
|
||||||
}
|
}
|
||||||
dotSize={1}
|
dotSize={1}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="flex flex-row justify-between mt-[10px]">
|
||||||
style={{
|
<PenColorComponent />
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
marginTop: "10px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
|
||||||
{allColor.map((data, key) => {
|
|
||||||
return (
|
|
||||||
<i
|
|
||||||
style={{
|
|
||||||
margin: "5px",
|
|
||||||
color: data,
|
|
||||||
borderBottom:
|
|
||||||
key === 0 && penColor === "blue"
|
|
||||||
? "2px solid blue"
|
|
||||||
: key === 1 && penColor === "red"
|
|
||||||
? "2px solid red"
|
|
||||||
: key === 2 && penColor === "black"
|
|
||||||
? "2px solid black"
|
|
||||||
: "2px solid white"
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
if (key === 0) {
|
|
||||||
setPenColor("blue");
|
|
||||||
} else if (key === 1) {
|
|
||||||
setPenColor("red");
|
|
||||||
} else if (key === 2) {
|
|
||||||
setPenColor("black");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
key={key}
|
|
||||||
className="fa solid fa-pen-nib"
|
|
||||||
width={20}
|
|
||||||
height={20}
|
|
||||||
></i>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
<SaveBtn />
|
<SaveBtn />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
import "../../styles/signature.css";
|
import "../../styles/signature.css";
|
||||||
function Signedby({ pdfDetails }) {
|
function Signedby({ pdfDetails }) {
|
||||||
const getFirstLetter = (name) => {
|
const getFirstLetter = (name) => {
|
||||||
@@ -8,52 +7,24 @@ function Signedby({ pdfDetails }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="signerComponent">
|
<div className="hidden md:block w-full h-full bg-base-100">
|
||||||
<div
|
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
className="signedStyle"
|
|
||||||
>
|
|
||||||
Signed By
|
Signed By
|
||||||
</div>
|
</div>
|
||||||
<div style={{ marginTop: "2px", background: "white" }}>
|
<div className="mt-[2px] bg-base-100">
|
||||||
<div
|
<div className="bg-[#93a3db] rounded-xl mx-1 flex flex-row items-center py-[10px]">
|
||||||
style={{
|
<div className="bg-[#576081] flex w-[30px] h-[30px] rounded-full justify-center items-center mx-1">
|
||||||
display: "flex",
|
<span className="text-[12px] text-center font-bold text-white uppercase">
|
||||||
flexDirection: "row",
|
|
||||||
padding: "10px",
|
|
||||||
background: "#93a3db"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="signerStyle"
|
|
||||||
style={{
|
|
||||||
background: "#abd1d0",
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
display: "flex",
|
|
||||||
borderRadius: 30 / 2,
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
marginRight: "20px",
|
|
||||||
marginTop: "5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: "8px",
|
|
||||||
textAlign: "center",
|
|
||||||
fontWeight: "bold"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{getFirstLetter(pdfDetails.ExtUserPtr.Name)}
|
{getFirstLetter(pdfDetails.ExtUserPtr.Name)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
<div className="flex flex-col">
|
||||||
<span className="userName">{pdfDetails.ExtUserPtr.Name}</span>
|
<span className="text-[12px] font-bold text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
|
||||||
<span className="useEmail">{pdfDetails.ExtUserPtr.Email}</span>
|
{pdfDetails.ExtUserPtr.Name}
|
||||||
|
</span>
|
||||||
|
<span className="text-[10px] font-medium text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
|
||||||
|
{pdfDetails.ExtUserPtr.Email}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { darkenColor, getFirstLetter } from "../../constant/Utils";
|
||||||
|
|
||||||
|
function SignerListComponent(props) {
|
||||||
|
const checkSignerBackColor = (obj) => {
|
||||||
|
if (obj) {
|
||||||
|
let data = "";
|
||||||
|
if (obj?.Id) {
|
||||||
|
data = props.signerPos.filter((data) => data.Id === obj.Id);
|
||||||
|
} else {
|
||||||
|
data = props.signerPos.filter(
|
||||||
|
(data) => data.signerObjId === obj.objectId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return data && data.length > 0 && data[0].blockColor;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const checkUserNameColor = (obj) => {
|
||||||
|
const getBackColor = checkSignerBackColor(obj);
|
||||||
|
if (getBackColor) {
|
||||||
|
const color = darkenColor(getBackColor, 0.4);
|
||||||
|
return color;
|
||||||
|
} else {
|
||||||
|
return "#abd1d0";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="rounded-xl mx-1 flex flex-row items-center py-[10px] mt-1"
|
||||||
|
style={{ background: checkSignerBackColor(props.obj) }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{ background: checkUserNameColor(props.obj) }}
|
||||||
|
className="flex w-[30px] h-[30px] rounded-full justify-center items-center mx-1"
|
||||||
|
>
|
||||||
|
<span className="text-[12px] text-center font-bold text-black uppercase">
|
||||||
|
{getFirstLetter(props?.obj?.Name || props?.obj?.Role)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="text-[12px] font-bold text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
|
||||||
|
{props.obj?.Name || props?.obj?.Role}
|
||||||
|
</span>
|
||||||
|
<span className="text-[10px] font-medium text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
|
||||||
|
{props.obj?.Email || props.obj?.email}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SignerListComponent;
|
||||||
@@ -1,33 +1,86 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
import RecipientList from "./RecipientList";
|
import RecipientList from "./RecipientList";
|
||||||
|
import { Tooltip } from "react-tooltip";
|
||||||
|
|
||||||
function SignerListPlace(props) {
|
function SignerListPlace(props) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
|
||||||
style={{
|
<span className="relative">
|
||||||
background: themeColor,
|
|
||||||
padding: "5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="signedStyle">
|
|
||||||
{props.title ? props.title : "Recipients"}
|
{props.title ? props.title : "Recipients"}
|
||||||
|
<span className="absolute text-xs z-[30] mt-1 ml-0.5">
|
||||||
|
{props?.title === "Roles" && (
|
||||||
|
<>
|
||||||
|
<a data-tooltip-id="my-tooltip">
|
||||||
|
<sup>
|
||||||
|
<i className="fa-light fa-question rounded-full border-[1px] border-base-content text-[11px] py-[1px] px-[3px]"></i>
|
||||||
|
</sup>
|
||||||
|
</a>
|
||||||
|
<Tooltip id="my-tooltip" className="z-[100]">
|
||||||
|
<div className="max-w-[450px] 2xl:max-w-[500px] 2xl:text-[20px] p-[1px]">
|
||||||
|
<p className="font-bold pb-[1px]">
|
||||||
|
What are template roles?
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Begin by specifying each role needed for the completion of
|
||||||
|
the document. Think about the parties involved in the
|
||||||
|
signing process and what their responsibilities are.
|
||||||
|
Common roles include HR for internal documents, Customer
|
||||||
|
for agreements or Vendor for business agreements.{" "}
|
||||||
|
</p>
|
||||||
|
<p className="font-bold">
|
||||||
|
Why pre-attach users to some roles?
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
For roles that consistently involve the same individual
|
||||||
|
(e.g., the CEO's signature on employee offer
|
||||||
|
letters), you can pre-attach a user to a role within the
|
||||||
|
template. This step is optional but recommended for
|
||||||
|
efficiency and consistency across documents.
|
||||||
|
</p>
|
||||||
|
<p className="font-bold">
|
||||||
|
When do i specify the user attached to each role?
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
When you create a document from your template, you'll
|
||||||
|
be prompted to attach users to each defined role. If a
|
||||||
|
role already has a user attached, this will be pre-filled,
|
||||||
|
but you can modify it as needed before sending out the
|
||||||
|
document.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="signerList">
|
<div className="overflow-auto hide-scrollbar max-h-[180px]">
|
||||||
<RecipientList {...props} />
|
<RecipientList {...props} />
|
||||||
</div>
|
</div>
|
||||||
{props.handleAddSigner && (
|
<div className="mx-1">
|
||||||
<div
|
{props.handleAddSigner ? (
|
||||||
data-tut="reactourAddbtn"
|
<div
|
||||||
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"
|
role="button"
|
||||||
onClick={() => props.handleAddSigner()}
|
data-tut="reactourAddbtn"
|
||||||
>
|
disabled={props?.isMailSend ? true : false}
|
||||||
<i className="fa-solid fa-plus"></i>
|
className="op-btn op-btn-accent op-btn-outline w-full mt-[14px]"
|
||||||
<span style={{ marginLeft: 2 }}>Add role</span>
|
onClick={() => props.handleAddSigner()}
|
||||||
</div>
|
>
|
||||||
)}
|
<i className="fa-light fa-plus"></i> Add role
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
role="button"
|
||||||
|
data-tut="addRecipient"
|
||||||
|
className="op-btn op-btn-accent op-btn-outline w-full mt-[14px]"
|
||||||
|
disabled={props?.isMailSend ? true : false}
|
||||||
|
onClick={() => props.setIsAddSigner(true)}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-plus"></i> Add recipients
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
|
import { fontColorArr, fontsizeArr } from "../../constant/Utils";
|
||||||
|
|
||||||
|
function TextFontSetting(props) {
|
||||||
|
return (
|
||||||
|
<ModalUi
|
||||||
|
headerColor={"#dc3545"}
|
||||||
|
isOpen={props.isTextSetting}
|
||||||
|
reduceWidth={"max-w-[350px]"}
|
||||||
|
title={"Text field"}
|
||||||
|
handleClose={() => {
|
||||||
|
props.setIsTextSetting(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="h-full p-[20px]">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<span>Font size:</span>
|
||||||
|
<select
|
||||||
|
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
|
||||||
|
value={
|
||||||
|
props.fontSize || props.currWidgetsDetails?.options?.fontSize
|
||||||
|
}
|
||||||
|
onChange={(e) => props.setFontSize(e.target.value)}
|
||||||
|
>
|
||||||
|
{fontsizeArr.map((size, ind) => {
|
||||||
|
return (
|
||||||
|
<option className="text-[13px]" value={size} key={ind}>
|
||||||
|
{size}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
<div className="flex flex-row gap-1 items-center ml-4">
|
||||||
|
<span>color: </span>
|
||||||
|
<select
|
||||||
|
value={
|
||||||
|
props.fontColor || props.currWidgetsDetails?.options?.fontColor
|
||||||
|
}
|
||||||
|
onChange={(e) => props.setFontColor(e.target.value)}
|
||||||
|
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
|
||||||
|
>
|
||||||
|
{fontColorArr.map((color, ind) => {
|
||||||
|
return (
|
||||||
|
<option value={color} key={ind}>
|
||||||
|
{color}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
background:
|
||||||
|
props.fontColor ||
|
||||||
|
props.currWidgetsDetails?.options?.fontColor
|
||||||
|
}}
|
||||||
|
className="w-5 h-[19px] ml-1"
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="h-[1px] bg-[#9f9f9f] w-full mt-[15px] mb-2"></div>
|
||||||
|
<button
|
||||||
|
onClick={() => props.handleSaveFontSize()}
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-primary mt-2"
|
||||||
|
>
|
||||||
|
save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TextFontSetting;
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Loader from "../../primitives/Loader";
|
||||||
|
|
||||||
|
function VerifyEmail(props) {
|
||||||
|
return (
|
||||||
|
<dialog className="op-modal op-modal-open absolute z-[1999]">
|
||||||
|
<div className="md:w-[40%] w-[80%] op-modal-box p-0 overflow-y-auto hide-scrollbar text-sm">
|
||||||
|
<h3 className="font-bold text-lg pt-[15px] px-[20px] text-base-content">
|
||||||
|
OTP verification
|
||||||
|
</h3>
|
||||||
|
{props.isVerifyModal ? (
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
props.setIsVerifyModal(false);
|
||||||
|
props.handleVerifyEmail(e);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="px-6 py-3 text-base-content">
|
||||||
|
<label className="mb-2">Enter OTP</label>
|
||||||
|
<input
|
||||||
|
required
|
||||||
|
type="tel"
|
||||||
|
pattern="[0-9]{4}"
|
||||||
|
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
||||||
|
placeholder="Enter OTP received over email"
|
||||||
|
value={props.otp}
|
||||||
|
onChange={(e) => props.setOtp(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="px-6 my-3">
|
||||||
|
<button type="submit" className="op-btn op-btn-primary">
|
||||||
|
Verify
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="op-btn op-btn-secondary ml-2"
|
||||||
|
onClick={(e) => props.handleResend(e)}
|
||||||
|
>
|
||||||
|
Resend
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
) : props.otpLoader ? (
|
||||||
|
<div className="h-[150px] flex items-center justify-center">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="px-6 py-3 text-base-content">
|
||||||
|
<p className="mb-2 text-sm">Please verify your email !</p>
|
||||||
|
<div className="px-0 mt-3">
|
||||||
|
<button
|
||||||
|
className="op-btn op-btn-primary"
|
||||||
|
type="submit"
|
||||||
|
onClick={() => {
|
||||||
|
props.handleVerifyBtn();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Send OTP
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VerifyEmail;
|
||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
textWidget,
|
textWidget,
|
||||||
widgets
|
widgets
|
||||||
} from "../../constant/Utils";
|
} from "../../constant/Utils";
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
function WidgetComponent({
|
function WidgetComponent({
|
||||||
dragSignature,
|
dragSignature,
|
||||||
signRef,
|
signRef,
|
||||||
@@ -34,8 +33,12 @@ function WidgetComponent({
|
|||||||
handleRoleChange,
|
handleRoleChange,
|
||||||
handleOnBlur,
|
handleOnBlur,
|
||||||
title,
|
title,
|
||||||
|
setSignersData,
|
||||||
isTemplateFlow
|
sendInOrder,
|
||||||
|
isTemplateFlow,
|
||||||
|
setBlockColor,
|
||||||
|
blockColor,
|
||||||
|
setIsAddSigner
|
||||||
}) {
|
}) {
|
||||||
const [isSignersModal, setIsSignersModal] = useState(false);
|
const [isSignersModal, setIsSignersModal] = useState(false);
|
||||||
|
|
||||||
@@ -233,118 +236,101 @@ function WidgetComponent({
|
|||||||
(data) =>
|
(data) =>
|
||||||
data.type !== "dropdown" &&
|
data.type !== "dropdown" &&
|
||||||
data.type !== radioButtonWidget &&
|
data.type !== radioButtonWidget &&
|
||||||
data.type !== textWidget
|
data.type !== textInputWidget
|
||||||
);
|
);
|
||||||
const textWidgetData = widget.filter((data) => data.type !== textWidget);
|
const textWidgetData = widget.filter((data) => data.type !== textWidget);
|
||||||
const updateWidgets = isSignYourself
|
const updateWidgets = isSignYourself
|
||||||
? filterWidgets
|
? filterWidgets
|
||||||
: isTemplateFlow
|
: isTemplateFlow
|
||||||
? textWidgetData
|
? textWidgetData
|
||||||
: widget;
|
: widget;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
!isMailSend && (
|
!isMailSend && (
|
||||||
<div
|
<div
|
||||||
data-tut={dataTut}
|
|
||||||
id="navbar"
|
id="navbar"
|
||||||
className="stickyfooter"
|
className="fixed z-[99] bottom-0 right-0"
|
||||||
style={{ width: window.innerWidth + "px" }}
|
style={{ width: window.innerWidth + "px" }}
|
||||||
>
|
>
|
||||||
{isSigners && (
|
<div className="mx-1">
|
||||||
<div
|
{isSigners && (
|
||||||
data-tut={dataTut}
|
<div
|
||||||
style={{
|
data-tut="recipientArea"
|
||||||
background: isSelectListId
|
className="py-[10px] flex justify-center items-center op-card"
|
||||||
? color[isSelectListId % color.length]
|
|
||||||
: color[0],
|
|
||||||
padding: "10px 20px",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
onClick={() => handleModal()}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
style={{
|
style={{
|
||||||
fontSize: "13px",
|
background: blockColor
|
||||||
fontWeight: "700",
|
? blockColor
|
||||||
textAlign: "center"
|
: isSelectListId
|
||||||
|
? color[isSelectListId % color.length]
|
||||||
|
: color[0]
|
||||||
}}
|
}}
|
||||||
|
onClick={() => handleModal()}
|
||||||
>
|
>
|
||||||
{title ? title : "Recipient"}
|
<span className="text-[13px] font-bold flex items-center">
|
||||||
</span>
|
{title ? title : "Recipient"}
|
||||||
<span
|
{signersdata[isSelectListId]?.Role && (
|
||||||
style={{
|
<div>
|
||||||
fontSize: "13px",
|
{signersdata[isSelectListId]?.Name ? (
|
||||||
fontWeight: "700",
|
<>
|
||||||
display: "flex",
|
:{" "}
|
||||||
alignItems: "center"
|
{signersdata[isSelectListId]?.Name?.length > 12
|
||||||
}}
|
? `${signersdata[isSelectListId].Name.slice(
|
||||||
>
|
0,
|
||||||
{signersdata[isSelectListId]?.Role && (
|
12
|
||||||
<div>
|
)}...`
|
||||||
{signersdata[isSelectListId]?.Name ? (
|
: signersdata[isSelectListId]?.Name}
|
||||||
<>
|
</>
|
||||||
:{" "}
|
) : (
|
||||||
{signersdata[isSelectListId]?.Name?.length > 12
|
<>
|
||||||
? `${signersdata[isSelectListId].Name.slice(
|
:{" "}
|
||||||
0,
|
{signersdata[isSelectListId]?.Role?.length > 12
|
||||||
12
|
? `${signersdata[isSelectListId].Role.slice(
|
||||||
)}...`
|
0,
|
||||||
: signersdata[isSelectListId]?.Name}
|
12
|
||||||
</>
|
)}...`
|
||||||
) : (
|
: signersdata[isSelectListId]?.Role}
|
||||||
<>
|
</>
|
||||||
:{" "}
|
)}
|
||||||
{signersdata[isSelectListId]?.Role?.length > 12
|
</div>
|
||||||
? `${signersdata[isSelectListId].Role.slice(
|
)}
|
||||||
0,
|
<div className="ml-[6px] text-[16px]">
|
||||||
12
|
<i className="fa-light fa-angle-down"></i>
|
||||||
)}...`
|
|
||||||
: signersdata[isSelectListId]?.Role}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</span>
|
||||||
<div style={{ marginLeft: 6, fontSize: 16 }}>
|
</div>
|
||||||
<i className="fa-solid fa-angle-down"></i>
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="mx-1">
|
||||||
|
{handleAddSigner ? (
|
||||||
|
<div
|
||||||
|
data-tut="reactourAddbtn"
|
||||||
|
className="op-btn op-btn-accent w-full my-[2px]"
|
||||||
|
onClick={() => handleAddSigner()}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-plus"></i>
|
||||||
|
<span>Add role</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
setIsAddSigner && (
|
||||||
|
<div
|
||||||
|
data-tut="addRecipient"
|
||||||
|
className="op-btn op-btn-accent w-full my-[2px]"
|
||||||
|
onClick={() => setIsAddSigner(true)}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-plus"></i>
|
||||||
|
<span>Add recipients</span>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
)
|
||||||
</div>
|
)}
|
||||||
)}
|
</div>
|
||||||
{handleAddSigner && (
|
|
||||||
<div
|
|
||||||
data-tut="reactourAddbtn"
|
|
||||||
style={{
|
|
||||||
margin: "5px 0 5px 0",
|
|
||||||
backgroundColor: themeColor,
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
|
|
||||||
onClick={() => handleAddSigner()}
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-plus"></i>
|
|
||||||
<span style={{ marginLeft: 2 }}>Add role</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
data-tut="addWidgets"
|
||||||
ref={scrollContainerRef}
|
ref={scrollContainerRef}
|
||||||
style={{
|
className="bg-base-100 border-[2px] border-t-primary"
|
||||||
background: "white",
|
|
||||||
borderTop: `2px solid ${themeColor}`
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div
|
<div className="flex whitespace-nowrap overflow-x-scroll pt-[10px] pb-[5px] pr-[5px]">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
overflowX: "scroll",
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
padding: "10px 5px 10px 1px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<WidgetList
|
<WidgetList
|
||||||
updateWidgets={updateWidgets}
|
updateWidgets={updateWidgets}
|
||||||
handleDivClick={handleDivClick}
|
handleDivClick={handleDivClick}
|
||||||
@@ -359,17 +345,20 @@ function WidgetComponent({
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<div data-tut={dataTut} className="signerComponent">
|
<div
|
||||||
<div
|
data-tut={dataTut}
|
||||||
style={{
|
className={`${
|
||||||
background: themeColor,
|
isMailSend ? "bg-opacity-50 pointer-events-none" : ""
|
||||||
padding: "5px"
|
} hidden md:block h-full bg-base-100`}
|
||||||
}}
|
>
|
||||||
>
|
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
|
||||||
<span className="signedStyle">Fields</span>
|
<span>Fields</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="signLayoutContainer1">
|
<div
|
||||||
|
className="p-[15px] flex flex-col pt-4 2xl:m-5"
|
||||||
|
data-tut="addWidgets"
|
||||||
|
>
|
||||||
<WidgetList
|
<WidgetList
|
||||||
updateWidgets={updateWidgets}
|
updateWidgets={updateWidgets}
|
||||||
handleDivClick={handleDivClick}
|
handleDivClick={handleDivClick}
|
||||||
@@ -381,35 +370,33 @@ function WidgetComponent({
|
|||||||
)}
|
)}
|
||||||
{isSignersModal && (
|
{isSignersModal && (
|
||||||
<ModalUi
|
<ModalUi
|
||||||
title={"Roles"}
|
title={title ? title : "Recipients"}
|
||||||
isOpen={isSignersModal}
|
isOpen={isSignersModal}
|
||||||
handleClose={handleModal}
|
handleClose={handleModal}
|
||||||
>
|
>
|
||||||
{signersdata.length > 0 ? (
|
{signersdata.length > 0 ? (
|
||||||
<RecipientList
|
<div className="max-h-[600px] overflow-auto pb-1">
|
||||||
signerPos={signerPos}
|
<RecipientList
|
||||||
signersdata={signersdata}
|
signerPos={signerPos}
|
||||||
isSelectListId={isSelectListId}
|
signersdata={signersdata}
|
||||||
setSignerObjId={setSignerObjId}
|
isSelectListId={isSelectListId}
|
||||||
setIsSelectId={setIsSelectId}
|
setSignerObjId={setSignerObjId}
|
||||||
setContractName={setContractName}
|
setIsSelectId={setIsSelectId}
|
||||||
setUniqueId={setUniqueId}
|
setContractName={setContractName}
|
||||||
setRoleName={setRoleName}
|
setUniqueId={setUniqueId}
|
||||||
handleDeleteUser={handleDeleteUser}
|
setRoleName={setRoleName}
|
||||||
handleRoleChange={handleRoleChange}
|
handleDeleteUser={handleDeleteUser}
|
||||||
handleOnBlur={handleOnBlur}
|
handleRoleChange={handleRoleChange}
|
||||||
handleModal={handleModal}
|
handleOnBlur={handleOnBlur}
|
||||||
/>
|
handleModal={handleModal}
|
||||||
|
sendInOrder={sendInOrder}
|
||||||
|
setSignersData={setSignersData}
|
||||||
|
setBlockColor={setBlockColor}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div className=" p-[20px] text-[15px] font-medium text-center">
|
||||||
style={{
|
Please add a {title ? title : "recipients"}
|
||||||
padding: 20,
|
|
||||||
fontSize: 15,
|
|
||||||
fontWeight: "500",
|
|
||||||
textAlign: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Please add a role
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import { getWidgetType } from "../../constant/Utils";
|
|||||||
function WidgetList(props) {
|
function WidgetList(props) {
|
||||||
return props.updateWidgets.map((item, ind) => {
|
return props.updateWidgets.map((item, ind) => {
|
||||||
return (
|
return (
|
||||||
<div key={ind} style={{ marginBottom: "5px" }}>
|
<div className="2xl:p-3 mb-[5px]" key={ind}>
|
||||||
<div
|
<div
|
||||||
className="widgets"
|
className="select-none mx-[2px] md:mx-0 cursor-all-scroll"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
props.addPositionOfSignature &&
|
props.addPositionOfSignature &&
|
||||||
props.addPositionOfSignature("onclick", item);
|
props.addPositionOfSignature("onclick", item);
|
||||||
@@ -22,11 +22,10 @@ function WidgetList(props) {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onMouseMove={props?.handleDivClick}
|
onMouseMove={props?.handleDivClick}
|
||||||
onMouseDown={() => {
|
onMouseDown={() => props?.handleMouseLeave()}
|
||||||
props?.handleMouseLeave();
|
onTouchStart={props?.handleDivClick}
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{item.ref && getWidgetType(item, props?.marginLeft)}
|
{item.ref && getWidgetType(item)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import ModalUi from "../../primitives/ModalUi";
|
|||||||
import "../../styles/AddUser.css";
|
import "../../styles/AddUser.css";
|
||||||
import RegexParser from "regex-parser";
|
import RegexParser from "regex-parser";
|
||||||
import { textInputWidget } from "../../constant/Utils";
|
import { textInputWidget } from "../../constant/Utils";
|
||||||
|
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
||||||
|
import Upgrade from "../../primitives/Upgrade";
|
||||||
|
import { isEnableSubscription } from "../../constant/const";
|
||||||
|
import Tooltip from "../../primitives/Tooltip";
|
||||||
|
|
||||||
const WidgetNameModal = (props) => {
|
const WidgetNameModal = (props) => {
|
||||||
const [formdata, setFormdata] = useState({
|
const [formdata, setFormdata] = useState({
|
||||||
@@ -10,11 +14,11 @@ 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"];
|
||||||
const inputOpt = ["email", "number"];
|
const inputOpt = ["text", "email", "number"];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.defaultdata) {
|
if (props.defaultdata) {
|
||||||
@@ -45,12 +49,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) => {
|
||||||
@@ -70,7 +78,7 @@ const WidgetNameModal = (props) => {
|
|||||||
return "/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/";
|
return "/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/";
|
||||||
case "number":
|
case "number":
|
||||||
return "/^\\d+$/";
|
return "/^\\d+$/";
|
||||||
case textInputWidget:
|
case "text":
|
||||||
return "/^[a-zA-Zs]+$/";
|
return "/^[a-zA-Zs]+$/";
|
||||||
default:
|
default:
|
||||||
return type;
|
return type;
|
||||||
@@ -79,7 +87,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(
|
||||||
@@ -98,14 +106,31 @@ const WidgetNameModal = (props) => {
|
|||||||
handleClose={props.handleClose && props.handleClose}
|
handleClose={props.handleClose && props.handleClose}
|
||||||
title={"Widget info"}
|
title={"Widget info"}
|
||||||
>
|
>
|
||||||
<form onSubmit={handleSubmit} style={{ padding: 20 }}>
|
{(props.defaultdata?.type === textInputWidget ||
|
||||||
<div className="form-section">
|
props.widgetName === textInputWidget) &&
|
||||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
!isEnableSubscription && (
|
||||||
|
<PremiumAlertHeader
|
||||||
|
message={
|
||||||
|
"Field validations are free in beta, this feature will incur a fee later."
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<form
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
className={`${
|
||||||
|
props.defaultdata?.type === textInputWidget ||
|
||||||
|
props.widgetName === textInputWidget
|
||||||
|
? "pt-0"
|
||||||
|
: ""
|
||||||
|
} p-[20px] text-base-content`}
|
||||||
|
>
|
||||||
|
<div className="mb-[0.75rem] text-[13px]">
|
||||||
|
<label htmlFor="name">
|
||||||
Name
|
Name
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
<span className="text-[red]"> *</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
className="addUserInput"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
name="name"
|
name="name"
|
||||||
value={formdata.name}
|
value={formdata.name}
|
||||||
onChange={(e) => handleChange(e)}
|
onChange={(e) => handleChange(e)}
|
||||||
@@ -115,44 +140,55 @@ const WidgetNameModal = (props) => {
|
|||||||
{(props.defaultdata?.type === textInputWidget ||
|
{(props.defaultdata?.type === textInputWidget ||
|
||||||
props.widgetName === textInputWidget) && (
|
props.widgetName === textInputWidget) && (
|
||||||
<>
|
<>
|
||||||
<div className="form-section">
|
<div className="mb-[0.75rem]">
|
||||||
<label htmlFor="textvalidate" style={{ fontSize: 13 }}>
|
<div className="flex items-center gap-1">
|
||||||
Validation
|
<label
|
||||||
</label>
|
htmlFor="textvalidate"
|
||||||
|
className={`${
|
||||||
|
!props.isSubscribe && isEnableSubscription
|
||||||
|
? "bg-opacity-50 pointer-events-none"
|
||||||
|
: ""
|
||||||
|
} text-[13px]`}
|
||||||
|
>
|
||||||
|
Validation
|
||||||
|
</label>
|
||||||
|
<Tooltip
|
||||||
|
url={"https://www.w3schools.com/jsref/jsref_obj_regexp.asp"}
|
||||||
|
/>
|
||||||
|
{!props.isSubscribe && isEnableSubscription && <Upgrade />}
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
className={`${
|
||||||
display: "flex",
|
!props.isSubscribe && isEnableSubscription
|
||||||
flexDirection: "row",
|
? "bg-opacity-50 pointer-events-none"
|
||||||
gap: 10,
|
: ""
|
||||||
marginBottom: "0.5rem"
|
} flex flex-row gap-[10px] mb-[0.5rem]`}
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div style={{ width: "100%", position: "relative" }}>
|
<div className="w-full relative group">
|
||||||
<input
|
<input
|
||||||
className="relative z-20 w-[87%] md:w-[92%] p-2.5 border-[1px] border-[#d1d5db] rounded-l-md outline-none text-xs"
|
className="z-20 relative op-input op-input-bordered rounded-r-none op-input-sm focus:outline-none group-hover:border-base-content w-[87%] md:w-[92%] text-xs"
|
||||||
name="textvalidate"
|
name="textvalidate"
|
||||||
placeholder="Enter custom expression"
|
placeholder="Enter custom regular expression"
|
||||||
value={formdata.textvalidate}
|
value={formdata.textvalidate}
|
||||||
onChange={(e) => handleChange(e)}
|
onChange={(e) => handleChange(e)}
|
||||||
// onBlur={() => handleBlurRegex()}
|
// onBlur={() => handleBlurRegex()}
|
||||||
/>
|
/>
|
||||||
<select
|
<select
|
||||||
className="validationlist addUserInput"
|
className="validationlist op-input op-input-bordered op-input-sm focus:outline-none group-hover:border-base-content w-full text-xs"
|
||||||
name="textvalidate"
|
name="textvalidate"
|
||||||
value={formdata.textvalidate}
|
value={formdata.textvalidate}
|
||||||
onChange={(e) => handleChange(e)}
|
onChange={(e) => handleChange(e)}
|
||||||
onBlur={() => handleBlurRegex()}
|
onBlur={() => handleBlurRegex()}
|
||||||
>
|
>
|
||||||
<option disabled style={{ fontSize: "13px" }}>
|
<option
|
||||||
|
disabled={formdata?.textvalidate}
|
||||||
|
className="text-[13px]"
|
||||||
|
>
|
||||||
Select...
|
Select...
|
||||||
</option>
|
</option>
|
||||||
{inputOpt.map((data, ind) => {
|
{inputOpt.map((data, ind) => {
|
||||||
return (
|
return (
|
||||||
<option
|
<option className="text-[13px]" key={ind} value={data}>
|
||||||
style={{ fontSize: "13px" }}
|
|
||||||
key={ind}
|
|
||||||
value={data}
|
|
||||||
>
|
|
||||||
{data}
|
{data}
|
||||||
</option>
|
</option>
|
||||||
);
|
);
|
||||||
@@ -161,60 +197,46 @@ const WidgetNameModal = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-section">
|
|
||||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
<div className="mb-[0.75rem]">
|
||||||
|
<label htmlFor="name" className="text-[13px]">
|
||||||
Default value
|
Default value
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
className="addUserInput"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
name="defaultValue"
|
name="defaultValue"
|
||||||
value={formdata.defaultValue}
|
value={formdata.defaultValue}
|
||||||
onChange={(e) => handledefaultChange(e)}
|
onChange={(e) => handledefaultChange(e)}
|
||||||
onBlur={() =>
|
autoComplete="off"
|
||||||
isValid === false &&
|
onBlur={() => {
|
||||||
setFormdata({ ...formdata, defaultValue: "" })
|
if (isValid === false) {
|
||||||
}
|
setFormdata({ ...formdata, defaultValue: "" });
|
||||||
|
setIsValid(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
{isValid === false ? (
|
{isValid === false && (
|
||||||
<p style={{ color: "Red", fontSize: 8 }}>
|
<div
|
||||||
invalid default value
|
className="warning defaultvalueWarning"
|
||||||
</p>
|
style={{ fontSize: 12 }}
|
||||||
) : (
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
color: "transparent",
|
|
||||||
fontSize: 10,
|
|
||||||
margin: "3px 8px"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
.
|
<i
|
||||||
</p>
|
className="fa-light fa-exclamation-circle text-[15px]"
|
||||||
|
style={{ color: "#fab005" }}
|
||||||
|
></i>
|
||||||
|
invalid default value
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div className="form-section">
|
<div className="mb-[0.75rem]">
|
||||||
<div
|
<div className="flex flex-row gap-[10px] mb-[0.5rem]">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
gap: 10,
|
|
||||||
marginBottom: "0.5rem"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{statusArr.map((data, ind) => {
|
{statusArr.map((data, ind) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div key={ind} className="flex flex-row gap-[5px] items-center">
|
||||||
key={ind}
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
gap: 5,
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
style={{ accentColor: "red", marginRight: "10px" }}
|
className="mr-[2px] op-radio op-radio-xs"
|
||||||
type="radio"
|
type="radio"
|
||||||
name="status"
|
name="status"
|
||||||
onChange={() =>
|
onChange={() =>
|
||||||
@@ -224,9 +246,7 @@ const WidgetNameModal = (props) => {
|
|||||||
formdata.status.toLowerCase() === data.toLowerCase()
|
formdata.status.toLowerCase() === data.toLowerCase()
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div style={{ fontSize: "13px", fontWeight: "500" }}>
|
<div className="text-[13px] font-medium">{data}</div>
|
||||||
{data}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -234,35 +254,20 @@ const WidgetNameModal = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
{(props.defaultdata?.type === textInputWidget ||
|
{(props.defaultdata?.type === textInputWidget ||
|
||||||
props?.widgetName === textInputWidget) && (
|
props?.widgetName === textInputWidget) && (
|
||||||
<div className="form-section">
|
<div className="mb-[0.75rem]">
|
||||||
<label htmlFor="hint" style={{ fontSize: 13 }}>
|
<label htmlFor="hint" className="text-[13px]">
|
||||||
Hint
|
Hint
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
className="addUserInput"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
name="hint"
|
name="hint"
|
||||||
value={formdata.hint}
|
value={formdata.hint}
|
||||||
onChange={(e) => handleChange(e)}
|
onChange={(e) => handleChange(e)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div
|
<div className="h-[1px] w-full mb-[16px] bg-[#b7b3b3]"></div>
|
||||||
style={{
|
<button type="submit" className="op-btn op-btn-primary">
|
||||||
height: 1,
|
|
||||||
backgroundColor: "#b7b3b3",
|
|
||||||
width: "100%",
|
|
||||||
marginBottom: "16px"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
padding: "5px 20px",
|
|
||||||
backgroundColor: "#32a3ac"
|
|
||||||
}}
|
|
||||||
type="submit"
|
|
||||||
className="finishBtn"
|
|
||||||
>
|
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import Alert from "../../../primitives/Alert";
|
import Alert from "../../../primitives/Alert";
|
||||||
|
import Loader from "../../../primitives/Loader";
|
||||||
|
|
||||||
const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
||||||
const folderPtr = {
|
const folderPtr = {
|
||||||
@@ -25,9 +26,13 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
|||||||
if (parentFolderId) {
|
if (parentFolderId) {
|
||||||
FolderQuery.equalTo("Folder", folderPtr);
|
FolderQuery.equalTo("Folder", folderPtr);
|
||||||
FolderQuery.equalTo("Type", "Folder");
|
FolderQuery.equalTo("Type", "Folder");
|
||||||
|
FolderQuery.notEqualTo("IsArchive", true);
|
||||||
|
FolderQuery.equalTo("CreatedBy", Parse.User.current());
|
||||||
} else {
|
} else {
|
||||||
FolderQuery.doesNotExist("Folder");
|
FolderQuery.doesNotExist("Folder");
|
||||||
FolderQuery.equalTo("Type", "Folder");
|
FolderQuery.equalTo("Type", "Folder");
|
||||||
|
FolderQuery.notEqualTo("IsArchive", true);
|
||||||
|
FolderQuery.equalTo("CreatedBy", Parse.User.current());
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await FolderQuery.find();
|
const res = await FolderQuery.find();
|
||||||
@@ -49,6 +54,7 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
|||||||
const exsitQuery = new Parse.Query(folderCls);
|
const exsitQuery = new Parse.Query(folderCls);
|
||||||
exsitQuery.equalTo("Name", name);
|
exsitQuery.equalTo("Name", name);
|
||||||
exsitQuery.equalTo("Type", "Folder");
|
exsitQuery.equalTo("Type", "Folder");
|
||||||
|
exsitQuery.notEqualTo("IsArchive", true);
|
||||||
if (parentFolderId) {
|
if (parentFolderId) {
|
||||||
exsitQuery.equalTo("Folder", folderPtr);
|
exsitQuery.equalTo("Folder", folderPtr);
|
||||||
}
|
}
|
||||||
@@ -110,20 +116,17 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
|||||||
{isAlert && <Alert type={alert.type}>{alert.message}</Alert>}
|
{isAlert && <Alert type={alert.type}>{alert.message}</Alert>}
|
||||||
<div id="createFolder" className="relative">
|
<div id="createFolder" className="relative">
|
||||||
{isLoader && (
|
{isLoader && (
|
||||||
<div className="absolute h-full w-full flex justify-center items-center ">
|
<div className="absolute h-full w-full flex justify-center items-center">
|
||||||
<div
|
<Loader />
|
||||||
style={{ fontSize: "45px", color: "#3dd3e0" }}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<h1 className="text-base font-semibold">Create Folder</h1>
|
<h1 className="text-base font-semibold mt-[0.4rem]">Create Folder</h1>
|
||||||
<div className="text-xs mt-2">
|
<div className="text-xs mt-2">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
Name<span className="text-red-500 text-[13px]">*</span>
|
Name<span className="text-red-500 text-[13px]">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
value={name}
|
value={name}
|
||||||
onChange={(e) => setName(e.target.value)}
|
onChange={(e) => setName(e.target.value)}
|
||||||
required
|
required
|
||||||
@@ -134,7 +137,7 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
|||||||
<select
|
<select
|
||||||
value={selectedParent}
|
value={selectedParent}
|
||||||
onChange={handleOptions}
|
onChange={handleOptions}
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
>
|
>
|
||||||
<option>select</option>
|
<option>select</option>
|
||||||
{folderList.length > 0 &&
|
{folderList.length > 0 &&
|
||||||
@@ -149,9 +152,9 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
|||||||
<button
|
<button
|
||||||
onClick={handleCreateFolder}
|
onClick={handleCreateFolder}
|
||||||
disabled={isLoader}
|
disabled={isLoader}
|
||||||
className="flex items-center rounded p-2 bg-[#32a3ac] text-white mt-3"
|
className="op-btn op-btn-primary op-btn-sm mt-3"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-plus mr-1"></i>
|
<i className="fa-light fa-plus"></i>
|
||||||
<span>Create</span>
|
<span>Create</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,267 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import Parse from "parse";
|
||||||
|
import CreateFolder from "./CreateFolder";
|
||||||
|
import ModalUi from "../../../primitives/ModalUi";
|
||||||
|
|
||||||
|
const FolderModal = (props) => {
|
||||||
|
const [clickFolder, setClickFolder] = useState("");
|
||||||
|
const [folderList, setFolderList] = useState([]);
|
||||||
|
const [tabList, setTabList] = useState([]);
|
||||||
|
const [isLoader, setIsLoader] = useState(false);
|
||||||
|
const [isAdd, setIsAdd] = useState(false);
|
||||||
|
// below useEffect is called when user open popup
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.isOpenModal) {
|
||||||
|
fetchFolder();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line
|
||||||
|
}, [props.isOpenModal]);
|
||||||
|
|
||||||
|
// `fetchFolder` is used to fetch of folder list created by user on basis of folderPtr or without folderPtr
|
||||||
|
const fetchFolder = async (folderPtr) => {
|
||||||
|
setIsLoader(true);
|
||||||
|
try {
|
||||||
|
const FolderQuery = new Parse.Query(props.folderCls);
|
||||||
|
if (folderPtr) {
|
||||||
|
FolderQuery.equalTo("Folder", folderPtr);
|
||||||
|
FolderQuery.descending("Type");
|
||||||
|
FolderQuery.notEqualTo("IsArchive", true);
|
||||||
|
FolderQuery.equalTo("CreatedBy", Parse.User.current());
|
||||||
|
} else {
|
||||||
|
FolderQuery.doesNotExist("Folder");
|
||||||
|
FolderQuery.descending("Type");
|
||||||
|
FolderQuery.notEqualTo("IsArchive", true);
|
||||||
|
FolderQuery.equalTo("CreatedBy", Parse.User.current());
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await FolderQuery.find();
|
||||||
|
if (res) {
|
||||||
|
const result = JSON.parse(JSON.stringify(res));
|
||||||
|
if (result) {
|
||||||
|
setFolderList(result);
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// `handleSelect` is used to save pointer of folder selected by user and it's path in state
|
||||||
|
const handleSelect = (item) => {
|
||||||
|
setFolderList([]);
|
||||||
|
setClickFolder({ ObjectId: item.objectId, Name: item.Name });
|
||||||
|
if (tabList.length > 0) {
|
||||||
|
const tab = tabList.some((x) => x.objectId === item.objectId);
|
||||||
|
if (!tab) {
|
||||||
|
setTabList((tabs) => [...tabs, item]);
|
||||||
|
const folderPtr = {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: props.folderCls,
|
||||||
|
objectId: item.objectId
|
||||||
|
};
|
||||||
|
fetchFolder(folderPtr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setTabList((tabs) => [...tabs, item]);
|
||||||
|
const folderPtr = {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: props.folderCls,
|
||||||
|
objectId: item.objectId
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchFolder(folderPtr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// `handleSubmit` is used to pass folderPtr to parent component
|
||||||
|
const handleSubmit = () => {
|
||||||
|
let url = "OpenSign™ Drive";
|
||||||
|
tabList.forEach((t) => {
|
||||||
|
url = url + " / " + t.Name;
|
||||||
|
});
|
||||||
|
if (props.onSuccess) {
|
||||||
|
props.onSuccess(clickFolder);
|
||||||
|
}
|
||||||
|
// SetIsOpen(false);
|
||||||
|
props.setIsOpenMoveModal(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// `handleCancel` is used to clear list of folder, close popup and folderUrl
|
||||||
|
const handleCancel = () => {
|
||||||
|
// SetIsOpen(false);
|
||||||
|
props.setIsOpenMoveModal(false);
|
||||||
|
setClickFolder({});
|
||||||
|
setFolderList([]);
|
||||||
|
setTabList([]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// `handleCancel` is call when user click on folder name from path/tab in popup
|
||||||
|
const removeTabListItem = async (e, i) => {
|
||||||
|
e.preventDefault();
|
||||||
|
// setEditable(false);
|
||||||
|
if (!isAdd) {
|
||||||
|
setIsLoader(true);
|
||||||
|
let folderPtr;
|
||||||
|
if (i) {
|
||||||
|
setFolderList([]);
|
||||||
|
let list = tabList.filter((itm, j) => {
|
||||||
|
if (j <= i) {
|
||||||
|
return itm;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _len = list.length - 1;
|
||||||
|
folderPtr = {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: props.folderCls,
|
||||||
|
objectId: list[_len].objectId
|
||||||
|
};
|
||||||
|
setTabList(list);
|
||||||
|
} else {
|
||||||
|
setClickFolder({});
|
||||||
|
setFolderList([]);
|
||||||
|
setTabList([]);
|
||||||
|
}
|
||||||
|
fetchFolder(folderPtr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// `handleCreate` is used to open folder creation form in popup
|
||||||
|
const handleCreate = () => {
|
||||||
|
setIsAdd(!isAdd);
|
||||||
|
};
|
||||||
|
// `handleAddFolder` is call when user folder created successfully and it fetch folder list on the basis of folderPtr or without folderPtr
|
||||||
|
const handleAddFolder = (newFolder) => {
|
||||||
|
props.setPdfData((prev) => [...prev, newFolder?.toJSON()]);
|
||||||
|
if (clickFolder && clickFolder.ObjectId) {
|
||||||
|
fetchFolder({
|
||||||
|
__type: "Pointer",
|
||||||
|
className: props.folderCls,
|
||||||
|
objectId: clickFolder.ObjectId
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
fetchFolder();
|
||||||
|
}
|
||||||
|
handleCreate();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="text-xs mt-2">
|
||||||
|
<ModalUi
|
||||||
|
title={"Select Folder"}
|
||||||
|
isOpen={props.isOpenModal}
|
||||||
|
handleClose={handleCancel}
|
||||||
|
>
|
||||||
|
<div className="w-full min-w-[300px] md:min-w-[500px] max-w-[500px] px-3">
|
||||||
|
<div className="pt-1 text-[#ac4848] text-[14px] font-[500]">
|
||||||
|
<span
|
||||||
|
className="cursor-pointer"
|
||||||
|
title="OpenSign™ Drive"
|
||||||
|
onClick={(e) => removeTabListItem(e)}
|
||||||
|
>
|
||||||
|
OpenSign™ Drive /{" "}
|
||||||
|
</span>
|
||||||
|
{tabList &&
|
||||||
|
tabList.map((tab, i) => (
|
||||||
|
<React.Fragment key={`${tab.objectId}-${i}`}>
|
||||||
|
<span
|
||||||
|
className="cursor-pointer"
|
||||||
|
title={tab.Name}
|
||||||
|
onClick={(e) => removeTabListItem(e, i)}
|
||||||
|
>
|
||||||
|
{tab.Name}
|
||||||
|
</span>
|
||||||
|
{" / "}
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
<hr className="bg-[#8a8a8a] mt-[0.750rem]" />
|
||||||
|
</div>
|
||||||
|
<div className="mt-2 mb-3">
|
||||||
|
<div className="max-h-[210px] overflow-auto">
|
||||||
|
{!isAdd && folderList.length > 0
|
||||||
|
? folderList.map((folder) => (
|
||||||
|
<div
|
||||||
|
key={folder.objectId}
|
||||||
|
className={`${
|
||||||
|
folder.Type === "Folder"
|
||||||
|
? "cursor-pointer"
|
||||||
|
: "cursor-default"
|
||||||
|
} border-b-[1px] border-[#8a8a8a] py-2 mb-0.5"`}
|
||||||
|
onClick={() =>
|
||||||
|
folder.Type === "Folder" && handleSelect(folder)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
{folder.Type === "Folder" ? (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
className="w-[1.4rem] h-[1.4rem] fill-current op-text-secondary"
|
||||||
|
>
|
||||||
|
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 384 512"
|
||||||
|
className="w-[1.4rem] h-[1.4rem] fill-current op-text-primary"
|
||||||
|
>
|
||||||
|
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
<span className="font-semibold">{folder.Name}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
: !isLoader && (
|
||||||
|
<div className="text-base-content text-center my-2">
|
||||||
|
No data found
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{isAdd && (
|
||||||
|
<CreateFolder
|
||||||
|
parentFolderId={clickFolder && clickFolder.ObjectId}
|
||||||
|
folderCls={props.folderCls}
|
||||||
|
onSuccess={handleAddFolder}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{isLoader && (
|
||||||
|
<div className="flex justify-center my-4">
|
||||||
|
<i className="fa-light fa-spinner fa-spin-pulse text-[30px]"></i>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
|
||||||
|
<div
|
||||||
|
className="op-btn op-btn-seconday op-btn-sm"
|
||||||
|
title="Save Here"
|
||||||
|
onClick={handleCreate}
|
||||||
|
>
|
||||||
|
{isAdd ? (
|
||||||
|
<>
|
||||||
|
<i className="fa-light fa-arrow-left" aria-hidden="true"></i>
|
||||||
|
<span className="text-xs">Back</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<i className="fa-light fa-square-plus" aria-hidden="true"></i>
|
||||||
|
<span className="">Add folder</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="op-btn op-btn-primary op-btn-sm"
|
||||||
|
title="Save Here"
|
||||||
|
onClick={handleSubmit}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-save" aria-hidden="true"></i>Save here
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FolderModal;
|
||||||
@@ -44,10 +44,14 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
|||||||
const FolderQuery = new Parse.Query(folderCls);
|
const FolderQuery = new Parse.Query(folderCls);
|
||||||
if (folderPtr) {
|
if (folderPtr) {
|
||||||
FolderQuery.equalTo("Folder", folderPtr);
|
FolderQuery.equalTo("Folder", folderPtr);
|
||||||
FolderQuery.equalTo("Type", "Folder");
|
FolderQuery.notEqualTo("IsArchive", true);
|
||||||
|
FolderQuery.descending("Type");
|
||||||
|
FolderQuery.equalTo("CreatedBy", Parse.User.current());
|
||||||
} else {
|
} else {
|
||||||
FolderQuery.doesNotExist("Folder");
|
FolderQuery.doesNotExist("Folder");
|
||||||
FolderQuery.equalTo("Type", "Folder");
|
FolderQuery.notEqualTo("IsArchive", true);
|
||||||
|
FolderQuery.descending("Type");
|
||||||
|
FolderQuery.equalTo("CreatedBy", Parse.User.current());
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await FolderQuery.find();
|
const res = await FolderQuery.find();
|
||||||
@@ -169,34 +173,41 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
|||||||
{required && <span className="text-red-500 text-[13px]">*</span>}
|
{required && <span className="text-red-500 text-[13px]">*</span>}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative rounded px-[20px] py-[20px] bg-white border border-gray-200 shadow flex max-w-sm gap-8 items-center">
|
<div className="relative max-w-sm">
|
||||||
<div>
|
<div
|
||||||
<i
|
onClick={() => SetIsOpen(true)}
|
||||||
className="far fa-folder-open text-[40px] text-[#33bbff]"
|
className="cursor-pointer rounded px-[20px] py-[20px] bg-base-100 border-[1px] border-base-200 shadow flex max-w-sm gap-8 items-center"
|
||||||
style={{ fontSize: "40px" }}
|
>
|
||||||
aria-hidden="true"
|
<div>
|
||||||
></i>
|
<svg
|
||||||
</div>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<div className="font-semibold ">
|
viewBox="0 0 512 512"
|
||||||
<div className="flex items-center gap-2">
|
className="w-[40px] h-[40px] fill-current op-text-secondary"
|
||||||
<p>
|
>
|
||||||
{selectFolder && selectFolder.Name
|
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
|
||||||
? selectFolder.Name
|
</svg>
|
||||||
: "OpenSign™ Drive"}
|
</div>
|
||||||
</p>
|
<div className="font-semibold ">
|
||||||
<div className="text-black text-sm" onClick={() => SetIsOpen(true)}>
|
<div className="flex items-center gap-2">
|
||||||
<i
|
<p>
|
||||||
className="fa fa-pencil"
|
{selectFolder && selectFolder.Name
|
||||||
title="Select Folder"
|
? selectFolder.Name
|
||||||
aria-hidden="true"
|
: "OpenSign™ Drive"}
|
||||||
></i>
|
</p>
|
||||||
</div>
|
<div className="text-black text-sm">
|
||||||
|
<i
|
||||||
|
className="fa-light fa-pencil cursor-pointer"
|
||||||
|
title="Select Folder"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className="text-[10px] text-gray-400">
|
||||||
|
{selectFolder && selectFolder.Name ? `(${folderPath})` : ""}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-[10px] text-gray-400">
|
|
||||||
{selectFolder && selectFolder.Name ? `(${folderPath})` : ""}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="absolute top-1 right-1 cursor-pointer">
|
<div className="absolute top-2 right-1 cursor-pointer">
|
||||||
<Tooltip
|
<Tooltip
|
||||||
message={
|
message={
|
||||||
"If you do not select a folder, your signed document will be saved in the Main OpenSign drive folder."
|
"If you do not select a folder, your signed document will be saved in the Main OpenSign drive folder."
|
||||||
@@ -210,7 +221,7 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
|||||||
handleClose={handleCancel}
|
handleClose={handleCancel}
|
||||||
>
|
>
|
||||||
<div className="w-full min-w-[300px] md:min-w-[500px] max-w-[500px] px-3">
|
<div className="w-full min-w-[300px] md:min-w-[500px] max-w-[500px] px-3">
|
||||||
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
|
<div className="pt-1 text-[#ac4848] text-[14px] font-[500]">
|
||||||
<span
|
<span
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
title="OpenSign™ Drive"
|
title="OpenSign™ Drive"
|
||||||
@@ -231,27 +242,50 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
|||||||
{" / "}
|
{" / "}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
<hr />
|
<hr className="bg-[#8a8a8a] mt-[0.750rem]" />
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 mb-3">
|
<div className="mb-2">
|
||||||
<div className="max-h-[210px] overflow-auto">
|
<div className="max-h-[210px] overflow-auto">
|
||||||
{!isAdd &&
|
{!isAdd && folderList.length > 0
|
||||||
folderList.length > 0 &&
|
? folderList.map((folder) => (
|
||||||
folderList.map((folder) => (
|
<div
|
||||||
<div
|
key={folder.objectId}
|
||||||
key={folder.Name}
|
className={`${
|
||||||
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer "
|
folder.Type === "Folder"
|
||||||
onClick={() => handleSelect(folder)}
|
? "cursor-pointer"
|
||||||
>
|
: "cursor-default"
|
||||||
<div className="flex items-center gap-2">
|
} border-b-[1px] border-[#8a8a8a] py-2 mb-0.5"`}
|
||||||
<i
|
onClick={() =>
|
||||||
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
|
folder.Type === "Folder" && handleSelect(folder)
|
||||||
aria-hidden="true"
|
}
|
||||||
></i>
|
>
|
||||||
<span className="font-semibold">{folder.Name}</span>
|
<div className="flex items-center gap-2">
|
||||||
|
{folder.Type === "Folder" ? (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
className="w-[1.4rem] h-[1.4rem] fill-current op-text-secondary"
|
||||||
|
>
|
||||||
|
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 384 512"
|
||||||
|
className="w-[1.4rem] h-[1.4rem] fill-current op-text-primary"
|
||||||
|
>
|
||||||
|
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
<span className="font-semibold">{folder.Name}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
))
|
||||||
))}
|
: !isLoader && (
|
||||||
|
<div className="text-base-content text-center my-2">
|
||||||
|
No data found
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{isAdd && (
|
{isAdd && (
|
||||||
<CreateFolder
|
<CreateFolder
|
||||||
@@ -261,8 +295,8 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isLoader && (
|
{isLoader && (
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center my-4">
|
||||||
<i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i>
|
<i className="fa-light fa-spinner fa-spin-pulse text-[30px]"></i>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -270,22 +304,28 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
|||||||
<hr />
|
<hr />
|
||||||
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
|
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
|
||||||
<div
|
<div
|
||||||
className="text-[30px] cursor-pointer text-[#32a3ac]"
|
className="op-btn op-btn-seconday op-btn-sm"
|
||||||
title="Save Here"
|
title="Save Here"
|
||||||
onClick={handleCreate}
|
onClick={handleCreate}
|
||||||
>
|
>
|
||||||
{isAdd ? (
|
{isAdd ? (
|
||||||
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
|
<>
|
||||||
|
<i className="fa-light fa-arrow-left" aria-hidden="true"></i>
|
||||||
|
<span className="text-xs">Back</span>
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
|
<>
|
||||||
|
<i className="fa-light fa-square-plus" aria-hidden="true"></i>
|
||||||
|
<span className="">Add folder</span>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-[30px] cursor-pointer"
|
className="op-btn op-btn-primary op-btn-sm"
|
||||||
title="Save Here"
|
title="Save Here"
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
>
|
>
|
||||||
<i className="fas fa-save" aria-hidden="true"></i>
|
<i className="fa-light fa-save" aria-hidden="true"></i>Save here
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
|
|||||||
@@ -1,18 +1,7 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import "../../../styles/AddUser.css";
|
|
||||||
import AsyncSelect from "react-select/async";
|
import AsyncSelect from "react-select/async";
|
||||||
|
|
||||||
const customStyles = {
|
|
||||||
control: (provided) => ({
|
|
||||||
...provided,
|
|
||||||
fontSize: "13px" // Font size for the control
|
|
||||||
}),
|
|
||||||
option: (provided) => ({
|
|
||||||
...provided,
|
|
||||||
fontSize: "13px" // Font size for the options
|
|
||||||
})
|
|
||||||
};
|
|
||||||
const SelectSigners = (props) => {
|
const SelectSigners = (props) => {
|
||||||
const [userList, setUserList] = useState([]);
|
const [userList, setUserList] = useState([]);
|
||||||
const [selected, setSelected] = useState();
|
const [selected, setSelected] = useState();
|
||||||
@@ -53,9 +42,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
|
||||||
}));
|
}));
|
||||||
@@ -66,32 +68,44 @@ const SelectSigners = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="addusercontainer">
|
<div className="h-full px-[20px] py-[10px] text-base-content">
|
||||||
<div className="form-wrapper">
|
<div className="w-full mx-auto p-[8px]">
|
||||||
<div className="form-section" style={{ marginBottom: 0 }}>
|
<div className="mb-0">
|
||||||
<label style={{ fontSize: 14, fontWeight: "700" }}>Choose User</label>
|
<label className="text-[14px] font-bold">Choose from contacts</label>
|
||||||
<AsyncSelect
|
<AsyncSelect
|
||||||
cacheOptions
|
cacheOptions
|
||||||
defaultOptions
|
defaultOptions
|
||||||
value={selected}
|
value={selected}
|
||||||
loadingMessage={() => "Loading..."}
|
loadingMessage={() => "Loading..."}
|
||||||
noOptionsMessage={() => "User not Found"}
|
noOptionsMessage={() => "Contact not found"}
|
||||||
loadOptions={loadOptions}
|
loadOptions={loadOptions}
|
||||||
onChange={handleOptions}
|
onChange={handleOptions}
|
||||||
styles={customStyles}
|
unstyled
|
||||||
|
classNames={{
|
||||||
|
control: () =>
|
||||||
|
"op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full h-full text-[11px]",
|
||||||
|
valueContainer: () =>
|
||||||
|
"flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]",
|
||||||
|
multiValue: () => "op-badge op-badge-primary h-full text-[11px]",
|
||||||
|
multiValueLabel: () => "mb-[2px]",
|
||||||
|
menu: () =>
|
||||||
|
"mt-1 shadow-md rounded-lg bg-base-200 text-base-content",
|
||||||
|
menuList: () => "shadow-md rounded-lg overflow-hidden",
|
||||||
|
option: () =>
|
||||||
|
"bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2",
|
||||||
|
noOptionsMessage: () => "p-2 bg-base-200 rounded-lg m-1 p-2"
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{isError ? (
|
<p
|
||||||
<p style={{ color: "red", fontSize: "12px", margin: "5px" }}>
|
className={`${
|
||||||
Please select signer
|
isError ? "text-[red]" : "text-transparent"
|
||||||
</p>
|
} text-[11px] ml-[6px] my-[2px]`}
|
||||||
) : (
|
>
|
||||||
<p style={{ color: "transparent", fontSize: "12px", margin: "5px" }}>
|
Please select signer
|
||||||
.
|
</p>
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
<div>
|
<div>
|
||||||
<button className="submitbutton" onClick={() => handleAdd()}>
|
<button className="op-btn op-btn-primary" onClick={() => handleAdd()}>
|
||||||
Submit
|
Submit
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,14 +1,30 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import Select from "react-select";
|
import Select from "react-select";
|
||||||
import AddSigner from "../../AddSigner";
|
import AddSigner from "../../AddSigner";
|
||||||
import Modal from "react-modal";
|
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
|
import Tooltip from "../../../primitives/Tooltip";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
function arrayMove(array, from, to) {
|
function arrayMove(array, from, to) {
|
||||||
array = array.slice();
|
array = array.slice();
|
||||||
array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]);
|
array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]);
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AddSignerModal = ({ isOpen, children }) => {
|
||||||
|
if (!isOpen) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createPortal(
|
||||||
|
<div className="op-modal op-modal-open">
|
||||||
|
<div className="op-modal-box p-0 min-w-[90%] md:min-w-[500px] max-h-90 overflow-y-auto hide-scrollbar text-sm">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>,
|
||||||
|
document.body
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* react-sortable-hoc is depcreated not usable from react 18.x.x
|
* react-sortable-hoc is depcreated not usable from react 18.x.x
|
||||||
* need to replace it with @dnd-kit
|
* need to replace it with @dnd-kit
|
||||||
@@ -16,7 +32,6 @@ function arrayMove(array, from, to) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const SignersInput = (props) => {
|
const SignersInput = (props) => {
|
||||||
Modal.setAppElement("body");
|
|
||||||
const [state, setState] = useState(undefined);
|
const [state, setState] = useState(undefined);
|
||||||
// const [editFormData, setEditFormData] = useState([]);
|
// const [editFormData, setEditFormData] = useState([]);
|
||||||
const [selected, setSelected] = useState([]);
|
const [selected, setSelected] = useState([]);
|
||||||
@@ -104,12 +119,20 @@ const SignersInput = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="text-xs mt-2 ">
|
<div className="text-xs mt-2 ">
|
||||||
<label className="block">
|
<label className="block relative">
|
||||||
Signers
|
Signers
|
||||||
{props.required && <span className="text-red-500 text-[13px]">*</span>}
|
{props.required && <span className="text-red-500 text-[13px]">*</span>}
|
||||||
|
<span className="absolute ml-1 text-xs z-30">
|
||||||
|
<Tooltip
|
||||||
|
id={"signer-tooltip"}
|
||||||
|
message={
|
||||||
|
"Begin typing a contact's name to see suggested signers from your saved contacts or add new ones. Arrange the signing order by adding signers in the desired sequence. Use the '+' button to include signers and the 'x' to remove them. Each signer will receive an email prompt to sign the document in the order listed."
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<div style={{ display: "flex", gap: 5 }}>
|
<div className="flex gap-x-[5px]">
|
||||||
<div style={{ flexWrap: "wrap", width: "100%" }}>
|
<div className="w-full">
|
||||||
<Select
|
<Select
|
||||||
onSortEnd={onSortEnd}
|
onSortEnd={onSortEnd}
|
||||||
distance={4}
|
distance={4}
|
||||||
@@ -119,6 +142,22 @@ const SignersInput = (props) => {
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
closeMenuOnSelect={false}
|
closeMenuOnSelect={false}
|
||||||
required={props.required}
|
required={props.required}
|
||||||
|
noOptionsMessage={() => "Contact not found"}
|
||||||
|
unstyled
|
||||||
|
classNames={{
|
||||||
|
control: () =>
|
||||||
|
"op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full h-full text-[11px]",
|
||||||
|
valueContainer: () =>
|
||||||
|
"flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]",
|
||||||
|
multiValue: () => "op-badge op-badge-primary h-full text-[11px]",
|
||||||
|
multiValueLabel: () => "mb-[2px]",
|
||||||
|
menu: () =>
|
||||||
|
"mt-1 shadow-md rounded-lg bg-base-200 text-base-content",
|
||||||
|
menuList: () => "shadow-md rounded-lg overflow-hidden",
|
||||||
|
option: () =>
|
||||||
|
"bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2",
|
||||||
|
noOptionsMessage: () => "p-2 bg-base-200 rounded-lg m-1 p-2"
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -126,66 +165,29 @@ const SignersInput = (props) => {
|
|||||||
setIsModel(true);
|
setIsModel(true);
|
||||||
openModal();
|
openModal();
|
||||||
}}
|
}}
|
||||||
style={{
|
className="cursor-pointer op-input op-input-bordered focus:outline-none hover:border-base-content max-h-[38px] min-w-[48px] flex justify-center items-center"
|
||||||
cursor: "pointer",
|
|
||||||
borderRadius: 4,
|
|
||||||
border: "1px solid #ccc",
|
|
||||||
minHeight: 38,
|
|
||||||
minWidth: 48,
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<i className="fas fa-plus"></i>
|
<i className="fa-light fa-plus"></i>
|
||||||
</div>
|
</div>
|
||||||
<Modal
|
<AddSignerModal isOpen={modalIsOpen}>
|
||||||
isOpen={modalIsOpen}
|
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||||
onRequestClose={handleModalCloseClick}
|
Add Signer
|
||||||
shouldCloseOnOverlayClick={false}
|
</h3>
|
||||||
id="modal1"
|
<button
|
||||||
contentLabel="Modal"
|
onClick={handleModalCloseClick}
|
||||||
style={{
|
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2"
|
||||||
content: {
|
>
|
||||||
top: "50%",
|
✕
|
||||||
left: "50%",
|
</button>
|
||||||
right: "auto",
|
{isModal && (
|
||||||
bottom: "auto",
|
<AddSigner
|
||||||
transform: "translate(-50%, -50%)",
|
valueKey={"objectId"}
|
||||||
border: "1px transparent",
|
displayKey={"Name"}
|
||||||
padding: 0
|
details={handleNewDetails}
|
||||||
},
|
closePopup={handleModalCloseClick}
|
||||||
overlay: {
|
/>
|
||||||
width: "100%",
|
)}
|
||||||
backgroundColor: "rgba(0, 0, 0, 0.75)",
|
</AddSignerModal>
|
||||||
zIndex: 50
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="min-w-full md:min-w-[500px]">
|
|
||||||
<div
|
|
||||||
className="flex justify-between rounded-t items-center py-[10px] px-[20px] text-white"
|
|
||||||
style={{ background: "#32a3ac" }}
|
|
||||||
>
|
|
||||||
<div className="text-[1.2rem] font-normal">Add Signer</div>
|
|
||||||
<button
|
|
||||||
onClick={handleModalCloseClick}
|
|
||||||
className="text-[1.5rem] cursor-pointer focus:outline-none"
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{isModal && (
|
|
||||||
<AddSigner
|
|
||||||
valueKey={"objectId"}
|
|
||||||
displayKey={"Name"}
|
|
||||||
details={handleNewDetails}
|
|
||||||
closePopup={handleModalCloseClick}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import React, { useState, useEffect, useRef } from "react";
|
||||||
|
import { findContact } from "../../../constant/Utils";
|
||||||
|
const SuggestionInput = (props) => {
|
||||||
|
const [inputValue, setInputValue] = useState(props?.value || "");
|
||||||
|
const [suggestions, setSuggestions] = useState([]);
|
||||||
|
const [showSuggestions, setShowSuggestions] = useState(false);
|
||||||
|
const ref = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.addEventListener("mousedown", Clickout);
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("mousedown", Clickout);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const Clickout = (event) => {
|
||||||
|
if (ref.current && !ref.current.contains(event.target)) {
|
||||||
|
setShowSuggestions(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// create debounce to avoid unnecessay api calls
|
||||||
|
useEffect(() => {
|
||||||
|
let timer;
|
||||||
|
if (inputValue) {
|
||||||
|
if (timer) clearTimeout(timer);
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
(async () => {
|
||||||
|
const res = await findContact(inputValue);
|
||||||
|
if (res?.length > 0) {
|
||||||
|
setSuggestions(res);
|
||||||
|
setShowSuggestions(true);
|
||||||
|
} else {
|
||||||
|
setSuggestions(res);
|
||||||
|
setShowSuggestions(false);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [inputValue]);
|
||||||
|
|
||||||
|
const handleInputChange = async (e) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
setInputValue(value?.toLowerCase());
|
||||||
|
if (props.onChange) {
|
||||||
|
props.onChange(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.trim() === "") {
|
||||||
|
setSuggestions([]);
|
||||||
|
setShowSuggestions(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleSuggestionClick = (suggestion) => {
|
||||||
|
setInputValue(suggestion.Email);
|
||||||
|
setSuggestions([]);
|
||||||
|
setShowSuggestions(false);
|
||||||
|
if (props.onChange) {
|
||||||
|
props.onChange(suggestion);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center relative text-base-content">
|
||||||
|
<input
|
||||||
|
type={props?.type || "text"}
|
||||||
|
value={inputValue}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
placeholder="Enter Email..."
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs lowercase"
|
||||||
|
required={props.required}
|
||||||
|
/>
|
||||||
|
{showSuggestions && (
|
||||||
|
<ul
|
||||||
|
ref={ref}
|
||||||
|
className="absolute z-50 left-0 top-[2.55rem] w-full max-h-[100px] overflow-auto bg-base-200 border border-gray-300 rounded shadow-md"
|
||||||
|
>
|
||||||
|
{suggestions.map((suggestion, index) => (
|
||||||
|
<li
|
||||||
|
key={index}
|
||||||
|
className="py-2 px-2 w-full text-sm cursor-pointer hover:bg-base-300"
|
||||||
|
onClick={() => handleSuggestionClick(suggestion)}
|
||||||
|
>
|
||||||
|
{suggestion.Email}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default SuggestionInput;
|
||||||
@@ -3,14 +3,18 @@ import { NavLink } from "react-router-dom";
|
|||||||
|
|
||||||
const Menu = ({ item, isOpen, closeSidebar }) => {
|
const Menu = ({ item, isOpen, closeSidebar }) => {
|
||||||
return (
|
return (
|
||||||
<li key={item.title} role="none">
|
<li key={item.title} role="none" className="my-0.5">
|
||||||
<NavLink
|
<NavLink
|
||||||
to={
|
to={
|
||||||
item.pageType
|
item.pageType
|
||||||
? `/${item.pageType}/${item.objectId}`
|
? `/${item.pageType}/${item.objectId}`
|
||||||
: `/${item.objectId}`
|
: `/${item.objectId}`
|
||||||
}
|
}
|
||||||
className="mx-auto flex items-center hover:bg-[#eef1f5] p-3 lg:p-4 cursor-pointer"
|
className={({ isActive }) =>
|
||||||
|
`${
|
||||||
|
isActive ? " bg-base-300 text-base-content" : ""
|
||||||
|
} flex items-center text-left p-3 lg:p-4 text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none`
|
||||||
|
}
|
||||||
onClick={closeSidebar}
|
onClick={closeSidebar}
|
||||||
tabIndex={isOpen ? 0 : -1}
|
tabIndex={isOpen ? 0 : -1}
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
|
|
||||||
import Menu from "./Menu";
|
import Menu from "./Menu";
|
||||||
import Submenu from "./SubMenu";
|
import Submenu from "./SubMenu";
|
||||||
import SocialMedia from "./SocialMedia";
|
import SocialMedia from "./SocialMedia";
|
||||||
|
|
||||||
import Parse from "parse";
|
|
||||||
import dp from "../../assets/images/dp.png";
|
import dp from "../../assets/images/dp.png";
|
||||||
|
import sidebarList from "../../json/menuJson";
|
||||||
|
|
||||||
const Sidebar = ({ isOpen, closeSidebar }) => {
|
const Sidebar = ({ isOpen, closeSidebar }) => {
|
||||||
const [menuList, setmenuList] = useState([]);
|
const [menuList, setmenuList] = useState([]);
|
||||||
|
const [submenuOpen, setSubmenuOpen] = useState(false);
|
||||||
let username = localStorage.getItem("username");
|
let username = localStorage.getItem("username");
|
||||||
const image = localStorage.getItem("profileImg") || dp;
|
const image = localStorage.getItem("profileImg") || dp;
|
||||||
const tenantname = localStorage.getItem("TenantName");
|
const tenantname = localStorage.getItem("Extand_Class")
|
||||||
|
? JSON.parse(localStorage.getItem("Extand_Class"))?.[0]?.Company
|
||||||
|
: "";
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (localStorage.getItem("accesstoken")) {
|
if (localStorage.getItem("accesstoken")) {
|
||||||
@@ -21,39 +22,73 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
|
|||||||
|
|
||||||
const menuItem = async () => {
|
const menuItem = async () => {
|
||||||
try {
|
try {
|
||||||
var sideMenu = Parse.Object.extend("w_menu");
|
if (localStorage.getItem("defaultmenuid")) {
|
||||||
var query = new Parse.Query(sideMenu);
|
const menuId = localStorage.getItem("defaultmenuid") !== "VPh91h0ZHk";
|
||||||
query.equalTo("objectId", localStorage.getItem("defaultmenuid"));
|
if (menuId) {
|
||||||
const results = await query.first();
|
setmenuList(sidebarList);
|
||||||
const resultjson = results.toJSON();
|
} else {
|
||||||
let result = resultjson;
|
const addUserForm = {
|
||||||
setmenuList(result.menuItems);
|
icon: "fa-light fa-user",
|
||||||
|
title: "Add User",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "form",
|
||||||
|
description: "",
|
||||||
|
objectId: "lM0xRnM3iE"
|
||||||
|
};
|
||||||
|
const newSidebarList = sidebarList.map((item) => {
|
||||||
|
if (item.title === "Settings") {
|
||||||
|
// Make a shallow copy of the item
|
||||||
|
const newItem = { ...item };
|
||||||
|
// Insert addUserForm at the second position
|
||||||
|
newItem.children.splice(1, 0, addUserForm);
|
||||||
|
return newItem;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
setmenuList(newSidebarList);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Problem", e);
|
console.error("Problem", e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleSubmenu = (title) => {
|
||||||
|
setSubmenuOpen({ [title]: !submenuOpen[title] });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMenuItem = () => {
|
||||||
|
closeSidebar();
|
||||||
|
setSubmenuOpen({});
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<aside
|
<aside
|
||||||
className={`bg-white text-[#444] h-screen w-full md:w-[300px] overflow-y-auto transform transition-transform z-40 md:translate-x-0
|
className={`absolute lg:relative bg-base-100 h-screen overflow-y-auto transition-all z-[999] shadow-lg hide-scrollbar
|
||||||
${isOpen ? "translate-x-0 block" : "-translate-x-full hidden"}`}
|
${isOpen ? "w-full md:w-[300px]" : "w-0"}`}
|
||||||
>
|
>
|
||||||
<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"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-[14px] font-bold">{username}</p>
|
<p className="text-[14px] font-bold text-base-content">{username}</p>
|
||||||
<p className={`text-[12px] ${tenantname ? "mt-2" : ""}`}>
|
<p
|
||||||
|
className={`text-[12px] text-base-content ${
|
||||||
|
tenantname ? "mt-2" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
{tenantname}
|
{tenantname}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<nav aria-label="OpenSign Sidebar Navigation">
|
<nav
|
||||||
|
className="op-menu op-menu-sm"
|
||||||
|
aria-label="OpenSign Sidebar Navigation"
|
||||||
|
>
|
||||||
<ul
|
<ul
|
||||||
className="text-sm"
|
className="text-sm"
|
||||||
role="menubar"
|
role="menubar"
|
||||||
@@ -65,19 +100,21 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
|
|||||||
key={item.title}
|
key={item.title}
|
||||||
item={item}
|
item={item}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
closeSidebar={closeSidebar}
|
closeSidebar={handleMenuItem}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Submenu
|
<Submenu
|
||||||
key={item.title}
|
key={item.title}
|
||||||
item={item}
|
item={item}
|
||||||
closeSidebar={closeSidebar}
|
closeSidebar={closeSidebar}
|
||||||
|
toggleSubmenu={toggleSubmenu}
|
||||||
|
submenuOpen={submenuOpen}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<footer className="mt-4 flex justify-center items-center text-[25px] text-black gap-3">
|
<footer className="mt-4 flex justify-center items-center text-[25px] text-base-content gap-3">
|
||||||
<SocialMedia />
|
<SocialMedia />
|
||||||
</footer>
|
</footer>
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@@ -1,19 +1,13 @@
|
|||||||
import React, { useState } from "react";
|
import React from "react";
|
||||||
import { NavLink } from "react-router-dom";
|
import { NavLink } from "react-router-dom";
|
||||||
|
|
||||||
const Submenu = ({ item, closeSidebar }) => {
|
const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
|
||||||
const [submenuOpen, setSubmenuOpen] = useState(false);
|
|
||||||
const { title, icon, children } = item;
|
const { title, icon, children } = item;
|
||||||
|
|
||||||
const toggleSubmenu = () => {
|
|
||||||
setSubmenuOpen(!submenuOpen);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li role="none">
|
<li role="none" className="my-0.5">
|
||||||
<button
|
<button
|
||||||
onClick={toggleSubmenu}
|
onClick={() => toggleSubmenu(item.title)}
|
||||||
className="w-full flex items-center text-left text-[#444] p-3 lg:p-4 hover:bg-[#eef1f5] focus:ring-2 focus:ring-blue-600"
|
className="flex items-center text-left p-3 lg:p-4 text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none "
|
||||||
aria-expanded={submenuOpen}
|
aria-expanded={submenuOpen}
|
||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
aria-controls={`submenu-${title}`}
|
aria-controls={`submenu-${title}`}
|
||||||
@@ -23,23 +17,29 @@ const Submenu = ({ item, closeSidebar }) => {
|
|||||||
<span className="ml-3 lg:ml-4">{title}</span>
|
<span className="ml-3 lg:ml-4">{title}</span>
|
||||||
<i
|
<i
|
||||||
className={`${
|
className={`${
|
||||||
submenuOpen ? "fa-solid fa-angle-down" : "fa-solid fa-angle-right"
|
submenuOpen[item.title]
|
||||||
|
? "fa-light fa-angle-down"
|
||||||
|
: "fa-light fa-angle-right"
|
||||||
}`}
|
}`}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
{submenuOpen && (
|
{submenuOpen[item.title] && (
|
||||||
<ul id={`submenu-${title}`} role="menu" aria-label={`${title} submenu`}>
|
<ul id={`submenu-${title}`} role="menu" aria-label={`${title} submenu`}>
|
||||||
{children.map((childItem) => (
|
{children.map((childItem) => (
|
||||||
<li key={childItem.title} role="none">
|
<li key={childItem.title} role="none" className="my-0.5">
|
||||||
<NavLink
|
<NavLink
|
||||||
to={
|
to={
|
||||||
childItem.pageType
|
childItem.pageType
|
||||||
? `/${childItem.pageType}/${childItem.objectId}`
|
? `/${childItem.pageType}/${childItem.objectId}`
|
||||||
: `/${childItem.objectId}`
|
: `/${childItem.objectId}`
|
||||||
}
|
}
|
||||||
className="block pl-6 md:pl-8 py-2 text-sm text-gray-700 hover:bg-blue-500 hover:text-white cursor-pointer"
|
className={({ isActive }) =>
|
||||||
|
`${
|
||||||
|
isActive ? "bg-base-300 text-base-content" : ""
|
||||||
|
} flex items-center text-left pl-6 md:pl-8 py-2 text-sm cursor-pointer text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none`
|
||||||
|
}
|
||||||
onClick={closeSidebar}
|
onClick={closeSidebar}
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
tabIndex={submenuOpen ? 0 : -1}
|
tabIndex={submenuOpen ? 0 : -1}
|
||||||
|
|||||||
+1005
-393
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,6 @@
|
|||||||
export const contactCls = "contracts_Contactbook";
|
export const contactCls = "contracts_Contactbook";
|
||||||
export const templateCls = "contracts_Template";
|
export const templateCls = "contracts_Template";
|
||||||
export const documentCls = "contracts_Document";
|
export const documentCls = "contracts_Document";
|
||||||
export const rejectBtn =
|
|
||||||
"bg-[#ffffff] rounded-sm shadow-md text-[12px] font-semibold uppercase text-black py-1.5 px-4 focus:outline-none text-center border-[1px] border-[#b4b4b4]";
|
|
||||||
export const submitBtn =
|
|
||||||
"bg-[#32a3ac] rounded-sm shadow-md text-[12px] font-semibold uppercase text-white py-1.5 px-4 focus:outline-none text-center";
|
|
||||||
export const modalSubmitBtnColor = "#17a2b8";
|
|
||||||
export const modalCancelBtnColor = "white";
|
|
||||||
export const themeColor = "#47a3ad";
|
export const themeColor = "#47a3ad";
|
||||||
export const iconColor = "#686968";
|
export const iconColor = "#686968";
|
||||||
|
export const isEnableSubscription = process.env.REACT_APP_ENABLE_SUBSCRIPTION;
|
||||||
|
|||||||
@@ -1,27 +1,30 @@
|
|||||||
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) => {
|
export const SaveFileSize = async (size, imageUrl, tenantId) => {
|
||||||
//checking server url and save file's size
|
//checking server url and save file's size
|
||||||
|
const tenantPtr = {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: "partners_Tenant",
|
||||||
|
objectId: tenantId
|
||||||
|
};
|
||||||
|
const _tenantPtr = JSON.stringify(tenantPtr);
|
||||||
try {
|
try {
|
||||||
const response = await axios
|
const res = await axios.get(
|
||||||
.get(`${serverUrl}classes/partners_TenantCredits`, {
|
`${serverUrl}/classes/partners_TenantCredits?where={"PartnersTenant":${_tenantPtr}}`,
|
||||||
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": parseAppId
|
"X-Parse-Application-Id": parseAppId
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.then((result) => {
|
);
|
||||||
const res = result.data;
|
const response = res.data.results;
|
||||||
// console.log("res", res);
|
|
||||||
|
|
||||||
return res.results;
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log("axois err ", err);
|
|
||||||
});
|
|
||||||
let data;
|
let data;
|
||||||
// console.log("response", response);
|
// console.log("response", response);
|
||||||
if (response && response.length > 0) {
|
if (response && response.length > 0) {
|
||||||
@@ -30,69 +33,48 @@ export const SaveFileSize = async (size, imageUrl) => {
|
|||||||
? response[0].usedStorage + size
|
? response[0].usedStorage + size
|
||||||
: size
|
: size
|
||||||
};
|
};
|
||||||
await axios
|
await axios.put(
|
||||||
.put(
|
`${serverUrl}/classes/partners_TenantCredits/${response[0].objectId}`,
|
||||||
`${serverUrl}classes/partners_TenantCredits/${response[0].objectId}`,
|
data,
|
||||||
data,
|
{
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
// const res = result.data;
|
|
||||||
// console.log("save res", res);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log("axois err ", err);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
data = {
|
|
||||||
usedStorage: size
|
|
||||||
};
|
|
||||||
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
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.then(() => {
|
);
|
||||||
// const res = result.data;
|
} else {
|
||||||
// console.log("res", res);
|
data = { usedStorage: size, PartnersTenant: tenantPtr };
|
||||||
})
|
await axios.post(`${serverUrl}/classes/partners_TenantCredits`, data, {
|
||||||
.catch((err) => {
|
headers: {
|
||||||
console.log("axois err ", err);
|
"Content-Type": "application/json",
|
||||||
});
|
"X-Parse-Application-Id": parseAppId
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
console.log("org app error", e);
|
console.log("err in save usage", err);
|
||||||
}
|
}
|
||||||
saveDataFile(size, imageUrl);
|
saveDataFile(size, imageUrl, tenantPtr);
|
||||||
};
|
};
|
||||||
|
|
||||||
//function for save fileUrl and file size in particular client db class partners_DataFiles
|
//function for save fileUrl and file size in particular client db class partners_DataFiles
|
||||||
const saveDataFile = async (size, imageUrl) => {
|
const saveDataFile = async (size, imageUrl, tenantPtr) => {
|
||||||
const data = {
|
const data = {
|
||||||
FileUrl: imageUrl,
|
FileUrl: imageUrl,
|
||||||
FileSize: size
|
FileSize: size,
|
||||||
|
TenantPtr: tenantPtr
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log("data save",file, data)
|
// console.log("data save",file, data)
|
||||||
await axios
|
try {
|
||||||
.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
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
// const res = result.data;
|
|
||||||
// console.log("res", res);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log("axois err ", err);
|
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in save usage ", err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,17 +2,72 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
body{
|
body {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Custom CSS to hide scrollbar */
|
/* Custom CSS to hide scrollbar */
|
||||||
.hide-scrollbar::-webkit-scrollbar {
|
.hide-scrollbar::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
|
||||||
|
|
||||||
.hide-scrollbar {
|
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
|
||||||
scrollbar-width: none; /* Firefox */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hide-scrollbar {
|
||||||
|
-ms-overflow-style: none; /* IE and Edge */
|
||||||
|
scrollbar-width: none; /* Firefox */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* below css class replace bootstrap background color with daisy */
|
||||||
|
.op-bg-primary {
|
||||||
|
@apply bg-primary;
|
||||||
|
}
|
||||||
|
.op-bg-secondary {
|
||||||
|
@apply bg-secondary;
|
||||||
|
}
|
||||||
|
.op-bg-info {
|
||||||
|
@apply bg-info;
|
||||||
|
}
|
||||||
|
.op-bg-success{
|
||||||
|
@apply bg-success;
|
||||||
|
}
|
||||||
|
.op-bg-warning {
|
||||||
|
@apply bg-warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* below css class replace bootstrap text color with daisy */
|
||||||
|
.op-text-primary {
|
||||||
|
@apply text-primary;
|
||||||
|
}
|
||||||
|
.op-text-secondary {
|
||||||
|
@apply text-secondary;
|
||||||
|
}
|
||||||
|
.op-text-info {
|
||||||
|
@apply text-info;
|
||||||
|
}
|
||||||
|
.op-text-success{
|
||||||
|
@apply text-success;
|
||||||
|
}
|
||||||
|
.op-text-warning {
|
||||||
|
@apply text-warning;
|
||||||
|
}
|
||||||
|
.op-border-primary{
|
||||||
|
@apply border-primary
|
||||||
|
}
|
||||||
|
/* CSS for scrollbar customization */
|
||||||
|
* {
|
||||||
|
scrollbar-width: thin; /* For Firefox */
|
||||||
|
scrollbar-color: gray; /* For Firefox */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For webkit-based browsers like Chrome, Safari */
|
||||||
|
*::-webkit-scrollbar {
|
||||||
|
width: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-webkit-scrollbar-track {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-webkit-scrollbar-thumb {
|
||||||
|
background-color: gray;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
@@ -15,6 +16,7 @@ import {
|
|||||||
import DragElement from "./components/pdf/DragElement";
|
import DragElement from "./components/pdf/DragElement";
|
||||||
import TagManager from "react-gtm-module";
|
import TagManager from "react-gtm-module";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
|
import './polyfills'
|
||||||
const appId = process.env.REACT_APP_APPID
|
const appId = process.env.REACT_APP_APPID
|
||||||
? process.env.REACT_APP_APPID
|
? process.env.REACT_APP_APPID
|
||||||
: "opensign";
|
: "opensign";
|
||||||
@@ -62,10 +64,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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export default function reportJson(id) {
|
|||||||
const head = ["Sr.No", "Title", "Note", "Folder", "File", "Owner", "Signers"];
|
const head = ["Sr.No", "Title", "Note", "Folder", "File", "Owner", "Signers"];
|
||||||
const contactbook = ["Sr.No", "Title", "Email", "Phone"];
|
const contactbook = ["Sr.No", "Title", "Email", "Phone"];
|
||||||
const dashboardReportHead = ["Title", "File", "Owner", "Signers"];
|
const dashboardReportHead = ["Title", "File", "Owner", "Signers"];
|
||||||
|
const templateReport = ["Sr.No", "Title", "File", "Owner", "Signers"];
|
||||||
switch (id) {
|
switch (id) {
|
||||||
// draft documents report
|
// draft documents report
|
||||||
case "ByHuevtCFY":
|
case "ByHuevtCFY":
|
||||||
@@ -12,13 +12,24 @@ export default function reportJson(id) {
|
|||||||
heading: head,
|
heading: head,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "sign",
|
btnId: "1231",
|
||||||
btnColor: "#4bd396",
|
hoverLabel: "Edit",
|
||||||
textColor: "white",
|
btnColor: "op-btn-primary",
|
||||||
btnIcon: "fa fa-plus",
|
btnIcon: "fa-light fa-pen",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "2142",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnColor: "op-btn-secondary",
|
||||||
|
btnIcon: "fa-light fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
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":
|
||||||
@@ -27,13 +38,17 @@ export default function reportJson(id) {
|
|||||||
heading: head,
|
heading: head,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
btnId: "4536",
|
||||||
btnLabel: "sign",
|
btnLabel: "sign",
|
||||||
btnColor: "#3ac9d6",
|
hoverLabel: "Sign",
|
||||||
textColor: "white",
|
btnColor: "op-btn-primary",
|
||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa-light fa-signature",
|
||||||
redirectUrl: "pdfRequestFiles"
|
redirectUrl: "pdfRequestFiles",
|
||||||
|
action: "redirect"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
helpMsg:
|
||||||
|
"This is a list of documents that are waiting for your signature"
|
||||||
};
|
};
|
||||||
// In progess report
|
// In progess report
|
||||||
case "1MwEuxLEkF":
|
case "1MwEuxLEkF":
|
||||||
@@ -42,13 +57,58 @@ export default function reportJson(id) {
|
|||||||
heading: head,
|
heading: head,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "View",
|
btnId: "8901",
|
||||||
btnColor: "#3ac9d6",
|
hoverLabel: "Share",
|
||||||
textColor: "white",
|
btnColor: "op-btn-primary",
|
||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa-light fa-share",
|
||||||
redirectUrl: "pdfRequestFiles"
|
redirectUrl: "",
|
||||||
|
action: "share"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1588",
|
||||||
|
hoverLabel: "View",
|
||||||
|
btnColor: "op-btn-secondary",
|
||||||
|
btnIcon: "fa-light fa-eye",
|
||||||
|
redirectUrl: "pdfRequestFiles",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "2234",
|
||||||
|
hoverLabel: "option",
|
||||||
|
btnColor: "",
|
||||||
|
textColor: "black",
|
||||||
|
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
|
||||||
|
action: "option",
|
||||||
|
subaction: [
|
||||||
|
{
|
||||||
|
btnId: "1630",
|
||||||
|
btnLabel: "Resend",
|
||||||
|
hoverLabel: "Resend",
|
||||||
|
btnIcon: "fa-light fa-envelope",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "resend"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1688",
|
||||||
|
btnLabel: "Revoke",
|
||||||
|
hoverLabel: "Revoke",
|
||||||
|
btnIcon: "fa-light fa-file-circle-xmark",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "revoke"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1488",
|
||||||
|
btnLabel: "Delete",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnIcon: "fa-light fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
helpMsg:
|
||||||
|
"This is a list of documents you've sent to other parties for signature."
|
||||||
};
|
};
|
||||||
// completed documents report
|
// completed documents report
|
||||||
case "kQUoW4hUXz":
|
case "kQUoW4hUXz":
|
||||||
@@ -57,13 +117,24 @@ export default function reportJson(id) {
|
|||||||
heading: head,
|
heading: head,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "View",
|
btnId: "1378",
|
||||||
btnColor: "#4bd396",
|
hoverLabel: "Edit",
|
||||||
textColor: "white",
|
btnColor: "op-btn-primary",
|
||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa-light fa-eye",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1278",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnColor: "op-btn-secondary",
|
||||||
|
btnIcon: "fa-light fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
helpMsg:
|
||||||
|
"This is a list of documents that have been signed by all parties."
|
||||||
};
|
};
|
||||||
// declined documents report
|
// declined documents report
|
||||||
case "UPr2Fm5WY3":
|
case "UPr2Fm5WY3":
|
||||||
@@ -72,13 +143,24 @@ export default function reportJson(id) {
|
|||||||
heading: head,
|
heading: head,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "View",
|
btnId: "1458",
|
||||||
btnColor: "#4bd396",
|
hoverLabel: "View",
|
||||||
textColor: "white",
|
btnColor: "op-btn-primary",
|
||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa-light fa-eye",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1358",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnColor: "op-btn-secondary",
|
||||||
|
btnIcon: "fa-light fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
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":
|
||||||
@@ -87,13 +169,24 @@ export default function reportJson(id) {
|
|||||||
heading: head,
|
heading: head,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "View",
|
btnId: "1898",
|
||||||
btnColor: "#4bd396",
|
hoverLabel: "View",
|
||||||
textColor: "white",
|
btnColor: "op-btn-primary",
|
||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa-light fa-eye",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1998",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnColor: "op-btn-secondary",
|
||||||
|
btnIcon: "fa-light fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
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":
|
||||||
@@ -102,11 +195,54 @@ export default function reportJson(id) {
|
|||||||
heading: dashboardReportHead,
|
heading: dashboardReportHead,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "View",
|
btnId: "1999",
|
||||||
btnColor: "#4bd396",
|
hoverLabel: "Share",
|
||||||
textColor: "white",
|
btnColor: "op-btn-primary",
|
||||||
btnIcon: "fa fa-eye",
|
btnIcon: "fa-light fa-share",
|
||||||
redirectUrl: "pdfRequestFiles"
|
redirectUrl: "",
|
||||||
|
action: "share"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1999",
|
||||||
|
hoverLabel: "View",
|
||||||
|
btnColor: "op-btn-secondary",
|
||||||
|
btnIcon: "fa-light fa-eye",
|
||||||
|
redirectUrl: "pdfRequestFiles",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "2234",
|
||||||
|
hoverLabel: "option",
|
||||||
|
btnColor: "",
|
||||||
|
textColor: "black",
|
||||||
|
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
|
||||||
|
action: "option",
|
||||||
|
subaction: [
|
||||||
|
{
|
||||||
|
btnId: "1631",
|
||||||
|
btnLabel: "Resend",
|
||||||
|
hoverLabel: "Resend",
|
||||||
|
btnIcon: "fa-light fa-envelope",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "resend"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "6788",
|
||||||
|
btnLabel: "Revoke",
|
||||||
|
hoverLabel: "Revoke",
|
||||||
|
btnIcon: "fa-light fa-file-circle-xmark",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "revoke"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "2000",
|
||||||
|
btnLabel: "Delete",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnIcon: "fa-light fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@@ -117,11 +253,13 @@ export default function reportJson(id) {
|
|||||||
heading: dashboardReportHead,
|
heading: dashboardReportHead,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "Sign",
|
btnId: "2001",
|
||||||
btnColor: "#4bd396",
|
btnLabel: "sign",
|
||||||
textColor: "white",
|
hoverLabel: "Sign",
|
||||||
btnIcon: "fa fa-eye",
|
btnColor: "op-btn-primary",
|
||||||
redirectUrl: "pdfRequestFiles"
|
btnIcon: "fa-light fa-signature",
|
||||||
|
redirectUrl: "pdfRequestFiles",
|
||||||
|
action: "redirect"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@@ -132,11 +270,20 @@ 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",
|
||||||
btnColor: "#4bd396",
|
hoverLabel: "Edit",
|
||||||
textColor: "white",
|
btnColor: "op-btn-primary",
|
||||||
btnIcon: "fa fa-plus",
|
btnIcon: "fa-light fa-pen",
|
||||||
redirectUrl: "draftDocument"
|
redirectUrl: "draftDocument",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "2004",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnColor: "op-btn-secondary",
|
||||||
|
btnIcon: "fa-light fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@@ -147,35 +294,79 @@ export default function reportJson(id) {
|
|||||||
heading: contactbook,
|
heading: contactbook,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
btnLabel: "",
|
btnId: "2204",
|
||||||
btnColor: "#f55a42",
|
hoverLabel: "Delete",
|
||||||
textColor: "white",
|
btnColor: "op-btn-secondary",
|
||||||
btnIcon: "fa-solid fa-trash"
|
btnIcon: "fa-light 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."
|
||||||
};
|
};
|
||||||
// template report
|
// template report
|
||||||
case "6TeaPr321t":
|
case "6TeaPr321t":
|
||||||
return {
|
return {
|
||||||
reportName: "Templates",
|
reportName: "Templates",
|
||||||
heading: head,
|
heading: templateReport,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
btnId: "2234",
|
||||||
btnLabel: "Use",
|
btnLabel: "Use",
|
||||||
btnColor: "#4bd396",
|
hoverLabel: "Use",
|
||||||
textColor: "white",
|
btnColor: "op-btn-primary",
|
||||||
btnIcon: "fa fa-plus",
|
btnIcon: "fa-light 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: "1631",
|
||||||
btnColor: "#00c9d5",
|
btnLabel: "Quick send",
|
||||||
textColor: "white",
|
hoverLabel: "Quick send",
|
||||||
btnIcon: "fa fa-plus",
|
btnColor: "op-btn-secondary",
|
||||||
redirectUrl: "template"
|
btnIcon: "fa-light fa-envelope",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "bulksend",
|
||||||
|
selector: "tourbulksend",
|
||||||
|
message:
|
||||||
|
"To quickly create and send multiple documents using an existing template, click the 'Quick Send' button."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "2234",
|
||||||
|
hoverLabel: "option",
|
||||||
|
btnColor: "",
|
||||||
|
textColor: "black",
|
||||||
|
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
|
||||||
|
action: "option",
|
||||||
|
selector: "reactourThird",
|
||||||
|
message:
|
||||||
|
"This menu reveals more options such as Edit & Delete. Use the 'Edit' button to add signer roles, modify fields, and update your template. Changes will apply to all future documents created from this template but won’t affect existing documents.Use the Delete button you can delete template. ",
|
||||||
|
subaction: [
|
||||||
|
{
|
||||||
|
btnId: "2434",
|
||||||
|
btnLabel: "Edit",
|
||||||
|
hoverLabel: "Edit",
|
||||||
|
btnIcon: "fa-light fa-pen",
|
||||||
|
redirectUrl: "template",
|
||||||
|
action: "redirect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "1834",
|
||||||
|
btnLabel: "Delete",
|
||||||
|
hoverLabel: "Delete",
|
||||||
|
btnIcon: "fa-light fa-trash",
|
||||||
|
redirectUrl: "",
|
||||||
|
action: "delete"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
helpMsg:
|
||||||
|
"This is a list of templates that are available to you for creating documents. You can click the 'use' button to create a new document using a template, modify the document & add signers in the next step."
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
const dashboardJson = [
|
||||||
|
{
|
||||||
|
id: "35KBoSgoAK",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
|
||||||
|
widget: {
|
||||||
|
type: "Card",
|
||||||
|
icon: "fa-light fa-signature",
|
||||||
|
bgColor: "op-bg-primary",
|
||||||
|
label: "Need your Signature",
|
||||||
|
description: null,
|
||||||
|
data: {
|
||||||
|
id: "e04ee9dc-932d-6b80-0202-703fd154eb74",
|
||||||
|
queryType: "",
|
||||||
|
class: "contracts_Document",
|
||||||
|
query:
|
||||||
|
'where={"$and":[{"AuditTrail.UserPtr":{"$ne":{"__type":"Pointer","className": "contracts_Users","objectId":"#objectId#"}}},{"AuditTrail.Activity":{"$ne":"Signed"}}],"Signers":{"$in":[{"__type":"Pointer","className":"contracts_Users","objectId":"#objectId#"}]},"IsDeclined":{"$ne":true},"IsCompleted":{"$ne":true},"Type":{"$ne":"Folder"},"Placeholders":{"$ne":null},"ExpiryDate":{"#*gt":{"__type":"#Date#","iso":"#today#"}}}&count=1',
|
||||||
|
key: "count",
|
||||||
|
Redirect_type: "Report",
|
||||||
|
Redirect_id: "4Hhwbp482K",
|
||||||
|
tourSection: "tourcard1",
|
||||||
|
tourMessage:
|
||||||
|
"Clicking on this card will take you to the list of documents awaiting your review."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
|
||||||
|
widget: {
|
||||||
|
type: "Card",
|
||||||
|
icon: "fa-light fa-sign-out-alt",
|
||||||
|
bgColor: "op-bg-secondary",
|
||||||
|
label: "Out for signatures",
|
||||||
|
description: null,
|
||||||
|
data: {
|
||||||
|
id: "c1935cc0-28d4-3d73-b72a-8c1e3d18a17f",
|
||||||
|
queryType: "",
|
||||||
|
class: "contracts_Document",
|
||||||
|
query:
|
||||||
|
'where={"Type":{"#*ne":"Folder"},"Signers":{"#*exists":true,"#*ne":[]},"Placeholders":{"#*ne":null},"IsCompleted":{"#*ne":true},"IsDeclined":{"#*ne":true},"IsArchive":{"#*ne":true},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"#UserId.objectId#"},"ExpiryDate":{"#*gt":{"__type":"#Date#","iso":"#today#"}}}&count=1',
|
||||||
|
key: "count",
|
||||||
|
Redirect_type: "Report",
|
||||||
|
Redirect_id: "1MwEuxLEkF",
|
||||||
|
tourSection: "tourcard2",
|
||||||
|
tourMessage:
|
||||||
|
"Clicking on this card will take you to a list of documents awaiting signature."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
|
||||||
|
widget: {
|
||||||
|
type: "report",
|
||||||
|
reportId: "5Go51Q7T8r",
|
||||||
|
data: {
|
||||||
|
tourSection: "tourreport1",
|
||||||
|
tourMessage:
|
||||||
|
"This is a list of documents that are waiting for your signature."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
|
||||||
|
widget: {
|
||||||
|
type: "report",
|
||||||
|
reportId: "d9k3UfYHBc",
|
||||||
|
data: {
|
||||||
|
tourSection: "tourreport2",
|
||||||
|
tourMessage:
|
||||||
|
"This is a list of documents you've sent to other parties for signature."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colsize: "col-span-12 md:col-span-12 lg:col-span-12",
|
||||||
|
widget: {
|
||||||
|
type: "report",
|
||||||
|
reportId: "kC5mfynCi4",
|
||||||
|
data: {
|
||||||
|
tourSection: "tourreport3",
|
||||||
|
tourMessage:
|
||||||
|
"This are documents you have started but have not finalized for sending."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
export default dashboardJson;
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
const sidebarList = [
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-tachometer-alt",
|
||||||
|
title: "Dashboard",
|
||||||
|
target: "",
|
||||||
|
pageType: "dashboard",
|
||||||
|
description: "",
|
||||||
|
objectId: "35KBoSgoAK"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-pen-nib",
|
||||||
|
title: "Sign yourself",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "form",
|
||||||
|
description: "",
|
||||||
|
objectId: "sHAnZphf69"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-paper-plane",
|
||||||
|
title: "Request signatures",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "form",
|
||||||
|
description: "",
|
||||||
|
objectId: "8mZzFxbG1z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-newspaper",
|
||||||
|
title: "Templates",
|
||||||
|
target: "_self",
|
||||||
|
pageType: null,
|
||||||
|
description: null,
|
||||||
|
objectId: null,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-file-signature",
|
||||||
|
title: "Create template",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "form",
|
||||||
|
description: "",
|
||||||
|
objectId: "template"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-file-contract",
|
||||||
|
title: "Manage templates",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "report",
|
||||||
|
description: "",
|
||||||
|
objectId: "6TeaPr321t"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-folder",
|
||||||
|
title: "OpenSign™ Drive",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "",
|
||||||
|
description: "",
|
||||||
|
objectId: "opensigndrive"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-address-card",
|
||||||
|
title: "Reports",
|
||||||
|
target: "_self",
|
||||||
|
pageType: null,
|
||||||
|
description: "",
|
||||||
|
objectId: null,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-signature",
|
||||||
|
title: "Need your sign",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "report",
|
||||||
|
description: "",
|
||||||
|
objectId: "4Hhwbp482K"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-tasks",
|
||||||
|
title: "In Progress",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "report",
|
||||||
|
description: "",
|
||||||
|
objectId: "1MwEuxLEkF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-check-circle",
|
||||||
|
title: "Completed",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "report",
|
||||||
|
description: "",
|
||||||
|
objectId: "kQUoW4hUXz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-edit",
|
||||||
|
title: "Drafts",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "report",
|
||||||
|
description: "",
|
||||||
|
objectId: "ByHuevtCFY"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-times-circle",
|
||||||
|
title: "Declined",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "report",
|
||||||
|
description: "",
|
||||||
|
objectId: "UPr2Fm5WY3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-hourglass-end",
|
||||||
|
title: "Expired",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "report",
|
||||||
|
description: "",
|
||||||
|
objectId: "zNqBHXHsYH"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-address-book",
|
||||||
|
title: "Contactbook",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "report",
|
||||||
|
description: "",
|
||||||
|
objectId: "5KhaPr482K"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-cog",
|
||||||
|
title: "Settings",
|
||||||
|
target: "_self",
|
||||||
|
pageType: null,
|
||||||
|
description: "",
|
||||||
|
objectId: null,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-pen-fancy",
|
||||||
|
title: "My Signature",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "",
|
||||||
|
description: "",
|
||||||
|
objectId: "managesign"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-key",
|
||||||
|
title: "API Token",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "generatetoken",
|
||||||
|
description: "",
|
||||||
|
objectId: ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-light fa-globe",
|
||||||
|
title: "Webhook",
|
||||||
|
target: "_self",
|
||||||
|
pageType: "webhook",
|
||||||
|
description: "",
|
||||||
|
objectId: ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
export default sidebarList;
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
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",
|
||||||
|
"Auto reminders"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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,65 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"planName": "SELF HOSTED",
|
|
||||||
"currency": "",
|
|
||||||
"price": "Free",
|
|
||||||
"subtitle": "Free for life One click install.",
|
|
||||||
"btnText": "Visit github",
|
|
||||||
"url": "https://github.com/opensignlabs/opensign",
|
|
||||||
"target": "_blank",
|
|
||||||
"benefits": [
|
|
||||||
"Sign Unlimited Documents",
|
|
||||||
"S3 Doc Storage",
|
|
||||||
"Unlimited Guest Signers",
|
|
||||||
"Unlimited completion certificates",
|
|
||||||
"Unique Code(OTP) verification for guest signers",
|
|
||||||
"Expiring docs & reject signature support",
|
|
||||||
"PDF Template Creation(coming soon)",
|
|
||||||
"Audit Trails",
|
|
||||||
"API support",
|
|
||||||
"Add-ons support(coming soon)",
|
|
||||||
"Self hosted cloud infrastructure",
|
|
||||||
"Free for lifetime",
|
|
||||||
"Community support"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"planName": "THANKS PLAN",
|
|
||||||
"currency": "$",
|
|
||||||
"price": "29.99",
|
|
||||||
"subtitle": "Use code <span style='background-color: yellow;'>'FREEBETA'</span> to get this for free(First 1000 users)",
|
|
||||||
"btnText": "Subscribe",
|
|
||||||
"url": "https://subscriptions.zoho.in/subscribe/ef798486e6a0a11ea65f2bae8f2af901dbadf3175d495584fd25b9af5d2f2b9e/thanks",
|
|
||||||
"target": "_self",
|
|
||||||
"benefits": [
|
|
||||||
"Sign Unlimited Documents",
|
|
||||||
"Unlimited Secure Doc Storage with OpenSign™ Drive",
|
|
||||||
"Unlimited Guest Signers",
|
|
||||||
"Unlimited completion certificates",
|
|
||||||
"Unique Code(OTP) verification for guest signers",
|
|
||||||
"Expiring docs & reject signature support",
|
|
||||||
"PDF Template Creation(coming soon)",
|
|
||||||
"Audit Trails",
|
|
||||||
"API support",
|
|
||||||
"Add-ons support(coming soon)",
|
|
||||||
"Self hosted cloud infrastructure"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"planName": "ENTERPRISE",
|
|
||||||
"currency": "",
|
|
||||||
"price": "Request Price",
|
|
||||||
"subtitle": "Customization available Priority support.",
|
|
||||||
"btnText": "Contact us",
|
|
||||||
"url": "https://www.opensignlabs.com/contact-us",
|
|
||||||
"target": "_blank",
|
|
||||||
"benefits": [
|
|
||||||
"All features",
|
|
||||||
"Custom domain",
|
|
||||||
"Whitelabeling",
|
|
||||||
"Uptime SLA",
|
|
||||||
"SSO support",
|
|
||||||
"24/7 support"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -5,48 +5,102 @@ import Sidebar from "../components/sidebar/Sidebar";
|
|||||||
import { useWindowSize } from "../hook/useWindowSize";
|
import { useWindowSize } from "../hook/useWindowSize";
|
||||||
import Tour from "reactour";
|
import Tour from "reactour";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import Parse from "parse";
|
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 { useCookies } from "react-cookie";
|
||||||
|
import { fetchSubscription } from "../constant/Utils";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
import { showHeader } from "../redux/reducers/showHeader";
|
||||||
|
|
||||||
const HomeLayout = () => {
|
const HomeLayout = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
const [isOpen, setIsOpen] = useState(true);
|
const [isOpen, setIsOpen] = useState(true);
|
||||||
const arr = useSelector((state) => state.TourSteps);
|
const arr = useSelector((state) => state.TourSteps);
|
||||||
const [isUserValid, setIsUserValid] = useState(true);
|
const [isUserValid, setIsUserValid] = useState(true);
|
||||||
const [isLoader, setIsLoader] = useState(true);
|
const [isLoader, setIsLoader] = useState(true);
|
||||||
useEffect(() => {
|
|
||||||
(async () => {
|
|
||||||
try {
|
|
||||||
// Use the session token to validate the user
|
|
||||||
const userQuery = new Parse.Query(Parse.User);
|
|
||||||
const user = await userQuery.get(Parse.User.current().id, {
|
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
|
||||||
});
|
|
||||||
if (user) {
|
|
||||||
setIsUserValid(true);
|
|
||||||
setIsLoader(false);
|
|
||||||
} else {
|
|
||||||
setIsUserValid(false);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// Session token is invalid or there was an error
|
|
||||||
setIsUserValid(false);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// reactour state
|
// reactour state
|
||||||
const [isCloseBtn, setIsCloseBtn] = useState(true);
|
const [isCloseBtn, setIsCloseBtn] = useState(true);
|
||||||
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"]);
|
||||||
|
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
useEffect(() => {
|
||||||
|
if (!tenantId) {
|
||||||
|
setIsUserValid(false);
|
||||||
|
} else {
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
// Use the session token to validate the user
|
||||||
|
const userQuery = new Parse.Query(Parse.User);
|
||||||
|
const user = await userQuery.get(Parse.User.current().id, {
|
||||||
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
|
});
|
||||||
|
if (user) {
|
||||||
|
localStorage.setItem("profileImg", user.get("ProfilePic") || "");
|
||||||
|
checkIsSubscribed();
|
||||||
|
} else {
|
||||||
|
setIsUserValid(false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Session token is invalid or there was an error
|
||||||
|
setIsUserValid(false);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
saveCookies();
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [tenantId]);
|
||||||
|
//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() {
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const res = await fetchSubscription();
|
||||||
|
if (res.plan === "freeplan") {
|
||||||
|
setIsUserValid(true);
|
||||||
|
setIsLoader(false);
|
||||||
|
} else if (res.billingDate) {
|
||||||
|
if (new Date(res.billingDate) > new Date()) {
|
||||||
|
setIsUserValid(true);
|
||||||
|
setIsLoader(false);
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsUserValid(true);
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
const showSidebar = () => {
|
const showSidebar = () => {
|
||||||
setIsOpen((value) => !value);
|
setIsOpen((value) => !value);
|
||||||
|
dispatch(showHeader(!isOpen));
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (width && width <= 768) {
|
if (width && width <= 768) {
|
||||||
@@ -180,7 +234,7 @@ const HomeLayout = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const closeSidebar = () => {
|
const closeSidebar = () => {
|
||||||
if (width <= 768) {
|
if (width <= 1023) {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -197,35 +251,24 @@ const HomeLayout = () => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="sticky top-0 z-50">
|
<div className="sticky top-0 z-[101]">
|
||||||
<Header showSidebar={showSidebar} />
|
{!isLoader && <Header showSidebar={showSidebar} />}
|
||||||
</div>
|
</div>
|
||||||
{isUserValid ? (
|
{isUserValid ? (
|
||||||
<>
|
<>
|
||||||
{isLoader ? (
|
{isLoader ? (
|
||||||
<div
|
<div className="flex h-[100vh] justify-center items-center">
|
||||||
style={{
|
<Loader />
|
||||||
height: "100vh",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="flex md:flex-row flex-col z-50">
|
<div className="flex md:flex-row flex-col z-50">
|
||||||
<Sidebar isOpen={isOpen} closeSidebar={closeSidebar} />
|
<Sidebar isOpen={isOpen} closeSidebar={closeSidebar} />
|
||||||
|
<div
|
||||||
<div className="relative h-screen flex flex-col justify-between w-full overflow-y-auto">
|
id="renderList"
|
||||||
<div className="bg-[#eef1f5] p-3">{<Outlet />}</div>
|
className="relative h-screen flex flex-col justify-between w-full overflow-y-auto"
|
||||||
|
>
|
||||||
|
<div className="bg-base-200 p-3">{<Outlet />}</div>
|
||||||
<div className="z-30">
|
<div className="z-30">
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
@@ -246,13 +289,10 @@ const HomeLayout = () => {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<ModalUi title={"Session Expired"} isOpen={true} showClose={false}>
|
<ModalUi showHeader={false} isOpen={true} showClose={false}>
|
||||||
<div className="flex flex-col justify-center items-center py-4 md:py-5 gap-5">
|
<div className="flex flex-col justify-center items-center py-4 md:py-5 gap-5">
|
||||||
<p className="text-xl font-normal">Your session has expired.</p>
|
<p className="text-xl font-medium">Your session has expired.</p>
|
||||||
<button
|
<button onClick={handleLoginBtn} className="op-btn op-btn-neutral">
|
||||||
onClick={handleLoginBtn}
|
|
||||||
className="text-base px-3 py-1.5 rounded shadow-md text-white bg-[#1ab6ce]"
|
|
||||||
>
|
|
||||||
Login
|
Login
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -49,13 +49,13 @@ function ChangePassword() {
|
|||||||
return <Navigate to="/" />;
|
return <Navigate to="/" />;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="w-full bg-white shadow rounded p-2">
|
<div className="w-full bg-base-100 text-base-content shadow rounded-box p-2">
|
||||||
<Title title={"Change Password"} />
|
<Title title="Change Password" />
|
||||||
<div className="text-xl font-bold border-b-[1px] border-gray-300">
|
<div className="text-xl font-bold border-b-[1px] border-gray-300">
|
||||||
Change Password
|
Change Password
|
||||||
</div>
|
</div>
|
||||||
<div className="m-2">
|
<div className="m-2">
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit} className=" flex flex-col gap-y-2">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="currentpassword" className="block text-xs ml-1">
|
<label htmlFor="currentpassword" className="block text-xs ml-1">
|
||||||
Current Password
|
Current Password
|
||||||
@@ -65,7 +65,7 @@ function ChangePassword() {
|
|||||||
name="currentpassword"
|
name="currentpassword"
|
||||||
value={currentpassword}
|
value={currentpassword}
|
||||||
onChange={(e) => setCurrentPassword(e.target.value)}
|
onChange={(e) => setCurrentPassword(e.target.value)}
|
||||||
className="px-3 py-2 mb-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm text-xs w-full"
|
||||||
placeholder="Current Password"
|
placeholder="Current Password"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
@@ -79,7 +79,7 @@ function ChangePassword() {
|
|||||||
name="newpassword"
|
name="newpassword"
|
||||||
value={newpassword}
|
value={newpassword}
|
||||||
onChange={(e) => setnewpassword(e.target.value)}
|
onChange={(e) => setnewpassword(e.target.value)}
|
||||||
className="px-3 py-2 mb-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm text-xs w-full"
|
||||||
placeholder="New Password"
|
placeholder="New Password"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
@@ -91,7 +91,7 @@ function ChangePassword() {
|
|||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
name="confirmpassword"
|
name="confirmpassword"
|
||||||
className="px-3 py-2 mb-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm text-xs w-full"
|
||||||
value={confirmpassword}
|
value={confirmpassword}
|
||||||
onChange={(e) => setconfirmpassword(e.target.value)}
|
onChange={(e) => setconfirmpassword(e.target.value)}
|
||||||
placeholder="Confirm Password"
|
placeholder="Confirm Password"
|
||||||
@@ -100,7 +100,7 @@ function ChangePassword() {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="bg-[#188ae2] m-2 px-4 py-3 rounded-sm shadow-md text-white text-xs font-semibold uppercase"
|
className="op-btn op-btn-primary shadow-md mt-2"
|
||||||
>
|
>
|
||||||
Change Password
|
Change Password
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import Parse from "parse";
|
|
||||||
import "../styles/loader.css";
|
|
||||||
import GetDashboard from "../components/dashboard/GetDashboard";
|
import GetDashboard from "../components/dashboard/GetDashboard";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import { save_tourSteps } from "../redux/actions";
|
import { useDispatch } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
import { saveTourSteps } from "../redux/reducers/TourStepsReducer";
|
||||||
const Dashboard = (props) => {
|
import dashboardJson from "../json/dashboardJson";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
|
||||||
|
const Dashboard = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const dispatch = useDispatch();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const [dashboard, setdashboard] = useState([]);
|
const [dashboard, setdashboard] = useState({});
|
||||||
const [classnameArray, setclassnameArray] = useState([]);
|
const [loading, setloading] = useState(true);
|
||||||
const [loading, setloading] = useState(false);
|
|
||||||
const [defaultQuery, setDefaultQuery] = useState("");
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (localStorage.getItem("accesstoken")) {
|
if (localStorage.getItem("accesstoken")) {
|
||||||
@@ -22,59 +22,16 @@ const Dashboard = (props) => {
|
|||||||
getDashboard(localStorage.getItem("PageLanding"));
|
getDashboard(localStorage.getItem("PageLanding"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
navigate("/", { replace: true, state: { from: location } });
|
navigate("/", { replace: true, state: { from: "" } });
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [id]);
|
}, [id]);
|
||||||
|
|
||||||
const getDashboard = async (id) => {
|
const getDashboard = async (id) => {
|
||||||
setloading(true);
|
|
||||||
try {
|
try {
|
||||||
var forms = Parse.Object.extend("w_dashboard");
|
const dashboard = dashboardJson.find((x) => x.id === id);
|
||||||
var query = new Parse.Query(forms);
|
setdashboard(dashboard);
|
||||||
query.equalTo("objectId", id);
|
const dashboardTour = dashboard.columns
|
||||||
const results = await query.first();
|
|
||||||
const resultjson = results.toJSON();
|
|
||||||
let classArray = [];
|
|
||||||
let DefaultQuery = "";
|
|
||||||
resultjson.rows.forEach((x) => {
|
|
||||||
let col_lg = "",
|
|
||||||
col_md = "",
|
|
||||||
col_xs = "",
|
|
||||||
col_sm = "",
|
|
||||||
col_ = "",
|
|
||||||
obj = {};
|
|
||||||
let subItem = [];
|
|
||||||
let item = "";
|
|
||||||
x.columns.forEach((y) => {
|
|
||||||
if (y.widget.type === "customeHtml") {
|
|
||||||
DefaultQuery = y.widget.data[0].default;
|
|
||||||
}
|
|
||||||
if (Number(y["collg"]) > 0) {
|
|
||||||
col_lg = "col-lg-" + y["collg"];
|
|
||||||
}
|
|
||||||
if (Number(y["colmd"]) > 0) {
|
|
||||||
col_md = "col-md-" + y["colmd"];
|
|
||||||
}
|
|
||||||
if (Number(y["colxs"]) > 0) {
|
|
||||||
col_xs = "col-xs-" + y["colxs"];
|
|
||||||
}
|
|
||||||
if (Number(y["colsm"]) > 0) {
|
|
||||||
col_sm = "col-sm-" + y["colsm"];
|
|
||||||
}
|
|
||||||
if (Number(y["col"]) > 0) {
|
|
||||||
col_ = "col-" + y["col"];
|
|
||||||
}
|
|
||||||
item =
|
|
||||||
col_lg + " " + col_md + " " + col_xs + " " + col_sm + " " + col_;
|
|
||||||
subItem.push(item);
|
|
||||||
});
|
|
||||||
obj = subItem;
|
|
||||||
classArray.push(obj);
|
|
||||||
});
|
|
||||||
setdashboard(resultjson.rows);
|
|
||||||
// console.log("resultjson.rows ", resultjson.rows);
|
|
||||||
const arr = resultjson.rows[0].columns
|
|
||||||
.filter((col) => {
|
.filter((col) => {
|
||||||
if (col.widget.data && col.widget.data.tourSection) {
|
if (col.widget.data && col.widget.data.tourSection) {
|
||||||
return col;
|
return col;
|
||||||
@@ -88,14 +45,7 @@ const Dashboard = (props) => {
|
|||||||
// style: { backgroundColor: "#abd4d2" },
|
// style: { backgroundColor: "#abd4d2" },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
props.save_tourSteps(arr);
|
dispatch(saveTourSteps(dashboardTour));
|
||||||
// console.log("arr ", arr);
|
|
||||||
setclassnameArray(classArray);
|
|
||||||
if (localStorage.getItem("DashboardDefaultFilter")) {
|
|
||||||
setDefaultQuery(localStorage.getItem("DashboardDefaultFilter"));
|
|
||||||
} else {
|
|
||||||
setDefaultQuery(DefaultQuery);
|
|
||||||
}
|
|
||||||
setloading(false);
|
setloading(false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Problem", e);
|
console.error("Problem", e);
|
||||||
@@ -103,36 +53,18 @@ const Dashboard = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let _dash = (
|
|
||||||
<GetDashboard
|
|
||||||
dashboard={dashboard}
|
|
||||||
classnameArray={classnameArray}
|
|
||||||
DefaultQuery={defaultQuery}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
if (loading) {
|
|
||||||
_dash = (
|
|
||||||
<div style={{ height: "300px", backgroundColor: "white" }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
marginLeft: "45%",
|
|
||||||
marginTop: "150px",
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Title title="Dashboard" />
|
<Title title="Dashboard" />
|
||||||
{_dash}
|
{loading ? (
|
||||||
|
<div className="h-[300px] w-full bg-white flex justify-center items-center rounded-md">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<GetDashboard dashboard={dashboard} />
|
||||||
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(null, {
|
export default Dashboard;
|
||||||
save_tourSteps
|
|
||||||
})(Dashboard);
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage";
|
import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage";
|
||||||
import "../styles/signature.css";
|
|
||||||
import "../styles/AddUser.css";
|
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import RenderDebugPdf from "../components/RenderDebugPdf";
|
import RenderDebugPdf from "../components/RenderDebugPdf";
|
||||||
import { pdfjs } from "react-pdf";
|
import { pdfjs } from "react-pdf";
|
||||||
@@ -58,7 +56,7 @@ const DebugPdf = () => {
|
|||||||
const fetchPdfMetadata = async () => {
|
const fetchPdfMetadata = async () => {
|
||||||
try {
|
try {
|
||||||
const pdfDataURL = URL.createObjectURL(pdf); // Convert File to data URL
|
const pdfDataURL = URL.createObjectURL(pdf); // Convert File to data URL
|
||||||
console.log("pdfDataURL ", pdfDataURL);
|
// console.log("pdfDataURL ", pdfDataURL);
|
||||||
const pdfInfo = await pdfjs.getDocument({ url: pdfDataURL }).promise;
|
const pdfInfo = await pdfjs.getDocument({ url: pdfDataURL }).promise;
|
||||||
const pdfType = await inferPdfType(pdfInfo);
|
const pdfType = await inferPdfType(pdfInfo);
|
||||||
setPdfDetails((prevDetails) => ({
|
setPdfDetails((prevDetails) => ({
|
||||||
@@ -76,7 +74,7 @@ const DebugPdf = () => {
|
|||||||
|
|
||||||
const inferPdfType = async (pdf) => {
|
const inferPdfType = async (pdf) => {
|
||||||
try {
|
try {
|
||||||
const firstPage = await pdf.getPage(1);
|
const firstPage = await pdf.getPage(2);
|
||||||
const scale = 1;
|
const scale = 1;
|
||||||
const { width, height } = firstPage.getViewport({ scale });
|
const { width, height } = firstPage.getViewport({ scale });
|
||||||
setPdfDimension({ width: width, height: height });
|
setPdfDimension({ width: width, height: height });
|
||||||
@@ -217,14 +215,18 @@ const DebugPdf = () => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{copied && <Alert type="success">Copied</Alert>}
|
{copied && (
|
||||||
|
<Alert type="success">
|
||||||
|
<span className="ml-3">Copied</span>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
<Title title={"Debug Pdf"} />
|
<Title title={"Debug Pdf"} />
|
||||||
{width < 800 ? (
|
{width < 800 ? (
|
||||||
<HandleError handleError={"Debug PDF only availble for PC"} />
|
<HandleError handleError={"Debug PDF only availble for PC"} />
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{!isModal && (
|
{!isModal && (
|
||||||
<div className="signatureContainer">
|
<div className="flex flex-row justify-between">
|
||||||
{/* 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={pdf}
|
signPdfUrl={pdf}
|
||||||
@@ -253,126 +255,68 @@ const DebugPdf = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ backgroundColor: "white", width: 220 }}>
|
<div className="w-[220px] bg-base-100">
|
||||||
<div
|
<div className="text-[18px] font-medium py-[10px] px-[12px] border-b-[1px] border-[gray]">
|
||||||
style={{
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: 500,
|
|
||||||
padding: "10px 12px",
|
|
||||||
borderBottom: "1px solid grey"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
PDF details
|
PDF details
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
<div className="text-[14px] py-[5px] px-[12px]">
|
||||||
Name: {pdfDetails?.name}
|
Name: {pdfDetails?.name}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
<div className="text-[14px] py-[5px] px-[12px]">
|
||||||
Pdf type: {pdfDetails?.pdftype}
|
Pdf type: {pdfDetails?.pdftype}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
<div className="text-[14px] py-[5px] px-[12px]">
|
||||||
Total Pages: {pdfDetails?.totalPages}
|
Total Pages: {pdfDetails?.totalPages}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
<div className="text-[14px] py-[5px] px-[12px]">
|
||||||
Current Page: {pdfDetails?.currentPage}
|
Current Page: {pdfDetails?.currentPage}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
<div className="text-[14px] py-[5px] px-[12px]">
|
||||||
Base64 : {pdfDetails?.base64.slice(0, 10)}...
|
Base64 : {pdfDetails?.base64.slice(0, 10)}...
|
||||||
<span
|
<span
|
||||||
style={{
|
className="op-btn op-btn-outline op-btn-primary op-btn-xs rounded-md w-[25px] h-[25px] text-[12px] m-[2px] "
|
||||||
borderRadius: 4,
|
|
||||||
padding: "3px 5px",
|
|
||||||
border: "1px solid gray",
|
|
||||||
fontSize: 12,
|
|
||||||
margin: 2,
|
|
||||||
cursor: "pointer"
|
|
||||||
}}
|
|
||||||
onClick={() => copytoclipboard(pdfDetails?.base64)}
|
onClick={() => copytoclipboard(pdfDetails?.base64)}
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-copy"></i>
|
<i className="fa-light fa-copy"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="text-[18px] font-medium py-[10px] px-[12px] border-b-[1px] border-[gray]">
|
||||||
style={{
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: 500,
|
|
||||||
padding: "10px 12px",
|
|
||||||
borderBottom: "1px solid grey"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Last click
|
Last click
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
<div className="text-[14px] py-[5px] px-[12px]">
|
||||||
x co-ordinate: {pdfDetails?.x}
|
x co-ordinate: {pdfDetails?.x}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
<div className="text-[14px] py-[5px] px-[12px]">
|
||||||
y co-ordinate: {pdfDetails?.y}
|
y co-ordinate: {pdfDetails?.y}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="text-[18px] font-medium py-[10px] px-[12px] border-y-[1px] border-[gray]">
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: 500,
|
|
||||||
padding: "10px 12px",
|
|
||||||
borderBottom: "1px solid grey",
|
|
||||||
borderTop: "1px solid grey"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Annotation
|
Annotation
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul className=" list-none p-[10px] h-[500px] overflow-y-auto">
|
||||||
style={{
|
|
||||||
listStyle: "none",
|
|
||||||
padding: 10,
|
|
||||||
height: 500,
|
|
||||||
overflowY: "auto",
|
|
||||||
scrollbarWidth: 5
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{annotations.map((coord, index) => (
|
{annotations.map((coord, index) => (
|
||||||
<li key={index}>
|
<li key={index}>
|
||||||
<span style={{ fontSize: 13, fontWeight: 500 }}>{`Box ${
|
<span className="text-[13px] font-medium">{`Box ${
|
||||||
index + 1
|
index + 1
|
||||||
}:`}</span>
|
}:`}</span>
|
||||||
<code
|
<code className="text-[12px] text-base-content select-none">
|
||||||
style={{
|
|
||||||
fontSize: 12,
|
|
||||||
color: "black",
|
|
||||||
cursor: "pointer"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{` ["page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]`}
|
{` ["page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]`}
|
||||||
</code>
|
</code>
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
style={{
|
className="op-btn op-btn-outline op-btn-primary op-btn-xs rounded-md w-[23px] h-[20px] text-[12px] m-[2px] "
|
||||||
borderRadius: 4,
|
|
||||||
padding: "3px 5px",
|
|
||||||
border: "1px solid gray",
|
|
||||||
fontSize: 12,
|
|
||||||
margin: 2,
|
|
||||||
cursor: "pointer"
|
|
||||||
}}
|
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
copytoclipboard(
|
copytoclipboard(
|
||||||
`"page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}`
|
`"page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-copy"></i>
|
<i className="fa-light fa-copy"></i>
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
style={{
|
className="op-btn op-btn-outline op-btn-error op-btn-xs rounded-md w-[23px] h-[20px] text-[12px] m-[2px] "
|
||||||
borderRadius: 4,
|
|
||||||
padding: "3px 5px",
|
|
||||||
border: "1px solid gray",
|
|
||||||
fontSize: 12,
|
|
||||||
margin: 2,
|
|
||||||
cursor: "pointer"
|
|
||||||
}}
|
|
||||||
onClick={() => handleDelete(coord.key)}
|
onClick={() => handleDelete(coord.key)}
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-trash-can"></i>
|
<i className="fa-light fa-trash-can"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@@ -382,38 +326,16 @@ const DebugPdf = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<ModalUi title={"Select PDF"} isOpen={isModal}>
|
<ModalUi title={"Select PDF"} isOpen={isModal}>
|
||||||
<form onSubmit={handleSubmit} style={{ margin: "10px" }}>
|
<form onSubmit={handleSubmit} className="m-[10px]">
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
onChange={(e) => handleFileChange(e.target.files)}
|
onChange={(e) => handleFileChange(e.target.files)}
|
||||||
style={{
|
className="op-file-input op-file-input-bordered op-file-input-sm focus:outline-none hover:border-base-content w-full h-[40px] text-xs"
|
||||||
width: "100%",
|
|
||||||
border: "1px solid grey",
|
|
||||||
borderRadius: "4px",
|
|
||||||
padding: "5px",
|
|
||||||
fontSize: 12
|
|
||||||
}}
|
|
||||||
accept=".pdf"
|
accept=".pdf"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<div
|
|
||||||
style={{ borderTop: "1px solid grey", margin: "10px 0" }}
|
|
||||||
></div>
|
|
||||||
<button
|
<button
|
||||||
style={{
|
className="op-btn op-btn-primary w-full mt-3 mb-1"
|
||||||
background: "#32a3ac",
|
|
||||||
borderRadius: "2px",
|
|
||||||
boxShadow:
|
|
||||||
"0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18)",
|
|
||||||
border: "none",
|
|
||||||
textTransform: "uppercase",
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: "600",
|
|
||||||
padding: "0.375rem 0.75rem",
|
|
||||||
textAlign: "center",
|
|
||||||
color: "#ffffff",
|
|
||||||
outline: "none"
|
|
||||||
}}
|
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
Submit
|
Submit
|
||||||
|
|||||||
@@ -1,18 +1,26 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { fetchAppInfo, forgetPassword } from "../redux/actions";
|
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import { NavLink } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import login_img from "../assets/images/login_img.svg";
|
import login_img from "../assets/images/login_img.svg";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
function ForgotPassword(props) {
|
import { appInfo } from "../constant/appinfo";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
import { getAppLogo } from "../constant/Utils";
|
||||||
|
|
||||||
|
function ForgotPassword() {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const navigate = useNavigate();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
email: "",
|
email: "",
|
||||||
password: "",
|
password: "",
|
||||||
hideNav: ""
|
hideNav: ""
|
||||||
});
|
});
|
||||||
const [sentStatus, setSentStatus] = useState("");
|
const [sentStatus, setSentStatus] = useState("");
|
||||||
|
const [image, setImage] = useState();
|
||||||
|
|
||||||
const handleChange = (event) => {
|
const handleChange = (event) => {
|
||||||
const { name, value } = event.target;
|
const { name, value } = event.target;
|
||||||
setState({ ...state, [name]: value });
|
setState({ ...state, [name]: value });
|
||||||
@@ -27,14 +35,11 @@ function ForgotPassword(props) {
|
|||||||
|
|
||||||
const handleSubmit = async (event) => {
|
const handleSubmit = async (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
localStorage.setItem("appLogo", props.appInfo.applogo);
|
localStorage.setItem("appLogo", appInfo.applogo);
|
||||||
localStorage.setItem("appName", props.appInfo.appname);
|
localStorage.setItem("appName", appInfo.appname);
|
||||||
localStorage.setItem("defaultmenuid", props.appInfo.defaultmenuid);
|
// localStorage.setItem("defaultmenuid", props.appInfo.defaultmenuid);
|
||||||
localStorage.setItem("PageLanding", props.appInfo.LandingPageId);
|
// localStorage.setItem("PageLanding", props.appInfo.LandingPageId);
|
||||||
localStorage.setItem(
|
localStorage.setItem("userSettings", JSON.stringify(appInfo.settings));
|
||||||
"userSettings",
|
|
||||||
JSON.stringify(props.appInfo.settings)
|
|
||||||
);
|
|
||||||
if (state.email) {
|
if (state.email) {
|
||||||
const username = state.email;
|
const username = state.email;
|
||||||
try {
|
try {
|
||||||
@@ -50,16 +55,27 @@ function ForgotPassword(props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
props.fetchAppInfo();
|
dispatch(fetchAppInfo());
|
||||||
|
saveLogo();
|
||||||
resize();
|
resize();
|
||||||
window.addEventListener("resize", resize);
|
window.addEventListener("resize", resize);
|
||||||
return () => window.removeEventListener("resize", resize);
|
return () => window.removeEventListener("resize", resize);
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
const saveLogo = async () => {
|
||||||
let image = props.appInfo.applogo;
|
if (isEnableSubscription) {
|
||||||
|
const logo = await getAppLogo();
|
||||||
|
if (logo) {
|
||||||
|
setImage(logo);
|
||||||
|
} else {
|
||||||
|
setImage(appInfo?.applogo || undefined);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setImage(appInfo?.applogo || undefined);
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="bg-white">
|
<div>
|
||||||
<Title title="Forgot password page" />
|
<Title title="Forgot password page" />
|
||||||
{sentStatus === "success" && (
|
{sentStatus === "success" && (
|
||||||
<Alert type="success">
|
<Alert type="success">
|
||||||
@@ -69,29 +85,31 @@ function ForgotPassword(props) {
|
|||||||
{sentStatus === "failed" && (
|
{sentStatus === "failed" && (
|
||||||
<Alert type={"danger"}>Please setup email adapter </Alert>
|
<Alert type={"danger"}>Please setup email adapter </Alert>
|
||||||
)}
|
)}
|
||||||
<div>
|
<div className="md:p-10 lg:p-16">
|
||||||
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
<div className="md:p-4 lg:p-10 p-4 bg-base-100 text-base-content op-card">
|
||||||
<div className="w-[250px] h-[66px] inline-block">
|
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
||||||
{state.hideNav ? (
|
{image && (
|
||||||
<img src={image} width="100%" alt="" />
|
<img
|
||||||
) : (
|
src={image}
|
||||||
<img src={image} width="100%" alt="" />
|
className="object-contain h-full"
|
||||||
|
alt="applogo"
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</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>
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<h2 className="text-[30px] mt-6">Welcome Back !</h2>
|
<h2 className="text-[30px] mt-6">Welcome Back !</h2>
|
||||||
<span className="text-[12px] text-[#878787]">
|
<span className="text-[12px] text-[#878787]">
|
||||||
Reset Your Password
|
Reset Your Password
|
||||||
</span>
|
</span>
|
||||||
<div className="shadow-md rounded my-4">
|
<div className="w-full my-4 op-card bg-base-100 shadow-md outline outline-1 outline-slate-300/50">
|
||||||
<div className="px-6 py-4">
|
<div className="px-6 py-4">
|
||||||
<label className="block text-xs">Email</label>
|
<label className="block text-xs">Email</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="email"
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
|
||||||
name="email"
|
name="email"
|
||||||
|
className="op-input op-input-bordered op-input-sm w-full"
|
||||||
value={state.email}
|
value={state.email}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
required
|
required
|
||||||
@@ -99,19 +117,16 @@ function ForgotPassword(props) {
|
|||||||
<hr className="my-2 border-none" />
|
<hr className="my-2 border-none" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center px-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-center text-xs font-bold">
|
||||||
<button
|
<button type="submit" className="op-btn op-btn-primary">
|
||||||
type="submit"
|
|
||||||
className="rounded-sm bg-[#3ac9d6] text-white px-4 py-3 text-xs font-semibold shadow uppercase"
|
|
||||||
>
|
|
||||||
Submit
|
Submit
|
||||||
</button>
|
</button>
|
||||||
<NavLink
|
<button
|
||||||
to="/"
|
onClick={() => navigate("/", { replace: true })}
|
||||||
className="rounded-sm bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] px-4 py-3 text-xs font-semibold shadow uppercase"
|
className="op-btn op-btn-secondary"
|
||||||
>
|
>
|
||||||
Login
|
Login
|
||||||
</NavLink>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -129,10 +144,4 @@ function ForgotPassword(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
export default ForgotPassword;
|
||||||
return { appInfo: state.appInfo, forgotPassword: state.forgotPassword };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, { fetchAppInfo, forgetPassword })(
|
|
||||||
ForgotPassword
|
|
||||||
);
|
|
||||||
|
|||||||
+690
-214
File diff suppressed because it is too large
Load Diff
@@ -3,19 +3,29 @@ import Title from "../components/Title";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import { rejectBtn, submitBtn } from "../constant/const";
|
import { isEnableSubscription } from "../constant/const";
|
||||||
import { openInNewTab } from "../constant/Utils";
|
import { checkIsSubscribed, copytoData, openInNewTab } from "../constant/Utils";
|
||||||
|
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||||
|
import Tooltip from "../primitives/Tooltip";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
import SubscribeCard from "../primitives/SubscribeCard";
|
||||||
|
import Tour from "reactour";
|
||||||
|
const tourSteps = [
|
||||||
|
{
|
||||||
|
selector: '[data-tut="apisubscribe"]',
|
||||||
|
content: "Upgrade now to generate API token"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
function GenerateToken() {
|
function GenerateToken() {
|
||||||
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 [apiToken, SetApiToken] = useState("");
|
const [apiToken, SetApiToken] = useState("");
|
||||||
const [isLoader, setIsLoader] = useState(true);
|
const [isLoader, setIsLoader] = useState(true);
|
||||||
const [copied, setCopied] = useState(false);
|
|
||||||
const [isGenerate, setIsGenerate] = useState(false);
|
|
||||||
const [isErr, setIsErr] = useState(false);
|
|
||||||
const [isModal, setIsModal] = useState(false);
|
const [isModal, setIsModal] = useState(false);
|
||||||
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||||
|
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||||
|
const [isTour, setIsTour] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchToken();
|
fetchToken();
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
@@ -23,6 +33,10 @@ function GenerateToken() {
|
|||||||
|
|
||||||
const fetchToken = async () => {
|
const fetchToken = async () => {
|
||||||
try {
|
try {
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const getIsSubscribe = await checkIsSubscribed();
|
||||||
|
setIsSubscribe(getIsSubscribe);
|
||||||
|
}
|
||||||
const url = parseBaseUrl + "functions/getapitoken";
|
const url = parseBaseUrl + "functions/getapitoken";
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -42,141 +56,168 @@ function GenerateToken() {
|
|||||||
};
|
};
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setIsLoader(true);
|
if (!isSubscribe && isEnableSubscription) {
|
||||||
setIsModal(false);
|
setIsTour(true);
|
||||||
try {
|
} else {
|
||||||
const url = parseBaseUrl + "functions/generateapitoken";
|
setIsLoader(true);
|
||||||
const headers = {
|
setIsModal(false);
|
||||||
"Content-Type": "application/json",
|
try {
|
||||||
"X-Parse-Application-Id": parseAppId,
|
const url = parseBaseUrl + "functions/generateapitoken";
|
||||||
sessiontoken: localStorage.getItem("accesstoken")
|
const headers = {
|
||||||
};
|
"Content-Type": "application/json",
|
||||||
await axios.post(url, {}, { headers: headers }).then((res) => {
|
"X-Parse-Application-Id": parseAppId,
|
||||||
|
sessiontoken: localStorage.getItem("accesstoken")
|
||||||
|
};
|
||||||
|
const res = await axios.post(url, {}, { headers: headers });
|
||||||
if (res) {
|
if (res) {
|
||||||
SetApiToken(res.data.result.token);
|
SetApiToken(res.data.result.token);
|
||||||
// localStorage.setItem("apiToken", res.data.result.token);
|
setIsAlert({ type: "success", msg: "Token generated successfully." });
|
||||||
setIsGenerate(true);
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsGenerate(false);
|
|
||||||
}, 1500);
|
|
||||||
setIsLoader(false);
|
|
||||||
} else {
|
} else {
|
||||||
console.error("Error while generating Token");
|
console.error("Error while generating Token");
|
||||||
setIsLoader(false);
|
setIsAlert({ type: "danger", msg: "Something went wrong." });
|
||||||
setIsErr(true);
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsErr(false);
|
|
||||||
}, 1500);
|
|
||||||
}
|
}
|
||||||
});
|
} catch (error) {
|
||||||
} catch (error) {
|
setIsAlert({ type: "danger", msg: "Something went wrong." });
|
||||||
setIsLoader(false);
|
console.log("while generating Token", error);
|
||||||
setIsErr(true);
|
} finally {
|
||||||
setTimeout(() => {
|
setIsLoader(false);
|
||||||
setIsErr(false);
|
setTimeout(() => {
|
||||||
}, 1500);
|
setIsAlert({ type: "success", msg: "" });
|
||||||
|
}, 1500);
|
||||||
console.log("err", error);
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const copytoclipboard = (text) => {
|
const copytoclipboard = (text) => {
|
||||||
navigator.clipboard.writeText(text);
|
copytoData(text);
|
||||||
setCopied(true);
|
setIsAlert({ type: "success", msg: "Copied" });
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setCopied(false);
|
setIsAlert({ type: "success", msg: "" });
|
||||||
}, 1500); // Reset copied state after 1.5 seconds
|
}, 1500); // Reset copied state after 1.5 seconds
|
||||||
};
|
};
|
||||||
const handleModal = () => setIsModal(!isModal);
|
const handleModal = () => setIsModal(!isModal);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Title title={"API Token"} />
|
<Title title={"API Token"} />
|
||||||
{isGenerate && (
|
{isAlert.msg && (
|
||||||
<Alert type="success">Token generated successfully!</Alert>
|
<Alert type={isAlert.type}>
|
||||||
|
<div className="ml-3">{isAlert.msg}</div>
|
||||||
|
</Alert>
|
||||||
)}
|
)}
|
||||||
{copied && <Alert type="success">Copied</Alert>}
|
|
||||||
{isErr && <Alert type="danger">Something went wrong!</Alert>}
|
|
||||||
{isLoader ? (
|
{isLoader ? (
|
||||||
<div
|
<div className="flex justify-center items-center h-screen">
|
||||||
style={{
|
<Loader />
|
||||||
height: "100vh",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="bg-white flex flex-col justify-center shadow rounded">
|
<>
|
||||||
<h1 className="ml-4 mt-3 mb-2 font-semibold">API Token</h1>
|
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box mb-3">
|
||||||
<ul className="w-full flex flex-col p-2 text-sm">
|
{!isEnableSubscription && <PremiumAlertHeader />}
|
||||||
<li
|
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
|
||||||
className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
|
OpenSign™ API{" "}
|
||||||
>
|
<Tooltip
|
||||||
<span className="w-[40%]">Api Token:</span>{" "}
|
url={
|
||||||
<span
|
|
||||||
id="token"
|
|
||||||
className="w-[60%] md:text-end cursor-pointer"
|
|
||||||
onClick={() => copytoclipboard(apiToken)}
|
|
||||||
>
|
|
||||||
{apiToken && apiToken}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div className="flex flex-col md:flex-row items-center justify-center gap-2 pb-4">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={apiToken ? handleModal : handleSubmit}
|
|
||||||
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base focus:outline-none"
|
|
||||||
>
|
|
||||||
{apiToken ? "Regenerate Token" : "Generate Token"}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() =>
|
|
||||||
openInNewTab(
|
|
||||||
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
||||||
)
|
}
|
||||||
}
|
isSubscribe={true}
|
||||||
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
|
/>
|
||||||
|
</h1>
|
||||||
|
<ul
|
||||||
|
className={"w-full flex flex-col p-2 text-sm"}
|
||||||
|
// isSubscribe || !isEnableSubscription
|
||||||
|
// ? "w-full flex flex-col p-2 text-sm "
|
||||||
|
// : "w-full flex flex-col p-2 text-sm opacity-20 pointer-events-none select-none"
|
||||||
>
|
>
|
||||||
View Docs
|
<li className="flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2">
|
||||||
</button>
|
<div className="w-full md:w-[70%] flex-col md:flex-row text-xs md:text-[15px] flex items-center gap-x-5">
|
||||||
</div>
|
<span className="ml-1">API Token:</span>{" "}
|
||||||
|
<span
|
||||||
<ModalUi
|
id="token"
|
||||||
isOpen={isModal}
|
className={`${
|
||||||
title={"Regenerate Token"}
|
isSubscribe || !isEnableSubscription
|
||||||
handleClose={handleModal}
|
? ""
|
||||||
>
|
: "bg-white/20 pointer-events-none select-none"
|
||||||
<div className="m-[20px]">
|
} md:text-end py-2 md:py-0`}
|
||||||
<div className="text-lg font-normal text-black">
|
>
|
||||||
Are you sure you want to regenerate token it will expire old
|
<span
|
||||||
token?
|
className="cursor-pointer"
|
||||||
</div>
|
onClick={() => copytoclipboard(apiToken)}
|
||||||
<hr className="bg-[#ccc] mt-4 " />
|
>
|
||||||
<div className="flex items-center mt-3 gap-2 text-white">
|
{apiToken ? apiToken : "_____"}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
className="op-btn op-btn-accent op-btn-outline op-btn-sm ml-2 cursor-pointer"
|
||||||
|
onClick={() => copytoclipboard(apiToken)}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-copy"></i>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={handleSubmit}
|
onClick={apiToken ? handleModal : handleSubmit}
|
||||||
className={submitBtn + "ml-[2px]"}
|
className="op-btn op-btn-primary"
|
||||||
>
|
>
|
||||||
Yes
|
{apiToken ? "Regenerate Token" : "Generate Token"}
|
||||||
</button>
|
</button>
|
||||||
<button onClick={handleModal} className={rejectBtn}>
|
</li>
|
||||||
No
|
</ul>
|
||||||
</button>
|
<div className="flex items-center justify-center">
|
||||||
</div>
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() =>
|
||||||
|
openInNewTab(
|
||||||
|
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
className="op-btn op-btn-secondary mt-2 mb-3 px-8"
|
||||||
|
>
|
||||||
|
View Docs
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</ModalUi>
|
<ModalUi
|
||||||
</div>
|
isOpen={isModal}
|
||||||
|
title={apiToken ? "Regenerate Token" : "Generate Token"}
|
||||||
|
handleClose={handleModal}
|
||||||
|
>
|
||||||
|
<div className="m-[20px]">
|
||||||
|
<div className="text-lg font-normal text-base-content">
|
||||||
|
Are you sure you want to regenerate token it will expire old
|
||||||
|
token?
|
||||||
|
</div>
|
||||||
|
<hr className="bg-[#ccc] mt-4" />
|
||||||
|
<div className="flex items-center mt-3 gap-2 text-white">
|
||||||
|
<button
|
||||||
|
onClick={handleSubmit}
|
||||||
|
className="op-btn op-btn-primary ml-[2px]"
|
||||||
|
>
|
||||||
|
Yes
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleModal}
|
||||||
|
className="op-btn op-btn-secondary"
|
||||||
|
>
|
||||||
|
No
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
|
</div>
|
||||||
|
{!isSubscribe && isEnableSubscription && (
|
||||||
|
<div data-tut="apisubscribe">
|
||||||
|
<SubscribeCard />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
<Tour
|
||||||
|
onRequestClose={() => setIsTour(false)}
|
||||||
|
steps={tourSteps}
|
||||||
|
isOpen={isTour}
|
||||||
|
closeWithMask={false}
|
||||||
|
disableKeyboardNavigation={["esc"]}
|
||||||
|
scrollOffset={-100}
|
||||||
|
rounded={5}
|
||||||
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,80 +1,103 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import "../styles/loginPage.css";
|
|
||||||
import loader from "../assets/images/loader2.gif";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { themeColor } from "../constant/const";
|
import { isEnableSubscription } 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";
|
||||||
|
import Parse from "parse";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
|
||||||
function GuestLogin() {
|
function GuestLogin() {
|
||||||
const { id, userMail, contactBookId, serverUrl } = useParams();
|
const { id, userMail, contactBookId, base64url } = useParams();
|
||||||
let navigate = useNavigate();
|
const 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);
|
||||||
|
const [sendmail, setSendmail] = useState();
|
||||||
|
const [contact, setContact] = useState({ name: "", phone: "", email: "" });
|
||||||
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]);
|
||||||
|
setContact((prev) => ({ ...prev, email: checkSplit[1] }));
|
||||||
|
setEmail(checkSplit[1]);
|
||||||
|
const contactId = checkSplit?.[2];
|
||||||
|
setSendmail(checkSplit[3]);
|
||||||
|
if (!contactId) {
|
||||||
|
const params = { email: checkSplit[1], docId: checkSplit[0] };
|
||||||
|
try {
|
||||||
|
const linkContactRes = await Parse.Cloud.run(
|
||||||
|
"linkcontacttodoc",
|
||||||
|
params
|
||||||
|
);
|
||||||
|
// console.log("linkContactRes ", linkContactRes);
|
||||||
|
setContactId(linkContactRes?.contactId);
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err in link ext contact", err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setContactId(checkSplit[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChange = (event) => {
|
|
||||||
const { value } = event.target;
|
|
||||||
setOTP(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
//send email OTP function
|
//send email OTP function
|
||||||
const SendOtp = async (e) => {
|
const SendOtp = async () => {
|
||||||
const serverUrl =
|
setLoading(true);
|
||||||
localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl");
|
setEmail(email);
|
||||||
const parseId =
|
try {
|
||||||
localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId");
|
const params = { email: email.toString(), docId: documentId };
|
||||||
if (serverUrl && localStorage) {
|
const Otp = await Parse.Cloud.run("SendOTPMailV1", params);
|
||||||
setLoading(true);
|
if (Otp) {
|
||||||
e.preventDefault();
|
setLoading(false);
|
||||||
setEmail(email);
|
setEnterOtp(true);
|
||||||
|
|
||||||
try {
|
|
||||||
let url = `${serverUrl}functions/SendOTPMailV1/`;
|
|
||||||
const headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseId
|
|
||||||
};
|
|
||||||
let body = {
|
|
||||||
email: email.toString()
|
|
||||||
};
|
|
||||||
let Otp = await axios.post(url, body, { headers: headers });
|
|
||||||
|
|
||||||
if (Otp) {
|
|
||||||
setLoading(false);
|
|
||||||
setEnterOtp(true);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
alert("something went wrong!");
|
|
||||||
}
|
}
|
||||||
} else {
|
} catch (error) {
|
||||||
alert("something went wrong!");
|
alert("something went wrong!");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSendOTPBtn = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
await SendOtp();
|
||||||
|
};
|
||||||
|
|
||||||
//verify OTP send on via email
|
//verify OTP send on via email
|
||||||
const VerifyOTP = async (e) => {
|
const VerifyOTP = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -110,7 +133,8 @@ function GuestLogin() {
|
|||||||
`Parse/${parseId}/currentUser`,
|
`Parse/${parseId}/currentUser`,
|
||||||
JSON.stringify(_user)
|
JSON.stringify(_user)
|
||||||
);
|
);
|
||||||
if (contractUserDetails) {
|
// console.log("contractUserDetails ", contractUserDetails);
|
||||||
|
if (contractUserDetails && contractUserDetails.length > 0) {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"Extand_Class",
|
"Extand_Class",
|
||||||
JSON.stringify(contractUserDetails)
|
JSON.stringify(contractUserDetails)
|
||||||
@@ -122,7 +146,13 @@ 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}`);
|
if (sendmail === "false") {
|
||||||
|
navigate(
|
||||||
|
`/load/recipientSignPdf/${documentId}/${contactId}?sendmail=${sendmail}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
navigate(`/load/recipientSignPdf/${documentId}/${contactId}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("err ", error);
|
console.log("err ", error);
|
||||||
@@ -131,154 +161,169 @@ function GuestLogin() {
|
|||||||
alert("Please Enter OTP!");
|
alert("Please Enter OTP!");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const handleUserData = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const params = { ...contact, docId: documentId };
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
const linkContactRes = await Parse.Cloud.run("linkcontacttodoc", params);
|
||||||
|
// console.log("linkContactRes ", linkContactRes);
|
||||||
|
setContactId(linkContactRes.contactId);
|
||||||
|
setEnterOtp(true);
|
||||||
|
await SendOtp();
|
||||||
|
} catch (err) {
|
||||||
|
setLoading(false);
|
||||||
|
alert("something went wron, please try agian later.");
|
||||||
|
console.log("Err in link ext contact", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleInputChange = (e) => {
|
||||||
|
setContact((prev) => ({ ...prev, [e.target.name]: e.target.value }));
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: "2rem", background: "white" }}>
|
<div className="p-[2rem]">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div
|
<div className="flex flex-col justify-center items-center h-[100vh]">
|
||||||
style={{
|
<Loader />
|
||||||
display: "flex",
|
<span className="text-[13px] text-[gray]">{isLoading.message}</span>
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
height: "100vh",
|
|
||||||
flexDirection: "column"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="no img"
|
|
||||||
src={loader}
|
|
||||||
style={{ width: "80px", height: "80px" }}
|
|
||||||
/>
|
|
||||||
<span style={{ fontSize: "13px", color: "gray" }}>
|
|
||||||
{isLoading.message}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div className="m-1 md:m-2 p-[30px] text-base-content bg-base-100 op-card shadow-md">
|
||||||
style={{
|
<div className="md:w-[250px] md:h-[66px] inline-block overflow-hidden mt-2 mb-11">
|
||||||
margin: "10px",
|
{appLogo && (
|
||||||
border: "0.5px solid #c5c7c9",
|
<img src={appLogo} className="object-contain" alt="logo" />
|
||||||
padding: "30px",
|
)}
|
||||||
boxShadow: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="main_head">
|
|
||||||
<div className="main-logo">
|
|
||||||
<img
|
|
||||||
alt="sign img"
|
|
||||||
src="https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"
|
|
||||||
width="100%"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
{contactId ? (
|
||||||
{!EnterOTP ? (
|
<>
|
||||||
<div className="row">
|
{!EnterOTP ? (
|
||||||
<div className="col-sm-6 KLO">
|
<div className="w-full md:w-[50%] text-base-content">
|
||||||
<span className="welcomeText">Welcome Back !</span>
|
<h1 className="text-2xl md:text-[30px]">Welcome Back!</h1>
|
||||||
<br />
|
<legend className="text-[12px] text-[#878787] mt-2 mb-1">
|
||||||
<span className="KNLO">
|
Verification code is sent to your email
|
||||||
Verification code is sent to your email
|
</legend>
|
||||||
</span>
|
<div className="p-[20px] outline outline-1 outline-slate-300/50 my-2 op-card shadow-md">
|
||||||
<div className="card card-box" style={{ borderRadius: "0px" }}>
|
|
||||||
<div className="card-body">
|
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
name="mobile"
|
name="mobile"
|
||||||
value={email}
|
value={email}
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full disabled:text-[#5c5c5c] text-xs"
|
||||||
disabled
|
disabled
|
||||||
className="loginInput"
|
|
||||||
/>
|
/>
|
||||||
<br />
|
</div>
|
||||||
|
<div className="mt-3">
|
||||||
|
<button
|
||||||
|
className="op-btn op-btn-primary"
|
||||||
|
onClick={(e) => handleSendOTPBtn(e)}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
{loading ? "Loading..." : "Get verification code"}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="btnContainer">
|
) : (
|
||||||
{loading ? (
|
<form
|
||||||
<button
|
className="w-full md:w-[50%] text-base-content"
|
||||||
type="button"
|
onSubmit={VerifyOTP}
|
||||||
style={{
|
>
|
||||||
background: themeColor,
|
<h1 className="text-2xl md:text-[30px]">Welcome Back!</h1>
|
||||||
color: "white"
|
<legend className="text-[12px] text-[#878787] mt-2">
|
||||||
}}
|
You will get a verification code via Email
|
||||||
className="verifyBtn"
|
</legend>
|
||||||
disabled
|
<div className="p-[20px] pt-[15px] outline outline-1 outline-slate-300/50 op-card my-2 shadow-md">
|
||||||
>
|
<p className="text-sm">Enter Verification Code</p>
|
||||||
<span
|
|
||||||
className="spinner-border spinner-border-sm "
|
|
||||||
role="status"
|
|
||||||
aria-hidden="true"
|
|
||||||
></span>
|
|
||||||
Loading...
|
|
||||||
</button>
|
|
||||||
) : (
|
|
||||||
<button
|
|
||||||
className="verifyBtn"
|
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white",
|
|
||||||
marginLeft: "0px !important"
|
|
||||||
}}
|
|
||||||
onClick={(e) => SendOtp(e)}
|
|
||||||
>
|
|
||||||
Send OTP
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="row">
|
|
||||||
<div className="col-sm-6 KLO">
|
|
||||||
<span className="welcomeText">Welcome Back !</span>
|
|
||||||
<br />
|
|
||||||
<span className="KNLO">You will get a OTP via Email</span>
|
|
||||||
<div className="card card-box">
|
|
||||||
<div className="card-body">
|
|
||||||
<label>Enter Verification Code</label>
|
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
className="loginInput"
|
className="mt-2 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
name="OTP"
|
name="OTP"
|
||||||
value={OTP}
|
value={OTP}
|
||||||
onChange={handleChange}
|
onChange={(e) => setOTP(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<br />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="mt-2.5">
|
||||||
<div>
|
|
||||||
{loading ? (
|
|
||||||
<button
|
<button
|
||||||
style={{
|
className="op-btn op-btn-primary"
|
||||||
background: themeColor,
|
type="submit"
|
||||||
color: "white"
|
disabled={loading}
|
||||||
}}
|
|
||||||
className="verifyBtn"
|
|
||||||
type="button"
|
|
||||||
disabled
|
|
||||||
>
|
>
|
||||||
<span
|
{loading ? "Loading..." : "Verify"}
|
||||||
className="spinner-border spinner-border-sm "
|
|
||||||
role="status"
|
|
||||||
aria-hidden="true"
|
|
||||||
></span>
|
|
||||||
Loading...
|
|
||||||
</button>
|
</button>
|
||||||
) : (
|
</div>
|
||||||
<button
|
</form>
|
||||||
type="button"
|
)}
|
||||||
onClick={(e) => VerifyOTP(e)}
|
</>
|
||||||
style={{
|
) : (
|
||||||
background: themeColor,
|
<div className="w-full md:w-[50%] text-base-content">
|
||||||
color: "white"
|
<h1 className="text-2xl md:text-[30px]">Welcome</h1>
|
||||||
}}
|
<legend className="text-[12px] text-[#878787] mt-2">
|
||||||
className="verifyBtn"
|
Provide your details
|
||||||
>
|
</legend>
|
||||||
Verify
|
<form
|
||||||
</button>
|
className="p-[20px] pt-[15px] outline outline-1 outline-slate-300/50 my-2 op-card shadow-md"
|
||||||
)}
|
onSubmit={handleUserData}
|
||||||
|
>
|
||||||
|
<div className="mb-2">
|
||||||
|
<label
|
||||||
|
htmlFor="name"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
Name
|
||||||
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
value={contact.name}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
disabled={loading}
|
||||||
|
required
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="mb-2">
|
||||||
|
<label
|
||||||
|
htmlFor="email"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
Email
|
||||||
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
value={contact.email}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
required
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mt-2.5">
|
||||||
|
<label
|
||||||
|
htmlFor="phone"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
Phone
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="phone"
|
||||||
|
value={contact.phone}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
disabled={loading}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mt-2 flex justify-start">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="op-btn op-btn-primary"
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
{loading ? "Loading..." : "Next"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+416
-345
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,9 @@ import "../styles/signature.css";
|
|||||||
import { toDataUrl } from "../constant/Utils";
|
import { toDataUrl } from "../constant/Utils";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import { appInfo } from "../constant/appinfo";
|
import { appInfo } from "../constant/appinfo";
|
||||||
|
import { SaveFileSize } from "../constant/saveFileSize";
|
||||||
|
import Alert from "../primitives/Alert";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
const ManageSign = () => {
|
const ManageSign = () => {
|
||||||
const appName = appInfo.appname;
|
const appName = appInfo.appname;
|
||||||
const [penColor, setPenColor] = useState("blue");
|
const [penColor, setPenColor] = useState("blue");
|
||||||
@@ -13,11 +16,10 @@ const ManageSign = () => {
|
|||||||
const [signName, setSignName] = useState("");
|
const [signName, setSignName] = useState("");
|
||||||
const [signature, setSignature] = useState("");
|
const [signature, setSignature] = useState("");
|
||||||
const [warning, setWarning] = useState(false);
|
const [warning, setWarning] = useState(false);
|
||||||
const [nameWarning, setNameWarning] = useState(false);
|
|
||||||
const [isvalue, setIsValue] = useState(false);
|
const [isvalue, setIsValue] = useState(false);
|
||||||
const allColor = ["blue", "red", "black"];
|
const allColor = ["blue", "red", "black"];
|
||||||
const [isLoader, setIsLoader] = useState(true);
|
const [isLoader, setIsLoader] = useState(true);
|
||||||
const [isSuccess, setIsSuccess] = useState(false);
|
const [isAlert, setIsAlert] = useState({ type: "success", message: "" });
|
||||||
const [Initials, setInitials] = useState("");
|
const [Initials, setInitials] = useState("");
|
||||||
const [isInitials, setIsInitials] = useState(false);
|
const [isInitials, setIsInitials] = useState(false);
|
||||||
const [id, setId] = useState("");
|
const [id, setId] = useState("");
|
||||||
@@ -105,9 +107,7 @@ const ManageSign = () => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const isUrl = image.includes("https");
|
const isUrl = image.includes("https");
|
||||||
|
|
||||||
if (!signName) {
|
if (!isvalue) {
|
||||||
setNameWarning(true);
|
|
||||||
} else if (!isvalue) {
|
|
||||||
setWarning(true);
|
setWarning(true);
|
||||||
setTimeout(() => setWarning(false), 1000);
|
setTimeout(() => setWarning(false), 1000);
|
||||||
} else {
|
} else {
|
||||||
@@ -161,7 +161,11 @@ const ManageSign = () => {
|
|||||||
try {
|
try {
|
||||||
const parseFile = new Parse.File(file.name, file);
|
const parseFile = new Parse.File(file.name, file);
|
||||||
const response = await parseFile.save();
|
const response = await parseFile.save();
|
||||||
return response?.url();
|
if (response?.url()) {
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
SaveFileSize(file.size, response.url(), tenantId);
|
||||||
|
return response?.url();
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("sign upload err", err);
|
console.log("sign upload err", err);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
@@ -183,12 +187,20 @@ const ManageSign = () => {
|
|||||||
updateSign.set("UserId", userId);
|
updateSign.set("UserId", userId);
|
||||||
const res = await updateSign.save();
|
const res = await updateSign.save();
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
setIsSuccess(true);
|
setIsAlert({
|
||||||
|
type: "success",
|
||||||
|
message: "Signature saved successfully."
|
||||||
|
});
|
||||||
|
setTimeout(() => setIsAlert({}), 2000);
|
||||||
return res;
|
return res;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
alert(`${err.message}`);
|
setIsAlert({
|
||||||
|
type: "danger",
|
||||||
|
message: `${err.message}`
|
||||||
|
});
|
||||||
|
setTimeout(() => setIsAlert({}), 2000);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
@@ -199,21 +211,24 @@ const ManageSign = () => {
|
|||||||
updateSign.set("UserId", userId);
|
updateSign.set("UserId", userId);
|
||||||
const res = await updateSign.save();
|
const res = await updateSign.save();
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
setIsSuccess(true);
|
setIsAlert({
|
||||||
|
type: "success",
|
||||||
|
message: "Signature saved successfully."
|
||||||
|
});
|
||||||
|
setTimeout(() => setIsAlert({}), 2000);
|
||||||
return res;
|
return res;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
alert(`${err.message}`);
|
setIsAlert({
|
||||||
|
type: "success",
|
||||||
|
message: `${err.message}`
|
||||||
|
});
|
||||||
|
setTimeout(() => setIsAlert({}), 2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleSignatureBtn = () => {
|
|
||||||
if (imageRef.current) {
|
|
||||||
imageRef.current.value = "";
|
|
||||||
}
|
|
||||||
setImage("");
|
|
||||||
};
|
|
||||||
const handleUploadBtn = () => {
|
const handleUploadBtn = () => {
|
||||||
imageRef.current.click();
|
imageRef.current.click();
|
||||||
};
|
};
|
||||||
@@ -222,278 +237,130 @@ const ManageSign = () => {
|
|||||||
setIsValue(true);
|
setIsValue(true);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="relative h-full bg-base-100 text-base-content flex shadow-md rounded-box overflow-auto">
|
||||||
style={{
|
|
||||||
backgroundColor: "white",
|
|
||||||
maxHeight: "500px",
|
|
||||||
overflow: "auto"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isLoader && (
|
{isLoader && (
|
||||||
<div className="absolute bg-black bg-opacity-75 inset-0 z-50 flex justify-center items-center">
|
<div className="absolute bg-black bg-opacity-30 z-50 w-full h-full flex justify-center items-center">
|
||||||
<div style={{ height: "300px" }}>
|
<Loader />
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
marginLeft: "45%",
|
|
||||||
marginTop: "150px",
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isSuccess && (
|
{isAlert?.message && <Alert type={isAlert.type}>{isAlert.message}</Alert>}
|
||||||
<div
|
<div className="relative w-full">
|
||||||
className="alert alert-success successBox"
|
<div className="ml-[5px] my-[20px] md:m-[20px]">
|
||||||
role="alert"
|
<div className="text-[20px] font-semibold m-[10px] md:m-0 mb-2">
|
||||||
onAnimationEnd={() => setIsSuccess(false)}
|
My Signature
|
||||||
>
|
|
||||||
Signature saved successfully!
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div
|
|
||||||
className="mainDiv"
|
|
||||||
style={{
|
|
||||||
width: "100%",
|
|
||||||
paddingRight: "10px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{ margin: 20 }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontWeight: "700",
|
|
||||||
fontSize: 15,
|
|
||||||
color: "#000",
|
|
||||||
paddingBottom: 8
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Manage Signature
|
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
<div className="flex flex-col md:flex-row gap-0 md:gap-[12px]">
|
||||||
<label
|
<div className="relative">
|
||||||
htmlFor="signName"
|
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
|
||||||
style={{
|
Signature
|
||||||
fontSize: 12,
|
</span>
|
||||||
position: "relative",
|
<input
|
||||||
paddingBottom: 5
|
type="file"
|
||||||
}}
|
onChange={onImageChange}
|
||||||
>
|
className="filetype"
|
||||||
Signer's Name
|
accept="image/*"
|
||||||
{nameWarning && (
|
ref={imageRef}
|
||||||
<div
|
hidden
|
||||||
className="warning nameWarning"
|
/>
|
||||||
style={{ fontSize: 12 }}
|
<div className="relative">
|
||||||
onAnimationEnd={() => setNameWarning(false)}
|
<div>
|
||||||
>
|
{image ? (
|
||||||
<i
|
<div className="signatureCanvas relative border-[2px] border-[#888] rounded-box">
|
||||||
className="fas fa-exclamation-circle"
|
<img
|
||||||
style={{ color: "#fab005", fontSize: 15 }}
|
alt="signature"
|
||||||
></i>{" "}
|
src={image}
|
||||||
Please fill input field
|
className="w-full h-full object-contain"
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="signName"
|
|
||||||
className="signInputManage"
|
|
||||||
value={signName}
|
|
||||||
style={{
|
|
||||||
border: "1px solid #ccc",
|
|
||||||
borderRadius: 4,
|
|
||||||
|
|
||||||
height: 35,
|
|
||||||
padding: "6px 12px",
|
|
||||||
marginBottom: 10,
|
|
||||||
fontSize: 12
|
|
||||||
}}
|
|
||||||
required
|
|
||||||
onFocus={() => setNameWarning(false)}
|
|
||||||
onChange={(e) => setSignName(e.target.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<label
|
|
||||||
htmlFor="imgoverview"
|
|
||||||
style={{
|
|
||||||
fontSize: 12,
|
|
||||||
paddingBottom: 5
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Signature/Image
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className="signBlock">
|
|
||||||
<div>
|
|
||||||
<div style={{ position: "relative" }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
width: "50%",
|
|
||||||
paddingLeft: 10
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-around",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: 10,
|
|
||||||
marginBottom: 10
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<>
|
|
||||||
<span
|
|
||||||
onClick={() => handleSignatureBtn()}
|
|
||||||
className="signature"
|
|
||||||
>
|
|
||||||
Signature
|
|
||||||
</span>
|
|
||||||
</>
|
|
||||||
|
|
||||||
<span
|
|
||||||
onClick={() => handleUploadBtn()}
|
|
||||||
className="imgupload"
|
|
||||||
>
|
|
||||||
Upload Image
|
|
||||||
</span>
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
onChange={onImageChange}
|
|
||||||
className="filetype"
|
|
||||||
accept="image/*"
|
|
||||||
ref={imageRef}
|
|
||||||
hidden
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ position: "relative" }}>
|
|
||||||
<div>
|
|
||||||
{image ? (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "relative",
|
|
||||||
border: "2px solid #888"
|
|
||||||
}}
|
|
||||||
className="signatureCanvas"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="preview image"
|
|
||||||
src={image}
|
|
||||||
style={{
|
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<SignatureCanvas
|
|
||||||
ref={canvasRef}
|
|
||||||
penColor={penColor}
|
|
||||||
canvasProps={{
|
|
||||||
width: "456px",
|
|
||||||
height: "180px",
|
|
||||||
className: "signatureCanvas"
|
|
||||||
}}
|
|
||||||
backgroundColor="rgb(255, 255, 255)"
|
|
||||||
onEnd={() =>
|
|
||||||
handleSignatureChange(canvasRef.current.toDataURL())
|
|
||||||
}
|
|
||||||
dotSize={1}
|
|
||||||
/>
|
/>
|
||||||
)}
|
</div>
|
||||||
<div
|
) : (
|
||||||
style={{
|
<SignatureCanvas
|
||||||
display: "flex",
|
ref={canvasRef}
|
||||||
flexDirection: "row",
|
penColor={penColor}
|
||||||
justifyContent: "space-between"
|
canvasProps={{
|
||||||
|
width: "456px",
|
||||||
|
height: "180px",
|
||||||
|
className: "signatureCanvas rounded-box"
|
||||||
}}
|
}}
|
||||||
className="penContainerDefault"
|
backgroundColor="rgb(255, 255, 255)"
|
||||||
>
|
onEnd={() =>
|
||||||
<div>
|
handleSignatureChange(canvasRef.current.toDataURL())
|
||||||
{!image && (
|
}
|
||||||
<div
|
dotSize={1}
|
||||||
style={{ display: "flex", flexDirection: "row" }}
|
/>
|
||||||
>
|
)}
|
||||||
{allColor.map((data, key) => {
|
<div className="penContainerDefault flex flex-row justify-between">
|
||||||
return (
|
<div>
|
||||||
<i
|
{!image && (
|
||||||
style={{
|
<div className="flex flex-row">
|
||||||
margin: "5px",
|
{allColor.map((data, key) => {
|
||||||
color: data,
|
return (
|
||||||
borderBottom:
|
<i
|
||||||
key === 0 && penColor === "blue"
|
style={{
|
||||||
? "2px solid blue"
|
margin: "5px",
|
||||||
: key === 1 && penColor === "red"
|
color: data,
|
||||||
? "2px solid red"
|
borderBottom:
|
||||||
: key === 2 && penColor === "black"
|
key === 0 && penColor === "blue"
|
||||||
? "2px solid black"
|
? "2px solid blue"
|
||||||
: "2px solid white"
|
: key === 1 && penColor === "red"
|
||||||
}}
|
? "2px solid red"
|
||||||
onClick={() => {
|
: key === 2 && penColor === "black"
|
||||||
if (key === 0) {
|
? "2px solid black"
|
||||||
setPenColor("blue");
|
: "2px solid white"
|
||||||
} else if (key === 1) {
|
}}
|
||||||
setPenColor("red");
|
onClick={() => {
|
||||||
} else if (key === 2) {
|
if (key === 0) {
|
||||||
setPenColor("black");
|
setPenColor("blue");
|
||||||
}
|
} else if (key === 1) {
|
||||||
}}
|
setPenColor("red");
|
||||||
key={key}
|
} else if (key === 2) {
|
||||||
className="fa solid fa-pen-nib"
|
setPenColor("black");
|
||||||
width={20}
|
}
|
||||||
height={20}
|
}}
|
||||||
></i>
|
key={key}
|
||||||
);
|
className="fa-light fa-pen-nib"
|
||||||
})}
|
width={20}
|
||||||
</div>
|
height={20}
|
||||||
)}
|
></i>
|
||||||
</div>
|
);
|
||||||
<div>
|
})}
|
||||||
<div
|
|
||||||
type="button"
|
|
||||||
className="clearbtn cursor-pointer"
|
|
||||||
onClick={() => handleClear()}
|
|
||||||
>
|
|
||||||
Clear
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row gap-2 text-sm md:text-base mr-1">
|
||||||
|
<div
|
||||||
|
type="button"
|
||||||
|
className="op-link"
|
||||||
|
onClick={() => handleUploadBtn()}
|
||||||
|
>
|
||||||
|
Upload image
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
type="button"
|
||||||
|
className="op-link"
|
||||||
|
onClick={() => handleClear()}
|
||||||
|
>
|
||||||
|
Clear
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{warning && (
|
|
||||||
<div
|
|
||||||
className="warning signWarning"
|
|
||||||
style={{ fontSize: 12 }}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fas fa-exclamation-circle"
|
|
||||||
style={{ color: "#fab005", fontSize: 15 }}
|
|
||||||
></i>{" "}
|
|
||||||
Please upload signature/Image
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
{warning && (
|
||||||
|
<span className="customwarning signWarning text-[12px] w-[220px] md:w-[300px]">
|
||||||
|
<i className="fa-light fa-exclamation-circle text-[#fab005] text-[15px] mr-[4px]"></i>
|
||||||
|
Please upload signature/Image
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ position: "relative" }}>
|
<div className="relative">
|
||||||
<div style={{ margin: "6px 5px 18px" }}>
|
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
|
||||||
<span className="signature">Initials</span>
|
Initials
|
||||||
</div>
|
</span>
|
||||||
<div>
|
<div>
|
||||||
{isInitials ? (
|
{isInitials ? (
|
||||||
<div
|
<div className="intialSignature relative border-[1px] border-[#888] rounded-box overflow-hidden">
|
||||||
style={{
|
|
||||||
position: "relative",
|
|
||||||
border: "2px solid #888"
|
|
||||||
}}
|
|
||||||
className="intialSignature"
|
|
||||||
>
|
|
||||||
<img
|
<img
|
||||||
alt="preview image"
|
alt="inititals"
|
||||||
src={Initials}
|
src={Initials}
|
||||||
style={{
|
style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
@@ -507,7 +374,7 @@ const ManageSign = () => {
|
|||||||
ref={initailsRef}
|
ref={initailsRef}
|
||||||
penColor={initialPen}
|
penColor={initialPen}
|
||||||
canvasProps={{
|
canvasProps={{
|
||||||
className: "intialSignature"
|
className: "intialSignature rounded-box"
|
||||||
}}
|
}}
|
||||||
backgroundColor="rgb(255, 255, 255)"
|
backgroundColor="rgb(255, 255, 255)"
|
||||||
onEnd={() =>
|
onEnd={() =>
|
||||||
@@ -516,17 +383,10 @@ const ManageSign = () => {
|
|||||||
dotSize={1}
|
dotSize={1}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div
|
<div className="flex flex-row justify-between w-[183px]">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-between"
|
|
||||||
}}
|
|
||||||
className="penContainerInitial"
|
|
||||||
>
|
|
||||||
<div>
|
<div>
|
||||||
{!isInitials && (
|
{!isInitials && (
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
<div className="flex flex-row">
|
||||||
{allColor.map((data, key) => {
|
{allColor.map((data, key) => {
|
||||||
return (
|
return (
|
||||||
<i
|
<i
|
||||||
@@ -552,7 +412,7 @@ const ManageSign = () => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
key={key}
|
key={key}
|
||||||
className="fa solid fa-pen-nib"
|
className="fa-light fa-pen-nib"
|
||||||
width={20}
|
width={20}
|
||||||
height={20}
|
height={20}
|
||||||
></i>
|
></i>
|
||||||
@@ -564,7 +424,7 @@ const ManageSign = () => {
|
|||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
type="button"
|
type="button"
|
||||||
className="clearbtn cursor-pointer"
|
className="op-link text-sm md:text-base mr-1"
|
||||||
onClick={() => handleClearInitials()}
|
onClick={() => handleClearInitials()}
|
||||||
>
|
>
|
||||||
Clear
|
Clear
|
||||||
@@ -572,20 +432,11 @@ const ManageSign = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* {!warning && (
|
|
||||||
<div className="warning signWarning" style={{ fontSize: 12 }}>
|
|
||||||
<i
|
|
||||||
className="fas fa-exclamation-circle"
|
|
||||||
style={{ color: "#fab005", fontSize: 15 }}
|
|
||||||
></i>{" "}
|
|
||||||
Please upload signature/Image
|
|
||||||
</div>
|
|
||||||
)} */}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ paddingTop: 10 }}>
|
<div className="pt-3 ml-2 md:ml-0">
|
||||||
<button
|
<button
|
||||||
className="customBtn successBtn"
|
className="op-btn op-btn-primary"
|
||||||
onClick={(e) => handleSubmit(e)}
|
onClick={(e) => handleSubmit(e)}
|
||||||
>
|
>
|
||||||
save
|
save
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,13 +4,11 @@ import Title from "../components/Title";
|
|||||||
|
|
||||||
const PageNotFound = ({ prefix }) => {
|
const PageNotFound = ({ prefix }) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center h-screen w-full bg-white rounded">
|
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
|
||||||
<Title title={"Page Not Found"} />
|
<Title title={"Page Not Found"} />
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<h1 className="text-[60px] lg:text-[120px] font-semibold text-black">
|
<h1 className="text-[60px] lg:text-[120px] font-semibold">404</h1>
|
||||||
404
|
<p className="text-[30px] lg:text-[50px]">
|
||||||
</h1>
|
|
||||||
<p className="text-[30px] lg:text-[50px] text-black">
|
|
||||||
{prefix ? prefix : "Page"} Not Found
|
{prefix ? prefix : "Page"} Not Found
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+122
-162
@@ -1,15 +1,18 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import "../styles/pgsignup.css";
|
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { fetchAppInfo, showTenantName } from "../redux/actions/index";
|
import { useDispatch } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import { useNavigate, useLocation } from "react-router-dom";
|
import { useNavigate, useLocation } from "react-router-dom";
|
||||||
|
import { appInfo } from "../constant/appinfo";
|
||||||
|
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||||
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
|
||||||
const PgSignUp = (props) => {
|
const PgSignUp = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
|
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
|
||||||
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
|
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
@@ -24,8 +27,7 @@ const PgSignUp = (props) => {
|
|||||||
|
|
||||||
// below useEffect is used to fetch App data and save to redux state
|
// below useEffect is used to fetch App data and save to redux state
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Parse.User.logOut()
|
dispatch(fetchAppInfo());
|
||||||
props.fetchAppInfo();
|
|
||||||
handleSignedUpUser();
|
handleSignedUpUser();
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
@@ -39,12 +41,8 @@ const PgSignUp = (props) => {
|
|||||||
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(
|
||||||
@@ -59,34 +57,27 @@ const PgSignUp = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// 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);
|
||||||
@@ -106,12 +97,8 @@ const PgSignUp = (props) => {
|
|||||||
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);
|
||||||
@@ -140,7 +127,9 @@ const PgSignUp = (props) => {
|
|||||||
user.set("username", zohoRes.data.result.email);
|
user.set("username", zohoRes.data.result.email);
|
||||||
user.set("password", obj.password);
|
user.set("password", obj.password);
|
||||||
user.set("email", zohoRes.data.result.email);
|
user.set("email", zohoRes.data.result.email);
|
||||||
user.set("phone", zohoRes.data.result.phone);
|
if (zohoRes?.data?.result?.phone) {
|
||||||
|
user.set("phone", zohoRes.data.result.phone);
|
||||||
|
}
|
||||||
user.set("name", zohoRes.data.result.name);
|
user.set("name", zohoRes.data.result.name);
|
||||||
|
|
||||||
const res = await user.signUp();
|
const res = await user.signUp();
|
||||||
@@ -153,21 +142,10 @@ const PgSignUp = (props) => {
|
|||||||
company: zohoRes.data.result.company,
|
company: zohoRes.data.result.company,
|
||||||
name: zohoRes.data.result.name,
|
name: zohoRes.data.result.name,
|
||||||
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);
|
||||||
@@ -243,8 +221,8 @@ const PgSignUp = (props) => {
|
|||||||
// Check extended class user role and tenentId
|
// Check extended class user role and tenentId
|
||||||
try {
|
try {
|
||||||
let userRoles = [];
|
let userRoles = [];
|
||||||
if (props.appInfo.settings) {
|
if (appInfo.settings) {
|
||||||
let userSettings = props.appInfo.settings;
|
let userSettings = appInfo.settings;
|
||||||
|
|
||||||
//Get Current user roles
|
//Get Current user roles
|
||||||
let url = `${baseUrl}functions/UserGroups`;
|
let url = `${baseUrl}functions/UserGroups`;
|
||||||
@@ -319,8 +297,8 @@ const PgSignUp = (props) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (tenentInfo.length) {
|
if (tenentInfo.length) {
|
||||||
props.showTenantName(
|
dispatch(
|
||||||
tenentInfo[0].tenentName || ""
|
showTenant(tenentInfo[0].tenentName || "")
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenantName",
|
"TenantName",
|
||||||
@@ -351,15 +329,15 @@ const PgSignUp = (props) => {
|
|||||||
tenentName: x.TenantId.TenantName || ""
|
tenentName: x.TenantId.TenantName || ""
|
||||||
};
|
};
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenetId",
|
"TenantId",
|
||||||
x.TenantId.objectId
|
x.TenantId.objectId
|
||||||
);
|
);
|
||||||
tenentInfo.push(obj);
|
tenentInfo.push(obj);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (tenentInfo.length) {
|
if (tenentInfo.length) {
|
||||||
props.showTenantName(
|
dispatch(
|
||||||
tenentInfo[0].tenentName || ""
|
showTenant(tenentInfo[0].tenentName || "")
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenantName",
|
"TenantName",
|
||||||
@@ -430,122 +408,104 @@ const PgSignUp = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="bg-white">
|
<div className="w-full h-screen">
|
||||||
<Title title={"Pgsignup page"} />
|
<Title title={"Pgsignup page"} />
|
||||||
{isLoader ? (
|
{isLoader ? (
|
||||||
<div
|
<div className="flex justify-center items-center h-[100vh]">
|
||||||
style={{
|
<Loader />
|
||||||
height: "100vh",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<form id="signup" className="pgsignup-content" onSubmit={handleSubmit}>
|
<div className="py-10 lg:p-16 flex justify-center">
|
||||||
<div className="pgsignup-container">
|
<form
|
||||||
<h1 className="text-2xl md:text-3xl font-bold">Choose Password</h1>
|
id="signup"
|
||||||
<hr className="hrt" />
|
className="w-[90%] md:w-[55%] bg-base-100 text-base-content op-card shadow-md"
|
||||||
<label htmlFor="password">
|
onSubmit={handleSubmit}
|
||||||
<b className="text-[13px]">Password</b>
|
>
|
||||||
</label>
|
<div className="p-[16px]">
|
||||||
<input
|
<h1 className="text-2xl md:text-3xl font-bold">
|
||||||
type="password"
|
Choose Password
|
||||||
placeholder="Enter Password"
|
</h1>
|
||||||
name="password"
|
<hr className="border-[1px] border-[#cecece] mb-[5px]" />
|
||||||
className="inputt"
|
<label htmlFor="password">
|
||||||
value={formData.password}
|
<b className="text-[13px]">Password</b>
|
||||||
onChange={handlePassowordChange}
|
</label>
|
||||||
required
|
<input
|
||||||
/>
|
type="password"
|
||||||
|
placeholder="Enter Password"
|
||||||
<label htmlFor="confirmPassword">
|
name="password"
|
||||||
<b className="text-[13px]">Confirm Password</b>
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
</label>
|
value={formData.password}
|
||||||
<input
|
onChange={handlePassowordChange}
|
||||||
type="password"
|
required
|
||||||
placeholder="Confirm Password"
|
/>
|
||||||
name="confirmPassword"
|
<label htmlFor="confirmPassword">
|
||||||
className="confirmInputt"
|
<b className="text-[13px]">Confirm Password</b>
|
||||||
style={{
|
</label>
|
||||||
border: validationMessage
|
<input
|
||||||
? validationMessage === "Passwords match!"
|
type="password"
|
||||||
? "2px solid green"
|
placeholder="Confirm Password"
|
||||||
: "2px solid red"
|
name="confirmPassword"
|
||||||
: "2px solid transparent",
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
outline: "none"
|
style={{
|
||||||
}}
|
border: validationMessage
|
||||||
value={formData.confirmPassword}
|
? validationMessage === "Passwords match!"
|
||||||
onChange={handleConFirmPassowordChange}
|
? "1px solid green"
|
||||||
required
|
: "1px solid red"
|
||||||
/>
|
: ""
|
||||||
<div
|
}}
|
||||||
className="icon"
|
value={formData.confirmPassword}
|
||||||
style={{
|
onChange={handleConFirmPassowordChange}
|
||||||
margin: validationMessage ? "0 2px 0 2px" : "0 2px 22px 2px",
|
required
|
||||||
color:
|
/>
|
||||||
validationMessage === "Passwords match!" ? "green" : "red",
|
<div
|
||||||
fontSize: 11
|
className={`${
|
||||||
}}
|
validationMessage === "Passwords match!"
|
||||||
>
|
? "text-[green]"
|
||||||
{validationMessage}
|
: "text-[red]"
|
||||||
</div>
|
} ml-[13px] text-[11px]`}
|
||||||
{formData.password.length > 0 && (
|
>
|
||||||
<div className="mt-1 text-[11px]">
|
{validationMessage}
|
||||||
<p
|
|
||||||
className={`${
|
|
||||||
lengthValid ? "text-green-600" : "text-red-600"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{lengthValid ? "✓" : "✗"} Password should be 8 characters long
|
|
||||||
</p>
|
|
||||||
<p
|
|
||||||
className={`${
|
|
||||||
caseDigitValid ? "text-green-600" : "text-red-600"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{caseDigitValid ? "✓" : "✗"} Password should contain uppercase
|
|
||||||
letter, lowercase letter, digit
|
|
||||||
</p>
|
|
||||||
<p
|
|
||||||
className={`${
|
|
||||||
specialCharValid ? "text-green-600" : "text-red-600"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{specialCharValid ? "✓" : "✗"} Password should contain special
|
|
||||||
character
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
{formData.password.length > 0 && (
|
||||||
<div className="clearfix">
|
<div className="mt-1 text-[11px]">
|
||||||
<button type="submit" className="signupbtn">
|
<p
|
||||||
|
className={`${
|
||||||
|
lengthValid ? "text-green-600" : "text-red-600"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{lengthValid ? "✓" : "✗"} Password should be 8 characters
|
||||||
|
long
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
className={`${
|
||||||
|
caseDigitValid ? "text-green-600" : "text-red-600"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{caseDigitValid ? "✓" : "✗"} Password should contain
|
||||||
|
uppercase letter, lowercase letter, digit
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
className={`${
|
||||||
|
specialCharValid ? "text-green-600" : "text-red-600"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{specialCharValid ? "✓" : "✗"} Password should contain
|
||||||
|
special character
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="op-btn op-btn-primary w-full mt-[8px]"
|
||||||
|
>
|
||||||
Submit
|
Submit
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</form>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
export default PgSignUp;
|
||||||
if (Object.keys(state.appInfo).length !== 0) {
|
|
||||||
return { appInfo: state.appInfo, isloginVisible: true };
|
|
||||||
} else {
|
|
||||||
return { appInfo: state.appInfo, isloginVisible: false };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, {
|
|
||||||
fetchAppInfo,
|
|
||||||
showTenantName
|
|
||||||
})(PgSignUp);
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,11 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useNavigate } from "react-router";
|
import { NavLink, useNavigate } from "react-router-dom";
|
||||||
import { NavLink } 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 { openInNewTab } from "../constant/Utils";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
const listItemStyle = {
|
const listItemStyle = {
|
||||||
paddingLeft: "20px", // Add padding to create space for the image
|
paddingLeft: "20px", // Add padding to create space for the image
|
||||||
backgroundImage: `url(${checkmark})`, // Set your image as the list style image
|
backgroundImage: `url(${checkmark})`, // Set your image as the list style image
|
||||||
@@ -16,18 +18,34 @@ const PlanSubscriptions = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [yearlyVisible, setYearlyVisible] = useState(false);
|
const [yearlyVisible, setYearlyVisible] = useState(false);
|
||||||
const [isLoader, setIsLoader] = useState(true);
|
const [isLoader, setIsLoader] = useState(true);
|
||||||
|
const extUser =
|
||||||
const userDetails = JSON.parse(localStorage.getItem("userDetails"));
|
localStorage.getItem("Extand_Class") &&
|
||||||
|
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
|
const user = {
|
||||||
|
name: extUser?.Name,
|
||||||
|
email: extUser?.Email,
|
||||||
|
company: extUser?.Company,
|
||||||
|
phone: extUser?.Phone
|
||||||
|
};
|
||||||
|
const userDetails = JSON.parse(localStorage.getItem("userDetails")) || user;
|
||||||
|
// console.log("userDetails ", userDetails);
|
||||||
const name =
|
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 +
|
||||||
@@ -35,57 +53,72 @@ const PlanSubscriptions = () => {
|
|||||||
company +
|
company +
|
||||||
phone;
|
phone;
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (localStorage.getItem("accesstoken")) {
|
// if (localStorage.getItem("accesstoken")) {
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
setYearlyVisible(false);
|
// } else {
|
||||||
} else {
|
// navigate("/", { replace: true });
|
||||||
navigate("/", { replace: true });
|
// }
|
||||||
}
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleFreePlan = async () => {
|
||||||
|
setIsLoader(true);
|
||||||
|
try {
|
||||||
|
const params = { userId: Parse.User.current().id };
|
||||||
|
const res = await Parse.Cloud.run("freesubscription", params);
|
||||||
|
if (res.status === "success" && res.result === "already subscribed!") {
|
||||||
|
setIsLoader(false);
|
||||||
|
alert("You have already subscribed to plan!");
|
||||||
|
} else if (res.status === "success") {
|
||||||
|
setIsLoader(false);
|
||||||
|
navigate("/");
|
||||||
|
} else if (res.status === "error") {
|
||||||
|
setIsLoader(false);
|
||||||
|
alert(res.result);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setIsLoader(false);
|
||||||
|
console.log("err in free subscribe", err.message);
|
||||||
|
alert("Somenthing went wrong, please try again later!");
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title title={"Subscriptions"} />
|
<Title title={"Subscriptions"} />
|
||||||
{isLoader ? (
|
{isLoader ? (
|
||||||
<div
|
<div className="flex items-center justify-center h-screen">
|
||||||
style={{
|
<Loader />
|
||||||
height: "100vh",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div className="overflow-y-auto max-h-full">
|
||||||
style={{
|
<div className="block my-2">
|
||||||
backgroundColor: "white",
|
<div className="flex flex-col justify-center items-center w-full">
|
||||||
overflowY: "auto",
|
<div
|
||||||
maxHeight: "100%",
|
role="tablist"
|
||||||
"--theme-color": "#7952b3",
|
className="op-tabs op-tabs-boxed bg-base-100 my-2 shadow-lg transition-all"
|
||||||
"--plan-width": 30
|
>
|
||||||
}}
|
<a
|
||||||
>
|
onClick={() => setYearlyVisible(false)}
|
||||||
<div
|
role="tab"
|
||||||
id="monthlyPlans"
|
className={`${!yearlyVisible ? "op-tab-active" : ""} op-tab`}
|
||||||
className={`${yearlyVisible ? "none" : "block my-2"}`}
|
>
|
||||||
>
|
Monthly
|
||||||
<div className="flex justify-center w-full my-2">
|
</a>
|
||||||
<ul className=" flex flex-col md:flex-row h-full bg-white justify-center border-collapse border-[1px] border-gray-300">
|
<a
|
||||||
|
onClick={() => setYearlyVisible(true)}
|
||||||
|
role="tab"
|
||||||
|
className={`${yearlyVisible ? "op-tab-active" : ""} op-tab`}
|
||||||
|
>
|
||||||
|
Yearly (10% off)
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<ul className="op-card flex flex-col md:flex-row h-full bg-base-100 justify-center shadow-lg">
|
||||||
{plansArr.map((item) => (
|
{plansArr.map((item) => (
|
||||||
<li
|
<li
|
||||||
className="flex flex-col md:my-0 text-center 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">
|
<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>
|
||||||
@@ -96,20 +129,20 @@ 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>}
|
||||||
{item.price}
|
{yearlyVisible
|
||||||
|
? item?.yearlyPrice
|
||||||
|
: item.monthlyPrice}
|
||||||
</span>
|
</span>
|
||||||
<div
|
<p className="font-semibold pt-2 text-sm">
|
||||||
className={`${
|
{yearlyVisible ? "Billed Yearly" : "Billed Monthly"}
|
||||||
item.subtitle.length <= 32
|
</p>
|
||||||
? "w-[150px] text-center"
|
<div className="max-w-[250px] h-[40px] text-center text-sm my-2">
|
||||||
: ""
|
<div
|
||||||
} text-sm text-center my-2`}
|
|
||||||
>
|
|
||||||
<p
|
|
||||||
style={{
|
style={{
|
||||||
|
textAlign: "center",
|
||||||
backgroundColor: item.subtitlecolor
|
backgroundColor: item.subtitlecolor
|
||||||
? item.subtitlecolor
|
? item.subtitlecolor
|
||||||
: "white"
|
: "white"
|
||||||
@@ -124,29 +157,37 @@ const PlanSubscriptions = () => {
|
|||||||
) : (
|
) : (
|
||||||
<span>{item.subtitle}</span>
|
<span>{item.subtitle}</span>
|
||||||
)}
|
)}
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{item.url ? (
|
||||||
<NavLink
|
<NavLink
|
||||||
to={
|
to={
|
||||||
item.btnText === "Subscribe"
|
item.btnText === "Subscribe"
|
||||||
? item.url + details
|
? yearlyVisible
|
||||||
: item.url
|
? item.yearlyUrl + details
|
||||||
}
|
: item.url + details
|
||||||
className="bg-[#002862] w-full text-white py-2 rounded uppercase hover:no-underline hover:text-white"
|
: item.url
|
||||||
target={item.target}
|
}
|
||||||
>
|
className="bg-[#002862] w-full text-white py-2 rounded uppercase hover:no-underline hover:text-white cursor-pointer"
|
||||||
{item.btnText}
|
target={item.target}
|
||||||
</NavLink>
|
>
|
||||||
|
{item.btnText}
|
||||||
|
</NavLink>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
className="bg-[#002862] w-full text-white py-2 rounded uppercase hover:text-white cursor-pointer"
|
||||||
|
onClick={() => handleFreePlan()}
|
||||||
|
>
|
||||||
|
{item.btnText}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<hr className="w-full bg-gray-300 p-[.5px]" />
|
<hr className="w-full bg-gray-300 h-[0.5px]" />
|
||||||
<ul className="mx-1 p-3 text-left break-words text-sm list-none">
|
<ul className="mx-1 p-3 text-left break-words text-sm list-none">
|
||||||
{item.benefits.map((subitem, index) => (
|
{item.benefits.map((subitem, index) => (
|
||||||
<li style={listItemStyle} key={index} className="m-1">
|
<li style={listItemStyle} key={index} className="m-1">
|
||||||
<span style={{ position: "relative" }}>
|
<span className="relative">{subitem}</span>
|
||||||
{subitem}
|
|
||||||
</span>
|
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
@@ -154,6 +195,24 @@ const PlanSubscriptions = () => {
|
|||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="text-sm flex justify-center items-center mt-3 mb-2">
|
||||||
|
<hr className="border-[2px] border-gray-350 w-[20%]" />
|
||||||
|
<span className="px-2 text-base-content cursor-default">or</span>
|
||||||
|
<hr className="border-[2px] border-gray-350 w-[20%]" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col justify-center items-center">
|
||||||
|
<h3 className="text-[#002862] mt-1 mb-2">
|
||||||
|
Host it yourself for free
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
className="op-btn op-btn-primary w-[200px]"
|
||||||
|
onClick={() =>
|
||||||
|
openInNewTab("https://github.com/OpenSignLabs/OpenSign")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Visit Github
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -6,17 +6,22 @@ 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";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
|
||||||
const Report = () => {
|
const Report = () => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const [List, setList] = useState([]);
|
const [List, setList] = useState([]);
|
||||||
const [isLoader, setIsLoader] = useState(true);
|
const [isLoader, setIsLoader] = useState(true);
|
||||||
const [reportName, setReportName] = useState("");
|
const [reportName, setReportName] = useState("");
|
||||||
|
const [reporthelp, setReportHelp] = useState("");
|
||||||
const [actions, setActions] = useState([]);
|
const [actions, setActions] = useState([]);
|
||||||
const [heading, setHeading] = useState([]);
|
const [heading, setHeading] = useState([]);
|
||||||
const [isNextRecord, setIsNextRecord] = useState(false);
|
const [isNextRecord, setIsNextRecord] = useState(false);
|
||||||
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;
|
||||||
|
|
||||||
@@ -45,6 +50,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);
|
||||||
@@ -53,6 +61,7 @@ const Report = () => {
|
|||||||
setHeading(json.heading);
|
setHeading(json.heading);
|
||||||
setReportName(json.reportName);
|
setReportName(json.reportName);
|
||||||
setForm(json.form);
|
setForm(json.form);
|
||||||
|
setReportHelp(json?.helpMsg);
|
||||||
const currentUser = Parse.User.current().id;
|
const currentUser = Parse.User.current().id;
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
@@ -67,6 +76,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 = [];
|
||||||
@@ -104,12 +149,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) {
|
||||||
@@ -127,21 +174,8 @@ const Report = () => {
|
|||||||
<>
|
<>
|
||||||
<Title title={reportName} />
|
<Title title={reportName} />
|
||||||
{isLoader ? (
|
{isLoader ? (
|
||||||
<div
|
<div className="h-[100vh] flex justify-center items-center">
|
||||||
style={{
|
<Loader />
|
||||||
height: "100vh",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
@@ -156,6 +190,9 @@ const Report = () => {
|
|||||||
isMoreDocs={isMoreDocs}
|
isMoreDocs={isMoreDocs}
|
||||||
docPerPage={docPerPage}
|
docPerPage={docPerPage}
|
||||||
form={form}
|
form={form}
|
||||||
|
report_help={reporthelp}
|
||||||
|
tourData={tourData}
|
||||||
|
isDontShow={isDontShow}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<PageNotFound prefix={"Report"} />
|
<PageNotFound prefix={"Report"} />
|
||||||
|
|||||||
@@ -0,0 +1,384 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
|
import Parse from "parse";
|
||||||
|
import axios from "axios";
|
||||||
|
import { appInfo } from "../constant/appinfo";
|
||||||
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
import { fetchSubscription } from "../constant/Utils";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||||
|
import ModalUi from "../primitives/ModalUi";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
|
||||||
|
const SSOVerify = () => {
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const [isModal, setIsModal] = useState(false);
|
||||||
|
const [message, setMessage] = useState("Verifying SSO...");
|
||||||
|
const [isLoader, setIsLoader] = useState(false);
|
||||||
|
const [userDetails, setUserDetails] = useState({
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
phone: "",
|
||||||
|
Destination: "",
|
||||||
|
Company: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
linkUserWithSSO();
|
||||||
|
// eslint-disable-next-line
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// `linkUserWithSSO` is used to sign in or sign up a user using an SSO code and check if the user is present in the extended class
|
||||||
|
const linkUserWithSSO = async () => {
|
||||||
|
const param = new URLSearchParams(location.search);
|
||||||
|
const code = param?.get("code");
|
||||||
|
const state = param?.get("state");
|
||||||
|
try {
|
||||||
|
// The `ssosign` cloud function is used to sign in or sign up a user
|
||||||
|
const ssosign = await Parse.Cloud.run("ssosign", {
|
||||||
|
code: code,
|
||||||
|
email: state
|
||||||
|
});
|
||||||
|
localStorage.setItem("accesstoken", ssosign.sessiontoken);
|
||||||
|
// `checkExtUser` checks if the user is present in the extended class `contracts_Users` and if not, initiates the new user flow
|
||||||
|
await checkExtUser(ssosign);
|
||||||
|
} catch (err) {
|
||||||
|
setMessage("Error: " + err.message);
|
||||||
|
console.log("err", err.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const checkExtUser = async (ssosign) => {
|
||||||
|
const params = { email: ssosign?.email };
|
||||||
|
try {
|
||||||
|
// `isextenduser` checks if the current user is present in the extended class
|
||||||
|
const extRes = await Parse.Cloud.run("isextenduser", params);
|
||||||
|
if (extRes?.isUserExist) {
|
||||||
|
// `getUserDetails` retrieves the current user's details from the extended class
|
||||||
|
const extRes = await Parse.Cloud.run("getUserDetails", params);
|
||||||
|
if (ssosign && ssosign.sessiontoken) {
|
||||||
|
const LocalUserDetails = {
|
||||||
|
name: extRes.Name,
|
||||||
|
email: extRes.email,
|
||||||
|
phone: extRes?.get("Phone") || "",
|
||||||
|
company: extRes.get("Company")
|
||||||
|
};
|
||||||
|
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
||||||
|
thirdpartyLoginfn(ssosign.sessiontoken);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsModal(true);
|
||||||
|
setUserDetails((prev) => ({
|
||||||
|
...prev,
|
||||||
|
name: ssosign.name,
|
||||||
|
email: ssosign.email,
|
||||||
|
phone: ssosign?.phone || ""
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err in isextenduser or getuserdetails cloud function", err);
|
||||||
|
setMessage("Error: " + err.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// `handleSubmitbtn` is used to create a user in the extended class
|
||||||
|
const handleSubmitbtn = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setIsLoader(true);
|
||||||
|
let phone;
|
||||||
|
if (userDetails?.phone) {
|
||||||
|
phone = validateInput(userDetails?.phone);
|
||||||
|
} else {
|
||||||
|
phone = true;
|
||||||
|
}
|
||||||
|
if (userDetails.Destination && userDetails.Company && phone) {
|
||||||
|
const payload = { sessionToken: localStorage.getItem("accesstoken") };
|
||||||
|
if (payload && payload.sessionToken) {
|
||||||
|
const params = {
|
||||||
|
userDetails: {
|
||||||
|
name: userDetails.name,
|
||||||
|
email: userDetails.email,
|
||||||
|
phone: userDetails?.phone || "",
|
||||||
|
role: "contracts_User",
|
||||||
|
company: userDetails.Company,
|
||||||
|
jobTitle: userDetails.Destination
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const userSignUp = await Parse.Cloud.run("usersignup", params);
|
||||||
|
if (userSignUp && userSignUp.sessionToken) {
|
||||||
|
const LocalUserDetails = params.userDetails;
|
||||||
|
localStorage.setItem(
|
||||||
|
"userDetails",
|
||||||
|
JSON.stringify(LocalUserDetails)
|
||||||
|
);
|
||||||
|
await thirdpartyLoginfn(userSignUp.sessionToken);
|
||||||
|
setIsLoader(false);
|
||||||
|
} else {
|
||||||
|
alert(userSignUp.message);
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("error in usersignup", err);
|
||||||
|
localStorage.removeItem("accesstoken");
|
||||||
|
alert("Something went wrong.");
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem("accesstoken");
|
||||||
|
alert("Internal server error.");
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert("Please fill required details correctly.");
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// `thirdpartyLoginfn` is used to save necessary parameters locally for the logged-in user
|
||||||
|
const thirdpartyLoginfn = async (sessionToken) => {
|
||||||
|
const baseUrl = localStorage.getItem("baseUrl");
|
||||||
|
const parseAppId = localStorage.getItem("parseAppId");
|
||||||
|
try {
|
||||||
|
const validUser = await Parse.User.become(sessionToken);
|
||||||
|
if (validUser) {
|
||||||
|
localStorage.setItem("accesstoken", sessionToken);
|
||||||
|
const _user = JSON.parse(JSON.stringify(validUser));
|
||||||
|
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
||||||
|
if (_user.ProfilePic) {
|
||||||
|
localStorage.setItem("profileImg", _user.ProfilePic);
|
||||||
|
} else {
|
||||||
|
localStorage.setItem("profileImg", "");
|
||||||
|
}
|
||||||
|
// Check extended class user role and tenentId
|
||||||
|
try {
|
||||||
|
let userRoles = [];
|
||||||
|
const userSettings = appInfo.settings;
|
||||||
|
//Get Current user roles
|
||||||
|
const url = `${baseUrl}functions/UserGroups`;
|
||||||
|
const headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Parse-Application-Id": parseAppId,
|
||||||
|
sessionToken: _user.sessionToken
|
||||||
|
};
|
||||||
|
const body = { appname: appInfo.appname };
|
||||||
|
const UserGroupsRes = await axios.post(url, JSON.stringify(body), {
|
||||||
|
headers: headers
|
||||||
|
});
|
||||||
|
userRoles = (UserGroupsRes.data && UserGroupsRes.data.result) || [];
|
||||||
|
if (userRoles) {
|
||||||
|
let _currentRole = "";
|
||||||
|
const excludeRoles = ["contracts_Guest", `contracts_appeditor`];
|
||||||
|
const filteredRole = userRoles.filter(
|
||||||
|
(x) => !excludeRoles.includes(x)
|
||||||
|
);
|
||||||
|
if (filteredRole?.length > 1) {
|
||||||
|
console.log("user has two roles");
|
||||||
|
// _currentRole = filteredRole.filter((x) => x === "contracts_User");
|
||||||
|
} else {
|
||||||
|
_currentRole = filteredRole?.[0] || "";
|
||||||
|
}
|
||||||
|
if (_currentRole) {
|
||||||
|
const roleSetting = userSettings?.find(
|
||||||
|
(setting) => setting.role === _currentRole
|
||||||
|
);
|
||||||
|
const redirectUrl =
|
||||||
|
location?.state?.from ||
|
||||||
|
`/${roleSetting.pageType}/${roleSetting.pageId}`;
|
||||||
|
const _role = _currentRole.replace(`${appInfo.appname}_`, "");
|
||||||
|
localStorage.setItem("_user_role", _role);
|
||||||
|
// Get TenentID from Extendend Class
|
||||||
|
localStorage.setItem(
|
||||||
|
"extended_class",
|
||||||
|
roleSetting.extended_class
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
const extUser = await Parse.Cloud.run("getUserDetails", {
|
||||||
|
email: _user.email
|
||||||
|
});
|
||||||
|
if (extUser) {
|
||||||
|
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||||
|
localStorage.setItem("userEmail", _extUser.Email);
|
||||||
|
localStorage.setItem("username", _extUser.Name);
|
||||||
|
localStorage.setItem("scriptId", true);
|
||||||
|
let tenentInfo = [];
|
||||||
|
const results = [extUser];
|
||||||
|
if (results) {
|
||||||
|
let extendedInfo_stringify = JSON.stringify(results);
|
||||||
|
localStorage.setItem(
|
||||||
|
"Extand_Class",
|
||||||
|
extendedInfo_stringify
|
||||||
|
);
|
||||||
|
if (_extUser.TenantId) {
|
||||||
|
const obj = {
|
||||||
|
tenentId: _extUser.TenantId.objectId,
|
||||||
|
tenentName: _extUser.TenantId.TenantName || ""
|
||||||
|
};
|
||||||
|
localStorage.setItem("TenantId", obj.tenentId);
|
||||||
|
tenentInfo.push(obj);
|
||||||
|
dispatch(showTenant(obj.tenentName || ""));
|
||||||
|
localStorage.setItem("TenantName", obj.tenentName || "");
|
||||||
|
}
|
||||||
|
localStorage.setItem("PageLanding", roleSetting.pageId);
|
||||||
|
localStorage.setItem("defaultmenuid", roleSetting.menuId);
|
||||||
|
localStorage.setItem("pageType", roleSetting.pageType);
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const res = await fetchSubscription();
|
||||||
|
const plan = res.plan;
|
||||||
|
const billingDate = res.billingDate;
|
||||||
|
if (plan === "freeplan") {
|
||||||
|
navigate(redirectUrl);
|
||||||
|
} else if (billingDate) {
|
||||||
|
if (new Date(billingDate) > new Date()) {
|
||||||
|
localStorage.removeItem("userDetails");
|
||||||
|
navigate(redirectUrl);
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`, {
|
||||||
|
replace: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`, {
|
||||||
|
replace: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navigate(redirectUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
alert("user not exist.");
|
||||||
|
setMessage("Error: User not exist.");
|
||||||
|
console.log("err in get extUser", err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert("Role does not exists.");
|
||||||
|
setMessage("Error: Role does not exists.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert("Role does not exists.");
|
||||||
|
setMessage("Error: Role does not exists.");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in usergroups", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err in become method", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// `handleCloseModal` is triggered when the user wants to close the new user flow modal
|
||||||
|
const handleCloseModal = () => {
|
||||||
|
setIsModal(false);
|
||||||
|
if (Parse?.User?.current()) {
|
||||||
|
Parse.User.logOut();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// `validateInput` is used to verify the phone pattern
|
||||||
|
function validateInput(input) {
|
||||||
|
if (input) {
|
||||||
|
const pattern = /^(?!.*\+.*\+)[\d+-]*$/;
|
||||||
|
return pattern.test(input);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="w-full h-screen flex flex-col justify-center items-center text-sm md:text-xl ">
|
||||||
|
{message === "Verifying SSO..." && <Loader />}
|
||||||
|
<div className="text-base-content">{message}</div>
|
||||||
|
</div>
|
||||||
|
<ModalUi isOpen={isModal} title="Additional Info" showClose={false}>
|
||||||
|
<div className="relative">
|
||||||
|
{isLoader && (
|
||||||
|
<div className="absolute w-full h-full bg-black bg-opacity-25 flex justify-center items-center">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<form
|
||||||
|
className="px-4 py-3 text-base-content"
|
||||||
|
onSubmit={handleSubmitbtn}
|
||||||
|
>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label htmlFor="Company" className="block text-xs font-semibold">
|
||||||
|
Phone <span className="text-[13px] text-[red]">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="tel"
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
id="Phone"
|
||||||
|
value={userDetails.phone}
|
||||||
|
onChange={(e) =>
|
||||||
|
setUserDetails({
|
||||||
|
...userDetails,
|
||||||
|
phone: e.target.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
disabled={isLoader}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<p className="text-[10px] text-[red] ml-2">
|
||||||
|
{!validateInput(userDetails.phone) && "Invalid phone value"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label htmlFor="Company" className="block text-xs font-semibold">
|
||||||
|
Company <span className="text-[13px] text-[red]">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
id="Company"
|
||||||
|
value={userDetails.Company}
|
||||||
|
onChange={(e) =>
|
||||||
|
setUserDetails({
|
||||||
|
...userDetails,
|
||||||
|
Company: e.target.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
disabled={isLoader}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label htmlFor="JobTitle" className="block text-xs font-semibold">
|
||||||
|
Job Title
|
||||||
|
<span className="text-[13px] text-[red]">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
id="JobTitle"
|
||||||
|
value={userDetails.Destination}
|
||||||
|
onChange={(e) =>
|
||||||
|
setUserDetails({
|
||||||
|
...userDetails,
|
||||||
|
Destination: e.target.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
disabled={isLoader}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mt-4">
|
||||||
|
<button type="submit" className="op-btn op-btn-primary">
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="op-btn op-btn-ghost ml-2"
|
||||||
|
onClick={handleCloseModal}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SSOVerify;
|
||||||
+145
-106
@@ -1,23 +1,30 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import { fetchAppInfo, showTenantName } from "../redux/actions";
|
import { useNavigate, useLocation } from "react-router-dom";
|
||||||
import { useNavigate, NavLink } from "react-router-dom";
|
|
||||||
import login_img from "../assets/images/login_img.svg";
|
import login_img from "../assets/images/login_img.svg";
|
||||||
import { useWindowSize } from "../hook/useWindowSize";
|
import { useWindowSize } from "../hook/useWindowSize";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
|
import { appInfo } from "../constant/appinfo";
|
||||||
const Signup = (props) => {
|
import { useDispatch } from "react-redux";
|
||||||
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
|
import { showTenant } from "../redux/reducers/ShowTenant";
|
||||||
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
import { getAppLogo, openInNewTab } from "../constant/Utils";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
const Signup = () => {
|
||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [phone, setPhone] = useState("");
|
const [phone, setPhone] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
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",
|
||||||
@@ -27,9 +34,8 @@ const Signup = (props) => {
|
|||||||
const [lengthValid, setLengthValid] = useState(false);
|
const [lengthValid, setLengthValid] = useState(false);
|
||||||
const [caseDigitValid, setCaseDigitValid] = useState(false);
|
const [caseDigitValid, setCaseDigitValid] = useState(false);
|
||||||
const [specialCharValid, setSpecialCharValid] = useState(false);
|
const [specialCharValid, setSpecialCharValid] = useState(false);
|
||||||
|
const [isAuthorize, setIsAuthorize] = useState(false);
|
||||||
const togglePasswordVisibility = () => setShowPassword(!showPassword);
|
const togglePasswordVisibility = () => setShowPassword(!showPassword);
|
||||||
const image = props.appInfo.applogo;
|
|
||||||
|
|
||||||
const clearStorage = async () => {
|
const clearStorage = async () => {
|
||||||
if (Parse.User.current()) {
|
if (Parse.User.current()) {
|
||||||
@@ -65,6 +71,19 @@ const Signup = (props) => {
|
|||||||
localStorage.setItem("baseUrl", baseUrl);
|
localStorage.setItem("baseUrl", baseUrl);
|
||||||
localStorage.setItem("parseAppId", appid);
|
localStorage.setItem("parseAppId", appid);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleFreePlan = async (id) => {
|
||||||
|
try {
|
||||||
|
const params = { userId: id };
|
||||||
|
const res = await Parse.Cloud.run("freesubscription", params);
|
||||||
|
if (res.status === "error") {
|
||||||
|
alert(res.result);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in free subscribe", err.message);
|
||||||
|
alert("Somenthing went wrong, please try again later!");
|
||||||
|
}
|
||||||
|
};
|
||||||
const handleSubmit = (event) => {
|
const handleSubmit = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (lengthValid && caseDigitValid && specialCharValid) {
|
if (lengthValid && caseDigitValid && specialCharValid) {
|
||||||
@@ -90,7 +109,7 @@ const Signup = (props) => {
|
|||||||
res
|
res
|
||||||
.then(async (r) => {
|
.then(async (r) => {
|
||||||
if (r) {
|
if (r) {
|
||||||
let roleData = props.appInfo.settings;
|
let roleData = appInfo.settings;
|
||||||
if (roleData && roleData.length > 0) {
|
if (roleData && roleData.length > 0) {
|
||||||
const params = {
|
const params = {
|
||||||
userDetails: {
|
userDetails: {
|
||||||
@@ -99,7 +118,7 @@ const Signup = (props) => {
|
|||||||
name: name,
|
name: name,
|
||||||
email: email,
|
email: email,
|
||||||
phone: phone,
|
phone: phone,
|
||||||
role: props.appInfo.defaultRole
|
role: appInfo.defaultRole
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
@@ -108,7 +127,13 @@ const Signup = (props) => {
|
|||||||
params
|
params
|
||||||
);
|
);
|
||||||
if (usersignup) {
|
if (usersignup) {
|
||||||
handleNavigation(r.getSessionToken());
|
const param = new URLSearchParams(location.search);
|
||||||
|
const isFreeplan =
|
||||||
|
param?.get("subscription") === "freeplan";
|
||||||
|
if (isFreeplan) {
|
||||||
|
await handleFreePlan(r.id);
|
||||||
|
}
|
||||||
|
handleNavigation(r.getSessionToken(), isFreeplan);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert(err.message);
|
alert(err.message);
|
||||||
@@ -153,7 +178,7 @@ const Signup = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleNavigation = async (sessionToken) => {
|
const handleNavigation = async (sessionToken, isFreeplan = false) => {
|
||||||
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", {
|
||||||
@@ -181,8 +206,8 @@ const Signup = (props) => {
|
|||||||
// Check extended class user role and tenentId
|
// Check extended class user role and tenentId
|
||||||
try {
|
try {
|
||||||
let userRoles = [];
|
let userRoles = [];
|
||||||
if (props.appInfo.settings) {
|
if (appInfo.settings) {
|
||||||
let userSettings = props.appInfo.settings;
|
let userSettings = appInfo.settings;
|
||||||
|
|
||||||
//Get Current user roles
|
//Get Current user roles
|
||||||
let url = `${baseUrl}functions/UserGroups`;
|
let url = `${baseUrl}functions/UserGroups`;
|
||||||
@@ -256,8 +281,8 @@ const Signup = (props) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (tenentInfo.length) {
|
if (tenentInfo.length) {
|
||||||
props.showTenantName(
|
dispatch(
|
||||||
tenentInfo[0].tenentName || ""
|
showTenant(tenentInfo[0].tenentName || "")
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenantName",
|
"TenantName",
|
||||||
@@ -293,15 +318,15 @@ const Signup = (props) => {
|
|||||||
tenentName: x.TenantId.TenantName || ""
|
tenentName: x.TenantId.TenantName || ""
|
||||||
};
|
};
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenetId",
|
"TenantId",
|
||||||
x.TenantId.objectId
|
x.TenantId.objectId
|
||||||
);
|
);
|
||||||
tenentInfo.push(obj);
|
tenentInfo.push(obj);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (tenentInfo.length) {
|
if (tenentInfo.length) {
|
||||||
props.showTenantName(
|
dispatch(
|
||||||
tenentInfo[0].tenentName || ""
|
showTenant(tenentInfo[0].tenentName || "")
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"TenantName",
|
"TenantName",
|
||||||
@@ -321,8 +346,14 @@ const Signup = (props) => {
|
|||||||
element.pageType
|
element.pageType
|
||||||
);
|
);
|
||||||
setState({ loading: false });
|
setState({ loading: false });
|
||||||
if (process.env.REACT_APP_ENABLE_SUBSCRIPTION) {
|
if (isEnableSubscription) {
|
||||||
navigate(`/subscription`, { replace: true });
|
if (isFreeplan) {
|
||||||
|
navigate(
|
||||||
|
`/${element.pageType}/${element.pageId}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`, { replace: true });
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
alert("Registered user successfully");
|
alert("Registered user successfully");
|
||||||
navigate(
|
navigate(
|
||||||
@@ -339,8 +370,14 @@ const Signup = (props) => {
|
|||||||
);
|
);
|
||||||
localStorage.setItem("pageType", element.pageType);
|
localStorage.setItem("pageType", element.pageType);
|
||||||
setState({ loading: false });
|
setState({ loading: false });
|
||||||
if (process.env.REACT_APP_ENABLE_SUBSCRIPTION) {
|
if (isEnableSubscription) {
|
||||||
navigate(`/subscription`, { replace: true });
|
if (isFreeplan) {
|
||||||
|
navigate(
|
||||||
|
`/${element.pageType}/${element.pageId}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
navigate(`/subscription`, { replace: true });
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
navigate(
|
navigate(
|
||||||
`/${element.pageType}/${element.pageId}`
|
`/${element.pageType}/${element.pageId}`
|
||||||
@@ -433,10 +470,24 @@ const Signup = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
props.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);
|
||||||
@@ -451,78 +502,58 @@ const Signup = (props) => {
|
|||||||
setSpecialCharValid(/[!@#$%^&*()\-_=+{};:,<.>]/.test(newPassword));
|
setSpecialCharValid(/[!@#$%^&*()\-_=+{};:,<.>]/.test(newPassword));
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="bg-white">
|
<div className="">
|
||||||
{state.loading && (
|
{state.loading && (
|
||||||
<div
|
<div className="fixed w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-50">
|
||||||
style={{
|
<Loader />
|
||||||
position: "fixed",
|
|
||||||
width: "100vw",
|
|
||||||
height: "100vh",
|
|
||||||
backgroundColor: "rgba(0,0,0,0.2)",
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
zIndex: 2
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "fixed",
|
|
||||||
fontSize: "50px",
|
|
||||||
color: "#3ac9d6",
|
|
||||||
top: "50%",
|
|
||||||
left: "45%"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Title title={"Signup page"} />
|
<Title title={"Signup page"} />
|
||||||
|
{appInfo && appInfo.applogo ? (
|
||||||
{props.isloginVisible && props.isloginVisible ? (
|
<div className="md:p-10 lg:p-16">
|
||||||
<div>
|
<div className="md:p-4 lg:p-10 p-4 bg-base-100 text-base-content op-card">
|
||||||
<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 overflow-hidden">
|
||||||
<div className="w-[250px] h-[66px] inline-block">
|
{image && (
|
||||||
<img src={image} width="100%" alt="" />
|
<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>
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<h2 className="text-[30px] mt-6">Create Account !</h2>
|
<h2 className="text-[30px] mt-6">Create Account !</h2>
|
||||||
<div className="outline outline-1 outline-slate-300/50 shadow-md rounded my-4">
|
<div className="w-full my-4 op-card bg-base-100 shadow-md outline outline-1 outline-slate-300/50">
|
||||||
<div className="px-6 py-4 text-xs">
|
<div className="px-6 py-4 text-xs">
|
||||||
<label className="block ">
|
<label className="block ">
|
||||||
Name{" "}
|
Name <span className="text-[red] text-[13px]">*</span>
|
||||||
<span style={{ color: "red", fontSize: 13 }}>*</span>
|
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
value={name}
|
value={name}
|
||||||
onChange={(e) => setName(e.target.value)}
|
onChange={(e) => setName(e.target.value)}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<hr className="my-2 border-none" />
|
<hr className="my-2 border-none" />
|
||||||
<label>
|
<label>
|
||||||
Email{" "}
|
Email <span className="text-[red] text-[13px]">*</span>
|
||||||
<span style={{ color: "red", fontSize: 13 }}>*</span>
|
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="email"
|
id="email"
|
||||||
type="text"
|
type="email"
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) =>
|
||||||
|
setEmail(e.target.value?.toLowerCase())
|
||||||
|
}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<hr className="my-2 border-none" />
|
<hr className="my-2 border-none" />
|
||||||
<label>
|
<label>
|
||||||
Phone{" "}
|
Phone <span className="text-[red] text-[13px]">*</span>
|
||||||
<span style={{ color: "red", fontSize: 13 }}>*</span>
|
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="tel"
|
type="tel"
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
value={phone}
|
value={phone}
|
||||||
onChange={(e) => setPhone(e.target.value)}
|
onChange={(e) => setPhone(e.target.value)}
|
||||||
required
|
required
|
||||||
@@ -530,11 +561,11 @@ const Signup = (props) => {
|
|||||||
<hr className="my-2 border-none" />
|
<hr className="my-2 border-none" />
|
||||||
<label>
|
<label>
|
||||||
Company{" "}
|
Company{" "}
|
||||||
<span style={{ color: "red", fontSize: 13 }}>*</span>
|
<span className="text-[red] text-[13px]">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
value={company}
|
value={company}
|
||||||
onChange={(e) => setCompany(e.target.value)}
|
onChange={(e) => setCompany(e.target.value)}
|
||||||
required
|
required
|
||||||
@@ -542,11 +573,11 @@ const Signup = (props) => {
|
|||||||
<hr className="my-2 border-none" />
|
<hr className="my-2 border-none" />
|
||||||
<label>
|
<label>
|
||||||
Job Title{" "}
|
Job Title{" "}
|
||||||
<span style={{ color: "red", fontSize: 13 }}>*</span>
|
<span className="text-[red] text-[13px]">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
value={jobTitle}
|
value={jobTitle}
|
||||||
onChange={(e) => setJobTitle(e.target.value)}
|
onChange={(e) => setJobTitle(e.target.value)}
|
||||||
required
|
required
|
||||||
@@ -554,21 +585,19 @@ const Signup = (props) => {
|
|||||||
<hr className="my-2 border-none" />
|
<hr className="my-2 border-none" />
|
||||||
<label>
|
<label>
|
||||||
Password{" "}
|
Password{" "}
|
||||||
<span style={{ color: "red", fontSize: 13 }}>*</span>
|
<span className="text-[red] text-[13px]">*</span>
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<input
|
<input
|
||||||
type={showPassword ? "text" : "password"}
|
type={showPassword ? "text" : "password"}
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
name="password"
|
name="password"
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => handlePasswordChange(e)}
|
onChange={(e) => handlePasswordChange(e)}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className={`absolute top-[50%] right-[10px] -translate-y-[50%] cursor-pointer ${
|
className={`absolute top-[50%] right-[10px] -translate-y-[50%] cursor-pointer text-base-content`}
|
||||||
showPassword ? "text-[#007bff]" : "text-black"
|
|
||||||
}`}
|
|
||||||
onClick={togglePasswordVisibility}
|
onClick={togglePasswordVisibility}
|
||||||
>
|
>
|
||||||
{showPassword ? (
|
{showPassword ? (
|
||||||
@@ -606,34 +635,62 @@ const Signup = (props) => {
|
|||||||
{specialCharValid ? "✓" : "✗"} Password should
|
{specialCharValid ? "✓" : "✗"} Password should
|
||||||
contain special character
|
contain special character
|
||||||
</p>
|
</p>
|
||||||
{/* </>
|
|
||||||
)} */}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<div className="mt-2.5 ml-1 flex flex-row items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="op-checkbox op-checkbox-sm"
|
||||||
|
id="termsandcondition"
|
||||||
|
checked={isAuthorize}
|
||||||
|
onChange={(e) => setIsAuthorize(e.target.checked)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
className="text-xs cursor-pointer ml-1 mb-0"
|
||||||
|
htmlFor="termsandcondition"
|
||||||
|
>
|
||||||
|
I agree to the
|
||||||
|
</label>
|
||||||
|
<span
|
||||||
|
className="underline cursor-pointer ml-1"
|
||||||
|
onClick={() =>
|
||||||
|
openInNewTab(
|
||||||
|
"https://www.opensignlabs.com/terms-and-conditions"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Terms of Service
|
||||||
|
</span>
|
||||||
|
<span>.</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col md:flex-row justify-between items-stretch gap-8 text-center text-xs font-bold mt-2">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-center text-xs font-bold mt-2">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="rounded-sm bg-[#3ac9d6] text-white w-full py-3 shadow uppercase"
|
className="op-btn op-btn-primary"
|
||||||
disabled={state.loading}
|
disabled={state.loading}
|
||||||
>
|
>
|
||||||
{state.loading ? "Loading..." : "Register"}
|
{state.loading ? "Loading..." : "Register"}
|
||||||
</button>
|
</button>
|
||||||
<NavLink
|
<button
|
||||||
className="rounded-sm cursor-pointer bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] w-full py-3 shadow uppercase"
|
type="button"
|
||||||
to="/"
|
className="op-btn op-btn-secondary"
|
||||||
style={width < 768 ? { textAlign: "center" } : {}}
|
disabled={state.loading}
|
||||||
|
onClick={() =>
|
||||||
|
navigate(location.search ? "/" + location.search : "/")
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Login
|
Login
|
||||||
</NavLink>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{width >= 768 && (
|
{width >= 768 && (
|
||||||
<div className="self-center">
|
<div className="self-center">
|
||||||
<div className="mx-auto md:w-[300px] lg:w-[400px] xl:w-[500px]">
|
<div className="mx-auto md:w-[300px] lg:w-[400px] xl:w-[500px]">
|
||||||
<img src={login_img} alt="bisec" width="100%" />
|
<img src={login_img} alt="loader" width="100%" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -642,30 +699,12 @@ const Signup = (props) => {
|
|||||||
<Alert type={state.alertType}>{state.alertMsg}</Alert>
|
<Alert type={state.alertType}>{state.alertMsg}</Alert>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div className="fixed w-full h-full flex justify-center items-center z-50">
|
||||||
style={{
|
<Loader />
|
||||||
position: "fixed",
|
</div>
|
||||||
fontSize: "50px",
|
|
||||||
color: "#3ac9d6",
|
|
||||||
top: "50%",
|
|
||||||
left: "45%"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
export default Signup;
|
||||||
if (Object.keys(state.appInfo).length !== 0) {
|
|
||||||
return { appInfo: state.appInfo, isloginVisible: true };
|
|
||||||
} else {
|
|
||||||
return { appInfo: state.appInfo, isloginVisible: false };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, {
|
|
||||||
fetchAppInfo,
|
|
||||||
showTenantName
|
|
||||||
})(Signup);
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user