Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e03c5bb15 | ||
|
|
e054777e14 | ||
|
|
328c3908e8 | ||
|
|
c5f5fca403 | ||
|
|
e296bff3b1 | ||
|
|
1a68b46d0b | ||
|
|
6eb28d6a94 | ||
|
|
d864cd012c | ||
|
|
28b7b27a73 | ||
|
|
5598162b29 | ||
|
|
9b095a0343 | ||
|
|
89df0824e5 | ||
|
|
bcb5d374a4 | ||
|
|
4bcab2c54d | ||
|
|
cc547d4faa | ||
|
|
38e13a3be9 | ||
|
|
213a578090 | ||
|
|
303a198bb7 | ||
|
|
4421480a9c | ||
|
|
c80aca9d66 | ||
|
|
cbc5a30efe | ||
|
|
d2bc27bff2 | ||
|
|
1ed9c828ea | ||
|
|
8d74276b90 | ||
|
|
a658996dd1 | ||
|
|
caa369cd64 | ||
|
|
3ea68c6c55 | ||
|
|
2aae91f71a | ||
|
|
45b52e989d | ||
|
|
251d3b73b8 | ||
|
|
ead4ec1f99 | ||
|
|
78b2575fa6 | ||
|
|
4ab926386e | ||
|
|
2123aedf12 | ||
|
|
ff194524d8 | ||
|
|
e5394bd691 | ||
|
|
885fead6e9 | ||
|
|
52fb2f818b | ||
|
|
a710b5da3d | ||
|
|
1266bf1712 | ||
|
|
bd481ccabc | ||
|
|
8e29305ef5 | ||
|
|
fe05535a4d | ||
|
|
c595e7a64f | ||
|
|
262135a66a | ||
|
|
7710f80ed1 | ||
|
|
f92431e6c3 | ||
|
|
7b49f89622 | ||
|
|
0cfdbc1e10 | ||
|
|
18866f3017 | ||
|
|
af8a40fe0a | ||
|
|
cb062d2668 | ||
|
|
5fdd3f5637 | ||
|
|
cabd4eec27 | ||
|
|
2315136323 | ||
|
|
110f49a160 | ||
|
|
73ecfa943e | ||
|
|
094e12240e | ||
|
|
207d80b40b | ||
|
|
b70d1920a2 | ||
|
|
be746dbd09 | ||
|
|
5384c8dea8 | ||
|
|
3380175d84 | ||
|
|
69fe0c1572 | ||
|
|
f855fa69c1 | ||
|
|
1379b04b23 | ||
|
|
9931d5f285 | ||
|
|
c14a71bcf5 | ||
|
|
2dc42a2692 | ||
|
|
0dc2d8fd3e | ||
|
|
133d179513 | ||
|
|
052f13a61b | ||
|
|
317c6db02c | ||
|
|
42c501a601 | ||
|
|
fa67b5ffa6 | ||
|
|
05772956c5 | ||
|
|
8ab28af991 | ||
|
|
0ee42102ca | ||
|
|
89bb1eb253 | ||
|
|
2de3b3856f | ||
|
|
2aeefa0624 | ||
|
|
00d70a9bd1 | ||
|
|
be6e80bb04 | ||
|
|
ff0f6a879d | ||
|
|
9db552a72c | ||
|
|
2ddc47ddfd | ||
|
|
780645081b | ||
|
|
854e169e7d | ||
|
|
d78120a7af | ||
|
|
19f031a1c3 | ||
|
|
1c0252ba71 | ||
|
|
1ebae01409 | ||
|
|
ae5c7bff14 | ||
|
|
00ed1d2578 | ||
|
|
b9d6efb0fb | ||
|
|
23cedef3f8 | ||
|
|
dc5060a0b3 | ||
|
|
79b7c0acd9 | ||
|
|
5145fd207c | ||
|
|
27c1c7ecd3 | ||
|
|
c3cf0057e3 | ||
|
|
3c25b09bf4 | ||
|
|
afe753fc85 | ||
|
|
bc05ef669b | ||
|
|
465d5e217c | ||
|
|
d1019e3ef6 | ||
|
|
5c3949239e | ||
|
|
3e0fb1cf15 | ||
|
|
9ffde3b609 | ||
|
|
235665dca2 | ||
|
|
baa1579d1b | ||
|
|
d95c559d01 | ||
|
|
2b3ff7ba92 | ||
|
|
42802da227 | ||
|
|
59c7440c61 | ||
|
|
047c43ecf4 | ||
|
|
a881fd6061 | ||
|
|
672bf237a8 | ||
|
|
1642955a4e | ||
|
|
232b1251fa | ||
|
|
d7846f299a | ||
|
|
aa6eec7a2c | ||
|
|
4c7094c0a5 | ||
|
|
6abdad8d84 | ||
|
|
67b7303c2b | ||
|
|
4ea968219b | ||
|
|
4138ab7e21 | ||
|
|
e7157b3de1 | ||
|
|
771bc3a04e | ||
|
|
db2b788ec9 | ||
|
|
8a7bdfff30 | ||
|
|
fcc1b0634c | ||
|
|
00fc014845 | ||
|
|
8c306714c3 | ||
|
|
e4d0dd9554 | ||
|
|
8287d3988e | ||
|
|
1c5160c356 | ||
|
|
c7dcfb908c | ||
|
|
1c09b6e1fa | ||
|
|
53ee5a36c7 | ||
|
|
c0b7cd08e5 | ||
|
|
bae0f228a8 | ||
|
|
edce724ad8 | ||
|
|
01b0f8ba94 | ||
|
|
94cb7b301c | ||
|
|
0835b1332b | ||
|
|
b98c10a28e | ||
|
|
5a84fcf89d | ||
|
|
26882f9a8b | ||
|
|
731a60f15b | ||
|
|
8f05404029 | ||
|
|
cc8ddc1e55 | ||
|
|
9052edb9c5 | ||
|
|
9073445b37 | ||
|
|
ca5e34e64d | ||
|
|
233c66044d | ||
|
|
64d768386e | ||
|
|
f0a8263aff | ||
|
|
a320835a73 | ||
|
|
805d0d1d84 | ||
|
|
b0d159462a | ||
|
|
84bdcfbcba | ||
|
|
e4a51b5390 | ||
|
|
891ff460a9 | ||
|
|
03c311ca7b | ||
|
|
620274e1eb | ||
|
|
dfb5b1bb94 | ||
|
|
0994f80891 | ||
|
|
cb9f75bf2f | ||
|
|
ee8525dac3 | ||
|
|
8919a2b2e9 | ||
|
|
efa5e2e491 | ||
|
|
c58566ea1b | ||
|
|
e1da69398c | ||
|
|
3f4cffb157 | ||
|
|
3d91b8b12e | ||
|
|
592f35f47f | ||
|
|
ed9fe3c5f9 | ||
|
|
c6e1593df5 | ||
|
|
900f929b53 | ||
|
|
e8093f1bf0 | ||
|
|
97912d2432 | ||
|
|
6fd6cd3eb8 | ||
|
|
37465082e4 | ||
|
|
d011edd3a1 | ||
|
|
694483aa2d | ||
|
|
c6be12b16a | ||
|
|
0213807732 | ||
|
|
d758062c07 | ||
|
|
cf698be79e | ||
|
|
c3298ccc6f | ||
|
|
eefa11d827 | ||
|
|
dadc79600f | ||
|
|
76d10d6ab9 | ||
|
|
c8733e6903 | ||
|
|
88ec854dbd | ||
|
|
717d2c0ddd | ||
|
|
8e2d463089 | ||
|
|
1344d8d12f | ||
|
|
51c8040d60 | ||
|
|
e505396e53 | ||
|
|
606bedd2ec | ||
|
|
dc82af0a0a | ||
|
|
8dfc61eeef | ||
|
|
2133a3a460 | ||
|
|
6f615db29d | ||
|
|
4141b3538c | ||
|
|
3bbb78b7b5 | ||
|
|
2caa231154 | ||
|
|
9ac382c188 | ||
|
|
852e109a52 | ||
|
|
d292b5bd6a | ||
|
|
d868fdf6f2 | ||
|
|
4145ce8c0c | ||
|
|
e093d7a5f4 | ||
|
|
3d4e43ede5 | ||
|
|
0bbfe5ae3d | ||
|
|
8538f0710a | ||
|
|
61be45cba2 | ||
|
|
162e07bacc | ||
|
|
806bb2e387 | ||
|
|
9de3331cd2 | ||
|
|
76699d7dc9 | ||
|
|
5888387dd0 | ||
|
|
83e9537176 | ||
|
|
d973a8fea4 | ||
|
|
ae6f727646 | ||
|
|
f9eb9201f0 | ||
|
|
0d884e2f4f | ||
|
|
1c70e4c059 | ||
|
|
e747d0d699 | ||
|
|
2edbafd520 | ||
|
|
14c57cceb3 | ||
|
|
6337f3057e | ||
|
|
537949b7c3 | ||
|
|
180e7c1435 | ||
|
|
9139422180 | ||
|
|
274d01b548 | ||
|
|
4d62048d36 | ||
|
|
921f7c89e9 | ||
|
|
6bfa3e61b5 | ||
|
|
840c7165ff | ||
|
|
9eeb1e9bc2 | ||
|
|
bc7f2d69cf | ||
|
|
34d9296c70 | ||
|
|
725b67e75e | ||
|
|
71bb6d6206 | ||
|
|
f271a113b6 | ||
|
|
71b254f69d | ||
|
|
28b6e9d4aa | ||
|
|
c6f57db04b | ||
|
|
5626b18ab0 | ||
|
|
5adf336119 | ||
|
|
ef1d4967d9 | ||
|
|
7680c8e140 | ||
|
|
0a14122cbf | ||
|
|
6587268f53 | ||
|
|
96d0db22c8 | ||
|
|
d35a03d588 | ||
|
|
7fd743f325 | ||
|
|
b81ff12ae5 | ||
|
|
65be6d1e20 | ||
|
|
9dfd1fb4f1 | ||
|
|
abbc0e91a9 | ||
|
|
1bf2f5622f | ||
|
|
8a1f2bc9a0 | ||
|
|
75518b3f6b | ||
|
|
53d874fd12 | ||
|
|
b7b61df983 | ||
|
|
20f1e68b13 | ||
|
|
e26fac8498 | ||
|
|
02dfec3a0f | ||
|
|
e6a04670b6 | ||
|
|
41aa91152d | ||
|
|
e69fb8eeba | ||
|
|
cb2dab8222 | ||
|
|
ad2672f205 | ||
|
|
e45314c1df | ||
|
|
34b0a1ca02 | ||
|
|
c05f541189 | ||
|
|
68cad8e10c | ||
|
|
2afad89b29 | ||
|
|
6c57ee6591 | ||
|
|
48bcaa5614 | ||
|
|
e595672e3c | ||
|
|
8fe31ee59b | ||
|
|
c6b139c456 | ||
|
|
10d99f12bb | ||
|
|
55ebdb5919 | ||
|
|
4b6712a0ff | ||
|
|
fcb983f68a | ||
|
|
f92ff170db | ||
|
|
c8b3f1fcbf | ||
|
|
936717fc6f | ||
|
|
be948ed4df | ||
|
|
5d8e7f738d | ||
|
|
128f6378cf | ||
|
|
1641217c43 | ||
|
|
63cc034b4a | ||
|
|
49a63eeb50 | ||
|
|
da45fcfc85 | ||
|
|
b73b0c6b2d | ||
|
|
c9fe580e44 | ||
|
|
b0556310dd | ||
|
|
9da13a23cc | ||
|
|
d727e16ef9 | ||
|
|
1508c63d0e | ||
|
|
8a198c1543 | ||
|
|
da0652d8ed | ||
|
|
59f1453176 | ||
|
|
ad748fbd03 | ||
|
|
2a1afca818 | ||
|
|
8e1cfd1ce5 | ||
|
|
6236353316 | ||
|
|
b5271017dc | ||
|
|
4b6b955fe5 | ||
|
|
a2b3761d5e | ||
|
|
2c5e311c7f | ||
|
|
98facb2f6d | ||
|
|
77618e57ea | ||
|
|
0bb8aa880d | ||
|
|
f97f2c1253 | ||
|
|
b76add3b2b | ||
|
|
07b14a0a47 | ||
|
|
aa7326a941 | ||
|
|
336d3424fe | ||
|
|
73ae7b1c06 | ||
|
|
ccfd7450d5 | ||
|
|
e23c04cf06 | ||
|
|
7bf661d584 | ||
|
|
98c18357cd | ||
|
|
8b7079bd8b | ||
|
|
9f0963d8a3 | ||
|
|
ebc79ddec7 | ||
|
|
24c6e9f5c0 | ||
|
|
475b2e09af | ||
|
|
05a922446a | ||
|
|
81a426b087 | ||
|
|
743b751b5a | ||
|
|
3d6e83b4af | ||
|
|
4f3e8ab95a | ||
|
|
cc00b35ac8 | ||
|
|
1c86caac1f | ||
|
|
20dd3c90d6 | ||
|
|
8b87a90e78 | ||
|
|
bd7937deb2 | ||
|
|
7b0dc4cf9a | ||
|
|
81c47190bf | ||
|
|
cecf22bb85 | ||
|
|
17eacfe86b | ||
|
|
8f5c9d1b40 | ||
|
|
f34e277657 | ||
|
|
7cc7e36f64 | ||
|
|
b340463ea7 | ||
|
|
9364bb7859 | ||
|
|
9f676c12e7 | ||
|
|
0077b71388 | ||
|
|
50af669bd2 | ||
|
|
45055b567f | ||
|
|
4a7fd118bb | ||
|
|
d27e8a43dc | ||
|
|
4d3635a5bd | ||
|
|
aeef6ca567 | ||
|
|
cc68dd109f | ||
|
|
7943f1444f | ||
|
|
876e04d815 | ||
|
|
43dbe71c99 | ||
|
|
73b36fafd7 | ||
|
|
095040713e | ||
|
|
ac884185b4 | ||
|
|
eede170d16 | ||
|
|
c4d6d8e442 | ||
|
|
14a2f6f78a | ||
|
|
dd28cefac8 | ||
|
|
00179f5415 | ||
|
|
7b465687ef | ||
|
|
e67fdfb134 | ||
|
|
ceee0e1089 | ||
|
|
1d184a69b0 | ||
|
|
8e09d7235b | ||
|
|
a39c01ef12 | ||
|
|
d96504bb30 | ||
|
|
0b8c4eac6e | ||
|
|
98f7de5e0c | ||
|
|
998a50412a | ||
|
|
e16c5e08a8 | ||
|
|
72a61bc621 | ||
|
|
f095629134 | ||
|
|
a0c1e08091 | ||
|
|
3583d7a549 | ||
|
|
69e679982a | ||
|
|
3303fcb895 | ||
|
|
6b5815f52a | ||
|
|
a01e361d14 | ||
|
|
c059e95fa9 | ||
|
|
70abddec3a | ||
|
|
ca8eaa492c | ||
|
|
94806c895f | ||
|
|
8b08995e7d | ||
|
|
de9c58e5fd | ||
|
|
6d914829e9 | ||
|
|
0193e4946f | ||
|
|
14c6b14c27 | ||
|
|
794365f6dc | ||
|
|
d0a0a28dec | ||
|
|
1385f12543 | ||
|
|
0d81ffe677 | ||
|
|
9d7376aedb | ||
|
|
5eb7d8ce13 | ||
|
|
4609bba4c1 | ||
|
|
de0de1973e | ||
|
|
16c48e9d23 | ||
|
|
344ccadfb1 | ||
|
|
eb1086e5b1 | ||
|
|
ae568a89d5 | ||
|
|
daa348c2e3 | ||
|
|
78532731da | ||
|
|
2e26d5687e | ||
|
|
4b8b7ed8d9 | ||
|
|
ac986af20f | ||
|
|
a96333bba5 | ||
|
|
78ca0d1fdb | ||
|
|
415760ba52 | ||
|
|
67bd246ef9 | ||
|
|
4963a7ad7f | ||
|
|
94b02105f3 | ||
|
|
6aaeeeeaf5 | ||
|
|
8039f5a744 | ||
|
|
a5ebd67967 | ||
|
|
266a4c5654 | ||
|
|
406a29054e | ||
|
|
57f8ba8a72 | ||
|
|
f1a70eac5a | ||
|
|
f228ae5ba8 | ||
|
|
2c1239dcf0 | ||
|
|
6ca9cbab16 | ||
|
|
9922f22ef7 | ||
|
|
84cc1d65fe | ||
|
|
7a5db1ca40 | ||
|
|
de79c9a4b3 | ||
|
|
7a7e1b506a | ||
|
|
fa2e66914d | ||
|
|
b0c65fe5f1 | ||
|
|
b0440876cd | ||
|
|
6359067839 | ||
|
|
71f36ff383 | ||
|
|
beab4bdfc9 | ||
|
|
c9e6750724 | ||
|
|
06c7355efd | ||
|
|
73f7d1b32f | ||
|
|
fecc87d8c3 | ||
|
|
57c89bf601 | ||
|
|
b10b2617b8 | ||
|
|
eaed35cefd | ||
|
|
44e92344fc | ||
|
|
9aebbde627 | ||
|
|
8ece6ef046 | ||
|
|
7d46e26365 | ||
|
|
e2646bd49f | ||
|
|
6158ac7bc4 | ||
|
|
596340bea9 | ||
|
|
73d1cdee00 | ||
|
|
f88f2c681b | ||
|
|
25ecf7221d | ||
|
|
bb18feaacf | ||
|
|
19324ad0d8 | ||
|
|
8a0f5c460f | ||
|
|
625689b203 | ||
|
|
d919e8514b | ||
|
|
18f183f48b | ||
|
|
69135afe6b | ||
|
|
474a20aa41 | ||
|
|
19478536b3 | ||
|
|
dc29d7a23b | ||
|
|
f5137f54b0 | ||
|
|
42f2122070 | ||
|
|
e4ca29c2c3 | ||
|
|
b8a039bc20 | ||
|
|
331b2d5a40 | ||
|
|
46e390d3c5 | ||
|
|
0b8fb87a29 | ||
|
|
e0249211d2 | ||
|
|
a244c1ba3d | ||
|
|
0a79807cb4 | ||
|
|
b70c473002 | ||
|
|
937390fca0 | ||
|
|
1140318719 | ||
|
|
655371c6d9 | ||
|
|
f07fc78eff | ||
|
|
60034a4ad8 | ||
|
|
ead7bf8841 | ||
|
|
15d2798aab | ||
|
|
58a0af40e6 | ||
|
|
1b79b45b1f | ||
|
|
f831ff3b7a | ||
|
|
f1b6859e9c | ||
|
|
2148f5196c | ||
|
|
5495e569df | ||
|
|
e121df48fe | ||
|
|
39c05b1eb3 | ||
|
|
78892a497d | ||
|
|
ccb08949ff | ||
|
|
74b091b1eb | ||
|
|
264214babd | ||
|
|
38930133f7 | ||
|
|
758cfc8e8d | ||
|
|
2a9ae74c33 | ||
|
|
2f73ba974c | ||
|
|
7c0b744c40 | ||
|
|
010d2dba60 | ||
|
|
c0b45e97ea | ||
|
|
7316fcd18a | ||
|
|
08a2d8a1a4 | ||
|
|
dbd53ba0d2 | ||
|
|
8b0c73c58e | ||
|
|
a292687a8c | ||
|
|
8659c1f4dc | ||
|
|
8ed73ba07b | ||
|
|
a41a31176d | ||
|
|
d6740efaf9 | ||
|
|
aac4ea8e2a | ||
|
|
3fe26cfb07 | ||
|
|
c837df6540 | ||
|
|
03b6b567fc | ||
|
|
09fbd442be | ||
|
|
5f32ca0140 | ||
|
|
46e5aa2815 | ||
|
|
db635f80f8 | ||
|
|
c3a101bc18 | ||
|
|
1af4bd430f | ||
|
|
0459c404f5 | ||
|
|
492f242e4d | ||
|
|
e06d6d5427 | ||
|
|
747c7c549c | ||
|
|
e91d615e68 | ||
|
|
2d527d59b0 | ||
|
|
340947a36d | ||
|
|
91d098ef65 | ||
|
|
d9f8ea8aca | ||
|
|
33bcb55124 | ||
|
|
5a93207dc2 | ||
|
|
fa7c36dbe2 | ||
|
|
faba8b8201 | ||
|
|
3422bc6f9e | ||
|
|
a195b758e6 | ||
|
|
083cd60f2d | ||
|
|
f4b7449262 | ||
|
|
fb68931538 | ||
|
|
be07fcec24 | ||
|
|
f6245cfada | ||
|
|
77cf6de722 | ||
|
|
2b17c26722 | ||
|
|
9862921297 | ||
|
|
685b2ceabd | ||
|
|
786b674db3 | ||
|
|
0b9074611a | ||
|
|
6ebfa038b3 | ||
|
|
4c809bb8d3 | ||
|
|
2dcb7eb7a2 | ||
|
|
743e89038c | ||
|
|
f9f25dc0c3 | ||
|
|
ca75698328 | ||
|
|
f117aeb7c4 | ||
|
|
e36557e844 | ||
|
|
e73b8ed5a5 | ||
|
|
0aaeb28eb7 | ||
|
|
305a5f6fda | ||
|
|
045961be02 | ||
|
|
c612dd3e70 | ||
|
|
ea4527e2dd | ||
|
|
aada33f23f | ||
|
|
1f44582658 | ||
|
|
198a58e524 | ||
|
|
0d78aef414 | ||
|
|
8f99cb0514 | ||
|
|
9a734d9b3c | ||
|
|
7a2c93a3e9 | ||
|
|
a5e1768f7e | ||
|
|
30e27062bd | ||
|
|
97d28a1b48 | ||
|
|
aade153f1c | ||
|
|
df6f5d4b33 | ||
|
|
ab14628769 | ||
|
|
69effb5af0 | ||
|
|
6e9078d64b | ||
|
|
9c73b7818f | ||
|
|
c5246d7a83 | ||
|
|
35511e08ac | ||
|
|
39dc8b226a | ||
|
|
7cb531b183 | ||
|
|
58422b17e5 | ||
|
|
0b2191f97c | ||
|
|
a3e672cde0 | ||
|
|
5a0b10bdff | ||
|
|
dfbf4d8a8f | ||
|
|
4727d622db | ||
|
|
e18e62754f | ||
|
|
bec7af5142 | ||
|
|
0db937eeeb | ||
|
|
c8d26a5ea9 | ||
|
|
1659ebd2ac | ||
|
|
7877d13776 | ||
|
|
2f7cacb933 | ||
|
|
16fcbf8a54 | ||
|
|
719a23c95b | ||
|
|
f4db8af201 | ||
|
|
3549c63cc0 | ||
|
|
b9ed7e5293 | ||
|
|
e34e2c4386 | ||
|
|
a09b2e186f | ||
|
|
cc273261c3 | ||
|
|
26c5c951b6 | ||
|
|
e63178b899 | ||
|
|
eb42f08640 | ||
|
|
2843bfd5c9 | ||
|
|
b2a838dc4e | ||
|
|
c682a6d8eb | ||
|
|
c4a23b4f1b | ||
|
|
12e74533c7 | ||
|
|
24c8f6012f | ||
|
|
b20fb9ea3f | ||
|
|
079e0defc4 | ||
|
|
00ad406e1b | ||
|
|
5c7a9e1d08 | ||
|
|
ea2c981a7f | ||
|
|
ee18d1b317 | ||
|
|
7f6771e56d | ||
|
|
1308b143c4 | ||
|
|
7be2d1f06a | ||
|
|
62021e8870 | ||
|
|
ea5f407786 | ||
|
|
2ecd1823e1 | ||
|
|
1e2eee63df | ||
|
|
8fda979870 | ||
|
|
c59002c375 | ||
|
|
1fe05b402b | ||
|
|
c7d5bef886 | ||
|
|
ca2fc2bd5c | ||
|
|
8bf9fb6299 | ||
|
|
031f24180a | ||
|
|
8663777097 | ||
|
|
342876cd0b | ||
|
|
beaa256e3f | ||
|
|
27ae27187d | ||
|
|
e8d692a707 | ||
|
|
4f71d1bd03 | ||
|
|
8d33d4c44e | ||
|
|
8be55a30c1 | ||
|
|
46a0cfa1eb | ||
|
|
6988bca7f4 | ||
|
|
1a2c0ecbfc | ||
|
|
f2281505a4 | ||
|
|
3ff790c57b | ||
|
|
d5b0fc4e3b | ||
|
|
69129c2d47 | ||
|
|
1486d66b9b | ||
|
|
67323d01f5 | ||
|
|
d0566e6645 | ||
|
|
a3e1fa866e | ||
|
|
6d6b70a888 | ||
|
|
c152d3bf35 | ||
|
|
56a0211b03 | ||
|
|
87fb943ddb | ||
|
|
dacc9bb27e | ||
|
|
43a9fa6820 | ||
|
|
523d7a0896 | ||
|
|
df53e243a5 | ||
|
|
b30d7e3337 | ||
|
|
7a8e2bcd02 | ||
|
|
7aa505f1a3 | ||
|
|
beecd2d26f | ||
|
|
96ecbe97f1 | ||
|
|
7161da4a2f | ||
|
|
462fdfe1be | ||
|
|
dc25133b10 | ||
|
|
bb7552a7bf | ||
|
|
79b4ca053a | ||
|
|
8d91bd218b | ||
|
|
8e0c96589a | ||
|
|
3ac66ea4c5 | ||
|
|
acbff61d9e | ||
|
|
83a1da04d1 | ||
|
|
b86155de49 | ||
|
|
2108ce52ca | ||
|
|
4af96da515 | ||
|
|
eda2085d4b | ||
|
|
6cdcf66e81 | ||
|
|
a701522dca | ||
|
|
ddeb31e530 | ||
|
|
f827ead0b6 | ||
|
|
ae87703a34 | ||
|
|
250c2d768b | ||
|
|
e5e6587490 | ||
|
|
4921152336 | ||
|
|
0c7da91fab | ||
|
|
add07026bc | ||
|
|
7f64418a6c | ||
|
|
e83ceaa815 | ||
|
|
e3dcb99438 | ||
|
|
78821cb5e4 | ||
|
|
548441dded | ||
|
|
7c53ae421c | ||
|
|
a71a867aea | ||
|
|
4d0d2e9a58 | ||
|
|
fcda1e325e | ||
|
|
b41fed0d12 | ||
|
|
ac533d92f6 | ||
|
|
792b48b75a | ||
|
|
175eb921c1 | ||
|
|
4cd959b34b | ||
|
|
0083efb7dc | ||
|
|
18738a56c0 | ||
|
|
3254fc8199 | ||
|
|
4a52299d35 | ||
|
|
7a1247051c | ||
|
|
71d34dd3d3 | ||
|
|
1971ffd221 | ||
|
|
a0af2145f3 | ||
|
|
64bd5cef35 | ||
|
|
4eb511e76e | ||
|
|
6e7fa2a7f8 | ||
|
|
1e3765990a | ||
|
|
2ef608fa33 | ||
|
|
479878a59d | ||
|
|
475eba8b7e | ||
|
|
c0ddec8896 | ||
|
|
38cd32b8c8 | ||
|
|
9a6ee0397b | ||
|
|
57f7bf6375 | ||
|
|
93f3cd7868 | ||
|
|
157b5a891e | ||
|
|
fcd10703a8 | ||
|
|
d17a8524c5 | ||
|
|
2d42013fed | ||
|
|
5288fe1512 | ||
|
|
3988361471 | ||
|
|
62204bda9d | ||
|
|
1ac4418d41 | ||
|
|
23914274b5 | ||
|
|
a668aa11db | ||
|
|
0aefb792dc | ||
|
|
54de1c1f5a | ||
|
|
f53f125e3e | ||
|
|
0269647d75 | ||
|
|
5fc05e7faa | ||
|
|
8c3caed1fb | ||
|
|
fbcb1fc47a | ||
|
|
fdd6e64060 | ||
|
|
3dd88f2453 | ||
|
|
d06bfefc40 | ||
|
|
30236206bc | ||
|
|
24b0231495 | ||
|
|
57946fea6d | ||
|
|
187990ce05 | ||
|
|
8cfcecf440 | ||
|
|
041d290f0f | ||
|
|
291791cb08 | ||
|
|
3d081cb7a0 | ||
|
|
0201159b31 | ||
|
|
4caaa203bb | ||
|
|
783bd63da0 | ||
|
|
82a187fe46 | ||
|
|
8ebf96f1e1 | ||
|
|
b25152a5e8 | ||
|
|
b1b488a8a0 | ||
|
|
8a76b92b5f | ||
|
|
724f3a9724 | ||
|
|
388d9cb29e | ||
|
|
6b463c6f1a | ||
|
|
4afca77d1e | ||
|
|
53d8e60ec3 | ||
|
|
23c22b79d8 | ||
|
|
4943517145 | ||
|
|
c71398c6e3 | ||
|
|
dfaa278636 | ||
|
|
139c3b42f5 | ||
|
|
d89c28334e | ||
|
|
7638bcad02 | ||
|
|
63090b82e3 | ||
|
|
63b7cb8188 | ||
|
|
ad9dda27ba | ||
|
|
3f3137874a | ||
|
|
440eaaeb26 | ||
|
|
2d6d8ce2be | ||
|
|
229d0731b8 | ||
|
|
418cd92f80 | ||
|
|
6e4ed4bc09 | ||
|
|
51b417aa7e | ||
|
|
0fc895ad17 | ||
|
|
2dea2172bc | ||
|
|
fcd3c15ec7 | ||
|
|
4cd9b08698 | ||
|
|
b21b641e2a | ||
|
|
af9c8d71c6 | ||
|
|
8bd1891fcc | ||
|
|
e5a62f17a5 | ||
|
|
db383d0e88 | ||
|
|
e519d86cad | ||
|
|
bf68656d05 | ||
|
|
69913151b6 | ||
|
|
46312eb138 | ||
|
|
1a13936681 | ||
|
|
251ea22f5f | ||
|
|
8f8808ce1c | ||
|
|
bb207b953c | ||
|
|
2984d6876d | ||
|
|
5d2b131c99 | ||
|
|
43c9b4db9c | ||
|
|
ce9e27e116 | ||
|
|
e25b7deaf3 | ||
|
|
81078073cb | ||
|
|
e6e5db95ba | ||
|
|
2cf3af242b | ||
|
|
ed664359a6 | ||
|
|
4a5e855b76 | ||
|
|
1e60863a40 | ||
|
|
10ad3ee5bd | ||
|
|
32c5a0a77a | ||
|
|
b6651f12e2 | ||
|
|
15ad35bf76 | ||
|
|
9a986dd000 | ||
|
|
714146f616 | ||
|
|
96d2b4e9fd | ||
|
|
122c42153e | ||
|
|
32c4ee16a0 | ||
|
|
53cdb411b7 | ||
|
|
0708e0ae1c | ||
|
|
95db24f8ed | ||
|
|
bcdd2e7feb | ||
|
|
4adfa9f830 | ||
|
|
dcc8f99991 | ||
|
|
3bdb56462d | ||
|
|
b8bffe97b5 | ||
|
|
af817b6bc3 | ||
|
|
8e1cbc65d7 | ||
|
|
e38a1f9c1a | ||
|
|
50c3133dae | ||
|
|
b1e2a74ad5 | ||
|
|
7e9dc8cd65 | ||
|
|
7d87cc27fc | ||
|
|
25714cde90 | ||
|
|
8241482c19 | ||
|
|
3044e010f6 | ||
|
|
9743b933da | ||
|
|
1ce8ec4758 | ||
|
|
cb99b7646c | ||
|
|
5af7279c67 | ||
|
|
224d9f6787 | ||
|
|
ed7df13f9b | ||
|
|
2c5f6631d7 | ||
|
|
a32b88f6b0 | ||
|
|
88cb271332 | ||
|
|
e18d1a7a16 | ||
|
|
b2dfc6f32c | ||
|
|
a64e30a94c | ||
|
|
6d5b28f75f | ||
|
|
c7decaec02 | ||
|
|
8600437c5a | ||
|
|
ece3f42ab3 | ||
|
|
32be8dfe3a | ||
|
|
2aebceda24 | ||
|
|
85b463f0e0 | ||
|
|
f6c8d4f51a | ||
|
|
b84c1c8821 | ||
|
|
a3334fdf2d | ||
|
|
d6b12b75b0 | ||
|
|
a9e623391b | ||
|
|
fd34ba778c | ||
|
|
d00d31eaf2 | ||
|
|
016a0f62bd | ||
|
|
cf52292f7c | ||
|
|
8b26c94ada | ||
|
|
582b10b5ee | ||
|
|
b51e152d10 | ||
|
|
5f197f5f9f | ||
|
|
5a3ee25dfd | ||
|
|
7050138e5e | ||
|
|
049d268314 | ||
|
|
6f71afb418 | ||
|
|
7e65692b5a | ||
|
|
bd1f44479b | ||
|
|
c0935001ce | ||
|
|
f65ab5dfea | ||
|
|
dbb7fd576f | ||
|
|
be5cc6126e | ||
|
|
6a4eb24630 | ||
|
|
61a8bc519f | ||
|
|
b15f3c0333 | ||
|
|
5830fda578 | ||
|
|
102f837263 | ||
|
|
5cee42a76e | ||
|
|
8fc7cc924a | ||
|
|
80170b814f | ||
|
|
91fcb71bc3 | ||
|
|
eb13d91bbb | ||
|
|
a464437b3a | ||
|
|
3a67dc9b08 | ||
|
|
a6ff20a657 | ||
|
|
4bf380edf8 | ||
|
|
ab3148b705 | ||
|
|
2ffd1ebf2a | ||
|
|
d1155bc8ef | ||
|
|
33ff706803 | ||
|
|
7fdd819722 | ||
|
|
aeaea23098 | ||
|
|
ff7f45f055 | ||
|
|
40665684a8 | ||
|
|
861f822151 | ||
|
|
62541f1450 | ||
|
|
a356e77f54 | ||
|
|
74abeff8d9 | ||
|
|
78dfaccd38 | ||
|
|
757b72161a | ||
|
|
c2065bf752 | ||
|
|
5608dae6e3 | ||
|
|
2288880eba | ||
|
|
ba7d0a9723 | ||
|
|
1ac8800b40 | ||
|
|
bb7827b762 | ||
|
|
8caa0275ab | ||
|
|
7e1d0f8a49 | ||
|
|
f7f5c2de37 | ||
|
|
f75710c836 | ||
|
|
a02cc89e5d | ||
|
|
f54a51c546 | ||
|
|
b12eb87b38 | ||
|
|
93f7408847 |
@@ -1,210 +0,0 @@
|
|||||||
{
|
|
||||||
"projectName": "OpenSign",
|
|
||||||
"projectOwner": "OpenSignLabs",
|
|
||||||
"files": [
|
|
||||||
"README.md"
|
|
||||||
],
|
|
||||||
"commitType": "docs",
|
|
||||||
"commitConvention": "angular",
|
|
||||||
"contributorsPerLine": 7,
|
|
||||||
"contributors": [
|
|
||||||
{
|
|
||||||
"login": "ajakov",
|
|
||||||
"name": "Aleksandar Jakovljevic",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/2115393?v=4",
|
|
||||||
"profile": "https://aleksandarjakovljevic.com/",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "BuilderPrid",
|
|
||||||
"name": "Priyanshu Dwivedi",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/106882895?v=4",
|
|
||||||
"profile": "https://github.com/BuilderPrid",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "Tashuuuu",
|
|
||||||
"name": "Akriti Sengar",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/85075827?v=4",
|
|
||||||
"profile": "https://github.com/Tashuuuu",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "parthrc",
|
|
||||||
"name": "Parth Chawande",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/101104958?v=4",
|
|
||||||
"profile": "https://github.com/parthrc",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "Rishabh-git10",
|
|
||||||
"name": "Rishabh Dewangan",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/107680241?v=4",
|
|
||||||
"profile": "https://github.com/Rishabh-git10",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "LemonDrop847",
|
|
||||||
"name": "Nitin Mishra",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/106615670?v=4",
|
|
||||||
"profile": "https://github.com/LemonDrop847",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "Jobin-S",
|
|
||||||
"name": "Jobin Selvanose",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/63976083?v=4",
|
|
||||||
"profile": "http://jobinselvanose.com",
|
|
||||||
"contributions": [
|
|
||||||
"doc"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "HansF",
|
|
||||||
"name": "Hans Fraiponts",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/1503?v=4",
|
|
||||||
"profile": "https://github.com/HansF",
|
|
||||||
"contributions": [
|
|
||||||
"doc"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "Monilprajapati",
|
|
||||||
"name": "Monil Prajapati",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/99136041?v=4",
|
|
||||||
"profile": "http://linktr.ee/monilprajapati",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "Emm-dev0",
|
|
||||||
"name": "Edogbanya Emmanuel",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/97445413?v=4",
|
|
||||||
"profile": "https://emm-dev0.github.io/portfolio/",
|
|
||||||
"contributions": [
|
|
||||||
"bug"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "pranav514",
|
|
||||||
"name": "pranav514",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/76992202?v=4",
|
|
||||||
"profile": "https://github.com/pranav514",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "arianxq",
|
|
||||||
"name": "Aria",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/122199576?v=4",
|
|
||||||
"profile": "https://github.com/arianxq",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "SoumyadiptoPal",
|
|
||||||
"name": "Soumyadipto Pal",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/119007659?v=4",
|
|
||||||
"profile": "https://github.com/SoumyadiptoPal",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "AndreyCurious",
|
|
||||||
"name": "Andrey Didenko",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/105622604?v=4",
|
|
||||||
"profile": "https://github.com/AndreyCurious",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "VishakhaSainani",
|
|
||||||
"name": "VishakhaSainani",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/113436770?v=4",
|
|
||||||
"profile": "https://github.com/VishakhaSainani",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "andrew-opensignlabs",
|
|
||||||
"name": "Andrew",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/148278535?v=4",
|
|
||||||
"profile": "https://github.com/andrew-opensignlabs",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "rishabjasrotia",
|
|
||||||
"name": "Rishab",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/33950743?v=4",
|
|
||||||
"profile": "https://github.com/rishabjasrotia",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "maoo",
|
|
||||||
"name": "Maurizio Pillitu",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/327285?v=4",
|
|
||||||
"profile": "https://session.it",
|
|
||||||
"contributions": [
|
|
||||||
"bug"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "lsprr",
|
|
||||||
"name": "Luis Parra",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/16653744?v=4",
|
|
||||||
"profile": "https://luisparra.dev",
|
|
||||||
"contributions": [
|
|
||||||
"a11y"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "Govinda04",
|
|
||||||
"name": "Govinda Kocharekar",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/50038172?v=4",
|
|
||||||
"profile": "https://github.com/Govinda04",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "crediblebilal",
|
|
||||||
"name": "Bilal Ahmad Bhat",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/55330484?v=4",
|
|
||||||
"profile": "https://bilal.cc",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "VikramNagwal",
|
|
||||||
"name": "Vikram",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/123088024?v=4",
|
|
||||||
"profile": "https://github.com/VikramNagwal",
|
|
||||||
"contributions": [
|
|
||||||
"code"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
# Frontend config ************************************************************************************************************************************************************************************************
|
|
||||||
|
|
||||||
# Set it to the URL form where the app home page will be accessed
|
|
||||||
PUBLIC_URL=https://app.opensignlabs.com/
|
|
||||||
# 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://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
|
|
||||||
# Google tag manager container id for configuring GTM on all pages of the app
|
|
||||||
REACT_APP_GTM=GTM-123N7LD
|
|
||||||
|
|
||||||
# Backend ExpressJS config ****************************************************************************************************************************************************************************************
|
|
||||||
# A 12 character long random app identifier. The value of this should be same as REACT_APP_APPID which is a variable used by Frontend React App.
|
|
||||||
APP_ID=opensign
|
|
||||||
# Name of the app. It will be visible in the verification emails sent out.
|
|
||||||
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.
|
|
||||||
MASTER_KEY=XnAadwKxxByMr
|
|
||||||
# Mongodb URI to connect to
|
|
||||||
MONGODB_URI=mongodb://username:password@localhost:27017
|
|
||||||
# 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
|
|
||||||
# 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)
|
|
||||||
SERVER_URL=https://app.opensignlabs.com/api/app
|
|
||||||
|
|
||||||
# Storage config ************************************************************************************************************************************************************************************************
|
|
||||||
# Digital ocean space name or AWS S3 bucket name for uploading documents
|
|
||||||
DO_SPACE=DOSPACENAME
|
|
||||||
# Digital ocean spaces endpoint or AWS S3 endpoint for uploading documents
|
|
||||||
DO_ENDPOINT=ams3.digitaloceanspaces.com
|
|
||||||
# Digital ocean baseurl or AWS S3 base URL
|
|
||||||
DO_BASEURL=https://DOSPACENAME.ams3.digitaloceanspaces.com
|
|
||||||
# Digital ocean spaces access key ID or AWS s3 Access key ID for uploading the docs
|
|
||||||
DO_ACCESS_KEY_ID=
|
|
||||||
# Digital ocean spaces secret access key or AWS s3 secret access key for uploading the docs
|
|
||||||
DO_SECRET_ACCESS_KEY=
|
|
||||||
# Digital ocean spaces region or AWS s3 region
|
|
||||||
DO_REGION=us-west
|
|
||||||
# Set this to true id you are using local storage instead of s3 compatible storage
|
|
||||||
# USE_LOCAL=TRUE
|
|
||||||
|
|
||||||
# Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
|
|
||||||
MAILGUN_API_KEY=XXXXX
|
|
||||||
MAILGUN_DOMAIN=mail.yourdomain.com
|
|
||||||
MAILGUN_SENDER=postmaster@mail.yourdomain.com
|
|
||||||
SMTP_ENABLE=
|
|
||||||
SMTP_HOST=
|
|
||||||
SMTP_PORT=
|
|
||||||
SMTP_USER_EMAIL=
|
|
||||||
SMTP_PASS=
|
|
||||||
|
|
||||||
# Base64 encoded PFX or p12 document signing certificate file *********************************************************************************************************************
|
|
||||||
PFX_BASE64=
|
|
||||||
|
|
||||||
# Provide Pass pharse of above PFX or p12 document
|
|
||||||
PASS_PHRASE=
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# Clone the repo and rename this file to .env if you want to run the frontend react app locally for some quick contributions to the project.
|
|
||||||
# When used as it is, this env config will connect to our hosted UAT backend
|
|
||||||
# Note that any data in staging will get cleared from time to time and you may have to sign up again and again
|
|
||||||
|
|
||||||
# Set it to the URL form where the app home page will be accessed
|
|
||||||
PUBLIC_URL=http://localhost:3000
|
|
||||||
# Set it to true if you want to generate the Sourcemap for debugging
|
|
||||||
GENERATE_SOURCEMAP=false
|
|
||||||
# Set it to the URL from where APIs will be accessible, for local development it should be localhost:3000/api/app (use your local port number instead)
|
|
||||||
REACT_APP_SERVERURL=https://staging-app.opensignlabs.com/api/app
|
|
||||||
# A 12 character long random app identifier. The value of this should be same as APP_ID which is a variable used by backend API.
|
|
||||||
REACT_APP_APPID=opensign
|
|
||||||
@@ -1,113 +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=http://localhost:8080/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
|
|
||||||
|
|
||||||
|
|
||||||
# Backend ExpressJS config ****************************************************************************************************************************************************************************************
|
|
||||||
# A 12 character long random app identifier. The value of this should be same as REACT_APP_APPID which is a variable used by Frontend React App.
|
|
||||||
APP_ID=opensign
|
|
||||||
# Name of the app. It will be visible in the verification emails sent out.
|
|
||||||
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.
|
|
||||||
MASTER_KEY=XnAadwKxxByMr
|
|
||||||
# Mongodb URI to connect to
|
|
||||||
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.
|
|
||||||
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)
|
|
||||||
SERVER_URL=http://127.0.0.1:8080/app
|
|
||||||
|
|
||||||
# Storage config ************************************************************************************************************************************************************************************************
|
|
||||||
# Digital ocean space name or AWS S3 bucket name for uploading documents
|
|
||||||
DO_SPACE=DOSPACENAME
|
|
||||||
# Digital ocean spaces endpoint or AWS S3 endpoint for uploading documents
|
|
||||||
DO_ENDPOINT=ams3.digitaloceanspaces.com
|
|
||||||
# Digital ocean baseurl or AWS S3 base URL
|
|
||||||
DO_BASEURL=https://DOSPACENAME.ams3.digitaloceanspaces.com
|
|
||||||
# Digital ocean spaces access key ID or AWS s3 Access key ID for uploading the docs
|
|
||||||
DO_ACCESS_KEY_ID=
|
|
||||||
# Digital ocean spaces secret access key or AWS s3 secret access key for uploading the docs
|
|
||||||
DO_SECRET_ACCESS_KEY=
|
|
||||||
# Digital ocean spaces region or AWS s3 region
|
|
||||||
DO_REGION=us-west
|
|
||||||
# local storage
|
|
||||||
USE_LOCAL=TRUE
|
|
||||||
|
|
||||||
# Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
|
|
||||||
MAILGUN_API_KEY=
|
|
||||||
MAILGUN_DOMAIN=mail.yourdomain.com
|
|
||||||
MAILGUN_SENDER=postmaster@mail.yourdomain.com
|
|
||||||
SMTP_ENABLE=
|
|
||||||
SMTP_HOST=smtp.yourhost.com
|
|
||||||
SMTP_PORT=443
|
|
||||||
SMTP_USER_EMAIL=mailer@yourdomain.com
|
|
||||||
SMTP_PASS=password # if your password includes spaces then write password in single quotes ('asdf pasd asdf bgds').
|
|
||||||
|
|
||||||
|
|
||||||
# Base64 encoded PFX or p12 document signing certificate file *********************************************************************************************************************
|
|
||||||
PFX_BASE64='MIIKCQIBAzCCCc8GCSqGSIb3DQEHAaCCCcAEggm8MIIJuDCCBG8GCSqGSIb3DQEH
|
|
||||||
BqCCBGAwggRcAgEAMIIEVQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIpumu
|
|
||||||
bFabBWACAggAgIIEKDqHS7Icd5MzIBk1dBokGK2s+5a2fA4308WA1QzEWmczqVYI
|
|
||||||
z6lYmW8qsiZIw4PFkRzdIx1+zCmP8jgWiiqh5RKnbHYmh1JPNyx9SqmUDILDXmjg
|
|
||||||
KxO9agRw9LXge4hgRL7YW0TxYZYw4EeXV9Yr7kcOq9DoO2MoRikJ+2Tuvvq/hfuV
|
|
||||||
9zFHsz4jpf7W95k1IeH6bZ92klz5R1e/EK8JuHy592i/u+BxxW1vTkiPpTaHD6s9
|
|
||||||
1lDSkT1j0LIDU6l9gVvJvFBV8j88vet/Z4QkTbHPMYvBnKNRstKuOvDasEJE4RkA
|
|
||||||
PV4TfBwFF6uvREZI1vBboM/18pzeyjoRX+mlJNfcH3kh1tkck+Jg+M2bLXAH1EdD
|
|
||||||
GRwENvnTNW1CFIn37VVja7SFBQNXA+E6rejmqtUmZ5XktSINDBUyjow9XuYTUtI/
|
|
||||||
sgcRSC0aB0EKKpphbFPp1niKCLm1ef33e+bWyWbtR2L2Kc3ETmhjNADpyapAGmzc
|
|
||||||
LP2BafGaKj18KiLAG4GL6+kXk0GUz7Fw5q8H8RY1T33o+xjWvC0+aJgvr65qWdKw
|
|
||||||
+ug6wuu4Cr2kFEuXxPKsnYqmE5NT/x+lfunlZ5iEQN3w2XO5J2u2eMXVRUsPH2T6
|
|
||||||
0sJKomjY0RB1JsqZBnyleWm+tYo0RpVAyJ3NGBp9dVb7a3Qw6jNZBG/xMW+gvtUJ
|
|
||||||
q6hfK/cD3cagD0NQFVD5STMOuGOSqq/bbwAKjZ/lrPmCCYATKwkjAFybYfHJVrrW
|
|
||||||
Y2tQgCQ/zrZLIxQjp7F17hU0+gT54x0MpF6AoqIM/qqNnHrQ0fi50ECmLvx3SqYa
|
|
||||||
nvjvt/HZhMZfqRXiXjeicIwpnNoG7+uQknySk+7cc9GNhHZR7cfPfkTpgvuuebrQ
|
|
||||||
l5YW+k9tG+xrX8g72nvtFMnammlBixlFwECJaEszEQk5tc2ti8uG2z+kGnFoDoBV
|
|
||||||
M6ZVMpKDJzXPxLdzT6ChIPyatjIkqOKe6vDpnmzcoEhbBhmtkVjWFA2dfX846ugV
|
|
||||||
y1QiecWgk8pMNWhh3IDd05v/wzbFwNcq+Gi+1dZsPmFH+egIcrQKZu2r3jCJtGHh
|
|
||||||
DNG/nyf/anqvKXF90bi4hRT3vdDXXuWgY7EUwfn9h5jYabCO6HsQxQOBjFYNmBrh
|
|
||||||
MfaiBZe72E8fzNAfIlwDcJ4AWY1SOM7hi8bqfRWw1NtNxuMUiRFoR31O6XkQauye
|
|
||||||
9hAmpdlZHZXtJ6LM0QaWkPJmG3058GMtIn/qS60V9nINh+zXhwza/1pnFB+e9MWc
|
|
||||||
hAPgo0nn55FusM//g1nM31PKe+nOm3Jyp0nEQ4m8aDtJS63o2fvp3e2KJbPWQMHE
|
|
||||||
a83W975diWg4NTdevV9lFpNllHclVoPoavUHIzHd7HF9TcPpjbXJSUZ7cITHHefr
|
|
||||||
kQTa/2G9cWuRhN9GKIHBdr13nfEvMIIFQQYJKoZIhvcNAQcBoIIFMgSCBS4wggUq
|
|
||||||
MIIFJgYLKoZIhvcNAQwKAQKgggTuMIIE6jAcBgoqhkiG9w0BDAEDMA4ECDgnjfOf
|
|
||||||
AjArAgIIAASCBMgkbVuptroBdyMY5gl/eBQj5+iAV02YSaF969ihStLSWI4x5FAf
|
|
||||||
HuDgqCyEMSl4RHG8ZvNaO9JoNfIpMK/TPQBoQRCzE2Vjf66VTERaQtU6h7tZrbQt
|
|
||||||
K96n9eqvohm/vXbXe08fsodYp2s79kAvKgpuGG5iX77qYVzJHBPed87cvczo4ToP
|
|
||||||
CpurDpByt8fGEmjtcikal8o+H9uoHjcFwqMigX1Q7IEjuKXrb5e6wTvxMRob8yfv
|
|
||||||
LVl6ahteKSkWCMb6rLZ5f12jDoCGX/YXRrSsU9t/lXe0Nxv5i7c8flb2EsNtwygD
|
|
||||||
fexVvn5u6ble6RDYNpuQkPgF41HyZh+JvGAF6i1r4tJPL9Pf4HnjEB8Y8IHgon+w
|
|
||||||
T5I+8LTgcrWyhptzblXMjKySTEp9OEa2cCVwZkl4z43PWJ5oIAQ2IDTOQ603/5o/
|
|
||||||
d9KA76/zMPQ5O0gv17OA7kwFv98v6sTcR4vgkQZqnyDpJSEPHyNxhw2MSBqS3jq3
|
|
||||||
YPhRz+3Ei1oFp9uYFhzn39f9gzNi++X9pOjSrDb8v3mcDXZKNrxQLuoRMSf0eQNI
|
|
||||||
dgJRqj/fuqNZ5ac3kd4P5BALCsnA1tM27zYrgUdpOnrc2D9FBthEjpRlQKMMzhQf
|
|
||||||
cNMFWmoNjakDilvvLcsQeQ3P6cXbN1ODoNnjgK3VzcmeKyzW2PrTXEPHARUM3j4V
|
|
||||||
sZzGaUOVKLqaaDrXWQKC0vrTvxP2WMfjQ1dTdXQP/kSZTXRC5rtB9tky38flBor0
|
|
||||||
N9rhUDIGMs5qBvyrkV2hKXiW39G69p1KWY+Cw28AzY+CNSjePRi60TsnUxgcOS7i
|
|
||||||
0AT25Gx3A4YqxmTY38MPB4wPcBPcw4hjNoQamaC9mqs+KVHcP5YHUlqykMeH0YVi
|
|
||||||
J+ehytJE9xuDcfBOjxjadxp3/q/Lku4rky89gdJGFQWuuz75VulDywPRZRwmQTel
|
|
||||||
sjEGMHR1zTOlPJdTDWhqaKmWvL4GhbCgEPIKwmqd1QKRTl/3Baa1nYllJeYVwiTT
|
|
||||||
qLCkbA6qXrLGj1ENZxrKn9yqr8HwOoApjwhARu4LF/BRMgdkzelK2kOXHnZ26sZ2
|
|
||||||
NY/MMtVmq4c59y6iQwmsbHr9tWGz3ahyXcZZufjNXU/AVnO1c92g7umAWZF4RohL
|
|
||||||
gMmh57cAhN9PEbEv6j/6BT3XXp8jB0ywcRriYxfxwidviCKH/76Q4sytYJQaDFI1
|
|
||||||
fnzmv0aDotbG2BdpWSiYPDOPm+3cmfjlULsn1FYWL4NDCX1f+C4lNtKVX9LU8c5M
|
|
||||||
m8dA1DUlDfnuNO5/BShuoGXG2z4O/XwxIaRFizMxWS2sWurbAEFJ6oNw3kC7WSah
|
|
||||||
NIe8aUC1umpc1Gk3X2f4Ytzj9OEqn0y55qoqLINJuejXMffF/gjopxHWadLVaVaj
|
|
||||||
Q1SewrECuEXdSbBR/a10po24wmRtkmlvRJXJl7sG95xE5ZCqp+m6sRPWGdf1yKbV
|
|
||||||
vyWNUe4Qvkxe4a0VAJpTyIGr980CKz/jkvtNQMobGl7AfhxKJ450wg454WcexMct
|
|
||||||
BYXvZMSdUDCgMLlh0nHJHl5btrFWqE0Z/fqWmIknZL2jZ4J+2hdVl/xB/sUt6kcu
|
|
||||||
txw+RfL+vNE8PxhTNaOdJFwD8yeN1mJ3yMUA8HHYpw9yljgxJTAjBgkqhkiG9w0B
|
|
||||||
CRUxFgQUDYlgGVxSxuOknhQc256x3++7BDwwMTAhMAkGBSsOAwIaBQAEFFjASdYl
|
|
||||||
3pXAXxZuvVvv9tsb4bdrBAhyb+KCIjp/gAICCAA='
|
|
||||||
|
|
||||||
# Provide Pass pharse of above PFX or p12 document
|
|
||||||
PASS_PHRASE=opensign
|
|
||||||
@@ -2,7 +2,7 @@ name: ci
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'staging'
|
- 'main'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
@@ -11,9 +11,9 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- image: amolshejole/OpenSign
|
- image: amolshejole/OpenSign
|
||||||
dockerfile: apps/OpenSign/Dockerhubfile
|
dockerfile: apps/OpenSign/Dockerfile
|
||||||
- image: amolshejole/OpenSignServer
|
- image: amolshejole/OpenSignServer
|
||||||
dockerfile: apps/OpenSignServer/Dockerhubfile
|
dockerfile: apps/OpenSignServer/Dockerfile
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
@@ -31,11 +31,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
images: ${{ matrix.image }}
|
images: ${{ matrix.image }}
|
||||||
-
|
-
|
||||||
name: Debug - List files opensign
|
name: Debug - List files
|
||||||
run: ls -R apps/OpenSign/ # Adjust the path as needed
|
run: ls -R apps/OpenSign/ # Adjust the path as needed
|
||||||
-
|
|
||||||
name: Debug - List files opensignserver
|
|
||||||
run: ls -R apps/OpenSignServer/ # Adjust the path as needed
|
|
||||||
-
|
-
|
||||||
name: Build and push
|
name: Build and push
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v4
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
name: Deploy to GitHub Pages
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- feat-docs
|
||||||
|
# Review gh actions docs if you want to further define triggers, paths, etc
|
||||||
|
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
name: Deploy to GitHub Pages
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
cache: npm
|
||||||
|
- name: Install dependencies
|
||||||
|
working-directory: ./docs
|
||||||
|
run: npm ci
|
||||||
|
- name: Clean api-docs
|
||||||
|
working-directory: ./docs
|
||||||
|
run: npm run docusaurus clean-api-docs all
|
||||||
|
- name: Build api-docs
|
||||||
|
working-directory: ./docs
|
||||||
|
run: npm run docusaurus gen-api-docs all
|
||||||
|
- name: Build website
|
||||||
|
working-directory: ./docs
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
# Popular action to deploy to GitHub Pages:
|
||||||
|
# Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
# Build output to publish to the `gh-pages` branch:
|
||||||
|
publish_dir: ./docs/build
|
||||||
|
# The following lines assign commit authorship to the official
|
||||||
|
# GH-Actions bot for deploys to `gh-pages` branch:
|
||||||
|
# https://github.com/actions/checkout/issues/13#issuecomment-724415212
|
||||||
|
# The GH actions bot is used by default if you didn't specify the two fields.
|
||||||
|
# You can swap them out with your own user credentials.
|
||||||
|
user_name: github-actions[bot]
|
||||||
|
user_email: 41898282+github-actions[bot]@users.noreply.github.com
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
|
|
||||||
# INSTALLATON INSTRUCTIONS HAS A NEW HOME
|
|
||||||
|
|
||||||
We've updated our installation instructions and moved them to our dedicated documentation portal to provide you with a better experience and updated guidance. Whether you're looking to self-host OpenSign™ or contribute to its development, you can find detailed instructions tailored to your needs at [docs.opensignlabs.com](https://docs.opensignlabs.com).
|
|
||||||
|
|
||||||
## Self Hosting
|
|
||||||
|
|
||||||
If you're interested in self-hosting OpenSign™, our new documentation portal provides comprehensive, step-by-step instructions to help you set up OpenSign™ in your own environment. This section is designed for system administrators and those looking to deploy OpenSign™ within their organization or for personal use.
|
|
||||||
|
|
||||||
- **Access Self Hosting Instructions:** [Self Hosting Guide](https://docs.opensignlabs.com/docs/category/docker)
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
For developers and contributors who are looking to build upon or contribute to OpenSign™, we've prepared a separate section that covers the setup, development environment configuration, and guidelines for contributing to the OpenSign™ project.
|
|
||||||
|
|
||||||
- **Access Contributor Instructions:** [Contributors Guide](https://docs.opensignlabs.com/docs/contribute/INSTALLATION)
|
|
||||||
|
|
||||||
## Additional Resources
|
|
||||||
|
|
||||||
Should you need further assistance or have any questions, please feel free to reach out to us through our support channels:
|
|
||||||
|
|
||||||
- **Twitter:** [OpenSignHQ on Twitter](https://twitter.com/OpenSignHQ)
|
|
||||||
- **Facebook:** [OpenSign on Facebook](https://www.facebook.com/profile.php?id=61551030403669)
|
|
||||||
- **LinkedIn:** [OpenSign™ on LinkedIn](https://www.linkedin.com/company/opensign%E2%84%A2/)
|
|
||||||
- **Discord:** [Join our Discord Community](https://discord.com/invite/opensign)
|
|
||||||
- **YouTube:** [OpenSignHQ on YouTube](https://www.youtube.com/@opensignhq)
|
|
||||||
|
|
||||||
We are committed to providing you with the support you need to successfully install and use OpenSign™. Visit our website at [www.opensignlabs.com](https://www.opensignlabs.com) for more information about our project and its features.
|
|
||||||
|
|
||||||
@@ -1,661 +0,0 @@
|
|||||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 19 November 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The GNU Affero General Public License is a free, copyleft license for
|
|
||||||
software and other kinds of works, specifically designed to ensure
|
|
||||||
cooperation with the community in the case of network server software.
|
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
|
||||||
to take away your freedom to share and change the works. By contrast,
|
|
||||||
our General Public Licenses are intended to guarantee your freedom to
|
|
||||||
share and change all versions of a program--to make sure it remains free
|
|
||||||
software for all its users.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
them if you wish), that you receive source code or can get it if you
|
|
||||||
want it, that you can change the software or use pieces of it in new
|
|
||||||
free programs, and that you know you can do these things.
|
|
||||||
|
|
||||||
Developers that use our General Public Licenses protect your rights
|
|
||||||
with two steps: (1) assert copyright on the software, and (2) offer
|
|
||||||
you this License which gives you legal permission to copy, distribute
|
|
||||||
and/or modify the software.
|
|
||||||
|
|
||||||
A secondary benefit of defending all users' freedom is that
|
|
||||||
improvements made in alternate versions of the program, if they
|
|
||||||
receive widespread use, become available for other developers to
|
|
||||||
incorporate. Many developers of free software are heartened and
|
|
||||||
encouraged by the resulting cooperation. However, in the case of
|
|
||||||
software used on network servers, this result may fail to come about.
|
|
||||||
The GNU General Public License permits making a modified version and
|
|
||||||
letting the public access it on a server without ever releasing its
|
|
||||||
source code to the public.
|
|
||||||
|
|
||||||
The GNU Affero General Public License is designed specifically to
|
|
||||||
ensure that, in such cases, the modified source code becomes available
|
|
||||||
to the community. It requires the operator of a network server to
|
|
||||||
provide the source code of the modified version running there to the
|
|
||||||
users of that server. Therefore, public use of a modified version, on
|
|
||||||
a publicly accessible server, gives the public access to the source
|
|
||||||
code of the modified version.
|
|
||||||
|
|
||||||
An older license, called the Affero General Public License and
|
|
||||||
published by Affero, was designed to accomplish similar goals. This is
|
|
||||||
a different license, not a version of the Affero GPL, but Affero has
|
|
||||||
released a new version of the Affero GPL which permits relicensing under
|
|
||||||
this license.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
0. Definitions.
|
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
|
||||||
works, such as semiconductor masks.
|
|
||||||
|
|
||||||
"The Program" refers to any copyrightable work licensed under this
|
|
||||||
License. Each licensee is addressed as "you". "Licensees" and
|
|
||||||
"recipients" may be individuals or organizations.
|
|
||||||
|
|
||||||
To "modify" a work means to copy from or adapt all or part of the work
|
|
||||||
in a fashion requiring copyright permission, other than the making of an
|
|
||||||
exact copy. The resulting work is called a "modified version" of the
|
|
||||||
earlier work or a work "based on" the earlier work.
|
|
||||||
|
|
||||||
A "covered work" means either the unmodified Program or a work based
|
|
||||||
on the Program.
|
|
||||||
|
|
||||||
To "propagate" a work means to do anything with it that, without
|
|
||||||
permission, would make you directly or secondarily liable for
|
|
||||||
infringement under applicable copyright law, except executing it on a
|
|
||||||
computer or modifying a private copy. Propagation includes copying,
|
|
||||||
distribution (with or without modification), making available to the
|
|
||||||
public, and in some countries other activities as well.
|
|
||||||
|
|
||||||
To "convey" a work means any kind of propagation that enables other
|
|
||||||
parties to make or receive copies. Mere interaction with a user through
|
|
||||||
a computer network, with no transfer of a copy, is not conveying.
|
|
||||||
|
|
||||||
An interactive user interface displays "Appropriate Legal Notices"
|
|
||||||
to the extent that it includes a convenient and prominently visible
|
|
||||||
feature that (1) displays an appropriate copyright notice, and (2)
|
|
||||||
tells the user that there is no warranty for the work (except to the
|
|
||||||
extent that warranties are provided), that licensees may convey the
|
|
||||||
work under this License, and how to view a copy of this License. If
|
|
||||||
the interface presents a list of user commands or options, such as a
|
|
||||||
menu, a prominent item in the list meets this criterion.
|
|
||||||
|
|
||||||
1. Source Code.
|
|
||||||
|
|
||||||
The "source code" for a work means the preferred form of the work
|
|
||||||
for making modifications to it. "Object code" means any non-source
|
|
||||||
form of a work.
|
|
||||||
|
|
||||||
A "Standard Interface" means an interface that either is an official
|
|
||||||
standard defined by a recognized standards body, or, in the case of
|
|
||||||
interfaces specified for a particular programming language, one that
|
|
||||||
is widely used among developers working in that language.
|
|
||||||
|
|
||||||
The "System Libraries" of an executable work include anything, other
|
|
||||||
than the work as a whole, that (a) is included in the normal form of
|
|
||||||
packaging a Major Component, but which is not part of that Major
|
|
||||||
Component, and (b) serves only to enable use of the work with that
|
|
||||||
Major Component, or to implement a Standard Interface for which an
|
|
||||||
implementation is available to the public in source code form. A
|
|
||||||
"Major Component", in this context, means a major essential component
|
|
||||||
(kernel, window system, and so on) of the specific operating system
|
|
||||||
(if any) on which the executable work runs, or a compiler used to
|
|
||||||
produce the work, or an object code interpreter used to run it.
|
|
||||||
|
|
||||||
The "Corresponding Source" for a work in object code form means all
|
|
||||||
the source code needed to generate, install, and (for an executable
|
|
||||||
work) run the object code and to modify the work, including scripts to
|
|
||||||
control those activities. However, it does not include the work's
|
|
||||||
System Libraries, or general-purpose tools or generally available free
|
|
||||||
programs which are used unmodified in performing those activities but
|
|
||||||
which are not part of the work. For example, Corresponding Source
|
|
||||||
includes interface definition files associated with source files for
|
|
||||||
the work, and the source code for shared libraries and dynamically
|
|
||||||
linked subprograms that the work is specifically designed to require,
|
|
||||||
such as by intimate data communication or control flow between those
|
|
||||||
subprograms and other parts of the work.
|
|
||||||
|
|
||||||
The Corresponding Source need not include anything that users
|
|
||||||
can regenerate automatically from other parts of the Corresponding
|
|
||||||
Source.
|
|
||||||
|
|
||||||
The Corresponding Source for a work in source code form is that
|
|
||||||
same work.
|
|
||||||
|
|
||||||
2. Basic Permissions.
|
|
||||||
|
|
||||||
All rights granted under this License are granted for the term of
|
|
||||||
copyright on the Program, and are irrevocable provided the stated
|
|
||||||
conditions are met. This License explicitly affirms your unlimited
|
|
||||||
permission to run the unmodified Program. The output from running a
|
|
||||||
covered work is covered by this License only if the output, given its
|
|
||||||
content, constitutes a covered work. This License acknowledges your
|
|
||||||
rights of fair use or other equivalent, as provided by copyright law.
|
|
||||||
|
|
||||||
You may make, run and propagate covered works that you do not
|
|
||||||
convey, without conditions so long as your license otherwise remains
|
|
||||||
in force. You may convey covered works to others for the sole purpose
|
|
||||||
of having them make modifications exclusively for you, or provide you
|
|
||||||
with facilities for running those works, provided that you comply with
|
|
||||||
the terms of this License in conveying all material for which you do
|
|
||||||
not control copyright. Those thus making or running the covered works
|
|
||||||
for you must do so exclusively on your behalf, under your direction
|
|
||||||
and control, on terms that prohibit them from making any copies of
|
|
||||||
your copyrighted material outside their relationship with you.
|
|
||||||
|
|
||||||
Conveying under any other circumstances is permitted solely under
|
|
||||||
the conditions stated below. Sublicensing is not allowed; section 10
|
|
||||||
makes it unnecessary.
|
|
||||||
|
|
||||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
|
||||||
|
|
||||||
No covered work shall be deemed part of an effective technological
|
|
||||||
measure under any applicable law fulfilling obligations under article
|
|
||||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
|
||||||
similar laws prohibiting or restricting circumvention of such
|
|
||||||
measures.
|
|
||||||
|
|
||||||
When you convey a covered work, you waive any legal power to forbid
|
|
||||||
circumvention of technological measures to the extent such circumvention
|
|
||||||
is effected by exercising rights under this License with respect to
|
|
||||||
the covered work, and you disclaim any intention to limit operation or
|
|
||||||
modification of the work as a means of enforcing, against the work's
|
|
||||||
users, your or third parties' legal rights to forbid circumvention of
|
|
||||||
technological measures.
|
|
||||||
|
|
||||||
4. Conveying Verbatim Copies.
|
|
||||||
|
|
||||||
You may convey verbatim copies of the Program's source code as you
|
|
||||||
receive it, in any medium, provided that you conspicuously and
|
|
||||||
appropriately publish on each copy an appropriate copyright notice;
|
|
||||||
keep intact all notices stating that this License and any
|
|
||||||
non-permissive terms added in accord with section 7 apply to the code;
|
|
||||||
keep intact all notices of the absence of any warranty; and give all
|
|
||||||
recipients a copy of this License along with the Program.
|
|
||||||
|
|
||||||
You may charge any price or no price for each copy that you convey,
|
|
||||||
and you may offer support or warranty protection for a fee.
|
|
||||||
|
|
||||||
5. Conveying Modified Source Versions.
|
|
||||||
|
|
||||||
You may convey a work based on the Program, or the modifications to
|
|
||||||
produce it from the Program, in the form of source code under the
|
|
||||||
terms of section 4, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The work must carry prominent notices stating that you modified
|
|
||||||
it, and giving a relevant date.
|
|
||||||
|
|
||||||
b) The work must carry prominent notices stating that it is
|
|
||||||
released under this License and any conditions added under section
|
|
||||||
7. This requirement modifies the requirement in section 4 to
|
|
||||||
"keep intact all notices".
|
|
||||||
|
|
||||||
c) You must license the entire work, as a whole, under this
|
|
||||||
License to anyone who comes into possession of a copy. This
|
|
||||||
License will therefore apply, along with any applicable section 7
|
|
||||||
additional terms, to the whole of the work, and all its parts,
|
|
||||||
regardless of how they are packaged. This License gives no
|
|
||||||
permission to license the work in any other way, but it does not
|
|
||||||
invalidate such permission if you have separately received it.
|
|
||||||
|
|
||||||
d) If the work has interactive user interfaces, each must display
|
|
||||||
Appropriate Legal Notices; however, if the Program has interactive
|
|
||||||
interfaces that do not display Appropriate Legal Notices, your
|
|
||||||
work need not make them do so.
|
|
||||||
|
|
||||||
A compilation of a covered work with other separate and independent
|
|
||||||
works, which are not by their nature extensions of the covered work,
|
|
||||||
and which are not combined with it such as to form a larger program,
|
|
||||||
in or on a volume of a storage or distribution medium, is called an
|
|
||||||
"aggregate" if the compilation and its resulting copyright are not
|
|
||||||
used to limit the access or legal rights of the compilation's users
|
|
||||||
beyond what the individual works permit. Inclusion of a covered work
|
|
||||||
in an aggregate does not cause this License to apply to the other
|
|
||||||
parts of the aggregate.
|
|
||||||
|
|
||||||
6. Conveying Non-Source Forms.
|
|
||||||
|
|
||||||
You may convey a covered work in object code form under the terms
|
|
||||||
of sections 4 and 5, provided that you also convey the
|
|
||||||
machine-readable Corresponding Source under the terms of this License,
|
|
||||||
in one of these ways:
|
|
||||||
|
|
||||||
a) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by the
|
|
||||||
Corresponding Source fixed on a durable physical medium
|
|
||||||
customarily used for software interchange.
|
|
||||||
|
|
||||||
b) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by a
|
|
||||||
written offer, valid for at least three years and valid for as
|
|
||||||
long as you offer spare parts or customer support for that product
|
|
||||||
model, to give anyone who possesses the object code either (1) a
|
|
||||||
copy of the Corresponding Source for all the software in the
|
|
||||||
product that is covered by this License, on a durable physical
|
|
||||||
medium customarily used for software interchange, for a price no
|
|
||||||
more than your reasonable cost of physically performing this
|
|
||||||
conveying of source, or (2) access to copy the
|
|
||||||
Corresponding Source from a network server at no charge.
|
|
||||||
|
|
||||||
c) Convey individual copies of the object code with a copy of the
|
|
||||||
written offer to provide the Corresponding Source. This
|
|
||||||
alternative is allowed only occasionally and noncommercially, and
|
|
||||||
only if you received the object code with such an offer, in accord
|
|
||||||
with subsection 6b.
|
|
||||||
|
|
||||||
d) Convey the object code by offering access from a designated
|
|
||||||
place (gratis or for a charge), and offer equivalent access to the
|
|
||||||
Corresponding Source in the same way through the same place at no
|
|
||||||
further charge. You need not require recipients to copy the
|
|
||||||
Corresponding Source along with the object code. If the place to
|
|
||||||
copy the object code is a network server, the Corresponding Source
|
|
||||||
may be on a different server (operated by you or a third party)
|
|
||||||
that supports equivalent copying facilities, provided you maintain
|
|
||||||
clear directions next to the object code saying where to find the
|
|
||||||
Corresponding Source. Regardless of what server hosts the
|
|
||||||
Corresponding Source, you remain obligated to ensure that it is
|
|
||||||
available for as long as needed to satisfy these requirements.
|
|
||||||
|
|
||||||
e) Convey the object code using peer-to-peer transmission, provided
|
|
||||||
you inform other peers where the object code and Corresponding
|
|
||||||
Source of the work are being offered to the general public at no
|
|
||||||
charge under subsection 6d.
|
|
||||||
|
|
||||||
A separable portion of the object code, whose source code is excluded
|
|
||||||
from the Corresponding Source as a System Library, need not be
|
|
||||||
included in conveying the object code work.
|
|
||||||
|
|
||||||
A "User Product" is either (1) a "consumer product", which means any
|
|
||||||
tangible personal property which is normally used for personal, family,
|
|
||||||
or household purposes, or (2) anything designed or sold for incorporation
|
|
||||||
into a dwelling. In determining whether a product is a consumer product,
|
|
||||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
|
||||||
product received by a particular user, "normally used" refers to a
|
|
||||||
typical or common use of that class of product, regardless of the status
|
|
||||||
of the particular user or of the way in which the particular user
|
|
||||||
actually uses, or expects or is expected to use, the product. A product
|
|
||||||
is a consumer product regardless of whether the product has substantial
|
|
||||||
commercial, industrial or non-consumer uses, unless such uses represent
|
|
||||||
the only significant mode of use of the product.
|
|
||||||
|
|
||||||
"Installation Information" for a User Product means any methods,
|
|
||||||
procedures, authorization keys, or other information required to install
|
|
||||||
and execute modified versions of a covered work in that User Product from
|
|
||||||
a modified version of its Corresponding Source. The information must
|
|
||||||
suffice to ensure that the continued functioning of the modified object
|
|
||||||
code is in no case prevented or interfered with solely because
|
|
||||||
modification has been made.
|
|
||||||
|
|
||||||
If you convey an object code work under this section in, or with, or
|
|
||||||
specifically for use in, a User Product, and the conveying occurs as
|
|
||||||
part of a transaction in which the right of possession and use of the
|
|
||||||
User Product is transferred to the recipient in perpetuity or for a
|
|
||||||
fixed term (regardless of how the transaction is characterized), the
|
|
||||||
Corresponding Source conveyed under this section must be accompanied
|
|
||||||
by the Installation Information. But this requirement does not apply
|
|
||||||
if neither you nor any third party retains the ability to install
|
|
||||||
modified object code on the User Product (for example, the work has
|
|
||||||
been installed in ROM).
|
|
||||||
|
|
||||||
The requirement to provide Installation Information does not include a
|
|
||||||
requirement to continue to provide support service, warranty, or updates
|
|
||||||
for a work that has been modified or installed by the recipient, or for
|
|
||||||
the User Product in which it has been modified or installed. Access to a
|
|
||||||
network may be denied when the modification itself materially and
|
|
||||||
adversely affects the operation of the network or violates the rules and
|
|
||||||
protocols for communication across the network.
|
|
||||||
|
|
||||||
Corresponding Source conveyed, and Installation Information provided,
|
|
||||||
in accord with this section must be in a format that is publicly
|
|
||||||
documented (and with an implementation available to the public in
|
|
||||||
source code form), and must require no special password or key for
|
|
||||||
unpacking, reading or copying.
|
|
||||||
|
|
||||||
7. Additional Terms.
|
|
||||||
|
|
||||||
"Additional permissions" are terms that supplement the terms of this
|
|
||||||
License by making exceptions from one or more of its conditions.
|
|
||||||
Additional permissions that are applicable to the entire Program shall
|
|
||||||
be treated as though they were included in this License, to the extent
|
|
||||||
that they are valid under applicable law. If additional permissions
|
|
||||||
apply only to part of the Program, that part may be used separately
|
|
||||||
under those permissions, but the entire Program remains governed by
|
|
||||||
this License without regard to the additional permissions.
|
|
||||||
|
|
||||||
When you convey a copy of a covered work, you may at your option
|
|
||||||
remove any additional permissions from that copy, or from any part of
|
|
||||||
it. (Additional permissions may be written to require their own
|
|
||||||
removal in certain cases when you modify the work.) You may place
|
|
||||||
additional permissions on material, added by you to a covered work,
|
|
||||||
for which you have or can give appropriate copyright permission.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, for material you
|
|
||||||
add to a covered work, you may (if authorized by the copyright holders of
|
|
||||||
that material) supplement the terms of this License with terms:
|
|
||||||
|
|
||||||
a) Disclaiming warranty or limiting liability differently from the
|
|
||||||
terms of sections 15 and 16 of this License; or
|
|
||||||
|
|
||||||
b) Requiring preservation of specified reasonable legal notices or
|
|
||||||
author attributions in that material or in the Appropriate Legal
|
|
||||||
Notices displayed by works containing it; or
|
|
||||||
|
|
||||||
c) Prohibiting misrepresentation of the origin of that material, or
|
|
||||||
requiring that modified versions of such material be marked in
|
|
||||||
reasonable ways as different from the original version; or
|
|
||||||
|
|
||||||
d) Limiting the use for publicity purposes of names of licensors or
|
|
||||||
authors of the material; or
|
|
||||||
|
|
||||||
e) Declining to grant rights under trademark law for use of some
|
|
||||||
trade names, trademarks, or service marks; or
|
|
||||||
|
|
||||||
f) Requiring indemnification of licensors and authors of that
|
|
||||||
material by anyone who conveys the material (or modified versions of
|
|
||||||
it) with contractual assumptions of liability to the recipient, for
|
|
||||||
any liability that these contractual assumptions directly impose on
|
|
||||||
those licensors and authors.
|
|
||||||
|
|
||||||
All other non-permissive additional terms are considered "further
|
|
||||||
restrictions" within the meaning of section 10. If the Program as you
|
|
||||||
received it, or any part of it, contains a notice stating that it is
|
|
||||||
governed by this License along with a term that is a further
|
|
||||||
restriction, you may remove that term. If a license document contains
|
|
||||||
a further restriction but permits relicensing or conveying under this
|
|
||||||
License, you may add to a covered work material governed by the terms
|
|
||||||
of that license document, provided that the further restriction does
|
|
||||||
not survive such relicensing or conveying.
|
|
||||||
|
|
||||||
If you add terms to a covered work in accord with this section, you
|
|
||||||
must place, in the relevant source files, a statement of the
|
|
||||||
additional terms that apply to those files, or a notice indicating
|
|
||||||
where to find the applicable terms.
|
|
||||||
|
|
||||||
Additional terms, permissive or non-permissive, may be stated in the
|
|
||||||
form of a separately written license, or stated as exceptions;
|
|
||||||
the above requirements apply either way.
|
|
||||||
|
|
||||||
8. Termination.
|
|
||||||
|
|
||||||
You may not propagate or modify a covered work except as expressly
|
|
||||||
provided under this License. Any attempt otherwise to propagate or
|
|
||||||
modify it is void, and will automatically terminate your rights under
|
|
||||||
this License (including any patent licenses granted under the third
|
|
||||||
paragraph of section 11).
|
|
||||||
|
|
||||||
However, if you cease all violation of this License, then your
|
|
||||||
license from a particular copyright holder is reinstated (a)
|
|
||||||
provisionally, unless and until the copyright holder explicitly and
|
|
||||||
finally terminates your license, and (b) permanently, if the copyright
|
|
||||||
holder fails to notify you of the violation by some reasonable means
|
|
||||||
prior to 60 days after the cessation.
|
|
||||||
|
|
||||||
Moreover, your license from a particular copyright holder is
|
|
||||||
reinstated permanently if the copyright holder notifies you of the
|
|
||||||
violation by some reasonable means, this is the first time you have
|
|
||||||
received notice of violation of this License (for any work) from that
|
|
||||||
copyright holder, and you cure the violation prior to 30 days after
|
|
||||||
your receipt of the notice.
|
|
||||||
|
|
||||||
Termination of your rights under this section does not terminate the
|
|
||||||
licenses of parties who have received copies or rights from you under
|
|
||||||
this License. If your rights have been terminated and not permanently
|
|
||||||
reinstated, you do not qualify to receive new licenses for the same
|
|
||||||
material under section 10.
|
|
||||||
|
|
||||||
9. Acceptance Not Required for Having Copies.
|
|
||||||
|
|
||||||
You are not required to accept this License in order to receive or
|
|
||||||
run a copy of the Program. Ancillary propagation of a covered work
|
|
||||||
occurring solely as a consequence of using peer-to-peer transmission
|
|
||||||
to receive a copy likewise does not require acceptance. However,
|
|
||||||
nothing other than this License grants you permission to propagate or
|
|
||||||
modify any covered work. These actions infringe copyright if you do
|
|
||||||
not accept this License. Therefore, by modifying or propagating a
|
|
||||||
covered work, you indicate your acceptance of this License to do so.
|
|
||||||
|
|
||||||
10. Automatic Licensing of Downstream Recipients.
|
|
||||||
|
|
||||||
Each time you convey a covered work, the recipient automatically
|
|
||||||
receives a license from the original licensors, to run, modify and
|
|
||||||
propagate that work, subject to this License. You are not responsible
|
|
||||||
for enforcing compliance by third parties with this License.
|
|
||||||
|
|
||||||
An "entity transaction" is a transaction transferring control of an
|
|
||||||
organization, or substantially all assets of one, or subdividing an
|
|
||||||
organization, or merging organizations. If propagation of a covered
|
|
||||||
work results from an entity transaction, each party to that
|
|
||||||
transaction who receives a copy of the work also receives whatever
|
|
||||||
licenses to the work the party's predecessor in interest had or could
|
|
||||||
give under the previous paragraph, plus a right to possession of the
|
|
||||||
Corresponding Source of the work from the predecessor in interest, if
|
|
||||||
the predecessor has it or can get it with reasonable efforts.
|
|
||||||
|
|
||||||
You may not impose any further restrictions on the exercise of the
|
|
||||||
rights granted or affirmed under this License. For example, you may
|
|
||||||
not impose a license fee, royalty, or other charge for exercise of
|
|
||||||
rights granted under this License, and you may not initiate litigation
|
|
||||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
|
||||||
any patent claim is infringed by making, using, selling, offering for
|
|
||||||
sale, or importing the Program or any portion of it.
|
|
||||||
|
|
||||||
11. Patents.
|
|
||||||
|
|
||||||
A "contributor" is a copyright holder who authorizes use under this
|
|
||||||
License of the Program or a work on which the Program is based. The
|
|
||||||
work thus licensed is called the contributor's "contributor version".
|
|
||||||
|
|
||||||
A contributor's "essential patent claims" are all patent claims
|
|
||||||
owned or controlled by the contributor, whether already acquired or
|
|
||||||
hereafter acquired, that would be infringed by some manner, permitted
|
|
||||||
by this License, of making, using, or selling its contributor version,
|
|
||||||
but do not include claims that would be infringed only as a
|
|
||||||
consequence of further modification of the contributor version. For
|
|
||||||
purposes of this definition, "control" includes the right to grant
|
|
||||||
patent sublicenses in a manner consistent with the requirements of
|
|
||||||
this License.
|
|
||||||
|
|
||||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
|
||||||
patent license under the contributor's essential patent claims, to
|
|
||||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
|
||||||
propagate the contents of its contributor version.
|
|
||||||
|
|
||||||
In the following three paragraphs, a "patent license" is any express
|
|
||||||
agreement or commitment, however denominated, not to enforce a patent
|
|
||||||
(such as an express permission to practice a patent or covenant not to
|
|
||||||
sue for patent infringement). To "grant" such a patent license to a
|
|
||||||
party means to make such an agreement or commitment not to enforce a
|
|
||||||
patent against the party.
|
|
||||||
|
|
||||||
If you convey a covered work, knowingly relying on a patent license,
|
|
||||||
and the Corresponding Source of the work is not available for anyone
|
|
||||||
to copy, free of charge and under the terms of this License, through a
|
|
||||||
publicly available network server or other readily accessible means,
|
|
||||||
then you must either (1) cause the Corresponding Source to be so
|
|
||||||
available, or (2) arrange to deprive yourself of the benefit of the
|
|
||||||
patent license for this particular work, or (3) arrange, in a manner
|
|
||||||
consistent with the requirements of this License, to extend the patent
|
|
||||||
license to downstream recipients. "Knowingly relying" means you have
|
|
||||||
actual knowledge that, but for the patent license, your conveying the
|
|
||||||
covered work in a country, or your recipient's use of the covered work
|
|
||||||
in a country, would infringe one or more identifiable patents in that
|
|
||||||
country that you have reason to believe are valid.
|
|
||||||
|
|
||||||
If, pursuant to or in connection with a single transaction or
|
|
||||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
|
||||||
covered work, and grant a patent license to some of the parties
|
|
||||||
receiving the covered work authorizing them to use, propagate, modify
|
|
||||||
or convey a specific copy of the covered work, then the patent license
|
|
||||||
you grant is automatically extended to all recipients of the covered
|
|
||||||
work and works based on it.
|
|
||||||
|
|
||||||
A patent license is "discriminatory" if it does not include within
|
|
||||||
the scope of its coverage, prohibits the exercise of, or is
|
|
||||||
conditioned on the non-exercise of one or more of the rights that are
|
|
||||||
specifically granted under this License. You may not convey a covered
|
|
||||||
work if you are a party to an arrangement with a third party that is
|
|
||||||
in the business of distributing software, under which you make payment
|
|
||||||
to the third party based on the extent of your activity of conveying
|
|
||||||
the work, and under which the third party grants, to any of the
|
|
||||||
parties who would receive the covered work from you, a discriminatory
|
|
||||||
patent license (a) in connection with copies of the covered work
|
|
||||||
conveyed by you (or copies made from those copies), or (b) primarily
|
|
||||||
for and in connection with specific products or compilations that
|
|
||||||
contain the covered work, unless you entered into that arrangement,
|
|
||||||
or that patent license was granted, prior to 28 March 2007.
|
|
||||||
|
|
||||||
Nothing in this License shall be construed as excluding or limiting
|
|
||||||
any implied license or other defenses to infringement that may
|
|
||||||
otherwise be available to you under applicable patent law.
|
|
||||||
|
|
||||||
12. No Surrender of Others' Freedom.
|
|
||||||
|
|
||||||
If conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot convey a
|
|
||||||
covered work so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you may
|
|
||||||
not convey it at all. For example, if you agree to terms that obligate you
|
|
||||||
to collect a royalty for further conveying from those to whom you convey
|
|
||||||
the Program, the only way you could satisfy both those terms and this
|
|
||||||
License would be to refrain entirely from conveying the Program.
|
|
||||||
|
|
||||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, if you modify the
|
|
||||||
Program, your modified version must prominently offer all users
|
|
||||||
interacting with it remotely through a computer network (if your version
|
|
||||||
supports such interaction) an opportunity to receive the Corresponding
|
|
||||||
Source of your version by providing access to the Corresponding Source
|
|
||||||
from a network server at no charge, through some standard or customary
|
|
||||||
means of facilitating copying of software. This Corresponding Source
|
|
||||||
shall include the Corresponding Source for any work covered by version 3
|
|
||||||
of the GNU General Public License that is incorporated pursuant to the
|
|
||||||
following paragraph.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
|
||||||
permission to link or combine any covered work with a work licensed
|
|
||||||
under version 3 of the GNU General Public License into a single
|
|
||||||
combined work, and to convey the resulting work. The terms of this
|
|
||||||
License will continue to apply to the part which is the covered work,
|
|
||||||
but the work with which it is combined will remain governed by version
|
|
||||||
3 of the GNU General Public License.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
|
||||||
the GNU Affero General Public License from time to time. Such new versions
|
|
||||||
will be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Program specifies that a certain numbered version of the GNU Affero General
|
|
||||||
Public License "or any later version" applies to it, you have the
|
|
||||||
option of following the terms and conditions either of that numbered
|
|
||||||
version or of any later version published by the Free Software
|
|
||||||
Foundation. If the Program does not specify a version number of the
|
|
||||||
GNU Affero General Public License, you may choose any version ever published
|
|
||||||
by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
|
||||||
versions of the GNU Affero General Public License can be used, that proxy's
|
|
||||||
public statement of acceptance of a version permanently authorizes you
|
|
||||||
to choose that version for the Program.
|
|
||||||
|
|
||||||
Later license versions may give you additional or different
|
|
||||||
permissions. However, no additional obligations are imposed on any
|
|
||||||
author or copyright holder as a result of your choosing to follow a
|
|
||||||
later version.
|
|
||||||
|
|
||||||
15. Disclaimer of Warranty.
|
|
||||||
|
|
||||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
|
||||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
|
||||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
|
||||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
|
||||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
|
||||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. Limitation of Liability.
|
|
||||||
|
|
||||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
|
||||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
|
||||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
|
||||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
|
||||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
|
||||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
|
||||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
|
||||||
SUCH DAMAGES.
|
|
||||||
|
|
||||||
17. Interpretation of Sections 15 and 16.
|
|
||||||
|
|
||||||
If the disclaimer of warranty and limitation of liability provided
|
|
||||||
above cannot be given local legal effect according to their terms,
|
|
||||||
reviewing courts shall apply local law that most closely approximates
|
|
||||||
an absolute waiver of all civil liability in connection with the
|
|
||||||
Program, unless a warranty or assumption of liability accompanies a
|
|
||||||
copy of the Program in return for a fee.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
state the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published
|
|
||||||
by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If your software can interact with users remotely through a computer
|
|
||||||
network, you should also make sure that it provides a way for users to
|
|
||||||
get its source. For example, if your program is a web application, its
|
|
||||||
interface could display a "Source" link that leads users to an archive
|
|
||||||
of the code. There are many ways you could offer source, and different
|
|
||||||
solutions will be better for different programs; see section 13 for the
|
|
||||||
specific requirements.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
|
||||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
build:
|
|
||||||
cp .env.local_dev .env
|
|
||||||
cd apps/OpenSign && cp ../../.env.local_dev .env && npm install && npm run build
|
|
||||||
docker compose up --build --force-recreate
|
|
||||||
|
|
||||||
run:
|
|
||||||
cp .env.local_dev .env
|
|
||||||
docker compose up -d
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
<h1 align="center"><a href='https://www.opensignlabs.com'><img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/e518cc9c-5de3-47da-950b-f93336b9f14e></a>
|
|
||||||
</h1><div align="center">
|
|
||||||
|
|
||||||
[The free and open source alternative to DocuSign](https://www.opensignlabs.com)
|
|
||||||
|
|
||||||
[](http://isitmaintained.com/project/opensignlabs/opensign "Average time to resolve an issue")
|
|
||||||
[](#contributors)
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
<a href="https://www.opensignlabs.com/">Website</a>
|
|
||||||
<span> • </span>
|
|
||||||
<a href="https://www.opensignlabs.com">Docs</a>
|
|
||||||
<span> • </span>
|
|
||||||
<a href="https://www.opensignlabs.com/blog">Blog</a>
|
|
||||||
<span> • </span>
|
|
||||||
<a href="https://discord.com/invite/xe9TDuyAyj">Discord</a>
|
|
||||||
<span> • </span>
|
|
||||||
<a href="https://twitter.com/opensignlabs">Twitter</a>
|
|
||||||
<span> • </span>
|
|
||||||
<a href="https://www.linkedin.com/company/opensign%E2%84%A2/about/">LinkedIn</a>
|
|
||||||
|
|
||||||
|
|
||||||
## The open-source document e-signing solution
|
|
||||||
|
|
||||||
---
|
|
||||||
</div>
|
|
||||||
|
|
||||||
### Table of Contents
|
|
||||||
|
|
||||||
1. [Introduction](#introduction)
|
|
||||||
2. [Features](#features)
|
|
||||||
3. [Installation](#installation)
|
|
||||||
4. [Usage](#usage)
|
|
||||||
5. [Contribution Guidelines](#contribution-guidelines)
|
|
||||||
6. [License](#license)
|
|
||||||
7. [Acknowledgments](#acknowledgments)
|
|
||||||
|
|
||||||
---
|
|
||||||
Please star ⭐ the repo to support us! 😀
|
|
||||||
|
|
||||||
### Introduction
|
|
||||||
|
|
||||||
Welcome to OpenSign, the premier open source docusign alternative - document e-signing solution designed to provide a secure, reliable and free alternative to commercial esign platforms like DocuSign, PandaDoc, SignNow, Adobe Sign, Smartwaiver, SignRequest, HelloSign & Zoho sign. Our mission is to democratize the e-signing process, making it accessible and straightforward for everyone.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
- **Secure PDF E-Signing:** With the help of robust encryption algorithms, OpenSign™ ensures maximum security, privacy & compatibility.
|
|
||||||
- **Annotate Documents:** OpenSign™ allows you to annotate PDF documents with an advanced signing pad that allows hand drawn signatures, uploaded images, typed signatures & saved signatures for the simplest signing experience ever.
|
|
||||||
- **User-Friendly Interface:** OpenSign™ was built while keeping Intuitive design in mind for ease of use. Features like "Sign yourself", "Templates", "One click signatures" and "OpenSign™ Drive" makes it stand out of the crowd and even makes it better than a lot of so-called industry leaders.
|
|
||||||
- **Multi-signer Support:** OpenSign's ability to invite multiple signers for signing along with the ability to invite witnesses & being able to enforce signing in a sequence makes it the only open source solution that is fully loaded and allows it to compete head-to-head with established players in e-signature space.
|
|
||||||
- **Email Unique Code(OTP) verification support for guest signers:** With OpenSign™, your documents are fully secure even when being signed by guest users. Guest signers can only sign the document after entering a unique code sent to their email address.
|
|
||||||
- **"Expiring Docs" & "Rejection":** You can set documents to expire after certain number of days after which nobody will be able to sign. Not just this, OpenSign™ also allows signers to reject signing a document.
|
|
||||||
- **Beautiful email templates:** All document signing invitations, completion notifications & reminders are formatted using great looking email templates.
|
|
||||||
- **PDF Template Creation:** OpenSign™ allows you to create and store PDF document templates for repeated use thereby saving you a lot of time & collect e-signatures seamlessly.
|
|
||||||
- **OpenSign™ Drive:** It is a centralised secure vault for your digital documents that makes storing, signing, organizing, sharing & achieving your docs a breeze.
|
|
||||||
- **Audit Trails & completion certificate:** Being a security focused solution, OpenSign™ makes it a top priority to save detailed logs for tracking document activities along with time-stamps, IP addresses, email IDs & phone numbers. A completion certificate is generated as soon as document is completed which contains all the document related logs for added safety.
|
|
||||||
- **API Support:** OpenSign™ API allows seamless integration into existing systems and software. You can generate an API key from the app and refer the [docs](https://docs.opensignlabs.com) to start integrating it in your existing applications.
|
|
||||||
- **Integrations:** Seamless integrations with various Cloud storage systems, CRMs & enterprise platforms is available. We also have a Zapier integration that allows you to integrate it with virtually any application.
|
|
||||||
|
|
||||||
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/b37ff443-7099-4273-9aeb-21c46d7154cf height='200'>
|
|
||||||
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/86db91b7-6c2f-4885-a33c-58f4fd35ec89 height='200'>
|
|
||||||
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/56835efd-c40e-42de-a206-20202c293876 height='200'>
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Installation
|
|
||||||
|
|
||||||
Please refer to the [Installation Guide](INSTALLATION.md) for detailed instructions on how to install OpenSign on your system.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Usage
|
|
||||||
|
|
||||||
For comprehensive guidelines on how to use OpenSign™, please consult our [User Manual](USAGE.md).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Contribution Guidelines
|
|
||||||
|
|
||||||
We welcome contributions from the open-source community. For more information on how to contribute, please read our [Contribution Guidelines](CONTRIBUTING.md).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### License
|
|
||||||
|
|
||||||
OpenSign is licensed under the AGPL License. For more details, see the [LICENSE](LICENSE) file.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Acknowledgments
|
|
||||||
|
|
||||||
We would like to thank all our contributors and users for their support and feedback. Special thanks to [OpenSignLabs](https://github.com/OpenSignLabs) for spearheading this initiative.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
||||||
<!-- prettier-ignore-start -->
|
|
||||||
<!-- markdownlint-disable -->
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://aleksandarjakovljevic.com/"><img src="https://avatars.githubusercontent.com/u/2115393?v=4?s=100" width="100px;" alt="Aleksandar Jakovljevic"/><br /><sub><b>Aleksandar Jakovljevic</b></sub></a><br /><a href="#code-ajakov" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BuilderPrid"><img src="https://avatars.githubusercontent.com/u/106882895?v=4?s=100" width="100px;" alt="Priyanshu Dwivedi"/><br /><sub><b>Priyanshu Dwivedi</b></sub></a><br /><a href="#code-BuilderPrid" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Tashuuuu"><img src="https://avatars.githubusercontent.com/u/85075827?v=4?s=100" width="100px;" alt="Akriti Sengar"/><br /><sub><b>Akriti Sengar</b></sub></a><br /><a href="#code-Tashuuuu" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/parthrc"><img src="https://avatars.githubusercontent.com/u/101104958?v=4?s=100" width="100px;" alt="Parth Chawande"/><br /><sub><b>Parth Chawande</b></sub></a><br /><a href="#code-parthrc" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Rishabh-git10"><img src="https://avatars.githubusercontent.com/u/107680241?v=4?s=100" width="100px;" alt="Rishabh Dewangan"/><br /><sub><b>Rishabh Dewangan</b></sub></a><br /><a href="#code-Rishabh-git10" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LemonDrop847"><img src="https://avatars.githubusercontent.com/u/106615670?v=4?s=100" width="100px;" alt="Nitin Mishra"/><br /><sub><b>Nitin Mishra</b></sub></a><br /><a href="#code-LemonDrop847" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://jobinselvanose.com"><img src="https://avatars.githubusercontent.com/u/63976083?v=4?s=100" width="100px;" alt="Jobin Selvanose"/><br /><sub><b>Jobin Selvanose</b></sub></a><br /><a href="#doc-Jobin-S" title="Documentation">📖</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/HansF"><img src="https://avatars.githubusercontent.com/u/1503?v=4?s=100" width="100px;" alt="Hans Fraiponts"/><br /><sub><b>Hans Fraiponts</b></sub></a><br /><a href="#doc-HansF" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://linktr.ee/monilprajapati"><img src="https://avatars.githubusercontent.com/u/99136041?v=4?s=100" width="100px;" alt="Monil Prajapati"/><br /><sub><b>Monil Prajapati</b></sub></a><br /><a href="#code-Monilprajapati" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://emm-dev0.github.io/portfolio/"><img src="https://avatars.githubusercontent.com/u/97445413?v=4?s=100" width="100px;" alt="Edogbanya Emmanuel"/><br /><sub><b>Edogbanya Emmanuel</b></sub></a><br /><a href="#bug-Emm-dev0" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pranav514"><img src="https://avatars.githubusercontent.com/u/76992202?v=4?s=100" width="100px;" alt="pranav514"/><br /><sub><b>pranav514</b></sub></a><br /><a href="#code-pranav514" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/arianxq"><img src="https://avatars.githubusercontent.com/u/122199576?v=4?s=100" width="100px;" alt="Aria"/><br /><sub><b>Aria</b></sub></a><br /><a href="#code-arianxq" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SoumyadiptoPal"><img src="https://avatars.githubusercontent.com/u/119007659?v=4?s=100" width="100px;" alt="Soumyadipto Pal"/><br /><sub><b>Soumyadipto Pal</b></sub></a><br /><a href="#code-SoumyadiptoPal" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AndreyCurious"><img src="https://avatars.githubusercontent.com/u/105622604?v=4?s=100" width="100px;" alt="Andrey Didenko"/><br /><sub><b>Andrey Didenko</b></sub></a><br /><a href="#code-AndreyCurious" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/VishakhaSainani"><img src="https://avatars.githubusercontent.com/u/113436770?v=4?s=100" width="100px;" alt="VishakhaSainani"/><br /><sub><b>VishakhaSainani</b></sub></a><br /><a href="#code-VishakhaSainani" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/andrew-opensignlabs"><img src="https://avatars.githubusercontent.com/u/148278535?v=4?s=100" width="100px;" alt="Andrew"/><br /><sub><b>Andrew</b></sub></a><br /><a href="#code-andrew-opensignlabs" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rishabjasrotia"><img src="https://avatars.githubusercontent.com/u/33950743?v=4?s=100" width="100px;" alt="Rishab"/><br /><sub><b>Rishab</b></sub></a><br /><a href="#code-rishabjasrotia" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://session.it"><img src="https://avatars.githubusercontent.com/u/327285?v=4?s=100" width="100px;" alt="Maurizio Pillitu"/><br /><sub><b>Maurizio Pillitu</b></sub></a><br /><a href="#bug-maoo" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://luisparra.dev"><img src="https://avatars.githubusercontent.com/u/16653744?v=4?s=100" width="100px;" alt="Luis Parra"/><br /><sub><b>Luis Parra</b></sub></a><br /><a href="#a11y-lsprr" title="Accessibility">️️️️♿️</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Govinda04"><img src="https://avatars.githubusercontent.com/u/50038172?v=4?s=100" width="100px;" alt="Govinda Kocharekar"/><br /><sub><b>Govinda Kocharekar</b></sub></a><br /><a href="#code-Govinda04" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://bilal.cc"><img src="https://avatars.githubusercontent.com/u/55330484?v=4?s=100" width="100px;" alt="Bilal Ahmad Bhat"/><br /><sub><b>Bilal Ahmad Bhat</b></sub></a><br /><a href="#code-crediblebilal" title="Code">💻</a></td>
|
|
||||||
</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>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<!-- markdownlint-restore -->
|
|
||||||
<!-- prettier-ignore-end -->
|
|
||||||
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
||||||
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
The community is working hard to put together a great usage guide.
|
|
||||||
You will soon see one of the best usage guides here.
|
|
||||||
|
|
||||||
Till then you can view the quick promo video by clicking the link below -
|
|
||||||
|
|
||||||
[<img src="https://i.ytimg.com/vi/szYaBZhXZNo/maxresdefault.jpg" width="50%">](https://www.youtube.com/watch?v=szYaBZhXZNo "OpenSign promo")
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
[tool.commitizen]
|
|
||||||
version = "0.1.0" # This should be your current semver version
|
|
||||||
version_files = [
|
|
||||||
"package.json:\"version\":",
|
|
||||||
"package-lock.json:\"version\":",
|
|
||||||
]
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
node_modules
|
|
||||||
npm-debug.log
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"es2021": true
|
|
||||||
},
|
|
||||||
"extends": [
|
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:react/recommended",
|
|
||||||
"plugin:react-hooks/recommended"
|
|
||||||
],
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"jsx": true
|
|
||||||
},
|
|
||||||
"ecmaVersion": "latest",
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"plugins": ["react"],
|
|
||||||
"rules": {
|
|
||||||
"react/prop-types": 0,
|
|
||||||
"no-unused-vars": 1
|
|
||||||
},
|
|
||||||
"ignorePatterns": ["**/build/**", "**/*.config.js"],
|
|
||||||
"settings": {
|
|
||||||
"react": {
|
|
||||||
"version": "detect"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
/mfbuild
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.env
|
|
||||||
.DS_Store
|
|
||||||
.env.local
|
|
||||||
.env.development.local
|
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
npx eslint '**/*.{js,jsx}'
|
|
||||||
npx pretty-quick --staged '**/*.{js,jsx}'
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
node_modules/
|
|
||||||
public/
|
|
||||||
build/
|
|
||||||
package.json
|
|
||||||
package-lock.json
|
|
||||||
dist/
|
|
||||||
docs/
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"bracketSpacing": true,
|
|
||||||
"semi": true,
|
|
||||||
"trailingComma": "none",
|
|
||||||
"printWidth": 80,
|
|
||||||
"tabWidth": 2
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# Use an official Node runtime as the base image
|
|
||||||
FROM node:18
|
|
||||||
|
|
||||||
# Set the working directory inside the container
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
|
|
||||||
# Copy package.json and package-lock.json first to leverage Docker cache
|
|
||||||
COPY ./package*.json ./
|
|
||||||
|
|
||||||
# Install application dependencies
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
# Copy the current directory contents into the container
|
|
||||||
COPY ./ .
|
|
||||||
COPY ./.husky .
|
|
||||||
|
|
||||||
# Make port 3000 available to the world outside this container
|
|
||||||
EXPOSE 3000
|
|
||||||
|
|
||||||
# Define environment variables if needed
|
|
||||||
# ENV NODE_ENV production
|
|
||||||
|
|
||||||
# Run the application
|
|
||||||
ENTRYPOINT npm run start
|
|
||||||
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# Use an official Node runtime as the base image
|
|
||||||
FROM node:18
|
|
||||||
|
|
||||||
# Set the working directory inside the container
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
|
|
||||||
# Copy package.json and package-lock.json first to leverage Docker cache
|
|
||||||
COPY apps/OpenSign/package*.json ./
|
|
||||||
|
|
||||||
# Install application dependencies
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
# Copy the current directory contents into the container
|
|
||||||
COPY apps/OpenSign/ .
|
|
||||||
COPY apps/OpenSign/.husky .
|
|
||||||
|
|
||||||
# build
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
# Make port 3000 available to the world outside this container
|
|
||||||
EXPOSE 3000
|
|
||||||
|
|
||||||
# Define environment variables if needed
|
|
||||||
# ENV NODE_ENV production
|
|
||||||
|
|
||||||
# Run the application
|
|
||||||
CMD ["npm", "start"]
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# Open Sign
|
|
||||||
|
|
||||||
Open source is true platform to sign pdf with digital signature
|
|
||||||
|
|
||||||
## Available Scripts
|
|
||||||
|
|
||||||
In the project directory, you can run:
|
|
||||||
|
|
||||||
### `npm start`
|
|
||||||
|
|
||||||
Runs the app in the development mode.\
|
|
||||||
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
|
|
||||||
|
|
||||||
The page will reload when you make changes.\
|
|
||||||
You may also see any lint errors in the console.
|
|
||||||
|
|
||||||
### `npm run build`
|
|
||||||
|
|
||||||
Builds the app for production to the `build` folder.\
|
|
||||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
|
||||||
|
|
||||||
The build is minified and the filenames include the hashes.\
|
|
||||||
Your app is ready to be deployed!
|
|
||||||
|
|
||||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "open_sign",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"private": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@formkit/auto-animate": "^0.8.1",
|
|
||||||
"@radix-ui/themes": "^2.0.3",
|
|
||||||
"@react-pdf/renderer": "^3.4.0",
|
|
||||||
"@reduxjs/toolkit": "^2.2.1",
|
|
||||||
"axios": "^1.6.8",
|
|
||||||
"file-saver": "^2.0.5",
|
|
||||||
"jwt-decode": "^4.0.0",
|
|
||||||
"moment": "^2.30.1",
|
|
||||||
"parse": "^4.3.1",
|
|
||||||
"pdf-lib": "^1.17.1",
|
|
||||||
"print-js": "^1.6.0",
|
|
||||||
"radix-ui": "^1.0.1",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-bootstrap": "^2.10.2",
|
|
||||||
"react-datepicker": "^6.4.0",
|
|
||||||
"react-dnd": "^16.0.1",
|
|
||||||
"react-dnd-html5-backend": "^16.0.1",
|
|
||||||
"react-dnd-multi-backend": "^8.0.3",
|
|
||||||
"react-dnd-touch-backend": "^16.0.1",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"react-gtm-module": "^2.0.11",
|
|
||||||
"react-helmet": "^6.1.0",
|
|
||||||
"react-konva": "^18.2.10",
|
|
||||||
"react-modal": "^3.16.1",
|
|
||||||
"react-pdf": "^7.7.1",
|
|
||||||
"react-redux": "^9.1.0",
|
|
||||||
"react-rnd": "^10.4.1",
|
|
||||||
"react-router-dom": "^6.22.3",
|
|
||||||
"react-scripts": "5.0.1",
|
|
||||||
"react-scrollbars-custom": "^4.1.1",
|
|
||||||
"react-select": "^5.8.0",
|
|
||||||
"react-signature-canvas": "^1.0.6",
|
|
||||||
"react-tooltip": "^5.26.3",
|
|
||||||
"reactour": "^1.19.2",
|
|
||||||
"redux": "^5.0.1",
|
|
||||||
"redux-thunk": "^3.1.0",
|
|
||||||
"regex-parser": "^2.3.0",
|
|
||||||
"serve": "^14.2.1",
|
|
||||||
"styled-components": "^4.4.1",
|
|
||||||
"web-vitals": "^2.1.4"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"start": "serve -s build",
|
|
||||||
"start-dev": "react-scripts start",
|
|
||||||
"version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
|
|
||||||
"version-win": "powershell -Command \"Invoke-RestMethod -Uri 'https://api.github.com/repos/opensignlabs/opensign/releases/latest' | Select-Object -ExpandProperty tag_name | Out-File -FilePath ./public/version.txt\"",
|
|
||||||
"build": "npm run version && react-scripts build",
|
|
||||||
"build-win": "npm run version-win && react-scripts build",
|
|
||||||
"test": "react-scripts test",
|
|
||||||
"eject": "react-scripts eject",
|
|
||||||
"release": "standard-version",
|
|
||||||
"commit": "cz"
|
|
||||||
},
|
|
||||||
"eslintConfig": {
|
|
||||||
"extends": [
|
|
||||||
"react-app",
|
|
||||||
"react-app/jest"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"browserslist": {
|
|
||||||
"production": [
|
|
||||||
">0.2%",
|
|
||||||
"not dead",
|
|
||||||
"not op_mini all"
|
|
||||||
],
|
|
||||||
"development": [
|
|
||||||
"last 1 chrome version",
|
|
||||||
"last 1 firefox version",
|
|
||||||
"last 1 safari version"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"config": {
|
|
||||||
"commitizen": {
|
|
||||||
"path": "./node_modules/cz-conventional-changelog"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/runtime-corejs2": "^7.24.1",
|
|
||||||
"autoprefixer": "^10.4.18",
|
|
||||||
"commitizen": "^4.3.0",
|
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
|
||||||
"eslint-plugin-react": "^7.34.1",
|
|
||||||
"lint-staged": "^15.2.2",
|
|
||||||
"postcss": "^8.4.37",
|
|
||||||
"prettier": "^2.8.8",
|
|
||||||
"pretty-quick": "^3.3.1",
|
|
||||||
"tailwindcss": "^3.4.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
plugins: {
|
|
||||||
tailwindcss: {},
|
|
||||||
autoprefixer: {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,53 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
|
||||||
<!-- <link rel="icon" type="image/png"
|
|
||||||
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC"
|
|
||||||
sizes="40x40" /> -->
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<meta name="theme-color" content="#000000" />
|
|
||||||
<meta name="description" content="The fastest way to sign PDFs & request signatures from others" />
|
|
||||||
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> -->
|
|
||||||
<!--
|
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
|
||||||
-->
|
|
||||||
<link rel="manifest" href="%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
|
|
||||||
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"
|
|
||||||
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" />
|
|
||||||
|
|
||||||
<title>OpenSign™</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
||||||
<div id="root"></div>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
This HTML file is a template.
|
|
||||||
If you open it directly in the browser, you will see an empty page.
|
|
||||||
|
|
||||||
You can add webfonts, meta tags, or analytics to this file.
|
|
||||||
The build step will place the bundled scripts into the <body> tag.
|
|
||||||
|
|
||||||
To begin the development, run `npm start` or `yarn start`.
|
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
|
||||||
-->
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 11 KiB |
@@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"short_name": "Open sign",
|
|
||||||
"name": "Open sign",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "favicon.ico",
|
|
||||||
"sizes": "64x64 32x32 24x24 16x16",
|
|
||||||
"type": "image/x-icon"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "logo192.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "192x192"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "logo512.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "512x512"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"start_url": ".",
|
|
||||||
"display": "standalone",
|
|
||||||
"theme_color": "#000000",
|
|
||||||
"background_color": "#ffffff"
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# https://www.robotstxt.org/robotstxt.html
|
|
||||||
User-agent: *
|
|
||||||
Disallow:
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
import React, { useState, useEffect, lazy } from "react";
|
|
||||||
import { Routes, Route, BrowserRouter } from "react-router-dom";
|
|
||||||
import { pdfjs } from "react-pdf";
|
|
||||||
import Login from "./pages/Login";
|
|
||||||
import Form from "./pages/Form";
|
|
||||||
import Report from "./pages/Report";
|
|
||||||
import Dashboard from "./pages/Dashboard";
|
|
||||||
import HomeLayout from "./layout/HomeLayout";
|
|
||||||
import PageNotFound from "./pages/PageNotFound";
|
|
||||||
import ValidateRoute from "./primitives/ValidateRoute";
|
|
||||||
import Validate from "./primitives/Validate";
|
|
||||||
import TemplatePlaceholder from "./pages/TemplatePlaceholder";
|
|
||||||
import SignYourSelf from "./pages/SignyourselfPdf";
|
|
||||||
import DraftDocument from "./components/pdf/DraftDocument";
|
|
||||||
import PlaceHolderSign from "./pages/PlaceHolderSign";
|
|
||||||
import PdfRequestFiles from "./pages/PdfRequestFiles";
|
|
||||||
import LazyPage from "./primitives/LazyPage";
|
|
||||||
import { isEnableSubscription } from "./constant/const";
|
|
||||||
const DebugPdf = lazy(() => import("./pages/DebugPdf"));
|
|
||||||
const ForgetPassword = lazy(() => import("./pages/ForgetPassword"));
|
|
||||||
const GuestLogin = lazy(() => import("./pages/GuestLogin"));
|
|
||||||
const Pgsignup = lazy(() => import("./pages/Pgsignup"));
|
|
||||||
const Subscriptions = lazy(() => import("./pages/PlanSubscriptions"));
|
|
||||||
const ChangePassword = lazy(() => import("./pages/ChangePassword"));
|
|
||||||
const UserProfile = lazy(() => import("./pages/UserProfile"));
|
|
||||||
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 Webhook = lazy(() => import("./pages/Webhook"));
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
|
|
||||||
|
|
||||||
const Loader = () => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: "100vh",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
function App() {
|
|
||||||
const [isloading, setIsLoading] = useState(true);
|
|
||||||
useEffect(() => {
|
|
||||||
handleCredentials();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleCredentials = () => {
|
|
||||||
const appId = process.env.REACT_APP_APPID
|
|
||||||
? process.env.REACT_APP_APPID
|
|
||||||
: "opensign";
|
|
||||||
const baseurl = process.env.REACT_APP_SERVERURL
|
|
||||||
? process.env.REACT_APP_SERVERURL
|
|
||||||
: window.location.origin + "/api/app";
|
|
||||||
const appName = "contracts";
|
|
||||||
try {
|
|
||||||
localStorage.setItem("baseUrl", `${baseurl}/`);
|
|
||||||
localStorage.setItem("parseAppId", appId);
|
|
||||||
localStorage.setItem("domain", appName);
|
|
||||||
setIsLoading(false);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("err ", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="bg-[#eef1f5]">
|
|
||||||
{isloading ? (
|
|
||||||
<Loader />
|
|
||||||
) : (
|
|
||||||
<BrowserRouter>
|
|
||||||
<Routes>
|
|
||||||
<Route element={<ValidateRoute />}>
|
|
||||||
<Route exact path="/" element={<Login />} />
|
|
||||||
<Route path="/signup" element={<LazyPage Page={Signup} />} />
|
|
||||||
</Route>
|
|
||||||
<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
|
|
||||||
path="/loadmf/signmicroapp/login/:id/:userMail/:contactBookId/:serverUrl"
|
|
||||||
element={<LazyPage Page={GuestLogin} />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="/login/:id/:userMail/:contactBookId/:serverUrl"
|
|
||||||
element={<LazyPage Page={GuestLogin} />}
|
|
||||||
/>
|
|
||||||
<Route path="/debugpdf" element={<LazyPage Page={DebugPdf} />} />
|
|
||||||
<Route
|
|
||||||
path="/forgetpassword"
|
|
||||||
element={<LazyPage Page={ForgetPassword} />}
|
|
||||||
/>
|
|
||||||
{isEnableSubscription && (
|
|
||||||
<>
|
|
||||||
<Route
|
|
||||||
path="/pgsignup"
|
|
||||||
element={<LazyPage Page={Pgsignup} />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="/subscription"
|
|
||||||
element={<LazyPage Page={Subscriptions} />}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<Route element={<HomeLayout />}>
|
|
||||||
<Route
|
|
||||||
path="/changepassword"
|
|
||||||
element={<LazyPage Page={ChangePassword} />}
|
|
||||||
/>
|
|
||||||
<Route path="/form/:id" element={<Form />} />
|
|
||||||
<Route path="/report/:id" element={<Report />} />
|
|
||||||
<Route path="/dashboard/:id" element={<Dashboard />} />
|
|
||||||
<Route
|
|
||||||
path="/profile"
|
|
||||||
element={<LazyPage Page={UserProfile} />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
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="*" element={<PageNotFound />} />
|
|
||||||
</Routes>
|
|
||||||
</BrowserRouter>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App;
|
|
||||||
|
Before Width: | Height: | Size: 805 B |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 61 KiB |
@@ -1,184 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="691.365" height="586.346" viewBox="0 0 691.365 586.346">
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="linear-gradient" x1="0.5" y1="1" x2="0.5" y2="-0.001" gradientUnits="objectBoundingBox">
|
|
||||||
<stop offset="0" stop-color="gray" stop-opacity="0.251"/>
|
|
||||||
<stop offset="0.54" stop-color="gray" stop-opacity="0.122"/>
|
|
||||||
<stop offset="1" stop-color="gray" stop-opacity="0.102"/>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<g id="Group_644" data-name="Group 644" transform="translate(-588.635 -80)">
|
|
||||||
<g id="Group_642" data-name="Group 642" transform="translate(22538.635 6999)">
|
|
||||||
<path id="Path_472" data-name="Path 472" d="M482.764,637.675c51.612-29.22,67.336-29.693,124.954-17.169,81.646,17.758,88.43-49.93,108.306-186.933,33.946-233.98-108.306-295.737-108.306-295.737s-94.6-8.1-150.536-38.963C377.726,55.027,286.9,49.443,207.046,86.542c-51.069,23.7-93.125,56.714-100.31,102.034-20.09,126.746,12.9,196.58-48.819,237.954S48.944,581.5,96.263,577.564c34.968-2.906,80.842,52.415,130.687,60.111,17.382,2.684,88.7-13.043,99.578,0C341.327,655.4,464.763,647.87,482.764,637.675Z" transform="translate(-21979.895 -6980.982)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<g id="Group_641" data-name="Group 641" transform="translate(-21545.08 -6816.88)">
|
|
||||||
<rect id="Rectangle_263" data-name="Rectangle 263" width="217.867" height="15.073" transform="translate(0 39.052)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_264" data-name="Rectangle 264" width="217.867" height="15.073" transform="translate(0 104.137)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_265" data-name="Rectangle 265" width="217.867" height="15.073" transform="translate(0 171.964)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_266" data-name="Rectangle 266" width="13.702" height="39.052" transform="translate(19.183)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_267" data-name="Rectangle 267" width="13.702" height="2.74" transform="translate(19.183 6.166)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_268" data-name="Rectangle 268" width="13.702" height="2.74" transform="translate(19.183 27.405)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_269" data-name="Rectangle 269" width="13.702" height="39.052" transform="translate(39.737)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_270" data-name="Rectangle 270" width="13.702" height="2.74" transform="translate(39.737 6.166)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_271" data-name="Rectangle 271" width="13.702" height="2.74" transform="translate(39.737 27.405)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_272" data-name="Rectangle 272" width="13.702" height="39.052" transform="translate(60.29)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_273" data-name="Rectangle 273" width="13.702" height="2.74" transform="translate(60.29 6.166)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_274" data-name="Rectangle 274" width="13.702" height="2.74" transform="translate(60.29 27.405)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_275" data-name="Rectangle 275" width="13.702" height="39.052" transform="translate(80.844)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_276" data-name="Rectangle 276" width="13.702" height="2.74" transform="translate(80.844 6.166)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_277" data-name="Rectangle 277" width="13.702" height="2.74" transform="translate(80.844 27.405)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_278" data-name="Rectangle 278" width="13.702" height="39.052" transform="translate(101.397)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_279" data-name="Rectangle 279" width="13.702" height="2.74" transform="translate(101.397 6.166)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_280" data-name="Rectangle 280" width="13.702" height="2.74" transform="translate(101.397 27.405)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_281" data-name="Rectangle 281" width="13.702" height="39.052" transform="translate(121.95)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_282" data-name="Rectangle 282" width="13.702" height="2.74" transform="translate(121.95 6.166)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_283" data-name="Rectangle 283" width="13.702" height="2.74" transform="translate(121.95 27.405)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_284" data-name="Rectangle 284" width="13.702" height="39.052" transform="translate(142.504)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_285" data-name="Rectangle 285" width="13.702" height="2.74" transform="translate(142.504 6.166)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_286" data-name="Rectangle 286" width="13.702" height="2.74" transform="translate(142.504 27.405)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_287" data-name="Rectangle 287" width="13.702" height="39.052" transform="matrix(0.894, -0.448, 0.448, 0.894, 135.847, 138.025)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_288" data-name="Rectangle 288" width="13.702" height="2.74" transform="matrix(0.894, -0.448, 0.448, 0.894, 138.614, 143.541)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_289" data-name="Rectangle 289" width="13.702" height="2.74" transform="matrix(0.894, -0.448, 0.448, 0.894, 148.128, 162.529)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_290" data-name="Rectangle 290" width="13.702" height="39.052" transform="translate(19.183 65.771)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_291" data-name="Rectangle 291" width="13.702" height="2.74" transform="translate(19.183 71.937)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_292" data-name="Rectangle 292" width="13.702" height="2.74" transform="translate(19.183 93.176)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_293" data-name="Rectangle 293" width="13.702" height="39.052" transform="translate(39.737 65.771)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_294" data-name="Rectangle 294" width="13.702" height="2.74" transform="translate(39.737 71.937)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_295" data-name="Rectangle 295" width="13.702" height="2.74" transform="translate(39.737 93.176)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_296" data-name="Rectangle 296" width="13.702" height="39.052" transform="translate(60.29 65.771)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_297" data-name="Rectangle 297" width="13.702" height="2.74" transform="translate(60.29 71.937)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_298" data-name="Rectangle 298" width="13.702" height="2.74" transform="translate(60.29 93.176)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_299" data-name="Rectangle 299" width="13.702" height="39.052" transform="translate(145.93 65.771)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_300" data-name="Rectangle 300" width="13.702" height="2.74" transform="translate(145.93 71.937)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_301" data-name="Rectangle 301" width="13.702" height="2.74" transform="translate(145.93 93.176)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_302" data-name="Rectangle 302" width="13.702" height="39.052" transform="translate(166.483 65.771)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_303" data-name="Rectangle 303" width="13.702" height="2.74" transform="translate(166.483 71.937)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_304" data-name="Rectangle 304" width="13.702" height="2.74" transform="translate(166.483 93.176)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_305" data-name="Rectangle 305" width="13.702" height="39.052" transform="translate(187.036 65.771)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_306" data-name="Rectangle 306" width="13.702" height="2.74" transform="translate(187.036 71.937)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_307" data-name="Rectangle 307" width="13.702" height="2.74" transform="translate(187.036 93.176)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_308" data-name="Rectangle 308" width="13.702" height="39.052" transform="translate(19.183 132.912)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_309" data-name="Rectangle 309" width="13.702" height="2.74" transform="translate(19.183 139.078)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_310" data-name="Rectangle 310" width="13.702" height="2.74" transform="translate(19.183 160.317)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_311" data-name="Rectangle 311" width="13.702" height="39.052" transform="translate(39.737 132.912)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_312" data-name="Rectangle 312" width="13.702" height="2.74" transform="translate(39.737 139.078)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_313" data-name="Rectangle 313" width="13.702" height="2.74" transform="translate(39.737 160.317)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_314" data-name="Rectangle 314" width="13.702" height="39.052" transform="translate(60.29 132.912)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_315" data-name="Rectangle 315" width="13.702" height="2.74" transform="translate(60.29 139.078)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_316" data-name="Rectangle 316" width="13.702" height="2.74" transform="translate(60.29 160.317)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_317" data-name="Rectangle 317" width="13.702" height="39.052" transform="translate(80.844 132.912)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_318" data-name="Rectangle 318" width="13.702" height="2.74" transform="translate(80.844 139.078)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_319" data-name="Rectangle 319" width="13.702" height="2.74" transform="translate(80.844 160.317)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_320" data-name="Rectangle 320" width="13.702" height="39.052" transform="translate(101.397 132.912)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_321" data-name="Rectangle 321" width="13.702" height="2.74" transform="translate(101.397 139.078)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_322" data-name="Rectangle 322" width="13.702" height="2.74" transform="translate(101.397 160.317)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_323" data-name="Rectangle 323" width="13.702" height="39.052" transform="translate(121.95 132.912)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_324" data-name="Rectangle 324" width="13.702" height="2.74" transform="translate(121.95 139.078)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_325" data-name="Rectangle 325" width="13.702" height="2.74" transform="translate(121.95 160.317)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<path id="Path_473" data-name="Path 473" d="M797.862,159.09v35.571h-13.7V156.48Q791.039,157.693,797.862,159.09Z" transform="translate(-621.103 -155.61)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_326" data-name="Rectangle 326" width="13.702" height="2.74" transform="translate(163.057 6.166)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_327" data-name="Rectangle 327" width="13.702" height="2.74" transform="translate(163.057 27.405)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<path id="Path_474" data-name="Path 474" d="M827.862,165.719v30.83h-13.7V162.43c1.781.391,3.556.8,5.33,1.22Q823.7,164.636,827.862,165.719Z" transform="translate(-630.549 -157.483)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<path id="Path_475" data-name="Path 475" d="M827.862,166.285v.685h-13.7v-2.74h5.33Q823.7,165.2,827.862,166.285Z" transform="translate(-630.549 -158.05)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_328" data-name="Rectangle 328" width="13.702" height="2.74" transform="translate(183.611 27.405)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<path id="Path_476" data-name="Path 476" d="M691.358,287.276s-4.152-1.411-6.166,2.254a6.68,6.68,0,0,0,.089,6.426,9.4,9.4,0,0,0,9.146,5.179c4.35-.233,5.8-3.549,6.166-6.639a6.851,6.851,0,0,0-9.057-7.3Z" transform="translate(-589.693 -196.649)" fill="#00ddf1"/>
|
|
||||||
<path id="Path_477" data-name="Path 477" d="M686.2,296.239a6.68,6.68,0,0,1-.089-6.426c2-3.659,6.166-2.254,6.166-2.254l.212-.075a6.762,6.762,0,0,1,4.885.11,6.762,6.762,0,0,0-5.762-.548l-.212.075s-4.152-1.411-6.166,2.254a6.68,6.68,0,0,0,.089,6.426,9.982,9.982,0,0,0,4.7,4.446A10.277,10.277,0,0,1,686.2,296.239Z" transform="translate(-589.706 -196.595)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<path id="Path_478" data-name="Path 478" d="M691.42,290.06s1.542,1.213,5.282,0" transform="translate(-591.9 -197.672)" fill="#00ddf1" opacity="0.2"/>
|
|
||||||
<path id="Path_479" data-name="Path 479" d="M690.93,277.21s2.638,7.153,2.418,9.023l2.09-.219s-3.521-6.269-2.638-8.8Z" transform="translate(-591.746 -193.626)" fill="#00ddf1"/>
|
|
||||||
<path id="Path_480" data-name="Path 480" d="M690.93,277.21s2.638,7.153,2.418,9.023l2.09-.219s-3.521-6.269-2.638-8.8Z" transform="translate(-591.746 -193.626)" fill="#00ddf1" opacity="0.2"/>
|
|
||||||
<path id="Path_481" data-name="Path 481" d="M702.92,277.6s-4.159-2.124-6.015-.37-2.144,6.241-2.144,6.241S701.536,284.391,702.92,277.6Z" transform="translate(-592.952 -193.414)" fill="#00ddf1"/>
|
|
||||||
<path id="Path_482" data-name="Path 482" d="M702.92,277.6s-4.159-2.124-6.015-.37-2.144,6.241-2.144,6.241S701.536,284.391,702.92,277.6Z" transform="translate(-592.952 -193.414)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<path id="Path_483" data-name="Path 483" d="M694.75,283.958s1.089-5.207,8.16-5.878" transform="translate(-592.949 -193.9)" fill="#00ddf1"/>
|
|
||||||
<path id="Path_484" data-name="Path 484" d="M819.358,386.276s-4.152-1.411-6.166,2.254a6.68,6.68,0,0,0,.089,6.426,9.4,9.4,0,0,0,9.146,5.18c4.35-.233,5.8-3.549,6.166-6.639a6.851,6.851,0,0,0-9.057-7.3Z" transform="translate(-629.999 -227.823)" fill="#00ddf1"/>
|
|
||||||
<path id="Path_485" data-name="Path 485" d="M814.2,395.239a6.68,6.68,0,0,1-.089-6.426c2-3.659,6.166-2.254,6.166-2.254l.212-.075a6.762,6.762,0,0,1,4.885.11,6.762,6.762,0,0,0-5.762-.548l-.212.075s-4.152-1.411-6.166,2.254a6.68,6.68,0,0,0,.089,6.426,9.982,9.982,0,0,0,4.7,4.446A10.276,10.276,0,0,1,814.2,395.239Z" transform="translate(-630.011 -227.769)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<path id="Path_486" data-name="Path 486" d="M819.42,389.06s1.542,1.213,5.282,0" transform="translate(-632.206 -228.846)" fill="#00ddf1" opacity="0.2"/>
|
|
||||||
<path id="Path_487" data-name="Path 487" d="M818.93,376.21s2.638,7.153,2.419,9.023l2.09-.219s-3.522-6.269-2.638-8.8Z" transform="translate(-632.051 -224.799)" fill="#00ddf1"/>
|
|
||||||
<path id="Path_488" data-name="Path 488" d="M818.93,376.21s2.638,7.153,2.419,9.023l2.09-.219s-3.522-6.269-2.638-8.8Z" transform="translate(-632.051 -224.799)" fill="#00ddf1" opacity="0.2"/>
|
|
||||||
<path id="Path_489" data-name="Path 489" d="M830.92,376.6s-4.159-2.124-6.015-.37-2.144,6.241-2.144,6.241S829.536,383.391,830.92,376.6Z" transform="translate(-633.257 -224.588)" fill="#00ddf1"/>
|
|
||||||
<path id="Path_490" data-name="Path 490" d="M830.92,376.6s-4.159-2.124-6.015-.37-2.144,6.241-2.144,6.241S829.536,383.391,830.92,376.6Z" transform="translate(-633.257 -224.588)" fill="#00ddf1" opacity="0.1"/>
|
|
||||||
<path id="Path_491" data-name="Path 491" d="M822.75,382.958s1.089-5.207,8.16-5.878" transform="translate(-633.254 -225.073)" fill="#00ddf1"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g id="Group_643" data-name="Group 643" transform="translate(7 -63)">
|
|
||||||
<g id="Group_639" data-name="Group 639" transform="translate(21233 8372)">
|
|
||||||
<ellipse id="Ellipse_73" data-name="Ellipse 73" cx="49.851" cy="8.007" rx="49.851" ry="8.007" transform="translate(-20118.443 -7772.555)" fill="#00abf6" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_182" data-name="Rectangle 182" width="3.208" height="72.224" transform="translate(-20070.199 -7917.934)" fill="#535461"/>
|
|
||||||
<path id="Path_268" data-name="Path 268" d="M1025.906,587.251l-.2,3.254-.287,4.6-.118,1.913-.281,4.6-.123,1.913-.286,4.6-3.233,52.22a8.851,8.851,0,0,1-8.83,8.268H995.731a8.841,8.841,0,0,1-8.82-8.3l-3.244-52.225-.281-4.6-.117-1.913-.292-4.6-.117-1.913-.281-4.6-.2-3.254a4.6,4.6,0,0,1,4.574-4.865h34.391a4.6,4.6,0,0,1,4.569,4.9Z" transform="translate(-21072.734 -8433.181)" fill="#565661"/>
|
|
||||||
<path id="Path_269" data-name="Path 269" d="M990.949,517.36l-.287,4.589H948.106l-.286-4.589Z" transform="translate(-21037.977 -8360.036)" fill="#9d9cb5"/>
|
|
||||||
<path id="Path_270" data-name="Path 270" d="M990.93,530.08l-.281,4.594H948.9l-.286-4.594Z" transform="translate(-21038.363 -8366.248)" fill="#9d9cb5"/>
|
|
||||||
<path id="Path_271" data-name="Path 271" d="M990.912,542.8l-.287,4.589H949.686L949.4,542.8Z" transform="translate(-21038.748 -8372.46)" fill="#9d9cb5"/>
|
|
||||||
<path id="Path_272" data-name="Path 272" d="M933.875,490.464c18.684,13.517,26.466,34.656,26.466,34.656s-22.511-.773-41.2-14.289-26.46-34.651-26.46-34.651S915.2,476.953,933.875,490.464Z" transform="translate(-21028.934 -8381.328)" fill="#00abf6"/>
|
|
||||||
<path id="Path_273" data-name="Path 273" d="M892.68,476.18s23.365,12.969,30.865,23.708,36.8,25.233,36.8,25.233" transform="translate(-21028.934 -8381.328)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/>
|
|
||||||
<path id="Path_274" data-name="Path 274" d="M975.393,443.457c10.171,7.352,14.407,18.863,14.407,18.863s-12.279-.425-22.424-7.776S953,435.68,953,435.68,965.227,436.1,975.393,443.457Z" transform="translate(-21058.393 -8361.549)" fill="#00abf6"/>
|
|
||||||
<path id="Path_275" data-name="Path 275" d="M953,435.68s12.719,7.06,16.8,12.9,20.03,13.737,20.03,13.737" transform="translate(-21058.393 -8361.549)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/>
|
|
||||||
<path id="Path_276" data-name="Path 276" d="M1040.3,470.483c-11.68,12.836-14.151,29.612-14.151,29.612s16.469-4.042,28.139-16.883,14.151-29.612,14.151-29.612S1051.981,457.647,1040.3,470.483Z" transform="translate(-21094.119 -8370.301)" fill="#00abf6"/>
|
|
||||||
<path id="Path_277" data-name="Path 277" d="M1068.45,453.61s-15.215,13.159-19.083,22.224S1026.15,500.1,1026.15,500.1" transform="translate(-21094.119 -8370.306)" fill="none" stroke="#535461" stroke-miterlimit="10" stroke-width="2"/>
|
|
||||||
</g>
|
|
||||||
<g id="Group_638" data-name="Group 638" transform="translate(-40 36)">
|
|
||||||
<rect id="Rectangle_254" data-name="Rectangle 254" width="12.343" height="37.459" transform="translate(741.459 392.675)" fill="#3f3d56"/>
|
|
||||||
<rect id="Rectangle_255" data-name="Rectangle 255" width="12.343" height="39.629" transform="translate(1073.647 390.726)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_418" data-name="Path 418" d="M597.889,523.665v8.446l-98.7.909-1.052.02-37.511.344-.9.013-11.4.1h-.338l-69.5.643L264.408,535.2h-.1l-29.007.273-.312.007L106.1,536.658v-9.745l30.306-18.19,60.808-.507,1.3-.007.429-.007,1.3-.019,29.2-.24,1.306-.007.416-.007,1.3-.006,9.362-.078.247-.006,23.1-.195h.188l180.214-1.52,4.411-.032h.442l3.365-.033,24.459-.2,1.3-.02,1.2-.013h.624l7.607-.058,1.507-.02,2.02-.013,6.334-.058,10.05-.084,1.3-.013,2.261-.013h.422l48.536-.416Z" transform="translate(566.82 43)" fill="#65617d"/>
|
|
||||||
<path id="Path_419" data-name="Path 419" d="M597.889,523.665v8.446l-98.7.909-1.052.02-37.511.344-.9.013-11.4.1h-.338l-69.5.643L264.408,535.2h-.1l-29.007.273-.312.007L106.1,536.658v-9.745l30.306-18.19,60.808-.507,1.3-.007.429-.007,1.3-.019,29.2-.24,1.306-.007.416-.007,1.3-.006,9.362-.078.247-.006,23.1-.195h.188l180.214-1.52,4.411-.032h.442l3.365-.033,24.459-.2,1.3-.02,1.2-.013h.624l7.607-.058,1.507-.02,2.02-.013,6.334-.058,10.05-.084,1.3-.013,2.261-.013h.422l48.536-.416Z" transform="translate(566.82 43)" opacity="0.2"/>
|
|
||||||
<path id="Path_420" data-name="Path 420" d="M358.914,656.57v15.91a3.982,3.982,0,0,1-2.274,3.6,3.9,3.9,0,0,1-1.624.39l-22.673.481a3.9,3.9,0,0,1-1.754-.37,3.976,3.976,0,0,1-2.319-3.619V656.57Z" transform="translate(437.441 -122.381)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_421" data-name="Path 421" d="M358.914,656.57v15.91a3.982,3.982,0,0,1-2.274,3.6,3.9,3.9,0,0,1-1.624.39l-22.673.481a3.9,3.9,0,0,1-1.754-.37,3.976,3.976,0,0,1-2.319-3.619V656.57Z" transform="translate(437.441 -122.381)" opacity="0.1"/>
|
|
||||||
<path id="Path_422" data-name="Path 422" d="M360.914,656.57v15.91a3.982,3.982,0,0,1-2.274,3.6,3.9,3.9,0,0,1-1.624.39l-22.673.481a3.9,3.9,0,0,1-1.754-.37,3.976,3.976,0,0,1-2.319-3.619V656.57Z" transform="translate(436.74 -122.381)" fill="#3f3d56"/>
|
|
||||||
<rect id="Rectangle_256" data-name="Rectangle 256" width="30.644" height="20.464" transform="translate(1046.362 534.189)" fill="#3f3d56"/>
|
|
||||||
<rect id="Rectangle_257" data-name="Rectangle 257" width="30.644" height="20.464" transform="translate(1046.362 534.189)" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_258" data-name="Rectangle 258" width="30.644" height="20.464" transform="translate(1045.062 534.189)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_423" data-name="Path 423" d="M223.943,265.82v3.723l-12.343-.318v-3.4Z" transform="translate(529.859 126.848)" opacity="0.1"/>
|
|
||||||
<path id="Path_424" data-name="Path 424" d="M358.741,271.246,343.909,377.789a2.794,2.794,0,0,1-2.839,2.41L222.314,377.12l-2.254-.058a2.794,2.794,0,0,1-2.7-3.164l16.651-111.533a2.794,2.794,0,0,1,2.949-2.358l119.186,8.069a2.787,2.787,0,0,1,2.6,3.17Z" transform="translate(476.307 16.556)" fill="#65617d"/>
|
|
||||||
<path id="Path_425" data-name="Path 425" d="M169.158,99.16,156.6,197.472l109.142,3.463,13.422-94.85Z" transform="translate(549.128 185.237)" fill="#00ddf1"/>
|
|
||||||
<rect id="Rectangle_259" data-name="Rectangle 259" width="132.965" height="112.605" rx="5.33" transform="translate(853.849 282.877)" fill="#65617d"/>
|
|
||||||
<rect id="Rectangle_260" data-name="Rectangle 260" width="120.836" height="93.765" transform="translate(860.125 290.458)" fill="#00ddf1"/>
|
|
||||||
<path id="Path_426" data-name="Path 426" d="M735.273,262.82v2.462l-12.343.253V262.82Z" transform="translate(350.717 127.899)" opacity="0.1"/>
|
|
||||||
<path id="Path_427" data-name="Path 427" d="M833.626,371a2,2,0,0,1-1.949,2.131l-121.615,2.514a2,2,0,0,1-2.033-1.813L697.575,265.156a2,2,0,0,1,1.9-2.189l120.693-6,1.3-.065a1.994,1.994,0,0,1,2.092,1.819Z" transform="translate(308.06 17.643)" fill="#65617d"/>
|
|
||||||
<path id="Path_428" data-name="Path 428" d="M628.93,100.238,739.157,94.82l9.31,98.748-109.356,2.6Z" transform="translate(383.65 186.757)" fill="#00ddf1"/>
|
|
||||||
<path id="Path_429" data-name="Path 429" d="M899.741,371a2,2,0,0,1-1.949,2.131L886.28,256.963l1.3-.065a2,2,0,0,1,2.092,1.819Z" transform="translate(241.945 17.643)" opacity="0.1"/>
|
|
||||||
<rect id="Rectangle_261" data-name="Rectangle 261" width="12.343" height="11.096" transform="translate(741.459 419.038)" opacity="0.1"/>
|
|
||||||
<path id="Path_431" data-name="Path 431" d="M281.574,483.65v3.229l-30.644.819V483.65Z" transform="translate(516.08 50.533)" opacity="0.1"/>
|
|
||||||
<path id="Path_432" data-name="Path 432" d="M390.8,483.886V593.158a2.6,2.6,0,0,1-2.5,2.566l-124.506,3.313h-.033a2.6,2.6,0,0,1-2.566-2.566V483.886a2.6,2.6,0,0,1,2.566-2.566H388.23A2.6,2.6,0,0,1,390.8,483.886Z" transform="translate(460.942 -60.983)" fill="#65617d"/>
|
|
||||||
<path id="Path_434" data-name="Path 434" d="M194.6,319.15H309.914v96.311L194.6,418.06Z" transform="translate(535.815 108.164)" fill="#d4dfec"/>
|
|
||||||
<rect id="Rectangle_262" data-name="Rectangle 262" width="12.343" height="11.317" transform="translate(1073.647 419.038)" opacity="0.1"/>
|
|
||||||
<path id="Path_435" data-name="Path 435" d="M709.574,483.65v4.164L678.93,487V483.65Z" transform="translate(366.132 50.533)" opacity="0.1"/>
|
|
||||||
<path id="Path_436" data-name="Path 436" d="M797.782,483.886V596.471a2.6,2.6,0,0,1-2.6,2.566h0l-124.532-3.313a2.6,2.6,0,0,1-2.5-2.566V483.886a2.6,2.6,0,0,1,2.566-2.566H795.19a2.6,2.6,0,0,1,2.592,2.566Z" transform="translate(318.365 -60.983)" fill="#65617d"/>
|
|
||||||
<path id="Path_437" data-name="Path 437" d="M866.289,483.886V596.471a2.6,2.6,0,0,1-2.6,2.566h0V481.32h0a2.6,2.6,0,0,1,2.6,2.566Z" transform="translate(249.859 -60.983)" opacity="0.1"/>
|
|
||||||
<path id="Path_438" data-name="Path 438" d="M713.414,319.15H598.1v96.311l115.314,2.6Z" transform="translate(394.451 108.164)" fill="#d4dfec"/>
|
|
||||||
<path id="Path_439" data-name="Path 439" d="M593.3,483.886V593.158a2.6,2.6,0,0,1-2.5,2.566l-124.506,3.313h0a2.6,2.6,0,0,1-2.6-2.566V483.886a2.6,2.6,0,0,1,2.566-2.566H590.73A2.6,2.6,0,0,1,593.3,483.886Z" transform="translate(389.997 -60.983)" fill="#65617d"/>
|
|
||||||
<path id="Path_440" data-name="Path 440" d="M397.1,319.15H512.414v96.311L397.1,418.06Z" transform="translate(464.87 108.164)" fill="#d4dfec"/>
|
|
||||||
<path id="Path_441" data-name="Path 441" d="M597.889,533.65V542.1l-98.7.909-1.052.02-37.511.344-.9.013-11.4.1h-.338l-69.5.643-114.086,1.059h-.1l-29.007.273-.312.007L106.1,546.643V536.9l131.562-.864h.312l26.629-.182h.123l183.9-1.215h.188l.11-.006h.305l3.112-.019h.948l48.393-.325,2.858-.013.637-.007Z" transform="translate(566.82 33.015)" opacity="0.1"/>
|
|
||||||
<circle id="Ellipse_99" data-name="Ellipse 99" cx="33.347" cy="33.347" r="33.347" transform="translate(887.196 363.44)" fill="#fbbebe"/>
|
|
||||||
<path id="Path_442" data-name="Path 442" d="M383.74,592.973a.806.806,0,0,1,.065-.227c.65-2.332,1.806-6.276,2.67-9.427.11-.39.214-.773.312-1.137.955-3.554,2.813-11.876,3.846-17.066.364-1.826.65-3.248.708-3.963.13-1.1,2.085-5.795,4.3-11.194,1.553-3.794,3.248-7.939,4.489-11.434a39.876,39.876,0,0,0,1.9-6.4,3.313,3.313,0,0,0,0-1.384,9.543,9.543,0,0,1-.312-2.274h0c-.149-4.028,1.052-10.394,2.91-13.065,2.274-3.248,3.9-15.371,3.9-15.371s3.365.487,3.9-2.293a4,4,0,0,0,.065-.91,4.815,4.815,0,0,0-.058-.721c-.578-4.054,9.563-8.368,15.267-9.3a12.769,12.769,0,0,1,1.949-.182,17.694,17.694,0,0,0,4.06-.935q.909-.279,1.949-.65c2.391-.806,5.249-1.871,8.283-3.04,11.408-4.424,25.22-10.394,25.22-10.394.1-.461.208-.9.331-1.338a18,18,0,0,1,10.622-12.3h0v-1.3c0-2.241-.1-4.548-.195-6.847,0-.448-.039-.9-.065-1.345v-.734c0-.455-.046-.91-.071-1.358l-.117-.091a10.66,10.66,0,0,1-2.534-2.729,9.916,9.916,0,0,1-.923-1.949c-.812-2.2-1-4.658-1.546-6.984l-.117-.481a54.579,54.579,0,0,0-2.6-6.873c-1.436-3.521-2.54-7.146-3.638-10.817q-1-3.333-2.02-6.678l-1.026-3.4c-.195-.65-.39-1.3-.539-1.949h0a8.627,8.627,0,0,1-.169-.91h0a6.5,6.5,0,0,1,.156-2.995,20.854,20.854,0,0,1,.858-1.949,5.113,5.113,0,0,0,.325-.9h0a1.947,1.947,0,0,0,.052-.208,3.667,3.667,0,0,0,.071-.7,11.993,11.993,0,0,0-.338-2.527.045.045,0,0,1,0-.032,1.661,1.661,0,0,0-.032-.175,16.564,16.564,0,0,1-.234-1.949,18.483,18.483,0,0,1,2.254-10.115l.123-.234a16.383,16.383,0,0,1,1.2-1.806h0a9.122,9.122,0,0,1,.65-.793,2.594,2.594,0,0,1-3.606-.936,2.475,2.475,0,0,1-.149-.292c-.033-.078-.059-.162-.085-.247-.455-1.592.338-3.287,1.377-4.58a12.012,12.012,0,0,1,3.729-3.053h0a2.51,2.51,0,0,1,.26-.136,11.125,11.125,0,0,1,1.715-.689h0a9.781,9.781,0,0,1,1.059-.286l-2.41-.221-.974-.091A9.414,9.414,0,0,1,479,361.527h.7a7.625,7.625,0,0,1,1.02.084A2.885,2.885,0,0,1,479,358.8a9.362,9.362,0,0,0,5.97,1.988h.247a19.494,19.494,0,0,1-.221-2.124h0a21.545,21.545,0,0,1,0-2.9,5.483,5.483,0,0,0,4.4,1.468l-1.351-1.884a6.165,6.165,0,0,0,4.262,1.332l.312-.033a4.547,4.547,0,0,0,.773-.149h.058c-.123-.156-.234-.318-.344-.487l-.039-.078a6.282,6.282,0,0,1-.65-1.358,4.284,4.284,0,0,1-.156-.565h0a5.684,5.684,0,0,1,.292-3.541c2.1,1.754,4.4,4.151,7.146,2.339s2.839-5.139,7.146-4.8a6.626,6.626,0,0,1,5.464,3.976,4.385,4.385,0,0,1,4.983-1.137,4.45,4.45,0,0,1,2.521,4.476c1.786-.448,3.71-.89,5.425-.214s2.82,2.865,1.845,4.327a.931.931,0,0,1-.091.13c-.8,1.033-2.566,1.6-2.378,2.9l.273.195.845.611q4.97,3.586,9.68,7.536c1.611,1.351,3.326,2.975,3.437,5.087a5.617,5.617,0,0,1-.156,1.54h0c-.1.507-.247,1.013-.357,1.52a12.676,12.676,0,0,0-.221,3.93h0c.045.383.1.76.175,1.143.994,5.022,5.009,9.167,5.405,14.292v.364a11.546,11.546,0,0,1-.045,1.644c-.3,3.118-1.741,6.113-2.91,9.1-.072.182-.143.364-.208.546a90.5,90.5,0,0,0-4.548,18.294,65.14,65.14,0,0,1-1.3,6.555,17.365,17.365,0,0,1-3.307,6.776,10.536,10.536,0,0,1-2.183,1.949,12.132,12.132,0,0,1-1.722.916v.039c.071.4.13.793.2,1.189.039.208.071.416.11.65h0a.089.089,0,0,0,0,.039c.546,3.073,1.169,6.081,1.826,8.939l.331,1.423c8.186,2.956,9.154,9.011,9.212,11.33a6.259,6.259,0,0,1,0,.929s12.343.325,17.216,3.9a13.21,13.21,0,0,0,2.93,1.494,53.917,53.917,0,0,0,6.009,1.877c1.046.273,2.137.539,3.248.8,1.949.448,4.015.884,6.009,1.3,5.321,1.072,10.33,1.949,12.87,2.6,6.061,1.533,19.925,14.825,19.925,14.825s1.624,13.409,3.248,15.364,4.548,8.829,4.548,8.829l10.745,19.106,4.548,8.036h2.923a4.97,4.97,0,0,1,2.085,1.364c.773.689,1.631,1.546,2.384,2.326l1.247,1.332.78.864s4.723.117,6,3.852c3.846-.11,8.569.143,11.876,1.624a9.187,9.187,0,0,1,1.3.7,5.639,5.639,0,0,1,2.683,3.677,5.422,5.422,0,0,1,.117.935c0,.37,0,.741,0,1.1-.234,4.918-3.437,9.011-6.38,11.765l.208.37s-.1.234-.286.65c-.052.123-.117.26-.188.416h0c-.383.819-.994,2.046-1.793,3.482a41.136,41.136,0,0,1-6.217,8.556l-.188.195-37.511.344-.11-.13-7.276-8.679-3.619-4.314-.11-.136-.1,1.033-.351,3.443-.845,8.322-.045.416v.11l-.1.961.071-.961h-.188l-69.513.65-114.092,1.26v.546h-.091v-.546l-29.072.312Z" transform="translate(418.007 -14.269)" fill="url(#linear-gradient)"/>
|
|
||||||
<path id="Path_443" data-name="Path 443" d="M586.185,511.522s-64.641,7.8-58.469,0c2.235-2.82,2.852-11.174,2.729-20.691-.039-2.891-.143-5.886-.292-8.868-.715-14.292-2.436-28.26-2.436-28.26s56.52-26.636,50.023-5.522c-2.6,8.53-1.748,20.51.227,31.755.578,3.281,1.247,6.5,1.949,9.55a223.892,223.892,0,0,0,6.269,22.036Z" transform="translate(367.711 -46.521)" fill="#fbbebe"/>
|
|
||||||
<path id="Path_444" data-name="Path 444" d="M586.185,537.354s-64.641,7.8-58.469,0c2.235-2.82,2.852-11.174,2.729-20.692,9.855-4.21,22.394-1.072,22.394-1.072,13.2-2.631,21.666-2.118,27.078-.273A223.888,223.888,0,0,0,586.185,537.354Z" transform="translate(367.711 -72.353)" opacity="0.1"/>
|
|
||||||
<path id="Path_445" data-name="Path 445" d="M413.346,651.973v-.546l114.092-1.241,69.513-.65h.195l-.071.961.1-.961h.123v-.11l.89-8.738.338-3.307.1-1.033.091-.864,4.015-13.389,4.015-13.37,3.378-11.258,5.158-17.2s-2.923-6.821-4.548-8.77-3.248-15.267-3.248-15.267-13.864-13.208-19.925-14.728c-2.54-.65-7.555-1.514-12.883-2.6-1.994-.4-4.041-.832-6.009-1.3-1.111-.253-2.2-.52-3.248-.786a57.086,57.086,0,0,1-6.009-1.858,13.448,13.448,0,0,1-2.924-1.488c-4.775-3.5-16.742-3.9-17.2-3.9h0a.269.269,0,0,1,0-.045v-.058a6.66,6.66,0,0,0,0-.819,5.208,5.208,0,0,0-.059-.91.82.82,0,0,0-.045-.325c-.032-.234-.071-.481-.13-.741a3.226,3.226,0,0,0-.078-.344,11.181,11.181,0,0,0-.812-2.267c-.045-.1-.1-.214-.156-.318a11.861,11.861,0,0,0-1.1-1.709c-.084-.11-.175-.227-.273-.338a12.721,12.721,0,0,0-1.767-1.715c-.175-.136-.357-.279-.546-.409a3.026,3.026,0,0,0-.331-.234l-.578-.377-.539-.312c-.474-.26-.974-.513-1.52-.754-.169-.078-.351-.149-.533-.221s-.468-.182-.708-.273h-.039l-.487-.195c-.37-.123-.747-.234-1.143-.344l-.6-.156-.65-.149-.65-.136c-.65-.13-1.345-.247-2.072-.338l-.741-.091-.76-.078-.786-.065-1.117-.065-1.3-.045a81.017,81.017,0,0,0-17.054,1.814,46.946,46.946,0,0,0-11.855-1.093h-.565l-.65.039h-.416l-.838.078a6.224,6.224,0,0,0-.845.1c-.279.039-.572.071-.851.117l-.429.071c-.422.071-.851.149-1.3.24q-.214.039-.429.1c-.565.123-1.13.273-1.689.442-.279.078-.559.169-.838.266-.143.039-.279.091-.416.143l-.416.149-.409.162-.487.195c-.247.1-.487.214-.728.331-.136.058-.273.123-.4.195s-.266.13-.39.2a18.03,18.03,0,0,0-4.034,2.846l-.331.318-.325.331c-.11.11-.214.227-.318.344a15.473,15.473,0,0,0-1.182,1.462c-.1.136-.2.273-.3.416a17.335,17.335,0,0,0-1.117,1.9c-.084.156-.162.318-.24.474a21.243,21.243,0,0,0-1.3,3.411q-.182.65-.331,1.3s-13.753,6.068-25.161,10.46c-3.034,1.169-5.892,2.228-8.283,3.027-.7.234-1.345.448-1.949.65a17.347,17.347,0,0,1-4.06.935,12.778,12.778,0,0,0-1.949.182c-5.243.851-14.227,4.548-15.208,8.257a2.4,2.4,0,0,0-.065.91v.071c.65,4.548-3.9,3.9-3.9,3.9s-1.624,12.019-3.9,15.267c-1.644,2.339-2.768,7.555-2.91,11.492h0a12.741,12.741,0,0,0,.286,3.658v.091c.26.871-.364,3.248-1.423,6.3-1.15,3.346-2.826,7.5-4.437,11.427-2.43,5.925-4.716,11.3-4.859,12.486-.058.526-.227,1.468-.461,2.683-.948,4.95-3.053,14.377-4.093,18.19-.773,2.845-1.9,6.743-2.67,9.42a.91.91,0,0,1-.065.227l29.124-.286v.546h.091Z" transform="translate(417.856 -73.042)" fill="#00ddf1"/>
|
|
||||||
<path id="Path_446" data-name="Path 446" d="M445.44,607.57s37.03,19.165,50.348,16.891Z" transform="translate(396.391 -105.214)" opacity="0.1"/>
|
|
||||||
<path id="Path_447" data-name="Path 447" d="M561.44,595.57s36.056,11.694,48.074,13.318S561.44,595.57,561.44,595.57Z" transform="translate(355.751 -101.01)" opacity="0.1"/>
|
|
||||||
<path id="Path_448" data-name="Path 448" d="M585.443,530.686c-18.84,3.469-54.311,2.722-69.643,2.2,5.62-20.139,33.022-13.292,33.022-13.292C582.74,512.821,585.339,526.866,585.443,530.686Z" transform="translate(371.74 -73.754)" opacity="0.1"/>
|
|
||||||
<path id="Path_449" data-name="Path 449" d="M585.443,528.686c-18.84,3.469-54.311,2.722-69.643,2.2,5.62-20.139,33.022-13.292,33.022-13.292C582.74,510.821,585.339,524.866,585.443,528.686Z" transform="translate(371.74 -73.053)" fill="#00ddf1"/>
|
|
||||||
<path id="Path_450" data-name="Path 450" d="M776.94,672.008s22.192-3.411,22.628,6.334S788.25,694.9,788.25,694.9Z" transform="translate(280.251 -127.587)" fill="#fbbebe"/>
|
|
||||||
<path id="Path_451" data-name="Path 451" d="M578.17,479.936a30.558,30.558,0,0,1-2.923,1.13c-7,2.417-14.065,4.853-21.439,5.736s-15.111.1-21.543-3.573a18.685,18.685,0,0,1-1.949-1.267c-.715-14.292-2.436-28.26-2.436-28.26s56.52-26.636,50.023-5.522C575.318,456.711,576.195,468.69,578.17,479.936Z" transform="translate(367.508 -46.521)" opacity="0.1"/>
|
|
||||||
<path id="Path_452" data-name="Path 452" d="M536.9,360.29a6.153,6.153,0,0,1-5.405-1.137l1.351,1.878a5.5,5.5,0,0,1-4.4-1.462,22.146,22.146,0,0,0,.208,5.035,9.433,9.433,0,0,1-6.211-1.949,2.872,2.872,0,0,0,1.715,2.8,9.316,9.316,0,0,0-10.135,6.958l3.391.312a12,12,0,0,0-6.782,4.138c-1.039,1.3-1.832,2.962-1.377,4.548s2.651,2.6,3.846,1.468a18.151,18.151,0,0,0-3.963,14.806,9.4,9.4,0,0,1,.3,3.417,28.993,28.993,0,0,1-1.228,3.047c-.65,1.9-.032,3.956.546,5.847l3.047,10.018c1.1,3.619,2.2,7.244,3.645,10.745a53.328,53.328,0,0,1,2.6,6.828c.819,3.144.851,6.588,2.6,9.336a12.948,12.948,0,0,0,4.665,4.112c6.425,3.677,14.188,4.457,21.542,3.573s14.409-3.32,21.406-5.736a20.141,20.141,0,0,0,4.444-1.949c4.84-3.17,5.918-9.654,6.821-15.364a87.242,87.242,0,0,1,4.736-18.71c1.416-3.567,3.248-7.185,2.936-11.005-.4-5.074-4.411-9.186-5.405-14.175a12.344,12.344,0,0,1,.045-5.048,11.473,11.473,0,0,0,.513-3.053c-.11-2.092-1.826-3.7-3.437-5.048q-5.243-4.379-10.823-8.277c-.188-1.3,1.579-1.858,2.378-2.884,1.13-1.449-.039-3.748-1.754-4.424s-3.638-.234-5.425.214a4.281,4.281,0,0,0-7.5-3.32,6.627,6.627,0,0,0-5.47-3.95c-4.307-.338-4.392,2.956-7.146,4.768s-5.028-.578-7.146-2.319A6.029,6.029,0,0,0,536.9,360.29Z" transform="translate(374.5 -15.625)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_453" data-name="Path 453" d="M768.171,669.128s-.578,1.377-1.644,3.372a44.83,44.83,0,0,1-5.847,8.556l-.175.188h-1.052l-37.511.344h-.9l-.11-.13-7.276-8.634-2.741-3.255-.11-.136-.234-.273-.13-.156-.169-.2-5.334-6.328,1.949-8.121,3.32-13.682.084-.331.65-2.6.461-1.949,1.546-6.354,5.3-21.861,9.42,4.872,9.933,17.541,5.334,9.42h2.923c.552,0,1.819,1.065,3.092,2.293.455.435.91.9,1.3,1.3,1.156,1.2,2.072,2.222,2.072,2.222s4.736.1,6.009,3.833a4.537,4.537,0,0,1,.162.552,26.191,26.191,0,0,0,1.644,4.262c.838,1.826,1.891,3.9,2.956,5.97,1.981,3.8,4,7.419,4.736,8.731l.091.162Z" transform="translate(305.476 -105.217)" fill="#00ddf1"/>
|
|
||||||
<path id="Path_454" data-name="Path 454" d="M615.681,653.093l-.065.929v.065l-.11,1.494-.864,12.025L613.6,682.093l-.3,4.08-.65,8.731v.11l-69.513.65L429.061,696.9v.546h-.091v-.728l.292-9.329.559-18.229L430.3,653.7l.045-1.54a6.841,6.841,0,0,1,7.419-6.607c3.066.26,7.049.578,11.811.916l1.949.143c27.5,1.91,78.322,4.379,129.606,1.3,1.078-.059,2.163-.123,3.248-.2,7.952-.5,15.9-1.143,23.764-1.949a6.841,6.841,0,0,1,7.536,7.3Z" transform="translate(402.161 -118.514)" opacity="0.1"/>
|
|
||||||
<path id="Path_455" data-name="Path 455" d="M429.08,698.857v-.546l114.092-1.241,69.513-.65h.195v-.11l.65-8.731.279-3.9,1.065-14.689.838-11.629v-.286a6.893,6.893,0,0,0-.071-1.6.2.2,0,0,0,0-.065,6.751,6.751,0,0,0-1.3-3.014,6.847,6.847,0,0,0-6.12-2.6c-7.867.806-15.813,1.449-23.764,1.949-1.085.078-2.17.143-3.248.2-51.284,3.047-102.106.578-129.606-1.3l-1.949-.143c-4.762-.338-8.744-.65-11.811-.916a6.847,6.847,0,0,0-7.3,5.542,7.146,7.146,0,0,0-.117,1.065l-.442,14.4-.6,18.236-.286,9.329v.728Z" transform="translate(402.122 -119.926)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_456" data-name="Path 456" d="M615.925,661.692l-.8,9.959L613.937,686.5l-.3,3.716-.65,8.322-.039.416v.11h0l-.1.961.071-.961h-.188l-69.513.65L429.11,700.944v-.182l.318-9.329.65-18.229.416-12.116a4.132,4.132,0,0,1,1.988-3.411,4.061,4.061,0,0,1,2.456-.585c1.364.11,3.04.24,5,.383,3.177.234,7.094.507,11.655.793,8.445.533,19.041,1.1,31.183,1.572,33.782,1.3,79.388,1.735,122.707-2.059,1.949-.169,3.963-.357,5.931-.546a4.066,4.066,0,0,1,2.261.429,3.346,3.346,0,0,1,.559.351,3.989,3.989,0,0,1,1.3,1.6,2.315,2.315,0,0,1,.162.4A4.08,4.08,0,0,1,615.925,661.692Z" transform="translate(402.112 -122.559)" opacity="0.1"/>
|
|
||||||
<path id="Path_457" data-name="Path 457" d="M360.914,677.87v2.072a3.982,3.982,0,0,1-2.274,3.6l-26.051.5a3.976,3.976,0,0,1-2.319-3.619v-1.949Z" transform="translate(436.74 -129.843)" opacity="0.1"/>
|
|
||||||
<path id="Path_458" data-name="Path 458" d="M280.294,512.532l-33.944.65V507.55l33.944-.65Z" transform="translate(517.685 42.387)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_459" data-name="Path 459" d="M280.294,512.532l-33.944.65V507.55l33.944-.65Z" transform="translate(517.685 42.387)" opacity="0.1"/>
|
|
||||||
<path id="Path_460" data-name="Path 460" d="M282.294,512.532l-33.944.65V507.55l33.944-.65Z" transform="translate(516.984 42.387)" fill="#3f3d56"/>
|
|
||||||
<path id="Path_461" data-name="Path 461" d="M552.228,360.039A6.334,6.334,0,0,1,551,357.22a6.165,6.165,0,0,0,.273,2.988A5.847,5.847,0,0,0,552.228,360.039Z" transform="translate(359.434 -17.505)"/>
|
|
||||||
<path id="Path_462" data-name="Path 462" d="M540.1,366.9a22.83,22.83,0,0,1-.24-2.4c0,.8,0,1.6,0,2.41Z" transform="translate(363.311 -20.056)"/>
|
|
||||||
<path id="Path_463" data-name="Path 463" d="M621.706,398.627a11.912,11.912,0,0,1,.234-1.722,11.7,11.7,0,0,0,.52-3.047,4.008,4.008,0,0,0-.1-.689c-.11.6-.286,1.2-.416,1.787a12.433,12.433,0,0,0-.234,3.671Z" transform="translate(334.652 -30.1)"/>
|
|
||||||
<path id="Path_464" data-name="Path 464" d="M600.922,368.894l.708.513a12.8,12.8,0,0,0,1.67-1.442,2.384,2.384,0,0,0,.247-2.365,1.95,1.95,0,0,1-.247.416C602.5,367.042,600.734,367.607,600.922,368.894Z" transform="translate(341.923 -20.441)"/>
|
|
||||||
<path id="Path_465" data-name="Path 465" d="M518.455,380.29a8,8,0,0,0-.565,1.481,11.8,11.8,0,0,1,3.248-1.228Z" transform="translate(371.008 -25.587)"/>
|
|
||||||
<path id="Path_466" data-name="Path 466" d="M531.888,368.979a9.637,9.637,0,0,1-1.221-.8,2.758,2.758,0,0,0,.058.767,7.7,7.7,0,0,1,1.163.033Z" transform="translate(366.534 -21.345)"/>
|
|
||||||
<path id="Path_467" data-name="Path 467" d="M587.579,428.33c-.266,3.151-1.735,6.185-2.923,9.173a87.2,87.2,0,0,0-4.736,18.717c-.9,5.71-1.949,12.194-6.821,15.358a19.488,19.488,0,0,1-4.437,1.949c-7,2.423-14.065,4.853-21.439,5.736s-15.111.11-21.543-3.567a12.993,12.993,0,0,1-4.664-4.112c-1.735-2.748-1.767-6.191-2.6-9.336a53.424,53.424,0,0,0-2.6-6.834c-1.436-3.5-2.54-7.146-3.638-10.739q-1.527-5.009-3.047-10.024a18.716,18.716,0,0,1-.741-3.086,11.644,11.644,0,0,0,.741,5.035q1.52,5.022,3.047,10.024c1.1,3.619,2.2,7.244,3.638,10.739a53.417,53.417,0,0,1,2.6,6.834c.819,3.144.851,6.587,2.6,9.336a12.993,12.993,0,0,0,4.664,4.112c6.432,3.677,14.188,4.45,21.543,3.567s14.409-3.313,21.439-5.736a19.487,19.487,0,0,0,4.437-1.949c4.84-3.164,5.918-9.647,6.821-15.358a87.2,87.2,0,0,1,4.736-18.717c1.416-3.56,3.248-7.179,2.936-11.005C587.592,428.408,587.579,428.369,587.579,428.33Z" transform="translate(374.359 -42.418)"/>
|
|
||||||
<path id="Path_468" data-name="Path 468" d="M510.318,421.419v-.071a9.1,9.1,0,0,0-.3-3.411,17.272,17.272,0,0,1-.253-2.157,17.769,17.769,0,0,0,.253,4.106C510.123,420.393,510.24,420.906,510.318,421.419Z" transform="translate(373.864 -38.021)"/>
|
|
||||||
<path id="Path_469" data-name="Path 469" d="M512.452,397.929a18.02,18.02,0,0,1,1.7-2.384c-1.189,1.137-3.385.123-3.846-1.455a3.788,3.788,0,0,0,0,1.949,2.852,2.852,0,0,0,2.15,1.89Z" transform="translate(373.712 -30.422)"/>
|
|
||||||
<path id="Path_470" data-name="Path 470" d="M762.946,656.57s2.059,7.471,0,13.968S762.946,656.57,762.946,656.57Z" transform="translate(285.475 -122.381)" opacity="0.1"/>
|
|
||||||
<path id="Path_471" data-name="Path 471" d="M776,668.3s.864,9.485-1.085,11.168S776,668.3,776,668.3Z" transform="translate(281.189 -126.49)" opacity="0.1"/>
|
|
||||||
<line id="Line_88" data-name="Line 88" y1="0.65" x2="66.011" transform="translate(733.267 442.068)" fill="none" stroke="#00ddf1" stroke-miterlimit="10" stroke-width="2"/>
|
|
||||||
<line id="Line_89" data-name="Line 89" y1="0.643" x2="66.011" transform="translate(733.267 450.176)" fill="none" stroke="#00ddf1" stroke-miterlimit="10" stroke-width="2"/>
|
|
||||||
<line id="Line_90" data-name="Line 90" y1="0.65" x2="66.011" transform="translate(733.267 458.277)" fill="none" stroke="#00ddf1" stroke-miterlimit="10" stroke-width="2"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 234 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 12 KiB |
@@ -1,315 +0,0 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
|
||||||
import Parse from "parse";
|
|
||||||
import axios from "axios";
|
|
||||||
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const";
|
|
||||||
|
|
||||||
const AddSigner = (props) => {
|
|
||||||
const [name, setName] = useState("");
|
|
||||||
const [phone, setPhone] = useState("");
|
|
||||||
const [email, setEmail] = useState("");
|
|
||||||
const [addYourself, setAddYourself] = useState(false);
|
|
||||||
const [isLoader, setIsLoader] = useState(false);
|
|
||||||
const [isUserExist, setIsUserExist] = useState(false);
|
|
||||||
const parseBaseUrl = localStorage.getItem("baseUrl");
|
|
||||||
const parseAppId = localStorage.getItem("parseAppId");
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
checkUserExist();
|
|
||||||
}, []);
|
|
||||||
// Load user details from localStorage when the component mounts
|
|
||||||
useEffect(() => {
|
|
||||||
const savedUserDetails = JSON.parse(
|
|
||||||
localStorage.getItem("UserInformation")
|
|
||||||
);
|
|
||||||
if (savedUserDetails && addYourself) {
|
|
||||||
setName(savedUserDetails.name);
|
|
||||||
setPhone(savedUserDetails.phone);
|
|
||||||
setEmail(savedUserDetails.email);
|
|
||||||
}
|
|
||||||
}, [addYourself]);
|
|
||||||
|
|
||||||
const checkUserExist = async () => {
|
|
||||||
const user = Parse.User.current();
|
|
||||||
try {
|
|
||||||
const query = new Parse.Query("contracts_Contactbook");
|
|
||||||
query.equalTo("CreatedBy", user);
|
|
||||||
query.notEqualTo("IsDeleted", true);
|
|
||||||
query.equalTo("Email", user.getEmail());
|
|
||||||
const res = await query.first();
|
|
||||||
// console.log(res);
|
|
||||||
if (!res) {
|
|
||||||
setIsUserExist(true);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log("err", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Define a function to handle form submission
|
|
||||||
const handleSubmit = async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
setIsLoader(true);
|
|
||||||
try {
|
|
||||||
const contactQuery = new Parse.Object("contracts_Contactbook");
|
|
||||||
contactQuery.set("Name", name);
|
|
||||||
contactQuery.set("Phone", phone);
|
|
||||||
contactQuery.set("Email", email);
|
|
||||||
contactQuery.set("UserRole", "contracts_Guest");
|
|
||||||
|
|
||||||
if (localStorage.getItem("TenantId")) {
|
|
||||||
contactQuery.set("TenantId", {
|
|
||||||
__type: "Pointer",
|
|
||||||
className: "partners_Tenant",
|
|
||||||
objectId: localStorage.getItem("TenantId")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const _users = Parse.Object.extend("User");
|
|
||||||
const _user = new _users();
|
|
||||||
_user.set("name", name);
|
|
||||||
_user.set("username", email);
|
|
||||||
_user.set("email", email);
|
|
||||||
_user.set("phone", phone);
|
|
||||||
_user.set("password", phone);
|
|
||||||
|
|
||||||
const user = await _user.save();
|
|
||||||
if (user) {
|
|
||||||
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
|
|
||||||
const headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId,
|
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
|
||||||
};
|
|
||||||
const body = {
|
|
||||||
appName: localStorage.getItem("_appName"),
|
|
||||||
roleName: "contracts_Guest",
|
|
||||||
userId: user.id
|
|
||||||
};
|
|
||||||
await axios.post(roleurl, body, { headers: headers });
|
|
||||||
const currentUser = Parse.User.current();
|
|
||||||
contactQuery.set(
|
|
||||||
"CreatedBy",
|
|
||||||
Parse.User.createWithoutData(currentUser.id)
|
|
||||||
);
|
|
||||||
|
|
||||||
contactQuery.set("UserId", user);
|
|
||||||
const acl = new Parse.ACL();
|
|
||||||
acl.setPublicReadAccess(true);
|
|
||||||
acl.setPublicWriteAccess(true);
|
|
||||||
acl.setReadAccess(currentUser.id, true);
|
|
||||||
acl.setWriteAccess(currentUser.id, true);
|
|
||||||
|
|
||||||
contactQuery.setACL(acl);
|
|
||||||
|
|
||||||
const res = await contactQuery.save();
|
|
||||||
|
|
||||||
const parseData = JSON.parse(JSON.stringify(res));
|
|
||||||
if (props.details) {
|
|
||||||
props.details({
|
|
||||||
value: parseData[props.valueKey],
|
|
||||||
label: parseData[props.displayKey]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (props.closePopup) {
|
|
||||||
props.closePopup();
|
|
||||||
}
|
|
||||||
if (props.handleUserData) {
|
|
||||||
props.handleUserData(parseData);
|
|
||||||
}
|
|
||||||
|
|
||||||
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("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
// console.log("err", err);
|
|
||||||
setIsLoader(false);
|
|
||||||
alert("something went wrong!");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Define a function to handle the "add yourself" checkbox
|
|
||||||
const handleAddYourselfChange = () => {
|
|
||||||
if (addYourself) {
|
|
||||||
setAddYourself(false);
|
|
||||||
setName("");
|
|
||||||
setPhone("");
|
|
||||||
setEmail("");
|
|
||||||
} else {
|
|
||||||
setAddYourself(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleReset = () => {
|
|
||||||
setAddYourself(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="h-full p-[20px]">
|
|
||||||
{isLoader && (
|
|
||||||
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30">
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="w-full mx-auto p-2">
|
|
||||||
{isUserExist && (
|
|
||||||
<div className="mb-3">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
id="addYourself"
|
|
||||||
checked={addYourself}
|
|
||||||
onChange={handleAddYourselfChange}
|
|
||||||
className="form-checkbox"
|
|
||||||
/>
|
|
||||||
<label htmlFor="addYourself" className="ml-2 text-gray-700">
|
|
||||||
Add Yourself
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<form onSubmit={handleSubmit}>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="name"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Name
|
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="name"
|
|
||||||
value={name}
|
|
||||||
onChange={(e) => setName(e.target.value)}
|
|
||||||
required
|
|
||||||
disabled={addYourself}
|
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="email"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Email
|
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
id="email"
|
|
||||||
value={email}
|
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
|
||||||
required
|
|
||||||
disabled={addYourself}
|
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="phone"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Phone
|
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="phone"
|
|
||||||
value={phone}
|
|
||||||
onChange={(e) => setPhone(e.target.value)}
|
|
||||||
required
|
|
||||||
disabled={addYourself}
|
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-4 flex justify-start">
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
style={{ backgroundColor: modalSubmitBtnColor }}
|
|
||||||
className="mr-2 px-[20px] py-1.5 text-white rounded shadow-md text-center focus:outline-none "
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => handleReset()}
|
|
||||||
style={{ backgroundColor: modalCancelBtnColor }}
|
|
||||||
className="px-4 py-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none"
|
|
||||||
>
|
|
||||||
Reset
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AddSigner;
|
|
||||||
@@ -1,281 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import Parse from "parse";
|
|
||||||
import axios from "axios";
|
|
||||||
import Title from "./Title";
|
|
||||||
import Alert from "../primitives/Alert";
|
|
||||||
|
|
||||||
const AddUser = (props) => {
|
|
||||||
const [name, setName] = useState("");
|
|
||||||
const [phone, setPhone] = useState("");
|
|
||||||
const [email, setEmail] = useState("");
|
|
||||||
const [isLoader, setIsLoader] = useState(false);
|
|
||||||
const [isUserExist, setIsUserExist] = useState(false);
|
|
||||||
const parseBaseUrl = localStorage.getItem("baseUrl");
|
|
||||||
const parseAppId = localStorage.getItem("parseAppId");
|
|
||||||
|
|
||||||
const checkUserExist = async () => {
|
|
||||||
try {
|
|
||||||
const res = await Parse.Cloud.run("getUserDetails", {
|
|
||||||
email: email,
|
|
||||||
userId: Parse.User.current().id
|
|
||||||
});
|
|
||||||
if (res) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log("err", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Define a function to handle form submission
|
|
||||||
const handleSubmit = async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
setIsLoader(true);
|
|
||||||
const res = await checkUserExist();
|
|
||||||
if (res) {
|
|
||||||
setIsUserExist(true);
|
|
||||||
setIsLoader(false);
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsUserExist(false);
|
|
||||||
}, 1000);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
const contactQuery = new Parse.Object("contracts_Users");
|
|
||||||
contactQuery.set("Name", name);
|
|
||||||
contactQuery.set("Phone", phone);
|
|
||||||
contactQuery.set("Email", email);
|
|
||||||
contactQuery.set("UserRole", "contracts_User");
|
|
||||||
|
|
||||||
if (localStorage.getItem("TenantId")) {
|
|
||||||
contactQuery.set("TenantId", {
|
|
||||||
__type: "Pointer",
|
|
||||||
className: "partners_Tenant",
|
|
||||||
objectId: localStorage.getItem("TenantId")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const _users = Parse.Object.extend("User");
|
|
||||||
const _user = new _users();
|
|
||||||
_user.set("name", name);
|
|
||||||
_user.set("username", email);
|
|
||||||
_user.set("email", email);
|
|
||||||
_user.set("phone", phone);
|
|
||||||
_user.set("password", phone);
|
|
||||||
|
|
||||||
const user = await _user.save();
|
|
||||||
if (user) {
|
|
||||||
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
|
|
||||||
const headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId,
|
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
|
||||||
};
|
|
||||||
const body = {
|
|
||||||
appName: localStorage.getItem("_appName"),
|
|
||||||
roleName: "contracts_User",
|
|
||||||
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);
|
|
||||||
|
|
||||||
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_User",
|
|
||||||
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);
|
|
||||||
setName("");
|
|
||||||
setPhone("");
|
|
||||||
setEmail("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
// console.log("err", err);
|
|
||||||
setIsLoader(false);
|
|
||||||
alert("something went wrong!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Define a function to handle the "add yourself" checkbox
|
|
||||||
const handleReset = () => {
|
|
||||||
setName("");
|
|
||||||
setPhone("");
|
|
||||||
setEmail("");
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="shadow-md rounded my-2 p-3 bg-[#ffffff] md:border-[1px] md:border-gray-600/50">
|
|
||||||
<Title title={"Add User"} />
|
|
||||||
{isUserExist && <Alert type="danger">User already exists!</Alert>}
|
|
||||||
{isLoader && (
|
|
||||||
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30 z-50">
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="w-full mx-auto">
|
|
||||||
<form onSubmit={handleSubmit}>
|
|
||||||
<h1 className="text-[20px] font-semibold mb-4">Add User</h1>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="name"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Name
|
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="name"
|
|
||||||
value={name}
|
|
||||||
onChange={(e) => setName(e.target.value)}
|
|
||||||
required
|
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="email"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Email
|
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
id="email"
|
|
||||||
value={email}
|
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
|
||||||
required
|
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="phone"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Phone
|
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="phone"
|
|
||||||
value={phone}
|
|
||||||
onChange={(e) => setPhone(e.target.value)}
|
|
||||||
required
|
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center mt-3 gap-2 text-white">
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="bg-[#1ab6ce] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 focus:outline-none"
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
type="button"
|
|
||||||
onClick={() => handleReset()}
|
|
||||||
className="bg-[#188ae2] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 text-center ml-[2px] focus:outline-none"
|
|
||||||
>
|
|
||||||
Reset
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AddUser;
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import Package from "../../package.json";
|
|
||||||
import axios from "axios";
|
|
||||||
import { openInNewTab } from "../constant/Utils";
|
|
||||||
const Footer = () => {
|
|
||||||
const [showButton, setShowButton] = useState(false);
|
|
||||||
const [version, setVersion] = useState("");
|
|
||||||
useEffect(() => {
|
|
||||||
axios
|
|
||||||
.get("/version.txt")
|
|
||||||
.then((response) => {
|
|
||||||
setVersion(response.data); // Set the retrieved data to the state variable
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error reading the file:", error);
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleScroll = () => {
|
|
||||||
if (window.pageYOffset >= 50) {
|
|
||||||
setShowButton(true);
|
|
||||||
} else {
|
|
||||||
setShowButton(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const scrollToTop = () => {
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
setShowButton(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
window.addEventListener("scroll", handleScroll);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener("scroll", handleScroll);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const appName = "OpenSign™";
|
|
||||||
const openUrl = () => {
|
|
||||||
openInNewTab(
|
|
||||||
"https://github.com/OpenSignLabs/OpenSign/releases/tag/" + version
|
|
||||||
);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="bg-[#222c3c] text-[#98a6ba] text-center text-[13px] py-3">
|
|
||||||
All Rights Reserved © {new Date().getFullYear()}
|
|
||||||
<span onClick={openUrl} className="hover:underline cursor-pointer">
|
|
||||||
{appName} ( version: {version ? version : `${Package.version} `})
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
className={`${
|
|
||||||
showButton ? "block" : "hidden"
|
|
||||||
} fixed bottom-4 right-4 px-3 p-2 text-xl bg-blue-500 text-white rounded focus:outline-none`}
|
|
||||||
onClick={scrollToTop}
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-angle-up"></i>
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Footer;
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
// FullScreenButton.js
|
|
||||||
import React, { useState, useEffect } from "react";
|
|
||||||
|
|
||||||
const FullScreenButton = () => {
|
|
||||||
const [isFullScreen, setIsFullScreen] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
document.addEventListener("fullscreenchange", handleFullScreenChange);
|
|
||||||
document.addEventListener("webkitfullscreenchange", handleFullScreenChange);
|
|
||||||
document.addEventListener("mozfullscreenchange", handleFullScreenChange);
|
|
||||||
document.addEventListener("MSFullscreenChange", handleFullScreenChange);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener("fullscreenchange", handleFullScreenChange);
|
|
||||||
document.removeEventListener(
|
|
||||||
"webkitfullscreenchange",
|
|
||||||
handleFullScreenChange
|
|
||||||
);
|
|
||||||
document.removeEventListener(
|
|
||||||
"mozfullscreenchange",
|
|
||||||
handleFullScreenChange
|
|
||||||
);
|
|
||||||
document.removeEventListener(
|
|
||||||
"MSFullscreenChange",
|
|
||||||
handleFullScreenChange
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleFullScreenChange = () => {
|
|
||||||
setIsFullScreen(!!document.fullscreenElement);
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleFullScreen = () => {
|
|
||||||
if (isFullScreen) {
|
|
||||||
exitFullScreen();
|
|
||||||
} else {
|
|
||||||
requestFullScreen();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const requestFullScreen = () => {
|
|
||||||
if (document.documentElement.requestFullscreen) {
|
|
||||||
document.documentElement.requestFullscreen();
|
|
||||||
} else if (document.documentElement.mozRequestFullScreen) {
|
|
||||||
document.documentElement.mozRequestFullScreen();
|
|
||||||
} else if (document.documentElement.webkitRequestFullscreen) {
|
|
||||||
document.documentElement.webkitRequestFullscreen();
|
|
||||||
} else if (document.documentElement.msRequestFullscreen) {
|
|
||||||
document.documentElement.msRequestFullscreen();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const exitFullScreen = () => {
|
|
||||||
if (document.exitFullscreen) {
|
|
||||||
document.exitFullscreen();
|
|
||||||
} else if (document.mozCancelFullScreen) {
|
|
||||||
document.mozCancelFullScreen();
|
|
||||||
} else if (document.webkitExitFullscreen) {
|
|
||||||
document.webkitExitFullscreen();
|
|
||||||
} else if (document.msExitFullscreen) {
|
|
||||||
document.msExitFullscreen();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex items-center">
|
|
||||||
<button
|
|
||||||
onClick={toggleFullScreen}
|
|
||||||
className="text-black p-2 text-sm focus:outline-none"
|
|
||||||
>
|
|
||||||
{isFullScreen ? (
|
|
||||||
<i className="fa-solid fa-compress"></i>
|
|
||||||
) : (
|
|
||||||
<i className="fa fa-maximize"></i>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FullScreenButton;
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
|
||||||
import dp from "../assets/images/dp.png";
|
|
||||||
import FullScreenButton from "./FullScreenButton";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import Parse from "parse";
|
|
||||||
import { useWindowSize } from "../hook/useWindowSize";
|
|
||||||
import { checkIsSubscribed, openInNewTab } from "../constant/Utils";
|
|
||||||
import { isEnableSubscription } from "../constant/const";
|
|
||||||
|
|
||||||
const Header = ({ showSidebar }) => {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const { width } = useWindowSize();
|
|
||||||
let applogo = localStorage.getItem("appLogo") || "";
|
|
||||||
let username = localStorage.getItem("username");
|
|
||||||
const image = localStorage.getItem("profileImg") || dp;
|
|
||||||
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [isSubscribe, setIsSubscribe] = useState(true);
|
|
||||||
|
|
||||||
const toggleDropdown = () => {
|
|
||||||
setIsOpen(!isOpen);
|
|
||||||
};
|
|
||||||
useEffect(() => {
|
|
||||||
checkSubscription();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
async function checkSubscription() {
|
|
||||||
if (isEnableSubscription) {
|
|
||||||
const getIsSubscribe = await checkIsSubscribed();
|
|
||||||
setIsSubscribe(getIsSubscribe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const closeDropdown = () => {
|
|
||||||
setIsOpen(false);
|
|
||||||
Parse.User.logOut();
|
|
||||||
let appdata = localStorage.getItem("userSettings");
|
|
||||||
let applogo = localStorage.getItem("appLogo");
|
|
||||||
let appName = localStorage.getItem("appName");
|
|
||||||
let defaultmenuid = localStorage.getItem("defaultmenuid");
|
|
||||||
let PageLanding = localStorage.getItem("PageLanding");
|
|
||||||
let domain = localStorage.getItem("domain");
|
|
||||||
let _appName = localStorage.getItem("_appName");
|
|
||||||
let baseUrl = localStorage.getItem("baseUrl");
|
|
||||||
let appid = localStorage.getItem("parseAppId");
|
|
||||||
|
|
||||||
localStorage.clear();
|
|
||||||
|
|
||||||
localStorage.setItem("appLogo", applogo);
|
|
||||||
localStorage.setItem("appName", appName);
|
|
||||||
localStorage.setItem("_appName", _appName);
|
|
||||||
localStorage.setItem("defaultmenuid", defaultmenuid);
|
|
||||||
localStorage.setItem("PageLanding", PageLanding);
|
|
||||||
localStorage.setItem("domain", domain);
|
|
||||||
localStorage.setItem("userSettings", appdata);
|
|
||||||
localStorage.setItem("baseUrl", baseUrl);
|
|
||||||
localStorage.setItem("parseAppId", appid);
|
|
||||||
|
|
||||||
navigate("/");
|
|
||||||
};
|
|
||||||
|
|
||||||
//handle to close profile drop down menu onclick screen
|
|
||||||
useEffect(() => {
|
|
||||||
const closeMenuOnOutsideClick = (e) => {
|
|
||||||
if (isOpen && !e.target.closest("#profile-menu")) {
|
|
||||||
setIsOpen(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener("click", closeMenuOnOutsideClick);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
// Cleanup the event listener when the component unmounts
|
|
||||||
document.removeEventListener("click", closeMenuOnOutsideClick);
|
|
||||||
};
|
|
||||||
}, [isOpen]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-row justify-between items-center gap-x-3 md:gap-x-4 bg-white md:px-4 px-2 shadow h-[50px] md:w-full ">
|
|
||||||
<button
|
|
||||||
className="cursor-pointer focus:outline-none"
|
|
||||||
onClick={showSidebar}
|
|
||||||
>
|
|
||||||
<i className={`fa-solid fa-bars text-xl `}></i>
|
|
||||||
</button>
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="h-[25px] md:h-[40px] w-auto overflow-hidden">
|
|
||||||
<img
|
|
||||||
className="object-contain h-full w-auto"
|
|
||||||
src={applogo}
|
|
||||||
alt="img"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id="profile-menu"
|
|
||||||
className="flex justify-between items-center gap-x-3"
|
|
||||||
>
|
|
||||||
{!isSubscribe && (
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
className="text-xs bg-[#002864] p-2 text-white rounded shadow"
|
|
||||||
onClick={() => navigate("/subscription")}
|
|
||||||
>
|
|
||||||
Upgrade Now
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div>
|
|
||||||
<FullScreenButton />
|
|
||||||
</div>
|
|
||||||
{width >= 768 && (
|
|
||||||
<div
|
|
||||||
onClick={toggleDropdown}
|
|
||||||
className="cursor-pointer w-[35px] h-[35px] rounded-full ring-[1px] ring-offset-2 ring-gray-400 overflow-hidden"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
className="w-[35px] h-[35px] object-contain"
|
|
||||||
src={image}
|
|
||||||
alt="img"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{width >= 768 && (
|
|
||||||
<div onClick={toggleDropdown} className="cursor-pointer text-sm">
|
|
||||||
{username && username}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="relative">
|
|
||||||
<div className="cursor-pointer">
|
|
||||||
<i onClick={toggleDropdown} className="fa-solid fa-angle-down"></i>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`dropdown absolute text-sm text-gray-700 font-light right-0 mt-4 p-1 w-48 bg-white border rounded-lg shadow-lg z-10 ${
|
|
||||||
isOpen ? "block" : "hidden"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<ul>
|
|
||||||
<li
|
|
||||||
className="hover:bg-gray-100 rounded-t-lg py-1 px-2 cursor-pointer font-normal"
|
|
||||||
onClick={() => openInNewTab("https://docs.opensignlabs.com")}
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-book"></i> Docs
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
|
|
||||||
onClick={() => {
|
|
||||||
setIsOpen(false);
|
|
||||||
navigate("/profile");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i className="fa-regular fa-user"></i> Profile
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
|
|
||||||
onClick={() => {
|
|
||||||
setIsOpen(false);
|
|
||||||
navigate("/changepassword");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-lock"></i> Change Password
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
className="hover:bg-gray-100 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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Header;
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import Parse from "parse";
|
|
||||||
// import FacebookLogin from "react-facebook-login";
|
|
||||||
|
|
||||||
const LoginFacebook = ({
|
|
||||||
FBCred,
|
|
||||||
thirdpartyLoginfn,
|
|
||||||
thirdpartyLoader,
|
|
||||||
setThirdpartyLoader
|
|
||||||
}) => {
|
|
||||||
const [isModal, setIsModal] = useState(false);
|
|
||||||
const [userDetails, setUserDetails] = useState({
|
|
||||||
Phone: "",
|
|
||||||
Company: "",
|
|
||||||
Name: "",
|
|
||||||
Email: ""
|
|
||||||
});
|
|
||||||
const [fBDetails, setFBDetails] = useState({
|
|
||||||
Id: "",
|
|
||||||
AccessToken: "",
|
|
||||||
Name: "",
|
|
||||||
Email: ""
|
|
||||||
});
|
|
||||||
const responseFacebook = async (response) => {
|
|
||||||
// console.log("response ", response);
|
|
||||||
if (response.userID) {
|
|
||||||
setThirdpartyLoader(true);
|
|
||||||
const details = {
|
|
||||||
Email: response.email,
|
|
||||||
Name: response.name
|
|
||||||
};
|
|
||||||
setUserDetails({ ...userDetails, ...details });
|
|
||||||
const fDetails = {
|
|
||||||
Id: response.userID,
|
|
||||||
AccessToken: response.accessToken,
|
|
||||||
Name: response.name,
|
|
||||||
Email: response.email
|
|
||||||
};
|
|
||||||
setFBDetails({ ...fBDetails, ...fDetails });
|
|
||||||
const res = await checkExtUser(fDetails);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const checkExtUser = async (details) => {
|
|
||||||
// const extUser = new Parse.Query("contracts_Users");
|
|
||||||
// extUser.equalTo("Email", details.Email);
|
|
||||||
// const extRes = await extUser.first();
|
|
||||||
const params = { email: details.Email };
|
|
||||||
const extRes = await Parse.Cloud.run("getUserDetails", params);
|
|
||||||
// console.log("extRes ", extRes);
|
|
||||||
if (extRes) {
|
|
||||||
const params = { ...details, Phone: extRes.get("Phone") };
|
|
||||||
const payload = await Parse.Cloud.run("facebooksign", params);
|
|
||||||
// console.log("payload ", payload);
|
|
||||||
if (payload && payload.sessiontoken) {
|
|
||||||
const billingDate =
|
|
||||||
extRes.get("Next_billing_date") && extRes.get("Next_billing_date");
|
|
||||||
// console.log("billingDate expired", billingDate > new Date());
|
|
||||||
const LocalUserDetails = {
|
|
||||||
name: details.Name,
|
|
||||||
email: details.Email,
|
|
||||||
phone: extRes.get("Phone"),
|
|
||||||
company: extRes.get("Company")
|
|
||||||
};
|
|
||||||
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
|
||||||
thirdpartyLoginfn(payload.sessiontoken, billingDate);
|
|
||||||
}
|
|
||||||
return { msg: "exist" };
|
|
||||||
} else {
|
|
||||||
setIsModal(true);
|
|
||||||
setThirdpartyLoader(false);
|
|
||||||
return { msg: "notexist" };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleSubmitbtn = async () => {
|
|
||||||
if (userDetails.Phone && userDetails.Company) {
|
|
||||||
setThirdpartyLoader(true);
|
|
||||||
const params = { ...fBDetails, Phone: userDetails.Phone };
|
|
||||||
const payload = await Parse.Cloud.run("facebooksign", params);
|
|
||||||
// console.log("payload ", payload);
|
|
||||||
|
|
||||||
if (payload && payload.sessiontoken) {
|
|
||||||
const params = {
|
|
||||||
userDetails: {
|
|
||||||
name: userDetails.Name,
|
|
||||||
email: userDetails.Email,
|
|
||||||
// "passsword":userDetails.Phone,
|
|
||||||
phone: userDetails.Phone,
|
|
||||||
role: "contracts_User",
|
|
||||||
company: userDetails.Company
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const userSignUp = await Parse.Cloud.run("usersignup", params);
|
|
||||||
// console.log("userSignUp ", userSignUp);
|
|
||||||
if (userSignUp && userSignUp.sessionToken) {
|
|
||||||
const LocalUserDetails = {
|
|
||||||
name: userDetails.Name,
|
|
||||||
email: userDetails.Email,
|
|
||||||
phone: userDetails.Phone,
|
|
||||||
company: userDetails.Company
|
|
||||||
};
|
|
||||||
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
|
||||||
thirdpartyLoginfn(userSignUp.sessionToken);
|
|
||||||
} else {
|
|
||||||
alert(userSignUp.message);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
alert("Internal server error !");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
alert("Please fill required details!");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div style={{ position: "relative" }}>
|
|
||||||
{thirdpartyLoader && (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "fixed",
|
|
||||||
width: "100vw",
|
|
||||||
height: "100vh",
|
|
||||||
backgroundColor: "rgba(0,0,0,0.2)",
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
zIndex: 2
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "fixed",
|
|
||||||
fontSize: "50px",
|
|
||||||
color: "#3ac9d6",
|
|
||||||
top: "50%",
|
|
||||||
left: "45%"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{/* <FacebookLogin
|
|
||||||
appId={FBCred}
|
|
||||||
fields="name,email,picture"
|
|
||||||
callback={responseFacebook}
|
|
||||||
cssClass="btn btn-info btn-md btn-fb"
|
|
||||||
icon="fa fa-facebook-f"
|
|
||||||
/> */}
|
|
||||||
{isModal && (
|
|
||||||
<div
|
|
||||||
className="modal fade show"
|
|
||||||
id="exampleModal"
|
|
||||||
tabIndex="-1"
|
|
||||||
role="dialog"
|
|
||||||
style={{ display: "block", zIndex: 1 }}
|
|
||||||
>
|
|
||||||
<div className="modal-dialog" role="document">
|
|
||||||
<div className="modal-content">
|
|
||||||
<div className="modal-header">
|
|
||||||
<h5 className="modal-title">Sign up form</h5>
|
|
||||||
<span>
|
|
||||||
<span></span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="modal-body">
|
|
||||||
<form>
|
|
||||||
<div className="form-group">
|
|
||||||
<label
|
|
||||||
htmlFor="Phone"
|
|
||||||
style={{ display: "flex" }}
|
|
||||||
className="col-form-label"
|
|
||||||
>
|
|
||||||
Phone{" "}
|
|
||||||
<span style={{ fontSize: 13, color: "red" }}>*</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="tel"
|
|
||||||
className="form-control"
|
|
||||||
id="Phone"
|
|
||||||
value={userDetails.Phone}
|
|
||||||
onChange={(e) =>
|
|
||||||
setUserDetails({
|
|
||||||
...userDetails,
|
|
||||||
Phone: e.target.value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="form-group">
|
|
||||||
<label
|
|
||||||
htmlFor="Company"
|
|
||||||
style={{ display: "flex" }}
|
|
||||||
className="col-form-label"
|
|
||||||
>
|
|
||||||
Company{" "}
|
|
||||||
<span style={{ fontSize: 13, color: "red" }}>*</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="form-control"
|
|
||||||
id="Company"
|
|
||||||
value={userDetails.Company}
|
|
||||||
onChange={(e) =>
|
|
||||||
setUserDetails({
|
|
||||||
...userDetails,
|
|
||||||
Company: e.target.value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => handleSubmitbtn()}
|
|
||||||
className="btn btn-info"
|
|
||||||
style={{ marginRight: 10 }}
|
|
||||||
>
|
|
||||||
Sign up
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn btn-secondary"
|
|
||||||
onClick={() => setIsModal(false)}
|
|
||||||
style={{ width: 90 }}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LoginFacebook;
|
|
||||||
@@ -1,328 +0,0 @@
|
|||||||
import React, { useState, useRef } from "react";
|
|
||||||
import Parse from "parse";
|
|
||||||
import { jwtDecode } from "jwt-decode";
|
|
||||||
import { useScript } from "../hook/useScript";
|
|
||||||
import ModalUi from "../primitives/ModalUi";
|
|
||||||
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const";
|
|
||||||
|
|
||||||
/*
|
|
||||||
* `GoogleSignInBtn`as it's name indicates it render google sign in button
|
|
||||||
* and in this `useScript` in which we have created for generate google sign button
|
|
||||||
* and when user click on sign in with google it will be verify on server side
|
|
||||||
* and then generate token
|
|
||||||
*/
|
|
||||||
const GoogleSignInBtn = ({
|
|
||||||
GoogleCred,
|
|
||||||
thirdpartyLoginfn,
|
|
||||||
thirdpartyLoader,
|
|
||||||
setThirdpartyLoader
|
|
||||||
}) => {
|
|
||||||
const [isModal, setIsModal] = useState(false);
|
|
||||||
const googleBtn = useRef();
|
|
||||||
const [userDetails, setUserDetails] = useState({
|
|
||||||
Phone: "",
|
|
||||||
Company: "",
|
|
||||||
Name: "",
|
|
||||||
Email: "",
|
|
||||||
Destination: ""
|
|
||||||
});
|
|
||||||
const [googleDetails, setGoogleDetails] = useState({
|
|
||||||
Id: "",
|
|
||||||
TokenId: "",
|
|
||||||
Gmail: "",
|
|
||||||
Name: ""
|
|
||||||
});
|
|
||||||
useScript("https://accounts.google.com/gsi/client", () => {
|
|
||||||
window.google.accounts.id.initialize({
|
|
||||||
client_id: GoogleCred,
|
|
||||||
callback: responseGoogle,
|
|
||||||
auto_select: false
|
|
||||||
});
|
|
||||||
window.google.accounts.id.renderButton(googleBtn.current, {
|
|
||||||
theme: "outline",
|
|
||||||
size: "large",
|
|
||||||
width: "187px"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const clearStorage = async () => {
|
|
||||||
if (Parse.User.current()) {
|
|
||||||
await Parse.User.logOut();
|
|
||||||
}
|
|
||||||
let baseUrl = localStorage.getItem("baseUrl");
|
|
||||||
let appid = localStorage.getItem("parseAppId");
|
|
||||||
let applogo = localStorage.getItem("appLogo");
|
|
||||||
let domain = localStorage.getItem("domain");
|
|
||||||
let appversion = localStorage.getItem("appVersion");
|
|
||||||
let appTitle = localStorage.getItem("appTitle");
|
|
||||||
let defaultmenuid = localStorage.getItem("defaultmenuid");
|
|
||||||
let PageLanding = localStorage.getItem("PageLanding");
|
|
||||||
let _appName = localStorage.getItem("_appName");
|
|
||||||
let _app_objectId = localStorage.getItem("_app_objectId");
|
|
||||||
let appName = localStorage.getItem("appName");
|
|
||||||
let userSettings = localStorage.getItem("userSettings");
|
|
||||||
|
|
||||||
localStorage.clear();
|
|
||||||
|
|
||||||
localStorage.setItem("baseUrl", baseUrl);
|
|
||||||
localStorage.setItem("parseAppId", appid);
|
|
||||||
localStorage.setItem("appLogo", applogo);
|
|
||||||
localStorage.setItem("domain", domain);
|
|
||||||
localStorage.setItem("appversion", appversion);
|
|
||||||
localStorage.setItem("appTitle", appTitle);
|
|
||||||
localStorage.setItem("defaultmenuid", defaultmenuid);
|
|
||||||
localStorage.setItem("PageLanding", PageLanding);
|
|
||||||
localStorage.setItem("_appName", _appName);
|
|
||||||
localStorage.setItem("_app_objectId", _app_objectId);
|
|
||||||
localStorage.setItem("appName", appName);
|
|
||||||
localStorage.setItem("userSettings", userSettings);
|
|
||||||
localStorage.setItem("baseUrl", baseUrl);
|
|
||||||
localStorage.setItem("parseAppId", appid);
|
|
||||||
};
|
|
||||||
const responseGoogle = async (response) => {
|
|
||||||
clearStorage();
|
|
||||||
setThirdpartyLoader(true);
|
|
||||||
// console.log("response ", response);
|
|
||||||
if (response.credential) {
|
|
||||||
const data = jwtDecode(response.credential);
|
|
||||||
// console.log("data ", data);
|
|
||||||
if (data.sub && data.email) {
|
|
||||||
const details = {
|
|
||||||
Email: data.email,
|
|
||||||
Name: data.name
|
|
||||||
};
|
|
||||||
setUserDetails({ ...userDetails, ...details });
|
|
||||||
const Gdetails = {
|
|
||||||
Id: data.sub,
|
|
||||||
TokenId: response.credential,
|
|
||||||
Gmail: data.email,
|
|
||||||
Name: data.name
|
|
||||||
};
|
|
||||||
setGoogleDetails({ ...googleDetails, ...Gdetails });
|
|
||||||
await checkExtUser(Gdetails);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const checkExtUser = async (details) => {
|
|
||||||
// const extUser = new Parse.Query("contracts_Users");
|
|
||||||
// extUser.equalTo("Email", details.Gmail);
|
|
||||||
// const extRes = await extUser.first();
|
|
||||||
const params = { email: details.Gmail };
|
|
||||||
const extRes = await Parse.Cloud.run("getUserDetails", params);
|
|
||||||
// console.log("extRes ", extRes);
|
|
||||||
if (extRes) {
|
|
||||||
const params = { ...details, Phone: extRes.get("Phone") };
|
|
||||||
const payload = await Parse.Cloud.run("googlesign", params);
|
|
||||||
// console.log("payload ", payload);
|
|
||||||
if (payload && payload.sessiontoken) {
|
|
||||||
// setThirdpartyLoader(true);
|
|
||||||
const billingDate =
|
|
||||||
extRes.get("Next_billing_date") && extRes.get("Next_billing_date");
|
|
||||||
// console.log("billingDate expired", billingDate > new Date());
|
|
||||||
const LocalUserDetails = {
|
|
||||||
name: details.Name,
|
|
||||||
email: details.Gmail,
|
|
||||||
phone: extRes.get("Phone"),
|
|
||||||
company: extRes.get("Company")
|
|
||||||
};
|
|
||||||
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
|
||||||
thirdpartyLoginfn(payload.sessiontoken, billingDate);
|
|
||||||
}
|
|
||||||
return { msg: "exist" };
|
|
||||||
} else {
|
|
||||||
setIsModal(true);
|
|
||||||
setThirdpartyLoader(false);
|
|
||||||
return { msg: "notexist" };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleSubmitbtn = async () => {
|
|
||||||
if (userDetails.Phone && userDetails.Company) {
|
|
||||||
setThirdpartyLoader(true);
|
|
||||||
// e.preventDefault()
|
|
||||||
// console.log("handelSubmit", userDetails);
|
|
||||||
const params = { ...googleDetails, Phone: userDetails.Phone };
|
|
||||||
const payload = await Parse.Cloud.run("googlesign", params);
|
|
||||||
|
|
||||||
// console.log("payload ", payload);
|
|
||||||
if (payload && payload.sessiontoken) {
|
|
||||||
const params = {
|
|
||||||
userDetails: {
|
|
||||||
name: userDetails.Name,
|
|
||||||
email: userDetails.Email,
|
|
||||||
// "passsword":userDetails.Phone,
|
|
||||||
phone: userDetails.Phone,
|
|
||||||
role: "contracts_User",
|
|
||||||
company: userDetails.Company,
|
|
||||||
jobTitle: userDetails.Destination
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const userSignUp = await Parse.Cloud.run("usersignup", params);
|
|
||||||
// console.log("userSignUp ", userSignUp);
|
|
||||||
if (userSignUp && userSignUp.sessionToken) {
|
|
||||||
const LocalUserDetails = {
|
|
||||||
name: userDetails.Name,
|
|
||||||
email: userDetails.Email,
|
|
||||||
phone: userDetails.Phone,
|
|
||||||
company: userDetails.Company
|
|
||||||
// jobTitle: userDetails.JobTitle
|
|
||||||
};
|
|
||||||
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
|
|
||||||
thirdpartyLoginfn(userSignUp.sessionToken);
|
|
||||||
} else {
|
|
||||||
alert(userSignUp.message);
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
payload &&
|
|
||||||
payload.message.replace(/ /g, "_") === "Internal_server_err"
|
|
||||||
) {
|
|
||||||
alert("Internal server error !");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
alert("Please fill required details!");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleCloseModal = () => {
|
|
||||||
setIsModal(false);
|
|
||||||
Parse.User.logOut();
|
|
||||||
|
|
||||||
let appdata = localStorage.getItem("userSettings");
|
|
||||||
let applogo = localStorage.getItem("appLogo");
|
|
||||||
let appName = localStorage.getItem("appName");
|
|
||||||
let defaultmenuid = localStorage.getItem("defaultmenuid");
|
|
||||||
let PageLanding = localStorage.getItem("PageLanding");
|
|
||||||
let domain = localStorage.getItem("domain");
|
|
||||||
let _appName = localStorage.getItem("_appName");
|
|
||||||
let baseUrl = localStorage.getItem("baseUrl");
|
|
||||||
let appid = localStorage.getItem("parseAppId");
|
|
||||||
|
|
||||||
localStorage.clear();
|
|
||||||
|
|
||||||
localStorage.setItem("appLogo", applogo);
|
|
||||||
localStorage.setItem("appName", appName);
|
|
||||||
localStorage.setItem("_appName", _appName);
|
|
||||||
localStorage.setItem("defaultmenuid", defaultmenuid);
|
|
||||||
localStorage.setItem("PageLanding", PageLanding);
|
|
||||||
localStorage.setItem("domain", domain);
|
|
||||||
localStorage.setItem("userSettings", appdata);
|
|
||||||
localStorage.setItem("baseUrl", baseUrl);
|
|
||||||
localStorage.setItem("parseAppId", appid);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div style={{ position: "relative" }}>
|
|
||||||
{thirdpartyLoader && (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "fixed",
|
|
||||||
width: "100vw",
|
|
||||||
height: "100vh",
|
|
||||||
backgroundColor: "rgba(0,0,0,0.2)",
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
zIndex: 2
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "fixed",
|
|
||||||
fontSize: "50px",
|
|
||||||
color: "#3ac9d6",
|
|
||||||
top: "50%",
|
|
||||||
left: "45%"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div ref={googleBtn} className="text-sm"></div>
|
|
||||||
<ModalUi showClose={false} isOpen={isModal} title="Sign up form">
|
|
||||||
<form className="px-4 py-3">
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="Phone"
|
|
||||||
style={{ display: "flex" }}
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Phone <span style={{ fontSize: 13, color: "red" }}>*</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="tel"
|
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
|
||||||
id="Phone"
|
|
||||||
value={userDetails.Phone}
|
|
||||||
onChange={(e) =>
|
|
||||||
setUserDetails({
|
|
||||||
...userDetails,
|
|
||||||
Phone: e.target.value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="Company"
|
|
||||||
style={{ display: "flex" }}
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Company <span style={{ fontSize: 13, color: "red" }}>*</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
|
||||||
id="Company"
|
|
||||||
value={userDetails.Company}
|
|
||||||
onChange={(e) =>
|
|
||||||
setUserDetails({
|
|
||||||
...userDetails,
|
|
||||||
Company: e.target.value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="JobTitle"
|
|
||||||
style={{ display: "flex" }}
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
Job Title <span style={{ fontSize: 13, color: "red" }}>*</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
|
||||||
id="JobTitle"
|
|
||||||
value={userDetails.Destination}
|
|
||||||
onChange={(e) =>
|
|
||||||
setUserDetails({
|
|
||||||
...userDetails,
|
|
||||||
Destination: e.target.value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="px-3 py-1.5 text-white rounded shadow-md text-center focus:outline-none "
|
|
||||||
onClick={() => handleSubmitbtn()}
|
|
||||||
style={{ marginRight: 10, backgroundColor: modalSubmitBtnColor }}
|
|
||||||
>
|
|
||||||
Sign up
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="p-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none"
|
|
||||||
onClick={handleCloseModal}
|
|
||||||
style={{ width: 90, backgroundColor: modalCancelBtnColor }}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</ModalUi>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default GoogleSignInBtn;
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { Document, Page } from "react-pdf";
|
|
||||||
import { Stage, Layer, Rect } from "react-konva";
|
|
||||||
const RenderDebugPdf = (props) => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "sticky",
|
|
||||||
top: 0,
|
|
||||||
padding: 10,
|
|
||||||
zIndex: 1,
|
|
||||||
backgroundColor: "white",
|
|
||||||
border: "1px solid grey",
|
|
||||||
margin: "5px 0"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{`Co-ordinates: X - ${props.hoverCoordinates.x}, Y - ${props.hoverCoordinates.y}`}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
position: "relative",
|
|
||||||
border: "1px solid grey",
|
|
||||||
overflow: "auto"
|
|
||||||
}}
|
|
||||||
onMouseMove={props.handleMouseMoveDiv}
|
|
||||||
>
|
|
||||||
<Document
|
|
||||||
onLoadError={() => {
|
|
||||||
const load = {
|
|
||||||
status: false,
|
|
||||||
type: "failed"
|
|
||||||
};
|
|
||||||
props.setPdfLoadFail(load);
|
|
||||||
}}
|
|
||||||
loading={"Loading Document.."}
|
|
||||||
onLoadSuccess={props.pageDetails}
|
|
||||||
ref={props.pdfRef}
|
|
||||||
file={props.pdfUrl}
|
|
||||||
>
|
|
||||||
<Page
|
|
||||||
onLoadSuccess={props.handlePageLoadSuccess}
|
|
||||||
pageNumber={props.pageNumber}
|
|
||||||
renderAnnotationLayer={false}
|
|
||||||
renderTextLayer={false}
|
|
||||||
onGetAnnotationsError={(error) => {
|
|
||||||
console.log("annotation error", error);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Document>
|
|
||||||
|
|
||||||
<Stage
|
|
||||||
onMouseMove={props.handleMouseMove}
|
|
||||||
onMouseDown={props.handleMouseDown}
|
|
||||||
onMouseUp={props.handleMouseUp}
|
|
||||||
width={props.pdfDimension.width}
|
|
||||||
height={props.pdfDimension.height}
|
|
||||||
style={{ position: "absolute", top: 0, left: 0 }}
|
|
||||||
>
|
|
||||||
<Layer>
|
|
||||||
{props.annotations
|
|
||||||
.filter((value) => value.page === props.pageNumber)
|
|
||||||
.map((value) => {
|
|
||||||
return (
|
|
||||||
<Rect
|
|
||||||
key={value.key}
|
|
||||||
x={value.x}
|
|
||||||
y={value.y}
|
|
||||||
width={value.width}
|
|
||||||
height={value.height}
|
|
||||||
fill="transparent"
|
|
||||||
stroke="black"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Layer>
|
|
||||||
</Stage>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default RenderDebugPdf;
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { Helmet } from "react-helmet";
|
|
||||||
|
|
||||||
function Title({ title, drive }) {
|
|
||||||
return (
|
|
||||||
<Helmet>
|
|
||||||
<title>{drive ? title : `${title} - OpenSign™`}</title>
|
|
||||||
<meta name="description" content={`${title} - OpenSign™`} />
|
|
||||||
<link
|
|
||||||
rel="icon"
|
|
||||||
type="image/png"
|
|
||||||
href={localStorage.getItem("fev_Icon")}
|
|
||||||
sizes="40x40"
|
|
||||||
/>
|
|
||||||
</Helmet>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Title;
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import "../../styles/loader.css";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import { openInNewTab } from "../../constant/Utils";
|
|
||||||
|
|
||||||
const DashboardButton = (props) => {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
function openReport() {
|
|
||||||
if (props.Data && props.Data.Redirect_type) {
|
|
||||||
const Redirect_type = props.Data.Redirect_type;
|
|
||||||
const id = props.Data.Redirect_id;
|
|
||||||
if (Redirect_type === "Form") {
|
|
||||||
navigate(`/form/${id}`);
|
|
||||||
} else if (Redirect_type === "Report") {
|
|
||||||
navigate(`/report/${id}`);
|
|
||||||
} else if (Redirect_type === "Url") {
|
|
||||||
openInNewTab(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
onClick={() => openReport()}
|
|
||||||
className={`${
|
|
||||||
props.Data && props.Data.Redirect_type
|
|
||||||
? "cursor-pointer"
|
|
||||||
: "cursor-default"
|
|
||||||
} w-full px-3 py-2 flex text-white rounded-md shadow overflow-hidden`}
|
|
||||||
>
|
|
||||||
<div className="flex items-center justify-start gap-5">
|
|
||||||
<span className="rounded-full bg-black bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
|
|
||||||
<i
|
|
||||||
className={`${
|
|
||||||
props.Icon ? props.Icon : "fa fa-solid fa-info"
|
|
||||||
} text-[25px] lg:text-[30px]`}
|
|
||||||
></i>
|
|
||||||
</span>
|
|
||||||
<div className="">
|
|
||||||
<div className="text-base lg:text-lg text-black"> {props.Label}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DashboardButton;
|
|
||||||
@@ -1,363 +0,0 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
|
||||||
import axios from "axios";
|
|
||||||
import Parse from "parse";
|
|
||||||
import getReplacedHashQuery from "../../constant/getReplacedHashQuery";
|
|
||||||
import "../../styles/loader.css";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import Tooltip from "../../primitives/Tooltip";
|
|
||||||
|
|
||||||
const DashboardCard = (props) => {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
|
|
||||||
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
|
|
||||||
const [response, setresponse] = useState("");
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
|
|
||||||
const renderData = async () => {
|
|
||||||
if (props.Data.queryType === "function") {
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
let url = `${parseBaseUrl}${props.Data.class}`;
|
|
||||||
const headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId,
|
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
|
||||||
};
|
|
||||||
let body = {};
|
|
||||||
let currentUser;
|
|
||||||
let currentUser1 = Parse.User.current();
|
|
||||||
currentUser = currentUser1.id;
|
|
||||||
let res;
|
|
||||||
if (localStorage.getItem("Extand_Class")) {
|
|
||||||
let data = JSON.parse(localStorage.getItem("Extand_Class"));
|
|
||||||
res = data[0];
|
|
||||||
} else {
|
|
||||||
res = await Parse.Cloud.run("getUserDetails", {
|
|
||||||
email: currentUser.get("email")
|
|
||||||
});
|
|
||||||
if (res) res = res.toJSON();
|
|
||||||
}
|
|
||||||
if (res) {
|
|
||||||
let json = res;
|
|
||||||
var reg = /(\#.*?\#)/gi; // eslint-disable-line
|
|
||||||
var str = props.Data.query;
|
|
||||||
var test = "";
|
|
||||||
|
|
||||||
if (props.Data.extendkey) {
|
|
||||||
let a = props.Data.extendkey.split(".");
|
|
||||||
if (a.length > 0) {
|
|
||||||
test = str.replace(reg, json[a[0]][a[1]]);
|
|
||||||
} else {
|
|
||||||
test = str.replace(reg, json[a[0]]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
test = str.replace(reg, json.objectId);
|
|
||||||
}
|
|
||||||
if (str.replace(reg, json.objectId)) {
|
|
||||||
body = test;
|
|
||||||
} else {
|
|
||||||
body = props.Data.query;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
body = props.Data.query;
|
|
||||||
}
|
|
||||||
await axios.post(url, body, { headers: headers }).then((res) => {
|
|
||||||
if (res) {
|
|
||||||
if (res.data.result.length > 0) {
|
|
||||||
setresponse(res.data.result[0][props.Data.key]);
|
|
||||||
} else {
|
|
||||||
setresponse(0);
|
|
||||||
}
|
|
||||||
setLoading(false);
|
|
||||||
} else {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Problem", e.message);
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
const currentUser = Parse.User.current();
|
|
||||||
let reg1 = /(\#.*?\#)/gi; // eslint-disable-line
|
|
||||||
let _query = props.Data.query;
|
|
||||||
let str = _query;
|
|
||||||
var test1;
|
|
||||||
str = str.split("#$").join("$");
|
|
||||||
str = str.split("#*").join("$");
|
|
||||||
str = str.split("_DOT_").join(".");
|
|
||||||
|
|
||||||
if (str.includes("#")) {
|
|
||||||
let resr;
|
|
||||||
if (localStorage.getItem("Extand_Class")) {
|
|
||||||
let data = JSON.parse(localStorage.getItem("Extand_Class"));
|
|
||||||
resr = data[0];
|
|
||||||
} else {
|
|
||||||
resr = await Parse.Cloud.run("getUserDetails", {
|
|
||||||
email: currentUser.get("email")
|
|
||||||
});
|
|
||||||
if (resr) resr = resr.toJSON();
|
|
||||||
}
|
|
||||||
|
|
||||||
let json = resr;
|
|
||||||
let output = str.match(reg1);
|
|
||||||
const HashCount = str.match(reg1);
|
|
||||||
if (HashCount.length > 1) {
|
|
||||||
// `getReplacedHashQuery` is used to replace multiple hash keyword with actual values from query
|
|
||||||
test1 = getReplacedHashQuery(str, json);
|
|
||||||
} else {
|
|
||||||
output = output.join();
|
|
||||||
output = output.substring(1, output.length - 1);
|
|
||||||
output = output.split(".");
|
|
||||||
if (output.length > 1) {
|
|
||||||
test1 = str.replace(reg1, json[output[0]][output[1]]);
|
|
||||||
} else if (json[output[0]]) {
|
|
||||||
if (typeof json[output[0]] === "object") {
|
|
||||||
test1 = str.replace(reg1, JSON.stringify(json[output[0]]));
|
|
||||||
} else {
|
|
||||||
test1 = str.replace(reg1, json[output[0]]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
test1 = str.replace(reg1, currentUser.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
test1 = str.replace(reg1, currentUser.id);
|
|
||||||
}
|
|
||||||
let url = `${parseBaseUrl}classes/${props.Data.class}?${test1}`;
|
|
||||||
const headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId,
|
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
|
||||||
};
|
|
||||||
// handle need your sign report count
|
|
||||||
if (props.Data.Redirect_id === "4Hhwbp482K") {
|
|
||||||
const params = {
|
|
||||||
reportId: props.Data.Redirect_id,
|
|
||||||
skip: 0,
|
|
||||||
limit: 200
|
|
||||||
};
|
|
||||||
const url = `${parseBaseUrl}/functions/getReport`;
|
|
||||||
await axios
|
|
||||||
.post(url, params, {
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId,
|
|
||||||
sessiontoken: localStorage.getItem("accesstoken")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
const listData = res.data?.result.filter(
|
|
||||||
(x) => x.Signers.length > 0
|
|
||||||
);
|
|
||||||
let arr = [];
|
|
||||||
for (const obj of listData) {
|
|
||||||
const isSigner = obj.Signers.some(
|
|
||||||
(item) => item.UserId.objectId === currentUser.id
|
|
||||||
);
|
|
||||||
if (isSigner) {
|
|
||||||
let isRecord;
|
|
||||||
if (obj?.AuditTrail && obj?.AuditTrail.length > 0) {
|
|
||||||
isRecord = obj?.AuditTrail.some(
|
|
||||||
(item) =>
|
|
||||||
item?.UserPtr?.UserId?.objectId === currentUser.id &&
|
|
||||||
item.Activity === "Signed"
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
isRecord = false;
|
|
||||||
}
|
|
||||||
if (isRecord === false) {
|
|
||||||
arr.push(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setresponse(arr.length);
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await axios.get(url, { headers: headers }).then((res) => {
|
|
||||||
if (res.data.results.length > 0) {
|
|
||||||
setLoading(false);
|
|
||||||
if (props.Data.key !== "count") {
|
|
||||||
setresponse(res.data.results[0][props.Data.key]);
|
|
||||||
} else {
|
|
||||||
setresponse(res.data[props.Data.key]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setresponse(0);
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Problem", e);
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const filterRender = async () => {
|
|
||||||
if (props.FilterData && props.FilterData.queryType === "function") {
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
let url = `${parseBaseUrl}${props.FilterData.class}`;
|
|
||||||
const headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId,
|
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
|
||||||
};
|
|
||||||
|
|
||||||
let body = {};
|
|
||||||
var str = props.FilterData.query;
|
|
||||||
let restr = JSON.stringify(props.FilterData.query);
|
|
||||||
var reg = /(\#.*?\#)/gi; // eslint-disable-line
|
|
||||||
restr = restr.split("#$").join("$");
|
|
||||||
restr = restr.split("#*").join("$");
|
|
||||||
restr = restr.split("_DOT_").join(".");
|
|
||||||
|
|
||||||
if (restr.includes("#")) {
|
|
||||||
try {
|
|
||||||
const currentUser = Parse.User.current();
|
|
||||||
let res;
|
|
||||||
if (localStorage.getItem("Extand_Class")) {
|
|
||||||
let data = JSON.parse(localStorage.getItem("Extand_Class"));
|
|
||||||
res = data[0];
|
|
||||||
} else {
|
|
||||||
let resr = await Parse.Cloud.run("getUserDetails", {
|
|
||||||
email: currentUser.get("email")
|
|
||||||
});
|
|
||||||
if (res) res = resr.toJSON();
|
|
||||||
}
|
|
||||||
|
|
||||||
let json = res;
|
|
||||||
let output = restr.match(reg);
|
|
||||||
if (output.length === 1) {
|
|
||||||
output = output.filter((x) => x === "#filterCondition#");
|
|
||||||
if (output.length === 1) {
|
|
||||||
str = str.replace("#filterCondition#", props.Filter);
|
|
||||||
} else {
|
|
||||||
output = output.join();
|
|
||||||
output = output.substring(1, output.length - 1);
|
|
||||||
output = output.split(".");
|
|
||||||
if (output.length > 0) {
|
|
||||||
str = str.replace(reg, json[output[0]][output[1]]);
|
|
||||||
} else {
|
|
||||||
str = str.replace(reg, json[output[0]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (output.length === 2) {
|
|
||||||
output = output.filter((x) => x !== "#filterCondition#");
|
|
||||||
if (output.length === 1) {
|
|
||||||
str = str.replace("#filterCondition#", props.Filter);
|
|
||||||
output = output.join();
|
|
||||||
output = output.substring(1, output.length - 1);
|
|
||||||
output = output.split(".");
|
|
||||||
if (output.length > 1) {
|
|
||||||
str = str.replace(reg, json[output[0]][output[1]]);
|
|
||||||
} else {
|
|
||||||
str = str.replace(reg, json[output[0]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
body = str;
|
|
||||||
await axios
|
|
||||||
.post(url, body, { headers: headers })
|
|
||||||
.then((response) => {
|
|
||||||
try {
|
|
||||||
if (response.data.result.length > 0) {
|
|
||||||
setresponse(response.data.result[0][props.FilterData.key]);
|
|
||||||
setLoading(false);
|
|
||||||
} else {
|
|
||||||
setresponse("0");
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Problem", e);
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const setFormat = (val) => {
|
|
||||||
switch (props.Format) {
|
|
||||||
case "INR":
|
|
||||||
if (val)
|
|
||||||
return Number(val)
|
|
||||||
.toFixed(2)
|
|
||||||
.toString()
|
|
||||||
.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
renderData();
|
|
||||||
//eslint-disable-next-line
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (props.Filter) {
|
|
||||||
filterRender();
|
|
||||||
}
|
|
||||||
//eslint-disable-next-line
|
|
||||||
}, [props.Filter]);
|
|
||||||
|
|
||||||
function openReport() {
|
|
||||||
if (props.Data && props.Data.Redirect_type) {
|
|
||||||
const Redirect_type = props.Data.Redirect_type;
|
|
||||||
const id = props.Data.Redirect_id;
|
|
||||||
if (Redirect_type === "Form") {
|
|
||||||
navigate(`/form/${id}`);
|
|
||||||
} else if (Redirect_type === "Report") {
|
|
||||||
navigate(`/report/${id}`);
|
|
||||||
} else if (Redirect_type === "Url") {
|
|
||||||
window.location = id;
|
|
||||||
} else if (Redirect_type === "Microapp") {
|
|
||||||
navigate(`/microapp/${id}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
onClick={() => openReport()}
|
|
||||||
className={`${
|
|
||||||
props.Data && props.Data.Redirect_type
|
|
||||||
? "cursor-pointer"
|
|
||||||
: "cursor-default"
|
|
||||||
} w-full h-[140px] px-3 pt-4 pb-10 text-white rounded-md shadow overflow-hidden relative`}
|
|
||||||
>
|
|
||||||
<div className="flex items-center justify-start gap-5">
|
|
||||||
<span className="rounded-full bg-black bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
|
|
||||||
<i
|
|
||||||
className={`${
|
|
||||||
props.Icon ? props.Icon : "fa fa-solid fa-info"
|
|
||||||
} text-[25px] lg:text-[30px]`}
|
|
||||||
></i>
|
|
||||||
</span>
|
|
||||||
<div className="">
|
|
||||||
<div className="text-base lg:text-lg"> {props.Label}</div>
|
|
||||||
<div className="text-2xl font-light">
|
|
||||||
{loading ? <div className="loader-01"></div> : setFormat(response)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="text-xs absolute top-2 right-1">
|
|
||||||
<Tooltip id={props.Label} iconColor={"white"} message={props?.Data?.tourMessage} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DashboardCard;
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import Parse from "parse";
|
|
||||||
import ReportTable from "../../primitives/GetReportDisplay";
|
|
||||||
import reportJson from "../../json/ReportJson";
|
|
||||||
import axios from "axios";
|
|
||||||
function DashboardReport(props) {
|
|
||||||
// console.log("props ", props)
|
|
||||||
const [List, setList] = useState([]);
|
|
||||||
const [isLoader, setIsLoader] = useState(true);
|
|
||||||
const [reportName, setReportName] = useState("");
|
|
||||||
const [actions, setActions] = useState([]);
|
|
||||||
const [heading, setHeading] = useState([]);
|
|
||||||
const [isNextRecord, setIsNextRecord] = useState(false);
|
|
||||||
const [isMoreDocs, setIsMoreDocs] = useState(true);
|
|
||||||
const abortController = new AbortController();
|
|
||||||
const docPerPage = 5;
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setReportName("");
|
|
||||||
getReportData(props.Record.reportId);
|
|
||||||
|
|
||||||
// Function returned from useEffect is called on unmount
|
|
||||||
return () => {
|
|
||||||
setIsLoader(true);
|
|
||||||
setList([]);
|
|
||||||
setIsNextRecord(false);
|
|
||||||
// Here it'll abort the fetch
|
|
||||||
abortController.abort();
|
|
||||||
};
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [props.Record.reportId]);
|
|
||||||
|
|
||||||
// below useEffect call when isNextRecord state is true and fetch next record
|
|
||||||
useEffect(() => {
|
|
||||||
if (isNextRecord) {
|
|
||||||
getReportData(props.Record.reportId, List.length, 200);
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [isNextRecord]);
|
|
||||||
|
|
||||||
const getReportData = async (id, skipUserRecord = 0, limit = 200) => {
|
|
||||||
setIsLoader(true);
|
|
||||||
const json = reportJson(id);
|
|
||||||
if (json) {
|
|
||||||
setActions(json.actions);
|
|
||||||
setReportName(json.reportName);
|
|
||||||
setHeading(json.heading);
|
|
||||||
const currentUser = Parse.User.current().id;
|
|
||||||
|
|
||||||
const headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
|
||||||
sessiontoken: localStorage.getItem("accesstoken")
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
const params = { reportId: id, skip: skipUserRecord, limit: limit };
|
|
||||||
const url = `${localStorage.getItem("baseUrl")}/functions/getReport`;
|
|
||||||
const res = await axios.post(url, params, {
|
|
||||||
headers: headers,
|
|
||||||
signal: abortController.signal // is used to cancel fetch query
|
|
||||||
});
|
|
||||||
if (id === "5Go51Q7T8r") {
|
|
||||||
const listData = res.data?.result.filter((x) => x.Signers.length > 0);
|
|
||||||
let arr = [];
|
|
||||||
for (const obj of listData) {
|
|
||||||
const isSigner = obj.Signers.some(
|
|
||||||
(item) => item.UserId.objectId === currentUser
|
|
||||||
);
|
|
||||||
if (isSigner) {
|
|
||||||
let isRecord;
|
|
||||||
if (obj?.AuditTrail && obj?.AuditTrail.length > 0) {
|
|
||||||
isRecord = obj?.AuditTrail.some(
|
|
||||||
(item) =>
|
|
||||||
item?.UserPtr?.UserId?.objectId === currentUser &&
|
|
||||||
item.Activity === "Signed"
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
isRecord = false;
|
|
||||||
}
|
|
||||||
if (isRecord === false) {
|
|
||||||
arr.push(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (arr.length === docPerPage) {
|
|
||||||
setIsMoreDocs(true);
|
|
||||||
} else {
|
|
||||||
setIsMoreDocs(false);
|
|
||||||
}
|
|
||||||
setList((prevRecord) =>
|
|
||||||
prevRecord.length > 0 ? [...prevRecord, ...arr] : arr
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if (res.data.result.length === docPerPage) {
|
|
||||||
setIsMoreDocs(true);
|
|
||||||
} else {
|
|
||||||
setIsMoreDocs(false);
|
|
||||||
}
|
|
||||||
setIsNextRecord(false);
|
|
||||||
setList((prevRecord) =>
|
|
||||||
prevRecord.length > 0
|
|
||||||
? [...prevRecord, ...res.data.result]
|
|
||||||
: res.data.result
|
|
||||||
);
|
|
||||||
}
|
|
||||||
setIsLoader(false);
|
|
||||||
} catch (err) {
|
|
||||||
const isCancel = axios.isCancel(err);
|
|
||||||
if (!isCancel) {
|
|
||||||
console.log("err ", err);
|
|
||||||
setIsLoader(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setIsLoader(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{isLoader ? (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: "100vh",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{reportName ? (
|
|
||||||
<ReportTable
|
|
||||||
ReportName={reportName}
|
|
||||||
List={List}
|
|
||||||
setList={setList}
|
|
||||||
actions={actions}
|
|
||||||
heading={heading}
|
|
||||||
setIsNextRecord={setIsNextRecord}
|
|
||||||
isMoreDocs={isMoreDocs}
|
|
||||||
docPerPage={docPerPage}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div className="flex items-center justify-center h-[100px] w-full bg-white rounded">
|
|
||||||
<div className="text-center">
|
|
||||||
<p className="text-xl text-black">Report Not Found</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DashboardReport;
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
import React, { Suspense, lazy } from "react";
|
|
||||||
const DashboardButton = lazy(() => import("./DashboardButton"));
|
|
||||||
const DashboardCard = lazy(() => import("./DashboardCard"));
|
|
||||||
const DashboardReport = lazy(() => import("./DashboardReport"));
|
|
||||||
const buttonList = [
|
|
||||||
{
|
|
||||||
label: "Sign yourself",
|
|
||||||
redirectId: "sHAnZphf69",
|
|
||||||
redirectType: "Form",
|
|
||||||
icon: "fas fa-pen-nib"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Request signature",
|
|
||||||
redirectId: "8mZzFxbG1z",
|
|
||||||
redirectType: "Form",
|
|
||||||
icon: "fa-solid fa-paper-plane"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
const GetDashboard = (props) => {
|
|
||||||
const Button = ({ label, redirectId, redirectType, icon }) => (
|
|
||||||
<div className={"bg-white rounded-md shadow w-full"}>
|
|
||||||
<Suspense
|
|
||||||
fallback={
|
|
||||||
<div style={{ height: "300px" }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
marginLeft: "45%",
|
|
||||||
marginTop: "150px",
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<DashboardButton
|
|
||||||
Icon={icon}
|
|
||||||
Label={label}
|
|
||||||
Data={{ Redirect_type: redirectType, Redirect_id: redirectId }}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
const renderSwitchWithTour = (col) => {
|
|
||||||
switch (col.widget.type) {
|
|
||||||
case "Card":
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={"bg-[#2ed8b6] rounded-md shadow mb-3 md:mb-0"}
|
|
||||||
data-tut={col.widget.data.tourSection}
|
|
||||||
style={{ background: col.widget.bgColor }}
|
|
||||||
>
|
|
||||||
<Suspense
|
|
||||||
fallback={
|
|
||||||
<div style={{ height: "300px" }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
marginLeft: "45%",
|
|
||||||
marginTop: "150px",
|
|
||||||
fontSize: "45px",
|
|
||||||
color: "#3dd3e0"
|
|
||||||
}}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<DashboardCard
|
|
||||||
Icon={col.widget.icon}
|
|
||||||
Label={col.widget.label}
|
|
||||||
Format={col.widget.format && col.widget.format}
|
|
||||||
Data={col.widget.data}
|
|
||||||
FilterData={col.widget.filter}
|
|
||||||
DefaultQuery={props.DefaultQuery}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "report": {
|
|
||||||
return (
|
|
||||||
<div data-tut={col.widget.data.tourSection}>
|
|
||||||
<Suspense fallback={<div>please wait</div>}>
|
|
||||||
<div className="mb-3 md:mb-0">
|
|
||||||
<DashboardReport Record={col.widget} />
|
|
||||||
</div>
|
|
||||||
</Suspense>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const renderSwitch = (col) => {
|
|
||||||
switch (col.widget.type) {
|
|
||||||
case "Card":
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={"bg-[#2ed8b6] rounded-md shadow mb-3 md:mb-0"}
|
|
||||||
style={{ background: col.widget.bgColor }}
|
|
||||||
>
|
|
||||||
<Suspense fallback={<div>please wait</div>}>
|
|
||||||
<DashboardCard
|
|
||||||
Icon={col.widget.icon}
|
|
||||||
Label={col.widget.label}
|
|
||||||
Format={col.widget.format && col.widget.format}
|
|
||||||
Data={col.widget.data}
|
|
||||||
FilterData={col.widget.filter}
|
|
||||||
DefaultQuery={props.DefaultQuery}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "report": {
|
|
||||||
return (
|
|
||||||
<Suspense fallback={<div>please wait</div>}>
|
|
||||||
<div className="mb-3 md:mb-0">
|
|
||||||
<DashboardReport Record={col.widget} />
|
|
||||||
</div>
|
|
||||||
</Suspense>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<div
|
|
||||||
data-tut={"tourbutton"}
|
|
||||||
className="flex flex-col md:flex-row gap-6 md:gap-8"
|
|
||||||
>
|
|
||||||
{buttonList.map((btn) => (
|
|
||||||
<Button
|
|
||||||
key={btn.label}
|
|
||||||
label={btn.label}
|
|
||||||
redirectType={btn.redirectType}
|
|
||||||
redirectId={btn.redirectId}
|
|
||||||
icon={btn.icon}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{props.dashboard.map((val, key) => (
|
|
||||||
<div key={"a" + key} className="row">
|
|
||||||
{val.columns.map((col, i) =>
|
|
||||||
col.widget.data && col.widget.data.tourSection ? (
|
|
||||||
<div key={i} className={props.classnameArray[key][i]}>
|
|
||||||
{renderSwitchWithTour(col)}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div key={i} className={props.classnameArray[key][i]}>
|
|
||||||
{renderSwitch(col)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default GetDashboard;
|
|
||||||
@@ -1,656 +0,0 @@
|
|||||||
import React, { useState, useEffect, useRef } from "react";
|
|
||||||
import folder from "../../assets/images/folder.png";
|
|
||||||
import "../../styles/opensigndrive.css";
|
|
||||||
import pdfLogo from "../../assets/images/pdf3.png";
|
|
||||||
import axios from "axios";
|
|
||||||
import * as ContextMenu from "@radix-ui/react-context-menu";
|
|
||||||
import { saveAs } from "file-saver";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import Table from "react-bootstrap/Table";
|
|
||||||
import * as HoverCard from "@radix-ui/react-hover-card";
|
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
import FolderModal from "../shared/fields/FolderModal";
|
|
||||||
|
|
||||||
function DriveBody(props) {
|
|
||||||
const [rename, setRename] = useState("");
|
|
||||||
const [renameValue, setRenameValue] = useState("");
|
|
||||||
const inputRef = useRef(null);
|
|
||||||
const [isOpenMoveModal, setIsOpenMoveModal] = useState(false);
|
|
||||||
const [selectDoc, setSelectDoc] = useState();
|
|
||||||
const [isDeleteDoc, setIsDeleteDoc] = useState(false);
|
|
||||||
const contextMenu = [
|
|
||||||
{ type: "Download", icon: "fa-solid fa-arrow-down" },
|
|
||||||
{ type: "Rename", icon: "fa-solid fa-font" },
|
|
||||||
{ type: "Move", icon: "fa-solid fa-file-export" },
|
|
||||||
{ type: "Delete", icon: "fa-solid fa-trash" }
|
|
||||||
];
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
//to focus input box on press rename to change doc name
|
|
||||||
useEffect(() => {
|
|
||||||
if (rename && inputRef.current) {
|
|
||||||
setTimeout(() => {
|
|
||||||
inputRef.current.focus();
|
|
||||||
}, 10);
|
|
||||||
}
|
|
||||||
}, [rename]);
|
|
||||||
|
|
||||||
//function to handle folder component
|
|
||||||
const handleOnclikFolder = (data) => {
|
|
||||||
const folderData = {
|
|
||||||
name: data.Name,
|
|
||||||
objectId: data.objectId
|
|
||||||
};
|
|
||||||
props.setFolderName((prev) => [...prev, folderData]);
|
|
||||||
props.setIsLoading({
|
|
||||||
isLoad: true,
|
|
||||||
message: "This might take some time"
|
|
||||||
});
|
|
||||||
props.setDocId(data.objectId);
|
|
||||||
props.setPdfData([]);
|
|
||||||
props.setSkip(0);
|
|
||||||
};
|
|
||||||
//function for change doc name and update doc name in _document class
|
|
||||||
const handledRenameDoc = async (data) => {
|
|
||||||
setRename("");
|
|
||||||
const trimmedValue = renameValue.trim();
|
|
||||||
if (trimmedValue.length > 0) {
|
|
||||||
const updateName = {
|
|
||||||
Name: renameValue
|
|
||||||
};
|
|
||||||
const docId = data.objectId;
|
|
||||||
const docData = props.pdfData;
|
|
||||||
const updatedData = docData.map((item) => {
|
|
||||||
if (item.objectId === docId) {
|
|
||||||
// If the item's ID matches the target ID, update the name
|
|
||||||
return { ...item, Name: renameValue };
|
|
||||||
}
|
|
||||||
// If the item's ID doesn't match, keep it unchanged
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
props.setPdfData(updatedData);
|
|
||||||
await axios
|
|
||||||
.put(
|
|
||||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
|
||||||
"_appName"
|
|
||||||
)}_Document/${docId}`,
|
|
||||||
updateName,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
// const res = result.data;
|
|
||||||
// console.log("res", res);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log("Err ", err);
|
|
||||||
props.setIsAlert({
|
|
||||||
isShow: true,
|
|
||||||
alertMessage: "something went wrong"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//function for navigate user to microapp-signature component
|
|
||||||
const checkPdfStatus = async (data) => {
|
|
||||||
const signerExist = data.Signers && data.Signers;
|
|
||||||
const isDecline = data.IsDeclined && data.IsDeclined;
|
|
||||||
const isPlaceholder = data.Placeholders && data.Placeholders;
|
|
||||||
const signedUrl = data.SignedUrl;
|
|
||||||
//checking if document has completed and request signature flow
|
|
||||||
if (data?.IsCompleted && signerExist?.length > 0) {
|
|
||||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
|
||||||
}
|
|
||||||
//checking if document has completed and signyour-self flow
|
|
||||||
else if (!signerExist && !isPlaceholder) {
|
|
||||||
navigate(`/signaturePdf/${data.objectId}`);
|
|
||||||
}
|
|
||||||
//checking if document has declined by someone
|
|
||||||
else if (isDecline) {
|
|
||||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
|
||||||
//checking draft type document
|
|
||||||
} else if (
|
|
||||||
signerExist?.length > 0 &&
|
|
||||||
isPlaceholder?.length > 0 &&
|
|
||||||
!signedUrl
|
|
||||||
) {
|
|
||||||
navigate(`/placeHolderSign/${data.objectId}`);
|
|
||||||
}
|
|
||||||
//Inprogress document
|
|
||||||
else if (isPlaceholder?.length > 0 && signerExist?.length > 0) {
|
|
||||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
|
||||||
} //placeholder draft document
|
|
||||||
else if (
|
|
||||||
(signerExist?.length > 0 &&
|
|
||||||
(!isPlaceholder || isPlaceholder?.length === 0)) ||
|
|
||||||
((!signerExist || signerExist?.length === 0) && isPlaceholder?.length > 0)
|
|
||||||
) {
|
|
||||||
navigate(`/placeHolderSign/${data.objectId}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMenuItemClick = (selectType, data) => {
|
|
||||||
switch (selectType) {
|
|
||||||
case "Download": {
|
|
||||||
const pdfName = data && data.Name;
|
|
||||||
const pdfUrl = data && data.SignedUrl ? data.SignedUrl : data.URL;
|
|
||||||
saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "Rename": {
|
|
||||||
setRenameValue(data.Name);
|
|
||||||
setRename(data.objectId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "Delete": {
|
|
||||||
setIsDeleteDoc(true);
|
|
||||||
setSelectDoc(data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "Move": {
|
|
||||||
handleMoveDocument(data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//function for delete document
|
|
||||||
const handleDeleteDocument = async (docData) => {
|
|
||||||
setIsDeleteDoc(false);
|
|
||||||
const docId = docData.objectId;
|
|
||||||
const data = {
|
|
||||||
IsArchive: true
|
|
||||||
};
|
|
||||||
|
|
||||||
await axios
|
|
||||||
.put(
|
|
||||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
|
||||||
"_appName"
|
|
||||||
)}_Document/${docId}`,
|
|
||||||
data,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then((result) => {
|
|
||||||
const res = result.data;
|
|
||||||
if (res) {
|
|
||||||
const updatedData = props.pdfData.filter((x) => x.objectId !== docId);
|
|
||||||
props.setPdfData(updatedData);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log("Err ", err);
|
|
||||||
props.setIsAlert({
|
|
||||||
isShow: true,
|
|
||||||
alertMessage: "something went wrong"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const handleMoveDocument = async (docData) => {
|
|
||||||
setIsOpenMoveModal(true);
|
|
||||||
setSelectDoc(docData);
|
|
||||||
};
|
|
||||||
//function for move document from one folder to another folder
|
|
||||||
const handleMoveFolder = async (selectFolderData) => {
|
|
||||||
const selecFolderId = selectDoc?.Folder?.objectId;
|
|
||||||
const moveFolderId = selectFolderData?.ObjectId;
|
|
||||||
let updateDocId = selectDoc?.objectId;
|
|
||||||
let updateData;
|
|
||||||
const checkExist = moveFolderId
|
|
||||||
? selecFolderId === moveFolderId
|
|
||||||
? true
|
|
||||||
: false
|
|
||||||
: selecFolderId
|
|
||||||
? false
|
|
||||||
: true;
|
|
||||||
if (!checkExist) {
|
|
||||||
if (moveFolderId) {
|
|
||||||
updateData = {
|
|
||||||
Folder: {
|
|
||||||
__type: "Pointer",
|
|
||||||
className: `${localStorage.getItem("_appName")}_Document`,
|
|
||||||
objectId: moveFolderId
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
updateData = {
|
|
||||||
Folder: { __op: "Delete" }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
await axios
|
|
||||||
.put(
|
|
||||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
|
||||||
"_appName"
|
|
||||||
)}_Document/${updateDocId}`,
|
|
||||||
updateData,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
.then((Listdata) => {
|
|
||||||
// console.log("Listdata ", Listdata);
|
|
||||||
const res = Listdata.data;
|
|
||||||
if (res) {
|
|
||||||
const updatedData = props.pdfData.filter(
|
|
||||||
(x) => x.objectId !== updateDocId
|
|
||||||
);
|
|
||||||
props.setPdfData(updatedData);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log("err", err);
|
|
||||||
});
|
|
||||||
|
|
||||||
setIsOpenMoveModal(false);
|
|
||||||
} else {
|
|
||||||
alert("folder already exist!");
|
|
||||||
setIsOpenMoveModal(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const sanitizeFileName = (pdfName) => {
|
|
||||||
// Replace spaces with underscore
|
|
||||||
return pdfName.replace(/ /g, "_");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEnterPress = (e, data) => {
|
|
||||||
if (e.key === "Enter") {
|
|
||||||
handledRenameDoc(data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//component to handle type of document and render according to type
|
|
||||||
const handleFolderData = (data, ind, listType) => {
|
|
||||||
let createddate, status, isDecline, signerExist, isComplete;
|
|
||||||
if (data.Type !== "Folder") {
|
|
||||||
const expireDate = data.ExpiryDate && data.ExpiryDate.iso;
|
|
||||||
const createdDate = data.createdAt && data.createdAt;
|
|
||||||
createddate = new Date(createdDate).toLocaleDateString();
|
|
||||||
isComplete = data.IsCompleted && data.IsCompleted ? true : false;
|
|
||||||
isDecline = data.IsDeclined && data.IsDeclined;
|
|
||||||
signerExist = data.Signers && data.Signers;
|
|
||||||
const signedUrl = data.SignedUrl;
|
|
||||||
|
|
||||||
const expireUpdateDate = new Date(expireDate).getTime();
|
|
||||||
const currDate = new Date().getTime();
|
|
||||||
let isExpire = false;
|
|
||||||
if (currDate > expireUpdateDate) {
|
|
||||||
isExpire = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isComplete) {
|
|
||||||
status = "Completed";
|
|
||||||
} else if (isDecline) {
|
|
||||||
status = "Declined";
|
|
||||||
} else if (!signedUrl) {
|
|
||||||
status = "Draft";
|
|
||||||
} else if (isExpire) {
|
|
||||||
status = "Expired";
|
|
||||||
} else {
|
|
||||||
status = "In Progress";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const signersName = () => {
|
|
||||||
const getSignersName = signerExist.map((data) => data.Name);
|
|
||||||
const signerName = getSignersName.join(",");
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
className="statusSpan"
|
|
||||||
style={{ width: "90%", wordWrap: "break-word" }}
|
|
||||||
>
|
|
||||||
{signerName}{" "}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
return listType === "table" ? (
|
|
||||||
data.Type === "Folder" ? (
|
|
||||||
<tr onClick={() => handleOnclikFolder(data)}>
|
|
||||||
<td
|
|
||||||
style={{ cursor: "pointer", display: "flex", alignItems: "center" }}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-folder"
|
|
||||||
aria-hidden="true"
|
|
||||||
style={{ color: "#f0ad26", marginRight: "8px", fontSize: "26px" }}
|
|
||||||
></i>
|
|
||||||
|
|
||||||
<span style={{ fontSize: "12px", fontWeight: "500" }}>
|
|
||||||
{data.Name}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>_</td>
|
|
||||||
<td>Folder</td>
|
|
||||||
<td>_</td>
|
|
||||||
<td>_</td>
|
|
||||||
</tr>
|
|
||||||
) : (
|
|
||||||
<tr onClick={() => checkPdfStatus(data)}>
|
|
||||||
<td
|
|
||||||
style={{ cursor: "pointer", display: "flex", alignItems: "center" }}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-file-pdf"
|
|
||||||
style={{ color: "#ed4d0e", marginRight: "8px", fontSize: "26px" }}
|
|
||||||
></i>
|
|
||||||
|
|
||||||
<span style={{ fontSize: "12px", fontWeight: "500" }}>
|
|
||||||
{data.Name}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>{createddate}</td>
|
|
||||||
<td>Pdf</td>
|
|
||||||
<td>{status}</td>
|
|
||||||
<td>
|
|
||||||
<i
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleMenuItemClick("Download", data);
|
|
||||||
}}
|
|
||||||
className="fa fa-download"
|
|
||||||
aria-hidden="true"
|
|
||||||
style={{ color: "#ed280e", marginRight: "8px" }}
|
|
||||||
></i>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
)
|
|
||||||
) : listType === "list" && data.Type === "Folder" ? (
|
|
||||||
<div key={ind} className="folderBox">
|
|
||||||
<ContextMenu.Root>
|
|
||||||
<ContextMenu.Trigger className="ContextMenuTrigger">
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
cursor: "pointer"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="no img"
|
|
||||||
onClick={() => handleOnclikFolder(data)}
|
|
||||||
src={folder}
|
|
||||||
width={100}
|
|
||||||
height={103}
|
|
||||||
/>
|
|
||||||
{rename === data.objectId ? (
|
|
||||||
<input
|
|
||||||
onFocus={() => {
|
|
||||||
inputRef.current.setSelectionRange(0, 0);
|
|
||||||
const input = inputRef.current;
|
|
||||||
if (input) {
|
|
||||||
input.select();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
autoFocus={true}
|
|
||||||
type="text"
|
|
||||||
onBlur={() => handledRenameDoc(data)}
|
|
||||||
onKeyDown={(e) => handleEnterPress(e, data)}
|
|
||||||
ref={inputRef}
|
|
||||||
defaultValue={renameValue}
|
|
||||||
// value={renameValue}
|
|
||||||
onChange={(e) => setRenameValue(e.target.value)}
|
|
||||||
style={{
|
|
||||||
width: "100px",
|
|
||||||
border: "1.5px solid black",
|
|
||||||
borderRadius: "2px",
|
|
||||||
fontSize: "10px"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<span className="foldName">{data.Name}</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</ContextMenu.Trigger>
|
|
||||||
|
|
||||||
<ContextMenu.Portal>
|
|
||||||
<ContextMenu.Content
|
|
||||||
className="ContextMenuContent"
|
|
||||||
sideOffset={5}
|
|
||||||
align="end"
|
|
||||||
>
|
|
||||||
<ContextMenu.Item
|
|
||||||
onClick={() => handleMenuItemClick("Rename", data)}
|
|
||||||
className="ContextMenuItem"
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-font"></i>
|
|
||||||
<span style={{ marginLeft: "8px" }}>Rename</span>
|
|
||||||
</ContextMenu.Item>
|
|
||||||
</ContextMenu.Content>
|
|
||||||
</ContextMenu.Portal>
|
|
||||||
</ContextMenu.Root>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<HoverCard.Root openDelay={0} closeDelay={100}>
|
|
||||||
<HoverCard.Trigger asChild>
|
|
||||||
<div>
|
|
||||||
<ContextMenu.Root>
|
|
||||||
<div className="icon-container">
|
|
||||||
<ContextMenu.Trigger className="ContextMenuTrigger">
|
|
||||||
<img
|
|
||||||
alt="PDF"
|
|
||||||
className="pdf-icon"
|
|
||||||
src={pdfLogo}
|
|
||||||
onClick={() => checkPdfStatus(data)}
|
|
||||||
/>
|
|
||||||
{rename === data.objectId ? (
|
|
||||||
<input
|
|
||||||
autoFocus={true}
|
|
||||||
type="text"
|
|
||||||
onFocus={() => {
|
|
||||||
inputRef.current.setSelectionRange(0, 0);
|
|
||||||
const input = inputRef.current;
|
|
||||||
if (input) {
|
|
||||||
input.select();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onBlur={() => handledRenameDoc(data)}
|
|
||||||
onKeyDown={(e) => handleEnterPress(e, data)}
|
|
||||||
ref={inputRef}
|
|
||||||
defaultValue={renameValue}
|
|
||||||
// value={renameValue}
|
|
||||||
onChange={(e) => setRenameValue(e.target.value)}
|
|
||||||
style={{
|
|
||||||
width: "100px",
|
|
||||||
border: "1.5px solid black",
|
|
||||||
borderRadius: "2px",
|
|
||||||
fontSize: "10px"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<span className="fileName">{data.Name}</span>
|
|
||||||
)}
|
|
||||||
</ContextMenu.Trigger>
|
|
||||||
{status === "Completed" ? (
|
|
||||||
<div className="status-badge completed">
|
|
||||||
<i className="fas fa-check-circle"></i>
|
|
||||||
</div>
|
|
||||||
) : status === "Declined" ? (
|
|
||||||
<div className="status-badge declined">
|
|
||||||
<i className="fa fa-thumbs-down"></i>
|
|
||||||
</div>
|
|
||||||
) : status === "Expired" ? (
|
|
||||||
<div className="status-badge expired">
|
|
||||||
<i className="fa fa-hourglass-end"></i>
|
|
||||||
</div>
|
|
||||||
) : status === "Draft" ? (
|
|
||||||
<div className="status-badge draft">
|
|
||||||
<i className="fa fa-file"></i>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
status === "In Progress" && (
|
|
||||||
<div className="status-badge in-progress">
|
|
||||||
<i className="fa fa-paper-plane"></i>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ContextMenu.Portal>
|
|
||||||
<ContextMenu.Content
|
|
||||||
className="ContextMenuContent"
|
|
||||||
sideOffset={5}
|
|
||||||
align="end"
|
|
||||||
>
|
|
||||||
{contextMenu.map((menu, ind) => {
|
|
||||||
return (
|
|
||||||
<ContextMenu.Item
|
|
||||||
key={ind}
|
|
||||||
onClick={() => handleMenuItemClick(menu.type, data)}
|
|
||||||
className="ContextMenuItem"
|
|
||||||
>
|
|
||||||
<i className={menu.icon}></i>
|
|
||||||
<span style={{ marginLeft: "8px" }}>{menu.type}</span>
|
|
||||||
</ContextMenu.Item>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ContextMenu.Content>
|
|
||||||
</ContextMenu.Portal>
|
|
||||||
</ContextMenu.Root>
|
|
||||||
</div>
|
|
||||||
</HoverCard.Trigger>
|
|
||||||
<HoverCard.Portal>
|
|
||||||
<HoverCard.Content className="HoverCardContent" sideOffset={5}>
|
|
||||||
<strong style={{ fontSize: "13px" }}>Title: </strong>
|
|
||||||
<span className="statusSpan" style={{ marginBottom: "0px" }}>
|
|
||||||
{" "}
|
|
||||||
{data.Name}
|
|
||||||
</span>
|
|
||||||
<br />
|
|
||||||
<strong style={{ fontSize: "13px" }}>Status: </strong>
|
|
||||||
<span className="statusSpan"> {status}</span>
|
|
||||||
<br />
|
|
||||||
<strong style={{ fontSize: "13px" }}>Created Date: </strong>
|
|
||||||
<span className="statusSpan">{createddate}</span>
|
|
||||||
<br />
|
|
||||||
{signerExist && (
|
|
||||||
<>
|
|
||||||
<strong style={{ fontSize: "13px" }}>Signers: </strong>
|
|
||||||
{/* <span className="statusSpan">kjefjjnejkfnkbjs bbfjkdsbjbfjkbjk kscbjkbjkb</span> */}
|
|
||||||
{signersName()}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<HoverCard.Arrow className="HoverCardArrow" />
|
|
||||||
</HoverCard.Content>
|
|
||||||
</HoverCard.Portal>
|
|
||||||
</HoverCard.Root>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//component to handle type of document and render according to type
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{props.isList ? (
|
|
||||||
<div className="container" style={{ overflowX: "auto" }}>
|
|
||||||
<Table striped bordered hover>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Created Date</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>Action</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{props.pdfData.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={ind}>
|
|
||||||
{handleFolderData(data, ind, "table")}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</tbody>
|
|
||||||
</Table>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="pdfContainer">
|
|
||||||
{props.pdfData.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<div className="box" key={ind}>
|
|
||||||
{handleFolderData(data, ind, "list")}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isOpenMoveModal && (
|
|
||||||
<FolderModal
|
|
||||||
onSuccess={handleMoveFolder}
|
|
||||||
isOpenModal={isOpenMoveModal}
|
|
||||||
folderCls={"contracts_Document"}
|
|
||||||
setIsOpenMoveModal={setIsOpenMoveModal}
|
|
||||||
setPdfData={props.setPdfData}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<ModalUi
|
|
||||||
isOpen={isDeleteDoc}
|
|
||||||
headerColor={themeColor}
|
|
||||||
title={"Delete Document"}
|
|
||||||
handleClose={() => {
|
|
||||||
setIsDeleteDoc(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{ height: "100%", padding: 20 }}>
|
|
||||||
<p>Are you sure you want to delete this document?</p>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: "1px",
|
|
||||||
backgroundColor: "#9f9f9f",
|
|
||||||
width: "100%",
|
|
||||||
marginTop: "15px",
|
|
||||||
marginBottom: "15px"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
handleDeleteDocument(selectDoc);
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className="finishBtn"
|
|
||||||
>
|
|
||||||
Yes
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
setIsDeleteDoc(false);
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className="finishBtn cancelBtn"
|
|
||||||
>
|
|
||||||
No
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</ModalUi>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DriveBody;
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
|
||||||
|
|
||||||
const AddRoleModal = (props) => {
|
|
||||||
return (
|
|
||||||
<ModalUi
|
|
||||||
title={"Add Role"}
|
|
||||||
isOpen={props.isModalRole}
|
|
||||||
handleClose={props.handleCloseRoleModal}
|
|
||||||
>
|
|
||||||
<div className="addusercontainer">
|
|
||||||
<form
|
|
||||||
style={{ display: "flex", flexDirection: "column" }}
|
|
||||||
onSubmit={props.handleAddRole}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
value={props.roleName}
|
|
||||||
onChange={(e) => props.setRoleName(e.target.value)}
|
|
||||||
placeholder={
|
|
||||||
props.signersdata.length > 0
|
|
||||||
? "User " + (props.signersdata.length + 1)
|
|
||||||
: "User 1"
|
|
||||||
}
|
|
||||||
className="addUserInput"
|
|
||||||
/>
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
color: "grey",
|
|
||||||
fontSize: 11,
|
|
||||||
margin: "10px 0 10px 5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
e.g: Customer, Hr, Director, Manager, Student, etc...
|
|
||||||
</p>
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: "1px",
|
|
||||||
backgroundColor: "#9f9f9f",
|
|
||||||
width: "100%",
|
|
||||||
marginBottom: "15px"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
style={{
|
|
||||||
background: "#00a2b7"
|
|
||||||
}}
|
|
||||||
className="finishBtn"
|
|
||||||
>
|
|
||||||
Add
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={props.handleCloseRoleModal}
|
|
||||||
type="button"
|
|
||||||
className="finishBtn cancelBtn"
|
|
||||||
>
|
|
||||||
Close
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</ModalUi>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AddRoleModal;
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
|
|
||||||
function BorderResize({ right, top }) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="borderResize"
|
|
||||||
style={{
|
|
||||||
right: right ? right + "px" : "-1px",
|
|
||||||
bottom: top ? top + "px" : "-1px",
|
|
||||||
borderRight: "3px solid #188ae2",
|
|
||||||
borderBottom: "3px solid #188ae2"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BorderResize;
|
|
||||||
@@ -1,276 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import opensignLogo from "../../assets/images/logo.png";
|
|
||||||
import {
|
|
||||||
Page,
|
|
||||||
Text,
|
|
||||||
View,
|
|
||||||
Document,
|
|
||||||
StyleSheet,
|
|
||||||
Image
|
|
||||||
} from "@react-pdf/renderer";
|
|
||||||
|
|
||||||
function Certificate({ pdfData }) {
|
|
||||||
const [isMultiSigners, setIsMultiSigners] = useState();
|
|
||||||
const [multiSigner, setMultiSigners] = useState([]);
|
|
||||||
const [isLoad, setIsLoad] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
handleSignerData();
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleSignerData = () => {
|
|
||||||
const checkSigners = pdfData.filter((data) => data.Signers);
|
|
||||||
if (checkSigners && checkSigners.length > 0) {
|
|
||||||
setIsMultiSigners(true);
|
|
||||||
|
|
||||||
const checkSignSigners =
|
|
||||||
pdfData[0].AuditTrail &&
|
|
||||||
pdfData[0].AuditTrail.length > 0 &&
|
|
||||||
pdfData[0].AuditTrail.filter((data) => data.Activity === "Signed");
|
|
||||||
|
|
||||||
setMultiSigners(checkSignSigners);
|
|
||||||
} else {
|
|
||||||
setIsMultiSigners(false);
|
|
||||||
}
|
|
||||||
setIsLoad(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
page: {
|
|
||||||
borderRadius: "5px",
|
|
||||||
padding: "10px",
|
|
||||||
backgroundColor: "white"
|
|
||||||
},
|
|
||||||
section1: {
|
|
||||||
border: "1px solid rgb(177, 174, 174)",
|
|
||||||
padding: "20px"
|
|
||||||
},
|
|
||||||
textStyle: {
|
|
||||||
fontWeight: "bold",
|
|
||||||
fontSize: "11px",
|
|
||||||
marginBottom: "10px"
|
|
||||||
},
|
|
||||||
textStyle2: {
|
|
||||||
fontWeight: "600",
|
|
||||||
fontSize: "11px",
|
|
||||||
marginBottom: "10px",
|
|
||||||
color: "gray"
|
|
||||||
},
|
|
||||||
image: {
|
|
||||||
width: "71px",
|
|
||||||
height: "17px"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const generatedDate = () => {
|
|
||||||
const newDate = new Date();
|
|
||||||
const utcTime = newDate.toUTCString();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
color: "gray",
|
|
||||||
fontSize: "10px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Generated On {utcTime}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const changeCompletedDate = () => {
|
|
||||||
const completedOn = pdfData[0].updatedAt;
|
|
||||||
const newDate = new Date(completedOn);
|
|
||||||
const utcTime = newDate.toUTCString();
|
|
||||||
|
|
||||||
return <Text style={styles.textStyle2}>{utcTime}</Text>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const signerName = (data) => {
|
|
||||||
const getSignerName = pdfData[0].Signers.filter(
|
|
||||||
(sign) => sign.objectId === data.UserPtr.objectId
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
getSignerName[0] &&
|
|
||||||
getSignerName.length > 0 && (
|
|
||||||
<>
|
|
||||||
<Text style={styles.textStyle}>
|
|
||||||
Name :
|
|
||||||
<Text style={styles.textStyle2}>{getSignerName[0].Name}</Text>
|
|
||||||
</Text>
|
|
||||||
<Text style={styles.textStyle}>
|
|
||||||
Email :
|
|
||||||
<Text style={styles.textStyle2}>{getSignerName[0].Email}</Text>
|
|
||||||
</Text>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
isLoad && (
|
|
||||||
<Document>
|
|
||||||
{/** Page defines a single page of content. */}
|
|
||||||
<Page size="A4" style={styles.page}>
|
|
||||||
<View style={styles.section1}>
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
alignItems: "center",
|
|
||||||
marginBottom: "30px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Image src={opensignLogo} style={styles.image} />
|
|
||||||
{generatedDate()}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={{ justifyContent: "center" }}>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
textAlign: "center",
|
|
||||||
fontSize: "20px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
color: "#31bceb",
|
|
||||||
marginBottom: "10px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{" "}
|
|
||||||
Certificate of Completion
|
|
||||||
</Text>
|
|
||||||
<View style={{ border: "1px solid #bdbbbb" }}></View>
|
|
||||||
<View>
|
|
||||||
<View>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
fontSize: "16px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
color: "#31bceb",
|
|
||||||
margin: "10px 0px 10px 0px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Summary
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<View style={{ display: "flex", flexDirection: "column" }}>
|
|
||||||
<Text style={styles.textStyle}>
|
|
||||||
Document ID :
|
|
||||||
<Text style={styles.textStyle2}>{pdfData[0].objectId}</Text>
|
|
||||||
</Text>
|
|
||||||
<Text style={styles.textStyle}>
|
|
||||||
Document Name :
|
|
||||||
<Text style={styles.textStyle2}>{pdfData[0].Name}</Text>
|
|
||||||
</Text>
|
|
||||||
<Text style={styles.textStyle}>
|
|
||||||
Organization :
|
|
||||||
<Text style={styles.textStyle2}>
|
|
||||||
{pdfData[0].ExtUserPtr.Company}
|
|
||||||
</Text>
|
|
||||||
</Text>
|
|
||||||
<Text style={styles.textStyle}>
|
|
||||||
Completed on : {changeCompletedDate()}
|
|
||||||
</Text>
|
|
||||||
{multiSigner && multiSigner.length > 0 && (
|
|
||||||
<Text style={styles.textStyle}>
|
|
||||||
Signers :
|
|
||||||
<Text style={styles.textStyle2}>
|
|
||||||
{multiSigner.length}
|
|
||||||
</Text>
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
{isMultiSigners ? (
|
|
||||||
<View style={{ display: "flex", flexDirection: "column" }}>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
fontSize: "16px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
color: "#31bceb",
|
|
||||||
margin: "10px 0px 10px 0px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Recipients
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<View>
|
|
||||||
{multiSigner &&
|
|
||||||
multiSigner.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<View
|
|
||||||
key={ind}
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
border: "0.4px solid #bdbbbb",
|
|
||||||
marginBottom: "10px"
|
|
||||||
}}
|
|
||||||
></View>
|
|
||||||
{signerName(data)}
|
|
||||||
|
|
||||||
<Text style={styles.textStyle}>
|
|
||||||
Accessed from :
|
|
||||||
<Text style={styles.textStyle2}>
|
|
||||||
{data.ipAddress}
|
|
||||||
</Text>
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<View style={{ display: "flex", flexDirection: "column" }}>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
fontSize: "16px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
color: "#31bceb",
|
|
||||||
margin: "10px 0px 10px 0px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Recipients
|
|
||||||
</Text>
|
|
||||||
<Text style={styles.textStyle}>
|
|
||||||
Signers : <Text style={styles.textStyle2}>1</Text>
|
|
||||||
</Text>
|
|
||||||
<Text style={styles.textStyle}>
|
|
||||||
Name :
|
|
||||||
<Text style={styles.textStyle2}>
|
|
||||||
{pdfData[0].ExtUserPtr.Name}
|
|
||||||
</Text>
|
|
||||||
</Text>
|
|
||||||
<Text style={styles.textStyle}>
|
|
||||||
Email :
|
|
||||||
<Text style={styles.textStyle2}>
|
|
||||||
{pdfData[0].ExtUserPtr.Email}
|
|
||||||
</Text>
|
|
||||||
</Text>
|
|
||||||
<Text style={styles.textStyle}>
|
|
||||||
Accessed from :
|
|
||||||
<Text style={styles.textStyle2}>
|
|
||||||
{pdfData[0].AuditTrail &&
|
|
||||||
pdfData[0].AuditTrail[0].ipAddress}
|
|
||||||
</Text>
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text style={styles.textStyle}>
|
|
||||||
Signed on : {changeCompletedDate()}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Page>
|
|
||||||
</Document>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Certificate;
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
function DefaultSignature({ defaultSignImg, xyPostion, setDefaultSignAlert }) {
|
|
||||||
const confirmToaddDefaultSign = () => {
|
|
||||||
if (xyPostion.length > 0) {
|
|
||||||
setDefaultSignAlert({
|
|
||||||
isShow: true,
|
|
||||||
alertMessage:
|
|
||||||
"Are you sure you want to auto sign at requested all locations?"
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setDefaultSignAlert({
|
|
||||||
isShow: true,
|
|
||||||
alertMessage: "please select position!"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white",
|
|
||||||
padding: "5px",
|
|
||||||
fontFamily: "sans-serif",
|
|
||||||
marginTop: "5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Signature
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
|
||||||
marginTop: "10px",
|
|
||||||
fontWeight: "600"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<>
|
|
||||||
<p>Your Signature</p>
|
|
||||||
<div className="defaultSignBox">
|
|
||||||
<img
|
|
||||||
alt="default img"
|
|
||||||
style={{
|
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
src={defaultSignImg}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white",
|
|
||||||
marginTop: "20px",
|
|
||||||
cursor: "pointer",
|
|
||||||
marginBottom: "10px"
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className="finishBtn finishnHover"
|
|
||||||
onClick={() => confirmToaddDefaultSign()}
|
|
||||||
>
|
|
||||||
Auto Sign All
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DefaultSignature;
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import Loader from "../../primitives/LoaderWithMsg";
|
|
||||||
import { contractDocument } from "../../constant/Utils";
|
|
||||||
import HandleError from "../../primitives/HandleError";
|
|
||||||
function DraftDocument() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const [isLoading, setIsLoading] = useState({
|
|
||||||
isLoader: true,
|
|
||||||
message: "This might take some time"
|
|
||||||
});
|
|
||||||
|
|
||||||
const rowLevel =
|
|
||||||
localStorage.getItem("rowlevel") &&
|
|
||||||
JSON.parse(localStorage.getItem("rowlevel"));
|
|
||||||
const docId =
|
|
||||||
rowLevel && rowLevel?.id
|
|
||||||
? rowLevel.id
|
|
||||||
: rowLevel?.objectId && rowLevel.objectId;
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getDocumentDetails();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
//get document details
|
|
||||||
const getDocumentDetails = async () => {
|
|
||||||
//getting document details
|
|
||||||
const documentData = await contractDocument(docId);
|
|
||||||
if (documentData && documentData.length > 0) {
|
|
||||||
handleDraftDoc(documentData);
|
|
||||||
} else if (
|
|
||||||
documentData === "Error: Something went wrong!" ||
|
|
||||||
(documentData.result && documentData.result.error)
|
|
||||||
) {
|
|
||||||
setIsLoading({
|
|
||||||
isLoader: false,
|
|
||||||
message: "Error: Something went wrong!"
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setIsLoading({
|
|
||||||
isLoader: false,
|
|
||||||
message: "No data found!"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//check document type and render on signyour self and placeholder route
|
|
||||||
const handleDraftDoc = (documentData) => {
|
|
||||||
const data = documentData[0];
|
|
||||||
const signerExist = data.Signers && data.Signers;
|
|
||||||
const isDecline = data.IsDeclined && data.IsDeclined;
|
|
||||||
const isPlaceholder = data.Placeholders && data.Placeholders;
|
|
||||||
const signedUrl = data.SignedUrl;
|
|
||||||
//checking if document has completed and request signature flow
|
|
||||||
if (data?.IsCompleted && signerExist?.length > 0) {
|
|
||||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
|
||||||
}
|
|
||||||
//checking if document has completed and signyour-self flow
|
|
||||||
else if (!signerExist && !isPlaceholder) {
|
|
||||||
navigate(`/signaturePdf/${data.objectId}`);
|
|
||||||
}
|
|
||||||
//checking if document has declined by someone
|
|
||||||
else if (isDecline) {
|
|
||||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
|
||||||
//checking draft type document
|
|
||||||
} else if (
|
|
||||||
signerExist?.length > 0 &&
|
|
||||||
isPlaceholder?.length > 0 &&
|
|
||||||
!signedUrl
|
|
||||||
) {
|
|
||||||
navigate(`/placeHolderSign/${data.objectId}`);
|
|
||||||
}
|
|
||||||
//Inprogress document
|
|
||||||
else if (isPlaceholder?.length > 0 && signerExist?.length > 0) {
|
|
||||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
|
||||||
} //placeholder draft document
|
|
||||||
else if (
|
|
||||||
(signerExist?.length > 0 &&
|
|
||||||
(!isPlaceholder || isPlaceholder?.length === 0)) ||
|
|
||||||
((!signerExist || signerExist?.length === 0) && isPlaceholder?.length > 0)
|
|
||||||
) {
|
|
||||||
navigate(`/placeHolderSign/${data.objectId}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{isLoading.isLoader ? (
|
|
||||||
<Loader isLoading={isLoading} />
|
|
||||||
) : (
|
|
||||||
<HandleError handleError={isLoading.message} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DraftDocument;
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { getWidgetType, widgets } from "../../constant/Utils";
|
|
||||||
|
|
||||||
function DragElement(item) {
|
|
||||||
const getWidgets = widgets;
|
|
||||||
const filterWidgetPreview = getWidgets.filter(
|
|
||||||
(data) => data.type === item?.text
|
|
||||||
);
|
|
||||||
|
|
||||||
return <div>{getWidgetType(filterWidgetPreview[0])}</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DragElement;
|
|
||||||
@@ -1,451 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import { isEnableSubscription, themeColor } from "../../constant/const";
|
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
|
||||||
import { radioButtonWidget } from "../../constant/Utils";
|
|
||||||
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
|
||||||
import Upgrade from "../../primitives/Upgrade";
|
|
||||||
function DropdownWidgetOption(props) {
|
|
||||||
const [dropdownOptionList, setDropdownOptionList] = useState([
|
|
||||||
"option-1",
|
|
||||||
"option-2"
|
|
||||||
]);
|
|
||||||
const [minCount, setMinCount] = useState(0);
|
|
||||||
const [maxCount, setMaxCount] = useState(0);
|
|
||||||
const [dropdownName, setDropdownName] = useState(props.type);
|
|
||||||
const [isReadOnly, setIsReadOnly] = useState(false);
|
|
||||||
const [isHideLabel, setIsHideLabel] = useState(false);
|
|
||||||
const [status, setStatus] = useState("required");
|
|
||||||
const [defaultValue, setDefaultValue] = useState("");
|
|
||||||
const statusArr = ["required", "optional"];
|
|
||||||
const [defaultCheckbox, setDefaultCheckbox] = useState([]);
|
|
||||||
|
|
||||||
const resetState = () => {
|
|
||||||
setDropdownOptionList(["option-1", "option-2"]);
|
|
||||||
setDropdownName(props.type);
|
|
||||||
setIsReadOnly(false);
|
|
||||||
setIsHideLabel(false);
|
|
||||||
setMinCount(0);
|
|
||||||
setMaxCount(0);
|
|
||||||
setDefaultCheckbox([]);
|
|
||||||
setDefaultValue("");
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (
|
|
||||||
props.currWidgetsDetails?.options?.name &&
|
|
||||||
props.currWidgetsDetails?.options?.values
|
|
||||||
) {
|
|
||||||
setDropdownName(props.currWidgetsDetails?.options?.name);
|
|
||||||
setDropdownOptionList(props.currWidgetsDetails?.options?.values);
|
|
||||||
setMinCount(
|
|
||||||
props.currWidgetsDetails?.options?.validation?.minRequiredCount
|
|
||||||
);
|
|
||||||
setMaxCount(
|
|
||||||
props.currWidgetsDetails?.options?.validation?.maxRequiredCount
|
|
||||||
);
|
|
||||||
setIsReadOnly(props.currWidgetsDetails?.options?.isReadOnly);
|
|
||||||
setIsHideLabel(props.currWidgetsDetails?.options?.isHideLabel);
|
|
||||||
setStatus(props.currWidgetsDetails?.options?.status || "required");
|
|
||||||
setDefaultValue(props.currWidgetsDetails?.options?.defaultValue || "");
|
|
||||||
setDefaultCheckbox(props.currWidgetsDetails?.options?.defaultValue || []);
|
|
||||||
} else {
|
|
||||||
setStatus("required");
|
|
||||||
resetState();
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [props.currWidgetsDetails]);
|
|
||||||
const handleInputChange = (index, value) => {
|
|
||||||
setDropdownOptionList((prevInputs) => {
|
|
||||||
const newInputs = [...prevInputs];
|
|
||||||
newInputs[index] = value;
|
|
||||||
return newInputs;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//function add add checkbox option and add width of checkbox
|
|
||||||
const handleAddInput = () => {
|
|
||||||
const deleteOption = false;
|
|
||||||
const addOption = true;
|
|
||||||
setDropdownOptionList((prevInputs) => [...prevInputs, ""]);
|
|
||||||
props.handleSaveWidgetsOptions(
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
addOption,
|
|
||||||
deleteOption
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//function add add checkbox option and delete width of checkbox
|
|
||||||
const handleDeleteInput = (ind) => {
|
|
||||||
const deleteOption = true;
|
|
||||||
const addOption = false;
|
|
||||||
const getUpdatedOptions = dropdownOptionList.filter(
|
|
||||||
(data, index) => index !== ind
|
|
||||||
);
|
|
||||||
setDropdownOptionList(getUpdatedOptions);
|
|
||||||
props.handleSaveWidgetsOptions(
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
addOption,
|
|
||||||
deleteOption
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSaveOption = () => {
|
|
||||||
const defaultData =
|
|
||||||
defaultCheckbox && defaultCheckbox.length > 0
|
|
||||||
? defaultCheckbox
|
|
||||||
: defaultValue;
|
|
||||||
|
|
||||||
props.handleSaveWidgetsOptions(
|
|
||||||
dropdownName,
|
|
||||||
dropdownOptionList,
|
|
||||||
minCount,
|
|
||||||
maxCount,
|
|
||||||
isReadOnly,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
status,
|
|
||||||
defaultData,
|
|
||||||
isHideLabel
|
|
||||||
);
|
|
||||||
// props.setShowDropdown(false);
|
|
||||||
setDropdownOptionList(["option-1", "option-2"]);
|
|
||||||
setDropdownName(props.type);
|
|
||||||
// props.setCurrWidgetsDetails({});
|
|
||||||
setIsReadOnly(false);
|
|
||||||
setIsHideLabel(false);
|
|
||||||
setMinCount(0);
|
|
||||||
setMaxCount(0);
|
|
||||||
setDefaultCheckbox([]);
|
|
||||||
setDefaultValue("");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSetMinMax = (e) => {
|
|
||||||
const minValue = e.target.value;
|
|
||||||
if (minValue > dropdownOptionList.length) {
|
|
||||||
return "";
|
|
||||||
} else {
|
|
||||||
return minValue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDefaultCheck = (index) => {
|
|
||||||
const getDefaultCheck = defaultCheckbox.includes(index);
|
|
||||||
if (getDefaultCheck) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ModalUi isOpen={props.showDropdown} title={props.title} showClose={false}>
|
|
||||||
<div className="h-full p-[15px]">
|
|
||||||
<form
|
|
||||||
onSubmit={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
handleSaveOption();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<label style={{ fontSize: "13px", fontWeight: "600" }}>
|
|
||||||
Name<span style={{ color: "red", fontSize: 13 }}> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
required
|
|
||||||
defaultValue={dropdownName}
|
|
||||||
value={dropdownName}
|
|
||||||
onChange={(e) => setDropdownName(e.target.value)}
|
|
||||||
className="drodown-input"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<label
|
|
||||||
style={{ fontSize: "13px", fontWeight: "600", marginTop: "5px" }}
|
|
||||||
>
|
|
||||||
Options
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{dropdownOptionList.map((option, index) => (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
marginBottom: "5px",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.type === "checkbox" && !props.isSignYourself && (
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={handleDefaultCheck(index)}
|
|
||||||
onChange={(e) => {
|
|
||||||
if (e.target.checked) {
|
|
||||||
const getDefaultCheck =
|
|
||||||
defaultCheckbox?.includes(index);
|
|
||||||
if (!getDefaultCheck) {
|
|
||||||
setDefaultCheckbox((prev) => [...prev, index]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const removeOption = defaultCheckbox.filter(
|
|
||||||
(data) => data !== index
|
|
||||||
);
|
|
||||||
setDefaultCheckbox(removeOption);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
width: "23px",
|
|
||||||
height: "19px",
|
|
||||||
marginRight: "5px"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<input
|
|
||||||
required
|
|
||||||
className="drodown-input"
|
|
||||||
type="text"
|
|
||||||
value={option}
|
|
||||||
onChange={(e) => handleInputChange(index, e.target.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<i
|
|
||||||
className="fa-solid fa-rectangle-xmark"
|
|
||||||
onClick={() => handleDeleteInput(index)}
|
|
||||||
style={{
|
|
||||||
color: "red",
|
|
||||||
fontSize: "25px",
|
|
||||||
marginLeft: "10px"
|
|
||||||
}}
|
|
||||||
></i>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
<i
|
|
||||||
onClick={handleAddInput}
|
|
||||||
style={{
|
|
||||||
cursor: "pointer",
|
|
||||||
color: themeColor,
|
|
||||||
fontSize: "25px",
|
|
||||||
marginLeft: "10px"
|
|
||||||
}}
|
|
||||||
className="fa-solid fa-square-plus"
|
|
||||||
></i>
|
|
||||||
<div>
|
|
||||||
{props.type === "checkbox" && !props.isSignYourself && (
|
|
||||||
<>
|
|
||||||
<label
|
|
||||||
style={{
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: "600",
|
|
||||||
color: !props.isSubscribe && "gray"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Minimun check
|
|
||||||
</label>
|
|
||||||
{!props.isSubscribe && isEnableSubscription && <Upgrade />}
|
|
||||||
<input
|
|
||||||
required
|
|
||||||
defaultValue={0}
|
|
||||||
value={minCount}
|
|
||||||
onChange={(e) => {
|
|
||||||
const count = handleSetMinMax(e);
|
|
||||||
setMinCount(count);
|
|
||||||
}}
|
|
||||||
className={
|
|
||||||
props.isSubscribe || !isEnableSubscription
|
|
||||||
? "drodown-input"
|
|
||||||
: "disabled drodown-input"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<label
|
|
||||||
style={{
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: "600",
|
|
||||||
color: !props.isSubscribe && "gray"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Maximum check
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
required
|
|
||||||
defaultValue={0}
|
|
||||||
value={maxCount}
|
|
||||||
onChange={(e) => {
|
|
||||||
const count = handleSetMinMax(e);
|
|
||||||
setMaxCount(count);
|
|
||||||
}}
|
|
||||||
className={
|
|
||||||
props.isSubscribe || !isEnableSubscription
|
|
||||||
? "drodown-input"
|
|
||||||
: "disabled drodown-input"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{["dropdown", radioButtonWidget].includes(props.type) && (
|
|
||||||
<>
|
|
||||||
<label
|
|
||||||
style={{
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: "600",
|
|
||||||
marginTop: "5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Default value
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
onChange={(e) => setDefaultValue(e.target.value)}
|
|
||||||
className="drodown-input"
|
|
||||||
name="defaultvalue"
|
|
||||||
value={defaultValue}
|
|
||||||
placeholder="select default value"
|
|
||||||
>
|
|
||||||
<option value="" disabled hidden style={{ fontSize: "13px" }}>
|
|
||||||
Select...
|
|
||||||
</option>
|
|
||||||
{dropdownOptionList.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<option
|
|
||||||
style={{ fontSize: "13px" }}
|
|
||||||
key={ind}
|
|
||||||
value={data}
|
|
||||||
>
|
|
||||||
{data}
|
|
||||||
</option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</select>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{props.type !== "checkbox" && props.type !== radioButtonWidget && (
|
|
||||||
<>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
gap: 10,
|
|
||||||
marginTop: "0.5rem"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{statusArr.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={ind}
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
gap: 5,
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
style={{ accentColor: "red" }}
|
|
||||||
type="radio"
|
|
||||||
name="status"
|
|
||||||
onChange={() => setStatus(data.toLowerCase())}
|
|
||||||
checked={status.toLowerCase() === data.toLowerCase()}
|
|
||||||
/>
|
|
||||||
<div style={{ fontSize: "13px", fontWeight: "500" }}>
|
|
||||||
{data}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{["checkbox", radioButtonWidget].includes(props.type) && (
|
|
||||||
<div className="flex flex-row gap-5 mt-2 items-center text-center">
|
|
||||||
{!props.isSignYourself && (
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
id="isreadonly"
|
|
||||||
type="checkbox"
|
|
||||||
checked={isReadOnly}
|
|
||||||
onChange={(e) => {
|
|
||||||
setIsReadOnly(e.target.checked);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<label className="ml-1" htmlFor="isreadonly">
|
|
||||||
Is read only
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
id="ishidelabel"
|
|
||||||
type="checkbox"
|
|
||||||
checked={isHideLabel}
|
|
||||||
onChange={(e) => {
|
|
||||||
setIsHideLabel(e.target.checked);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<label className="ml-1" htmlFor="ishidelabel">
|
|
||||||
Hide labels
|
|
||||||
</label>
|
|
||||||
</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
|
|
||||||
className={`${
|
|
||||||
props.type === "checkbox" && !props.isSignYourself
|
|
||||||
? "mb-[15px]"
|
|
||||||
: "my-[15px]"
|
|
||||||
} w-full h-[1px] bg-[#9f9f9f]`}
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
disabled={dropdownOptionList.length === 0 && true}
|
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
type="submit"
|
|
||||||
className={"finishBtn"}
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
{props.currWidgetsDetails?.options?.values?.length > 0 && (
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="finishBtn cancelBtn"
|
|
||||||
onClick={() => {
|
|
||||||
props.handleClose && props.handleClose();
|
|
||||||
resetState();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</ModalUi>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DropdownWidgetOption;
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import "../../styles/AddUser.css";
|
|
||||||
// import SelectFolder from "../../premitives/SelectFolder";
|
|
||||||
|
|
||||||
const EditTemplate = ({ template, onSuccess }) => {
|
|
||||||
// const [folder, setFolder] = useState({ ObjectId: "", Name: "" });
|
|
||||||
const [formData, setFormData] = useState({
|
|
||||||
Name: template?.Name || "",
|
|
||||||
Note: template?.Note || "",
|
|
||||||
Description: template?.Description || "",
|
|
||||||
SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false"
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleStrInput = (e) => {
|
|
||||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
|
||||||
};
|
|
||||||
// const handleFolder = (data) => {
|
|
||||||
// console.log("handleFolder ", data)
|
|
||||||
// setFolder(data);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// Define a function to handle form submission
|
|
||||||
const handleSubmit = async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
const isChecked = formData.SendinOrder === "true" ? true : false;
|
|
||||||
const data = { ...formData, SendinOrder: isChecked };
|
|
||||||
onSuccess(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="addusercontainer">
|
|
||||||
<div className="form-wrapper">
|
|
||||||
<form onSubmit={handleSubmit}>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
|
||||||
File
|
|
||||||
</label>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
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 className="form-section">
|
|
||||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
|
||||||
Name
|
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="Name"
|
|
||||||
value={formData.Name}
|
|
||||||
onChange={(e) => handleStrInput(e)}
|
|
||||||
required
|
|
||||||
className="addUserInput"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="form-section">
|
|
||||||
<label htmlFor="Note" style={{ fontSize: 13 }}>
|
|
||||||
Note
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="Note"
|
|
||||||
id="Note"
|
|
||||||
value={formData.Note}
|
|
||||||
onChange={(e) => handleStrInput(e)}
|
|
||||||
className="addUserInput"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="form-section">
|
|
||||||
<label htmlFor="Description" style={{ fontSize: 13 }}>
|
|
||||||
Description
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="Description"
|
|
||||||
id="Description"
|
|
||||||
value={formData.Description}
|
|
||||||
onChange={(e) => handleStrInput(e)}
|
|
||||||
className="addUserInput"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="form-section">
|
|
||||||
<label style={{ fontSize: 13 }}>Send In Order</label>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: 8,
|
|
||||||
marginLeft: 8,
|
|
||||||
marginBottom: 5
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
value={"true"}
|
|
||||||
name="SendinOrder"
|
|
||||||
checked={formData.SendinOrder === "true"}
|
|
||||||
onChange={handleStrInput}
|
|
||||||
/>
|
|
||||||
<div style={{ fontSize: 12 }}>Yes</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: 8,
|
|
||||||
marginLeft: 8,
|
|
||||||
marginBottom: 5
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
value={"false"}
|
|
||||||
name="SendinOrder"
|
|
||||||
checked={formData.SendinOrder === "false"}
|
|
||||||
onChange={handleStrInput}
|
|
||||||
/>
|
|
||||||
<div style={{ fontSize: 12 }}>No</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* <SelectFolder onSuccess={handleFolder} folderCls={"contracts_Template"} /> */}
|
|
||||||
<div className="buttoncontainer">
|
|
||||||
<button type="submit" className="submitbutton">
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default EditTemplate;
|
|
||||||
@@ -1,431 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import { saveAs } from "file-saver";
|
|
||||||
import celebration from "../../assets/images/newCeleb.gif";
|
|
||||||
import axios from "axios";
|
|
||||||
import { getBase64FromUrl } from "../../constant/Utils";
|
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
import printModule from "print-js";
|
|
||||||
import loader from "../../assets/images/loader2.gif";
|
|
||||||
|
|
||||||
function EmailComponent({
|
|
||||||
isEmail,
|
|
||||||
pdfUrl,
|
|
||||||
isCeleb,
|
|
||||||
setIsEmail,
|
|
||||||
setSuccessEmail,
|
|
||||||
pdfName,
|
|
||||||
sender,
|
|
||||||
setIsAlert,
|
|
||||||
extUserId
|
|
||||||
}) {
|
|
||||||
const [emailList, setEmailList] = useState([]);
|
|
||||||
const [emailValue, setEmailValue] = useState();
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
//function for send email
|
|
||||||
const sendEmail = async () => {
|
|
||||||
setIsLoading(true);
|
|
||||||
let sendMail;
|
|
||||||
for (let i = 0; i < emailList.length; i++) {
|
|
||||||
try {
|
|
||||||
const imgPng =
|
|
||||||
"https://qikinnovation.ams3.digitaloceanspaces.com/logo.png";
|
|
||||||
|
|
||||||
let url = `${localStorage.getItem("baseUrl")}functions/sendmailv3/`;
|
|
||||||
const headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
|
||||||
sessionToken: localStorage.getItem("accesstoken")
|
|
||||||
};
|
|
||||||
const openSignUrl = "https://www.opensignlabs.com/contact-us";
|
|
||||||
const themeBGcolor = themeColor;
|
|
||||||
let params = {
|
|
||||||
extUserId: extUserId,
|
|
||||||
pdfName: pdfName,
|
|
||||||
url: pdfUrl,
|
|
||||||
recipient: emailList[i],
|
|
||||||
subject: `${sender.name} has signed the doc - ${pdfName}`,
|
|
||||||
from: sender.email,
|
|
||||||
html:
|
|
||||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=" +
|
|
||||||
imgPng +
|
|
||||||
" height='50' style='padding:20px,width:170px,height:40px'/> </div><div style='padding:2px;font-family:system-ui; background-color:" +
|
|
||||||
themeBGcolor +
|
|
||||||
";'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document Copy</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document <strong>" +
|
|
||||||
pdfName +
|
|
||||||
" </strong>is attached to this email. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
|
||||||
sender.email +
|
|
||||||
" directly. If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href= " +
|
|
||||||
openSignUrl +
|
|
||||||
" target=_blank>here</a> </p></div></div></body></html>"
|
|
||||||
};
|
|
||||||
sendMail = await axios.post(url, params, { headers: headers });
|
|
||||||
} catch (error) {
|
|
||||||
console.log("error", error);
|
|
||||||
setIsLoading(false);
|
|
||||||
setIsEmail(false);
|
|
||||||
setIsAlert({
|
|
||||||
isShow: true,
|
|
||||||
alertMessage: "something went wrong"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sendMail && sendMail.data.result.status === "success") {
|
|
||||||
setSuccessEmail(true);
|
|
||||||
setTimeout(() => {
|
|
||||||
setSuccessEmail(false);
|
|
||||||
setIsEmail(false);
|
|
||||||
setEmailValue("");
|
|
||||||
setEmailList([]);
|
|
||||||
}, 1500);
|
|
||||||
|
|
||||||
setIsLoading(false);
|
|
||||||
} else if (sendMail && sendMail.data.result.status === "error") {
|
|
||||||
setIsLoading(false);
|
|
||||||
setIsEmail(false);
|
|
||||||
setIsAlert({
|
|
||||||
isShow: true,
|
|
||||||
alertMessage: "something went wrong"
|
|
||||||
});
|
|
||||||
setEmailValue("");
|
|
||||||
setEmailList([]);
|
|
||||||
} else {
|
|
||||||
setIsLoading(false);
|
|
||||||
setIsEmail(false);
|
|
||||||
setIsAlert({
|
|
||||||
isShow: true,
|
|
||||||
alertMessage: "something went wrong"
|
|
||||||
});
|
|
||||||
setEmailValue("");
|
|
||||||
setEmailList([]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//function for remove email
|
|
||||||
const removeChip = (index) => {
|
|
||||||
const updateEmailCount = emailList.filter((data, key) => key !== index);
|
|
||||||
setEmailList(updateEmailCount);
|
|
||||||
};
|
|
||||||
//function for get email value
|
|
||||||
const handleEmailValue = (e) => {
|
|
||||||
const value = e.target.value;
|
|
||||||
setEmailValue(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
//function for save email in array after press enter
|
|
||||||
const handleEnterPress = (e) => {
|
|
||||||
if (e.key === "Enter" && emailValue) {
|
|
||||||
setEmailList((prev) => [...prev, emailValue]);
|
|
||||||
setEmailValue("");
|
|
||||||
} else if (e === "add" && emailValue) {
|
|
||||||
setEmailList((prev) => [...prev, emailValue]);
|
|
||||||
setEmailValue("");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// function for print signed 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 = () => {
|
|
||||||
saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
|
|
||||||
};
|
|
||||||
|
|
||||||
const sanitizeFileName = (pdfName) => {
|
|
||||||
// Replace spaces with underscore
|
|
||||||
return pdfName.replace(/ /g, "_");
|
|
||||||
};
|
|
||||||
|
|
||||||
const isAndroid = /Android/i.test(navigator.userAgent);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{/* isEmail */}
|
|
||||||
{isEmail && (
|
|
||||||
<div className="modaloverlay">
|
|
||||||
<div className="modalcontainer">
|
|
||||||
{isLoading && (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "absolute",
|
|
||||||
height: "100%",
|
|
||||||
width: "100%",
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
|
||||||
zIndex: "20",
|
|
||||||
backgroundColor: "#e6f2f2",
|
|
||||||
opacity: 0.8
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="no img"
|
|
||||||
src={loader}
|
|
||||||
style={{ width: "70px", height: "70px" }}
|
|
||||||
/>
|
|
||||||
<span style={{ fontSize: "12px", fontWeight: "bold" }}>
|
|
||||||
This might take some time
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div style={{ background: "#32a3ac" }} className="modalheader">
|
|
||||||
<span style={{ color: "white" }}>Successfully signed!</span>
|
|
||||||
|
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
|
||||||
<div></div>
|
|
||||||
{!isAndroid && (
|
|
||||||
<button
|
|
||||||
onClick={handleToPrint}
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
className="btn btn-primary btn-sm"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-print"
|
|
||||||
style={{
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px",
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Print
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<button
|
|
||||||
className="btn btn-danger btn-sm"
|
|
||||||
onClick={() => handleDownloadPdf()}
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
marginLeft: "10px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-download"
|
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Download
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ height: "100%", padding: 20 }}>
|
|
||||||
{isCeleb && (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "absolute",
|
|
||||||
marginLeft: "50px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="print img"
|
|
||||||
width={300}
|
|
||||||
height={250}
|
|
||||||
// style={styles.gifCeleb}
|
|
||||||
src={celebration}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
fontFamily: "system-ui",
|
|
||||||
verticalAlign: "baseline",
|
|
||||||
fontWeight: "500",
|
|
||||||
color: "#403f3e",
|
|
||||||
fontSize: "15px",
|
|
||||||
marginBottom: "5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Recipients added here will get a copy of the signed document.
|
|
||||||
</p>
|
|
||||||
{emailList.length > 0 ? (
|
|
||||||
<>
|
|
||||||
<div className="addEmail">
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
|
|
||||||
flexWrap: "wrap"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{emailList.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="emailChip"
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
key={ind}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: "13px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{data}
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: 13,
|
|
||||||
fontWeight: 600,
|
|
||||||
marginLeft: 7,
|
|
||||||
cursor: "pointer"
|
|
||||||
}}
|
|
||||||
onClick={() => removeChip(ind)}
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-xmark"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
{emailList.length <= 9 && (
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={emailValue}
|
|
||||||
className="addEmailInput"
|
|
||||||
onChange={handleEmailValue}
|
|
||||||
onKeyDown={handleEnterPress}
|
|
||||||
onBlur={() => {
|
|
||||||
if (emailValue) {
|
|
||||||
handleEnterPress("add");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={emailValue}
|
|
||||||
className="emailInput"
|
|
||||||
onChange={handleEmailValue}
|
|
||||||
onKeyDown={handleEnterPress}
|
|
||||||
placeholder="Add the email addresses"
|
|
||||||
onBlur={() => {
|
|
||||||
if (emailValue) {
|
|
||||||
handleEnterPress("add");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
cursor: emailValue && "pointer"
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
if (emailValue) {
|
|
||||||
handleEnterPress("add");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
style={{
|
|
||||||
backgroundColor: themeColor,
|
|
||||||
padding: "5px 7px",
|
|
||||||
marginTop: "10px",
|
|
||||||
color: "white",
|
|
||||||
borderRadius: "2px"
|
|
||||||
}}
|
|
||||||
className="fa fa-plus"
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
background: "#e3e2e1",
|
|
||||||
marginTop: "10px",
|
|
||||||
padding: "5px",
|
|
||||||
borderRadius: "3px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span style={{ fontWeight: "700" }}>Note:</span>
|
|
||||||
<span style={{ fontSize: "15px" }}>
|
|
||||||
{" "}
|
|
||||||
You can only send to ten recipients at a time.
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: "1px",
|
|
||||||
backgroundColor: "#9f9f9f",
|
|
||||||
width: "100%",
|
|
||||||
marginTop: "15px",
|
|
||||||
marginBottom: "15px"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
<button
|
|
||||||
disabled={emailList.length === 0 && true}
|
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className={emailList.length === 0 ? "defaultBtn" : "finishBtn"}
|
|
||||||
onClick={() => sendEmail()}
|
|
||||||
>
|
|
||||||
Send
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="finishBtn cancelBtn"
|
|
||||||
onClick={() => {
|
|
||||||
setIsEmail(false);
|
|
||||||
setEmailValue("");
|
|
||||||
setEmailList([]);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Close
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EmailComponent;
|
|
||||||
@@ -1,755 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import PrevNext from "./PrevNext";
|
|
||||||
import { PDFDownloadLink } from "@react-pdf/renderer";
|
|
||||||
import Certificate from "./Certificate";
|
|
||||||
import printModule from "print-js";
|
|
||||||
import { getBase64FromUrl } from "../../constant/Utils";
|
|
||||||
import { saveAs } from "file-saver";
|
|
||||||
import "../../styles/signature.css";
|
|
||||||
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
|
|
||||||
function Header({
|
|
||||||
isPdfRequestFiles,
|
|
||||||
isPlaceholder,
|
|
||||||
recipient,
|
|
||||||
setIsDecline,
|
|
||||||
pageNumber,
|
|
||||||
isAlreadySign,
|
|
||||||
allPages,
|
|
||||||
changePage,
|
|
||||||
pdfUrl,
|
|
||||||
documentStatus,
|
|
||||||
embedWidgetsData,
|
|
||||||
pdfDetails,
|
|
||||||
signerPos,
|
|
||||||
signersdata,
|
|
||||||
isMailSend,
|
|
||||||
alertSendEmail,
|
|
||||||
isCompleted,
|
|
||||||
isShowHeader,
|
|
||||||
decline,
|
|
||||||
currentSigner,
|
|
||||||
dataTut4,
|
|
||||||
alreadySign,
|
|
||||||
isSignYourself,
|
|
||||||
setIsEmail,
|
|
||||||
completeBtnTitle,
|
|
||||||
setIsEditTemplate
|
|
||||||
}) {
|
|
||||||
const filterPrefill =
|
|
||||||
signerPos && signerPos?.filter((data) => data.Role !== "prefill");
|
|
||||||
const isMobile = window.innerWidth < 767;
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
|
||||||
//for go to previous page
|
|
||||||
function previousPage() {
|
|
||||||
changePage(-1);
|
|
||||||
}
|
|
||||||
//for go to next page
|
|
||||||
function nextPage() {
|
|
||||||
changePage(1);
|
|
||||||
}
|
|
||||||
//function for show decline alert
|
|
||||||
const handleDeclinePdfAlert = async () => {
|
|
||||||
const currentDecline = {
|
|
||||||
currnt: "Sure",
|
|
||||||
isDeclined: true
|
|
||||||
};
|
|
||||||
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 (
|
|
||||||
<div style={{ padding: "5px 0px 5px 0px" }} className="mobileHead">
|
|
||||||
{isMobile && isShowHeader ? (
|
|
||||||
<div
|
|
||||||
id="navbar"
|
|
||||||
className={isGuestSigner ? "stickySignerHead" : "stickyHead"}
|
|
||||||
style={{
|
|
||||||
width: isGuestSigner
|
|
||||||
? window.innerWidth
|
|
||||||
: window.innerWidth - 30 + "px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="preBtn2">
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
navigate(-1);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-arrow-left"
|
|
||||||
aria-hidden="true"
|
|
||||||
style={{ color: themeColor, cursor: "pointer" }}
|
|
||||||
></i>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<i
|
|
||||||
onClick={() => {
|
|
||||||
if (pageNumber > 1) {
|
|
||||||
previousPage();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="fa fa-backward"
|
|
||||||
style={{ color: "gray", cursor: "pointer" }}
|
|
||||||
></i>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: "600",
|
|
||||||
marginLeft: "10px",
|
|
||||||
marginRight: "10px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
|
|
||||||
</span>
|
|
||||||
<i
|
|
||||||
onClick={() => {
|
|
||||||
if (pageNumber < allPages) {
|
|
||||||
nextPage();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="fa fa-forward"
|
|
||||||
style={{ color: "gray", cursor: "pointer" }}
|
|
||||||
></i>
|
|
||||||
</div>
|
|
||||||
{pdfUrl && alreadySign ? (
|
|
||||||
<DropdownMenu.Root>
|
|
||||||
<DropdownMenu.Trigger asChild>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
color: themeColor,
|
|
||||||
border: "none",
|
|
||||||
fontWeight: "650",
|
|
||||||
fontSize: "16px",
|
|
||||||
padding: "0px 3px 0px 5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i className="fa fa-ellipsis-v" aria-hidden="true"></i>
|
|
||||||
</div>
|
|
||||||
</DropdownMenu.Trigger>
|
|
||||||
|
|
||||||
<DropdownMenu.Portal>
|
|
||||||
<DropdownMenu.Content
|
|
||||||
className="DropdownMenuContent"
|
|
||||||
sideOffset={5}
|
|
||||||
>
|
|
||||||
<DropdownMenu.Item
|
|
||||||
className="DropdownMenuItem"
|
|
||||||
onClick={() => handleDownloadPdf()}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-arrow-down"
|
|
||||||
aria-hidden="true"
|
|
||||||
style={{ marginRight: "2px" }}
|
|
||||||
></i>
|
|
||||||
Download
|
|
||||||
</div>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
{recipient && pdfDetails[0] && pdfDetails.length > 0 ? (
|
|
||||||
<DropdownMenu.Item className="DropdownMenuItem">
|
|
||||||
<CertificateDropDown />
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
) : isPdfRequestFiles &&
|
|
||||||
alreadySign &&
|
|
||||||
isCompleted.isCertificate ? (
|
|
||||||
<DropdownMenu.Item className="DropdownMenuItem">
|
|
||||||
<CertificateDropDown />
|
|
||||||
</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
|
|
||||||
className="DropdownMenuItem"
|
|
||||||
onClick={handleToPrint}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{" "}
|
|
||||||
<i
|
|
||||||
className="fa fa-print"
|
|
||||||
aria-hidden="true"
|
|
||||||
style={{ marginRight: "2px" }}
|
|
||||||
></i>
|
|
||||||
Print
|
|
||||||
</div>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
</DropdownMenu.Content>
|
|
||||||
</DropdownMenu.Portal>
|
|
||||||
</DropdownMenu.Root>
|
|
||||||
) : (
|
|
||||||
<div style={{ display: "flex", justifyContent: "space-around" }}>
|
|
||||||
{/* current signer is checking user send request and check status of pdf sign than if current
|
|
||||||
user exist than show finish button else no
|
|
||||||
*/}
|
|
||||||
{currentSigner && (
|
|
||||||
<>
|
|
||||||
{decline && (
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
handleDeclinePdfAlert();
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
color: "red",
|
|
||||||
border: "none",
|
|
||||||
fontWeight: "650",
|
|
||||||
fontSize: "16px",
|
|
||||||
marginRight: "10px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Decline
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{isPlaceholder ? (
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
if (!isMailSend) {
|
|
||||||
alertSendEmail();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
color: isMailSend ? "gray" : themeColor,
|
|
||||||
border: "none",
|
|
||||||
fontWeight: "650",
|
|
||||||
fontSize: "16px"
|
|
||||||
}}
|
|
||||||
data-tut={dataTut4}
|
|
||||||
>
|
|
||||||
{completeBtnTitle ? completeBtnTitle : "Send"}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
data-tut="reactourThird"
|
|
||||||
onClick={() => {
|
|
||||||
if (!pdfUrl) {
|
|
||||||
embedWidgetsData();
|
|
||||||
} else if (isPdfRequestFiles) {
|
|
||||||
embedWidgetsData();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
color: themeColor,
|
|
||||||
border: "none",
|
|
||||||
fontWeight: "650",
|
|
||||||
fontSize: "16px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Finish
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="signatureHeader headerBtn">
|
|
||||||
<PrevNext
|
|
||||||
pageNumber={pageNumber}
|
|
||||||
allPages={allPages}
|
|
||||||
changePage={changePage}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{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 &&
|
|
||||||
signersdata.length > 0 &&
|
|
||||||
signersdata.length !== filterPrefill.length && (
|
|
||||||
<div>
|
|
||||||
{filterPrefill.length === 0 ? (
|
|
||||||
<span style={{ fontSize: "13px", color: "#f5405e" }}>
|
|
||||||
Add {signersdata.length - filterPrefill.length}{" "}
|
|
||||||
recipients signature
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
<span style={{ fontSize: "13px", color: "#f5405e" }}>
|
|
||||||
Add {signersdata.length - filterPrefill.length} more
|
|
||||||
recipients signature
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div>
|
|
||||||
{setIsEditTemplate && (
|
|
||||||
<button
|
|
||||||
onClick={() => setIsEditTemplate(true)}
|
|
||||||
style={{
|
|
||||||
border: "none",
|
|
||||||
outline: "none",
|
|
||||||
textAlign: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-gear fa-lg"></i>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
navigate(-1);
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className="defaultBtn backBtn"
|
|
||||||
>
|
|
||||||
Back
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
disabled={isMailSend && true}
|
|
||||||
data-tut="reactourFour"
|
|
||||||
style={{
|
|
||||||
background: isMailSend ? "rgb(203, 203, 203)" : "#188ae2",
|
|
||||||
color: isMailSend && "rgb(77, 75, 75)"
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
alertSendEmail();
|
|
||||||
}}
|
|
||||||
className={isMailSend ? "sendMail" : "sendMail sendHover"}
|
|
||||||
>
|
|
||||||
{completeBtnTitle ? completeBtnTitle : "Send"}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : isPdfRequestFiles ? (
|
|
||||||
alreadySign ? (
|
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
|
||||||
{isCompleted.isCertificate && <CertificateComponent />}
|
|
||||||
<button
|
|
||||||
onClick={handleToPrint}
|
|
||||||
type="button"
|
|
||||||
className="defaultBtn printBtn"
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-print"
|
|
||||||
style={{
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px",
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Print
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="defaultBtn downloadBtn"
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
onClick={() => handleDownloadPdf()}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-download"
|
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Download
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
navigate(-1);
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className="defaultBtn backBtn"
|
|
||||||
>
|
|
||||||
Back
|
|
||||||
</button>
|
|
||||||
{currentSigner && (
|
|
||||||
<>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
background: "#de4337"
|
|
||||||
}}
|
|
||||||
className="finishBtn hoverCss"
|
|
||||||
onClick={() => {
|
|
||||||
handleDeclinePdfAlert();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Decline
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
background: "#188ae2"
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className="finishBtn sendHover"
|
|
||||||
onClick={() => {
|
|
||||||
embedWidgetsData();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Finish
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
) : pdfUrl || (documentStatus && documentStatus.isCompleted) ? (
|
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
|
||||||
<CertificateComponent />
|
|
||||||
<button
|
|
||||||
onClick={handleToPrint}
|
|
||||||
type="button"
|
|
||||||
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"
|
|
||||||
className="defaultBtn downloadBtn"
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
marginLeft: "10px"
|
|
||||||
}}
|
|
||||||
onClick={() => handleDownloadPdf()}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-download"
|
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Download
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="defaultBtn mailBtn"
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
marginLeft: "10px"
|
|
||||||
}}
|
|
||||||
onClick={() => setIsEmail(true)}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa fa-envelope"
|
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
fontSize: "15px",
|
|
||||||
marginRight: "3px"
|
|
||||||
}}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
Mail
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
navigate(-1);
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className="defaultBtn backBtn"
|
|
||||||
>
|
|
||||||
Back
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
background: "#188ae2"
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className="finishBtn sendHover"
|
|
||||||
onClick={() => {
|
|
||||||
if (!pdfUrl) {
|
|
||||||
embedWidgetsData();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Finish
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Header;
|
|
||||||
@@ -1,751 +0,0 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
|
||||||
import BorderResize from "./BorderResize";
|
|
||||||
import PlaceholderBorder from "./PlaceholderBorder";
|
|
||||||
import { Rnd } from "react-rnd";
|
|
||||||
import {
|
|
||||||
defaultWidthHeight,
|
|
||||||
handleCopyNextToWidget,
|
|
||||||
isMobile,
|
|
||||||
onChangeInput,
|
|
||||||
radioButtonWidget,
|
|
||||||
textInputWidget,
|
|
||||||
textWidget
|
|
||||||
} from "../../constant/Utils";
|
|
||||||
import PlaceholderType from "./PlaceholderType";
|
|
||||||
import moment from "moment";
|
|
||||||
import "../../styles/opensigndrive.css";
|
|
||||||
|
|
||||||
const selectFormat = (data) => {
|
|
||||||
switch (data) {
|
|
||||||
case "L":
|
|
||||||
return "MM/dd/yyyy";
|
|
||||||
case "DD-MM-YYYY":
|
|
||||||
return "dd-MM-yyyy";
|
|
||||||
case "DD/MM/YYYY":
|
|
||||||
return "dd/MM/yyyy";
|
|
||||||
case "LL":
|
|
||||||
return "MMMM dd, yyyy";
|
|
||||||
case "DD MMM, YYYY":
|
|
||||||
return "dd MMM, yyyy";
|
|
||||||
case "YYYY-MM-DD":
|
|
||||||
return "yyyy-MM-dd";
|
|
||||||
case "MM-DD-YYYY":
|
|
||||||
return "MM-dd-yyyy";
|
|
||||||
case "MM.DD.YYYY":
|
|
||||||
return "MM.dd.yyyy";
|
|
||||||
case "MMM DD, YYYY":
|
|
||||||
return "MMM dd, yyyy";
|
|
||||||
case "DD MMMM, YYYY":
|
|
||||||
return "dd MMMM, yyyy";
|
|
||||||
default:
|
|
||||||
return "MM/dd/yyyy";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const changeDateToMomentFormat = (format) => {
|
|
||||||
switch (format) {
|
|
||||||
case "MM/dd/yyyy":
|
|
||||||
return "L";
|
|
||||||
case "dd-MM-yyyy":
|
|
||||||
return "DD-MM-YYYY";
|
|
||||||
case "dd/MM/yyyy":
|
|
||||||
return "DD/MM/YYYY";
|
|
||||||
case "MMMM dd, yyyy":
|
|
||||||
return "LL";
|
|
||||||
case "dd MMM, yyyy":
|
|
||||||
return "DD MMM, YYYY";
|
|
||||||
case "yyyy-MM-dd":
|
|
||||||
return "YYYY-MM-DD";
|
|
||||||
case "MM-dd-yyyy":
|
|
||||||
return "MM-DD-YYYY";
|
|
||||||
case "MM.dd.yyyy":
|
|
||||||
return "MM.DD.YYYY";
|
|
||||||
case "MMM dd, yyyy":
|
|
||||||
return "MMM DD, YYYY";
|
|
||||||
case "dd MMMM, yyyy":
|
|
||||||
return "DD MMMM, YYYY";
|
|
||||||
default:
|
|
||||||
return "L";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//function to get default date
|
|
||||||
const getDefaultdate = (selectedDate, format = "dd-MM-yyyy") => {
|
|
||||||
let date;
|
|
||||||
if (format && format === "dd-MM-yyyy") {
|
|
||||||
const newdate = selectedDate
|
|
||||||
? selectedDate
|
|
||||||
: moment(new Date()).format(changeDateToMomentFormat(format));
|
|
||||||
const [day, month, year] = newdate.split("-");
|
|
||||||
date = new Date(`${year}-${month}-${day}`);
|
|
||||||
} else {
|
|
||||||
date = new Date(selectedDate);
|
|
||||||
}
|
|
||||||
const value = date;
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
//function to get default format
|
|
||||||
const getDefaultFormat = (dateFormat) => dateFormat || "MM/dd/yyyy";
|
|
||||||
|
|
||||||
function Placeholder(props) {
|
|
||||||
const [isDraggingEnabled, setDraggingEnabled] = useState(true);
|
|
||||||
const [isShowDateFormat, setIsShowDateFormat] = useState(false);
|
|
||||||
const [selectDate, setSelectDate] = useState({
|
|
||||||
date:
|
|
||||||
props.pos.type === "date"
|
|
||||||
? moment(
|
|
||||||
getDefaultdate(
|
|
||||||
props?.pos?.options?.response,
|
|
||||||
props.pos?.options?.validation?.format
|
|
||||||
).getTime()
|
|
||||||
).format(
|
|
||||||
changeDateToMomentFormat(props.pos?.options?.validation?.format)
|
|
||||||
)
|
|
||||||
: "",
|
|
||||||
format:
|
|
||||||
props.pos.type === "date"
|
|
||||||
? getDefaultFormat(props.pos?.options?.validation?.format)
|
|
||||||
: ""
|
|
||||||
});
|
|
||||||
const [dateFormat, setDateFormat] = useState([]);
|
|
||||||
const [startDate, setStartDate] = useState(
|
|
||||||
props.pos.type === "date" &&
|
|
||||||
getDefaultdate(
|
|
||||||
props?.pos?.options?.response,
|
|
||||||
props.pos?.options?.validation?.format
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const [getCheckboxRenderWidth, setGetCheckboxRenderWidth] = useState({
|
|
||||||
width: null,
|
|
||||||
height: null
|
|
||||||
});
|
|
||||||
const dateFormatArr = [
|
|
||||||
"L",
|
|
||||||
"DD-MM-YYYY",
|
|
||||||
"YYYY-MM-DD",
|
|
||||||
"MM.DD.YYYY",
|
|
||||||
"MM-DD-YYYY",
|
|
||||||
"MMM DD, YYYY",
|
|
||||||
"LL",
|
|
||||||
"DD MMM, YYYY",
|
|
||||||
"DD MMMM, YYYY"
|
|
||||||
];
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const updateWidth = () => {
|
|
||||||
const rndElement = document.getElementById(props.pos.key);
|
|
||||||
if (rndElement) {
|
|
||||||
const { width, height } = rndElement.getBoundingClientRect();
|
|
||||||
setGetCheckboxRenderWidth({ width: width, height: height });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Delay to ensure rendering is complete
|
|
||||||
const timer = setTimeout(updateWidth, 0);
|
|
||||||
|
|
||||||
return () => clearTimeout(timer);
|
|
||||||
}, [props.pos]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const closeMenuOnOutsideClick = (e) => {
|
|
||||||
if (!isDraggingEnabled && !e.target.closest("#changeIsDragging")) {
|
|
||||||
setDraggingEnabled(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener("click", closeMenuOnOutsideClick);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
// Cleanup the event listener when the component unmounts
|
|
||||||
document.removeEventListener("click", closeMenuOnOutsideClick);
|
|
||||||
};
|
|
||||||
}, [isDraggingEnabled]);
|
|
||||||
//function change format array list with selected date and format
|
|
||||||
const changeDateFormat = () => {
|
|
||||||
const updateDate = [];
|
|
||||||
dateFormatArr.map((data) => {
|
|
||||||
let date;
|
|
||||||
if (selectDate && selectDate.format === "dd-MM-yyyy") {
|
|
||||||
const [day, month, year] = selectDate.date.split("-");
|
|
||||||
date = new Date(`${year}-${month}-${day}`);
|
|
||||||
} else {
|
|
||||||
date = new Date(selectDate?.date);
|
|
||||||
}
|
|
||||||
const milliseconds = date.getTime();
|
|
||||||
const newDate = moment(milliseconds).format(data);
|
|
||||||
const dateObj = {
|
|
||||||
date: newDate,
|
|
||||||
format: selectFormat(data)
|
|
||||||
};
|
|
||||||
updateDate.push(dateObj);
|
|
||||||
});
|
|
||||||
setDateFormat(updateDate);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (props.isPlaceholder || props.isSignYourself) {
|
|
||||||
selectDate && changeDateFormat();
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [selectDate]);
|
|
||||||
|
|
||||||
//it detect outside click of date dropdown menu
|
|
||||||
useEffect(() => {
|
|
||||||
const closeMenuOnOutsideClick = (e) => {
|
|
||||||
if (isShowDateFormat && !e.target.closest("#menu-container")) {
|
|
||||||
setIsShowDateFormat(!isShowDateFormat);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
document.addEventListener("click", closeMenuOnOutsideClick);
|
|
||||||
return () => {
|
|
||||||
// Cleanup the event listener when the component unmounts
|
|
||||||
document.removeEventListener("click", closeMenuOnOutsideClick);
|
|
||||||
};
|
|
||||||
}, [isShowDateFormat]);
|
|
||||||
|
|
||||||
//`handleWidgetIdandPopup` is used to set current widget id and open relative popup
|
|
||||||
const handleWidgetIdandPopup = () => {
|
|
||||||
if (props.setSelectWidgetId) {
|
|
||||||
props.setSelectWidgetId(props.pos.key);
|
|
||||||
}
|
|
||||||
|
|
||||||
const widgetTypeExist = [
|
|
||||||
textInputWidget,
|
|
||||||
"checkbox",
|
|
||||||
"name",
|
|
||||||
"company",
|
|
||||||
"job title",
|
|
||||||
"date",
|
|
||||||
"email",
|
|
||||||
textWidget
|
|
||||||
].includes(props.pos.type);
|
|
||||||
|
|
||||||
if (widgetTypeExist) {
|
|
||||||
setDraggingEnabled(false);
|
|
||||||
}
|
|
||||||
if ((props.isNeedSign || props.isSignYourself) && !props.isDragging) {
|
|
||||||
if (props.pos.type) {
|
|
||||||
if (
|
|
||||||
props.pos.type === "signature" ||
|
|
||||||
props.pos.type === "stamp" ||
|
|
||||||
props.pos.type === "image"
|
|
||||||
) {
|
|
||||||
props.setIsSignPad(true);
|
|
||||||
props.setSignKey(props.pos.key);
|
|
||||||
props.setIsStamp(props.pos.isStamp);
|
|
||||||
} else if (props.pos.type === "initials") {
|
|
||||||
props.setIsSignPad(true);
|
|
||||||
props.setSignKey(props.pos.key);
|
|
||||||
props.setIsStamp(props.pos.isStamp);
|
|
||||||
props.setIsInitial(true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
props.setIsSignPad(true);
|
|
||||||
props.setSignKey(props.pos.key);
|
|
||||||
props.setIsStamp(props.pos?.isStamp ? props.pos.isStamp : false);
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
props.isPlaceholder &&
|
|
||||||
!props.isDragging &&
|
|
||||||
props.pos.type !== textWidget
|
|
||||||
) {
|
|
||||||
if (props.pos.key === props.selectWidgetId) {
|
|
||||||
props.handleLinkUser(props.data.Id);
|
|
||||||
props.setUniqueId(props.data.Id);
|
|
||||||
}
|
|
||||||
} else if (!props.pos.type) {
|
|
||||||
if (
|
|
||||||
!props.pos.type &&
|
|
||||||
props.isNeedSign &&
|
|
||||||
props.data.signerObjId === props.signerObjId
|
|
||||||
) {
|
|
||||||
props.setIsSignPad(true);
|
|
||||||
props.setSignKey(props.pos.key);
|
|
||||||
props.setIsStamp(props.pos.isStamp);
|
|
||||||
} else if (
|
|
||||||
(props.isNeedSign && props.pos.type === "signature") ||
|
|
||||||
props.pos.type === "stamp"
|
|
||||||
) {
|
|
||||||
props.setIsSignPad(true);
|
|
||||||
props.setSignKey(props.pos.key);
|
|
||||||
props.setIsStamp(props.pos.isStamp);
|
|
||||||
} else if (props.isNeedSign && props.pos.type === "dropdown") {
|
|
||||||
props.setSignKey(props.pos.key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleOnClickPlaceholder = () => {
|
|
||||||
props.setCurrWidgetsDetails && props.setCurrWidgetsDetails(props.pos);
|
|
||||||
if (!props.isNeedSign) {
|
|
||||||
props.setWidgetType(props.pos.type);
|
|
||||||
}
|
|
||||||
if (props.isNeedSign && props.data?.signerObjId === props.signerObjId) {
|
|
||||||
handleWidgetIdandPopup();
|
|
||||||
} else if (props.isPlaceholder || props.isSignYourself) {
|
|
||||||
handleWidgetIdandPopup();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//`handleOnClickSettingIcon` is used set current widget details and open setting of it
|
|
||||||
const handleOnClickSettingIcon = () => {
|
|
||||||
if (props.pos.type === radioButtonWidget) {
|
|
||||||
props.setIsRadio(true);
|
|
||||||
} else if (props.pos.type === "dropdown") {
|
|
||||||
props?.setShowDropdown(true);
|
|
||||||
} else if (props.pos.type === "checkbox") {
|
|
||||||
props?.setIsCheckbox(true);
|
|
||||||
} else {
|
|
||||||
props?.handleNameModal(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.isPlaceholder && props.type !== textWidget) {
|
|
||||||
props.setUniqueId(props.data.Id);
|
|
||||||
}
|
|
||||||
props.setSignKey(props.pos.key);
|
|
||||||
props.setWidgetType(props.pos.type);
|
|
||||||
props.setCurrWidgetsDetails(props.pos);
|
|
||||||
};
|
|
||||||
//function to set required state value onclick on widget's copy icon
|
|
||||||
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) {
|
|
||||||
props.setSignerObjId(props?.data?.signerObjId);
|
|
||||||
props.setUniqueId(props?.data?.Id);
|
|
||||||
} else if (props.data && props.pos.type === textWidget) {
|
|
||||||
props.setTempSignerId(props.uniqueId);
|
|
||||||
props.setSignerObjId(props?.data?.signerObjId);
|
|
||||||
props.setUniqueId(props?.data?.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
//checking widget's type and open widget copy modal for required widgets
|
|
||||||
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
|
|
||||||
const handleSaveDate = (data, isDateChange) => {
|
|
||||||
let updateDate = data.date;
|
|
||||||
//check if date change by user
|
|
||||||
if (isDateChange) {
|
|
||||||
//`changeDateToMomentFormat` is used to convert date as per required to moment package
|
|
||||||
updateDate = moment(data.date).format(
|
|
||||||
changeDateToMomentFormat(data.format)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
//using moment package is used to change date as per the format provided in selectDate obj e.g. - MM/dd/yyyy -> 03/12/2024
|
|
||||||
//`getDefaultdate` is used to convert update date in new Date() format
|
|
||||||
const date = moment(
|
|
||||||
getDefaultdate(updateDate, data?.format).getTime()
|
|
||||||
).format(changeDateToMomentFormat(data?.format));
|
|
||||||
|
|
||||||
//`onChangeInput` is used to save data related to date in a placeholder field
|
|
||||||
onChangeInput(
|
|
||||||
date,
|
|
||||||
props.pos.key,
|
|
||||||
props.xyPostion,
|
|
||||||
props.index,
|
|
||||||
props.setXyPostion,
|
|
||||||
props.data && props.data.Id,
|
|
||||||
false,
|
|
||||||
data?.format
|
|
||||||
);
|
|
||||||
setSelectDate({ date: date, format: data?.format });
|
|
||||||
};
|
|
||||||
const PlaceholderIcon = () => {
|
|
||||||
return (
|
|
||||||
props.isShowBorder && (
|
|
||||||
<>
|
|
||||||
{(props.isPlaceholder || props.isSignYourself) && (
|
|
||||||
<>
|
|
||||||
{props.pos.type === "checkbox" && props.isSignYourself ? (
|
|
||||||
<i
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleOnClickSettingIcon();
|
|
||||||
}}
|
|
||||||
onTouchEnd={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleOnClickSettingIcon();
|
|
||||||
}}
|
|
||||||
className="fa-solid fa-gear settingIcon"
|
|
||||||
style={{
|
|
||||||
color: "#188ae2",
|
|
||||||
right: "29px",
|
|
||||||
top: "-19px"
|
|
||||||
}}
|
|
||||||
></i>
|
|
||||||
) : (
|
|
||||||
((!props?.pos?.type && props.pos.isStamp) ||
|
|
||||||
(props?.pos?.type &&
|
|
||||||
!["date", textWidget, "signature"].includes(
|
|
||||||
props.pos.type
|
|
||||||
) &&
|
|
||||||
!props.isSignYourself)) && (
|
|
||||||
<i
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleOnClickSettingIcon();
|
|
||||||
}}
|
|
||||||
onTouchEnd={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleOnClickSettingIcon();
|
|
||||||
}}
|
|
||||||
className="fa-solid fa-gear settingIcon"
|
|
||||||
style={{ color: "#188ae2", right: "47px", top: "-19px" }}
|
|
||||||
></i>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
|
|
||||||
{props.pos.type !== textWidget && !props.isSignYourself && (
|
|
||||||
<i
|
|
||||||
data-tut="reactourLinkUser"
|
|
||||||
className="fa-regular fa-user signUserIcon"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
props.handleLinkUser(props.data.Id);
|
|
||||||
props.setUniqueId(props.data.Id);
|
|
||||||
}}
|
|
||||||
onTouchEnd={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
props.handleLinkUser(props.data.Id);
|
|
||||||
props.setUniqueId(props.data.Id);
|
|
||||||
}}
|
|
||||||
style={{ color: "#188ae2", right: "32px", top: "-18px" }}
|
|
||||||
></i>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{props.pos.type === "date" && selectDate && (
|
|
||||||
<div
|
|
||||||
id="menu-container"
|
|
||||||
style={{
|
|
||||||
zIndex: "99",
|
|
||||||
top: "-19px",
|
|
||||||
right: props.isPlaceholder ? "60px" : "44px"
|
|
||||||
}}
|
|
||||||
className={
|
|
||||||
isShowDateFormat
|
|
||||||
? "dropdown signUserIcon show"
|
|
||||||
: "dropdown signUserIcon"
|
|
||||||
}
|
|
||||||
onClick={(e) => {
|
|
||||||
setIsShowDateFormat(!isShowDateFormat);
|
|
||||||
e.stopPropagation();
|
|
||||||
if (props.data) {
|
|
||||||
props.setSignKey(props.pos.key);
|
|
||||||
props.setUniqueId(props.data.Id);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onTouchEnd={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
setIsShowDateFormat(!isShowDateFormat);
|
|
||||||
if (props.data) {
|
|
||||||
props.setSignKey(props.pos.key);
|
|
||||||
props.setUniqueId(props.data.Id);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fa-solid fa-gear settingIcon"
|
|
||||||
style={{
|
|
||||||
color: "#188ae2",
|
|
||||||
fontSize: "14px"
|
|
||||||
}}
|
|
||||||
></i>
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
isShowDateFormat ? "dropdown-menu show" : "dropdown-menu"
|
|
||||||
}
|
|
||||||
aria-labelledby="dropdownMenuButton"
|
|
||||||
aria-expanded={isShowDateFormat ? "true" : "false"}
|
|
||||||
>
|
|
||||||
{dateFormat.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
key={ind}
|
|
||||||
onTouchEnd={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
setIsShowDateFormat(!isShowDateFormat);
|
|
||||||
setSelectDate(data);
|
|
||||||
handleSaveDate(data);
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
setIsShowDateFormat(!isShowDateFormat);
|
|
||||||
setSelectDate(data);
|
|
||||||
handleSaveDate(data);
|
|
||||||
}}
|
|
||||||
className="dropdown-item itemColor"
|
|
||||||
style={{ fontSize: "12px" }}
|
|
||||||
>
|
|
||||||
{data?.date ? data?.date : "nodata"}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<i
|
|
||||||
className="fa-regular fa-copy signCopy"
|
|
||||||
onClick={(e) => handleCopyPlaceholder(e)}
|
|
||||||
onTouchEnd={(e) => handleCopyPlaceholder(e)}
|
|
||||||
style={{ color: "#188ae2", right: "12px", top: "-18px" }}
|
|
||||||
></i>
|
|
||||||
<i
|
|
||||||
className="fa-regular fa-circle-xmark signCloseBtn"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
if (props.data) {
|
|
||||||
props.handleDeleteSign(props.pos.key, props.data.Id);
|
|
||||||
} else {
|
|
||||||
props.handleDeleteSign(props.pos.key);
|
|
||||||
props.setIsStamp(false);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onTouchEnd={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
if (props.data) {
|
|
||||||
props.handleDeleteSign(props.pos.key, props.data?.Id);
|
|
||||||
} else {
|
|
||||||
props.handleDeleteSign(props.pos.key);
|
|
||||||
props.setIsStamp(false);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{ color: "#188ae2", right: "-8px", top: "-18px" }}
|
|
||||||
></i>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Rnd
|
|
||||||
id={props.pos.key}
|
|
||||||
data-tut={props.pos.key === props.unSignedWidgetId ? "IsSigned" : ""}
|
|
||||||
key={props.pos.key}
|
|
||||||
lockAspectRatio={
|
|
||||||
props.pos.type !== textWidget &&
|
|
||||||
(props.pos.Width
|
|
||||||
? props.pos.Width / props.pos.Height
|
|
||||||
: defaultWidthHeight(props.pos.type).width /
|
|
||||||
defaultWidthHeight(props.pos.type).height)
|
|
||||||
}
|
|
||||||
enableResizing={{
|
|
||||||
top: false,
|
|
||||||
right: false,
|
|
||||||
bottom: false,
|
|
||||||
left: false,
|
|
||||||
topRight: false,
|
|
||||||
bottomRight:
|
|
||||||
props.data && props.isNeedSign
|
|
||||||
? props.data?.signerObjId === props.signerObjId &&
|
|
||||||
props.pos.type !== "checkbox" &&
|
|
||||||
props.pos.type !== radioButtonWidget
|
|
||||||
? true
|
|
||||||
: false
|
|
||||||
: props.pos.type !== radioButtonWidget &&
|
|
||||||
props.pos.type !== "checkbox" &&
|
|
||||||
props.pos.key === props.selectWidgetId &&
|
|
||||||
true,
|
|
||||||
bottomLeft: false,
|
|
||||||
topLeft: false
|
|
||||||
}}
|
|
||||||
bounds="parent"
|
|
||||||
className="signYourselfBlock"
|
|
||||||
style={{
|
|
||||||
border: "1px solid #007bff",
|
|
||||||
borderRadius: "2px",
|
|
||||||
textAlign:
|
|
||||||
props.pos.type !== "name" &&
|
|
||||||
props.pos.type !== "company" &&
|
|
||||||
props.pos.type !== "job title" &&
|
|
||||||
"center",
|
|
||||||
cursor:
|
|
||||||
props.data && props.isNeedSign
|
|
||||||
? props.data?.signerObjId === props.signerObjId
|
|
||||||
? "pointer"
|
|
||||||
: "not-allowed"
|
|
||||||
: "all-scroll",
|
|
||||||
zIndex:
|
|
||||||
props.pos.type === "date"
|
|
||||||
? props.pos.key === props.selectWidgetId
|
|
||||||
? 99 + 1
|
|
||||||
: 99
|
|
||||||
: props?.pos?.zIndex
|
|
||||||
? props.pos.zIndex
|
|
||||||
: "5",
|
|
||||||
background: props.data ? props.data.blockColor : "rgb(203 233 237)"
|
|
||||||
}}
|
|
||||||
onDrag={() => {
|
|
||||||
setDraggingEnabled(true);
|
|
||||||
props.handleTabDrag && props.handleTabDrag(props.pos.key);
|
|
||||||
}}
|
|
||||||
size={{
|
|
||||||
width:
|
|
||||||
props.pos.type === radioButtonWidget || props.pos.type === "checkbox"
|
|
||||||
? "auto"
|
|
||||||
: props.posWidth(props.pos, props.isSignYourself),
|
|
||||||
height:
|
|
||||||
props.pos.type === radioButtonWidget || props.pos.type === "checkbox"
|
|
||||||
? "auto"
|
|
||||||
: props.posHeight(props.pos, props.isSignYourself)
|
|
||||||
}}
|
|
||||||
onResizeStart={() => {
|
|
||||||
setDraggingEnabled(true);
|
|
||||||
props.setIsResize && props.setIsResize(true);
|
|
||||||
}}
|
|
||||||
onResizeStop={() => {
|
|
||||||
props.setIsResize && props.setIsResize(false);
|
|
||||||
}}
|
|
||||||
disableDragging={
|
|
||||||
props.isNeedSign
|
|
||||||
? true
|
|
||||||
: props.isPlaceholder && ![textWidget].includes(props.pos.type)
|
|
||||||
? false
|
|
||||||
: !isDraggingEnabled
|
|
||||||
}
|
|
||||||
onDragStop={(event, dragElement) =>
|
|
||||||
props.handleStop &&
|
|
||||||
props.handleStop(event, dragElement, props.data?.Id, props.pos?.key)
|
|
||||||
}
|
|
||||||
default={{
|
|
||||||
x: props.xPos(props.pos, props.isSignYourself),
|
|
||||||
y: props.yPos(props.pos, props.isSignYourself)
|
|
||||||
}}
|
|
||||||
onResize={(e, direction, ref) => {
|
|
||||||
props.handleSignYourselfImageResize &&
|
|
||||||
props.handleSignYourselfImageResize(
|
|
||||||
ref,
|
|
||||||
props.pos.key,
|
|
||||||
props.xyPostion,
|
|
||||||
props.setXyPostion,
|
|
||||||
props.index,
|
|
||||||
props.data && props.data.Id,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
onClick={() => handleOnClickPlaceholder()}
|
|
||||||
>
|
|
||||||
{props.isShowBorder &&
|
|
||||||
props.pos.type !== radioButtonWidget &&
|
|
||||||
props.pos.type !== "checkbox" &&
|
|
||||||
props.pos.key === props.selectWidgetId ? (
|
|
||||||
<BorderResize right={-12} top={-11} />
|
|
||||||
) : props.data && props.isNeedSign && props.pos.type !== "checkbox" ? (
|
|
||||||
props.data?.signerObjId === props.signerObjId &&
|
|
||||||
props.pos.type !== radioButtonWidget &&
|
|
||||||
props.pos.type !== "checkbox" ? (
|
|
||||||
<BorderResize />
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
props.pos.type !== radioButtonWidget &&
|
|
||||||
props.pos.type !== "checkbox" &&
|
|
||||||
props.pos.key === props.selectWidgetId && <BorderResize />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{props.isShowBorder && props.pos.key === props.selectWidgetId && (
|
|
||||||
<PlaceholderBorder
|
|
||||||
setDraggingEnabled={setDraggingEnabled}
|
|
||||||
pos={props.pos}
|
|
||||||
isPlaceholder={props.isPlaceholder}
|
|
||||||
getCheckboxRenderWidth={getCheckboxRenderWidth}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isMobile ? (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
left: props.xPos(props.pos, props.isSignYourself),
|
|
||||||
top: props.yPos(props.pos, props.isSignYourself),
|
|
||||||
width:
|
|
||||||
props.pos.type === radioButtonWidget ||
|
|
||||||
props.pos.type === "checkbox"
|
|
||||||
? "auto"
|
|
||||||
: props.posWidth(props.pos, props.isSignYourself),
|
|
||||||
// "auto", //props.posWidth(props.pos, props.isSignYourself),
|
|
||||||
// height: props.posHeight(props.pos, props.isSignYourself),
|
|
||||||
height:
|
|
||||||
props.pos.type === radioButtonWidget ||
|
|
||||||
props.pos.type === "checkbox"
|
|
||||||
? "auto"
|
|
||||||
: props.posHeight(props.pos, props.isSignYourself),
|
|
||||||
zIndex: "10"
|
|
||||||
}}
|
|
||||||
onTouchEnd={() => handleOnClickPlaceholder()}
|
|
||||||
>
|
|
||||||
{props.pos.key === props.selectWidgetId && <PlaceholderIcon />}
|
|
||||||
|
|
||||||
<PlaceholderType
|
|
||||||
pos={props.pos}
|
|
||||||
xyPostion={props.xyPostion}
|
|
||||||
index={props.index}
|
|
||||||
setXyPostion={props.setXyPostion}
|
|
||||||
data={props.data}
|
|
||||||
setSignKey={props.setSignKey}
|
|
||||||
isShowDropdown={props?.isShowDropdown}
|
|
||||||
isPlaceholder={props.isPlaceholder}
|
|
||||||
isSignYourself={props.isSignYourself}
|
|
||||||
signerObjId={props.signerObjId}
|
|
||||||
handleUserName={props.handleUserName}
|
|
||||||
setDraggingEnabled={setDraggingEnabled}
|
|
||||||
pdfDetails={props?.pdfDetails && props?.pdfDetails[0]}
|
|
||||||
isNeedSign={props.isNeedSign}
|
|
||||||
setSelectDate={setSelectDate}
|
|
||||||
selectDate={selectDate}
|
|
||||||
setValidateAlert={props.setValidateAlert}
|
|
||||||
setStartDate={setStartDate}
|
|
||||||
startDate={startDate}
|
|
||||||
handleSaveDate={handleSaveDate}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{props.pos.key === props.selectWidgetId && <PlaceholderIcon />}
|
|
||||||
<PlaceholderType
|
|
||||||
pos={props.pos}
|
|
||||||
xyPostion={props.xyPostion}
|
|
||||||
index={props.index}
|
|
||||||
setXyPostion={props.setXyPostion}
|
|
||||||
data={props.data}
|
|
||||||
setSignKey={props.setSignKey}
|
|
||||||
isShowDropdown={props?.isShowDropdown}
|
|
||||||
isPlaceholder={props.isPlaceholder}
|
|
||||||
isSignYourself={props.isSignYourself}
|
|
||||||
signerObjId={props.signerObjId}
|
|
||||||
handleUserName={props.handleUserName}
|
|
||||||
setDraggingEnabled={setDraggingEnabled}
|
|
||||||
pdfDetails={props?.pdfDetails && props?.pdfDetails[0]}
|
|
||||||
isNeedSign={props.isNeedSign}
|
|
||||||
setSelectDate={setSelectDate}
|
|
||||||
selectDate={selectDate}
|
|
||||||
setValidateAlert={props.setValidateAlert}
|
|
||||||
setStartDate={setStartDate}
|
|
||||||
startDate={startDate}
|
|
||||||
handleSaveDate={handleSaveDate}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Rnd>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Placeholder;
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
import {
|
|
||||||
defaultWidthHeight,
|
|
||||||
isMobile,
|
|
||||||
radioButtonWidget,
|
|
||||||
resizeBorderExtraWidth,
|
|
||||||
textWidget
|
|
||||||
} from "../../constant/Utils";
|
|
||||||
function PlaceholderBorder(props) {
|
|
||||||
const getResizeBorderExtraWidth = resizeBorderExtraWidth();
|
|
||||||
const defaultWidth = defaultWidthHeight(props.pos.type).width;
|
|
||||||
const defaultHeight = defaultWidthHeight(props.pos.type).height;
|
|
||||||
|
|
||||||
const handleMinWidth = () => {
|
|
||||||
if (props.pos.type === "checkbox" || props.pos.type === radioButtonWidget) {
|
|
||||||
return props.getCheckboxRenderWidth.width + getResizeBorderExtraWidth;
|
|
||||||
} else {
|
|
||||||
return props.pos.Width
|
|
||||||
? props.pos.Width + getResizeBorderExtraWidth
|
|
||||||
: defaultWidth + getResizeBorderExtraWidth;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleMinHeight = () => {
|
|
||||||
if (props.pos.type === "checkbox" || props.pos.type === radioButtonWidget) {
|
|
||||||
return props.getCheckboxRenderWidth.height + getResizeBorderExtraWidth;
|
|
||||||
} else {
|
|
||||||
return props.pos.Height
|
|
||||||
? props.pos.Height + getResizeBorderExtraWidth
|
|
||||||
: defaultHeight + getResizeBorderExtraWidth;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
onMouseEnter={() => !isMobile && props?.setDraggingEnabled(true)}
|
|
||||||
onTouchEnd={() =>
|
|
||||||
props.pos.type === textWidget && props?.setDraggingEnabled(true)
|
|
||||||
}
|
|
||||||
className="borderResize"
|
|
||||||
style={{
|
|
||||||
borderColor: themeColor,
|
|
||||||
borderStyle: "dashed",
|
|
||||||
minWidth: handleMinWidth(),
|
|
||||||
minHeight: handleMinHeight(),
|
|
||||||
borderWidth: "0.2px",
|
|
||||||
overflow: "hidden"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PlaceholderBorder;
|
|
||||||
@@ -1,252 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
|
||||||
import { randomId, textWidget } from "../../constant/Utils";
|
|
||||||
|
|
||||||
function PlaceholderCopy(props) {
|
|
||||||
const copyType = ["All pages", "All pages but last", "All pages but first"];
|
|
||||||
const [selectCopyType, setSelectCopyType] = useState("");
|
|
||||||
|
|
||||||
//function for get copy placeholder position
|
|
||||||
const getCopyPlaceholderPosition = (
|
|
||||||
type,
|
|
||||||
currentPlaceholder,
|
|
||||||
newPageNumber,
|
|
||||||
existPlaceholderPosition
|
|
||||||
) => {
|
|
||||||
const filterPosition =
|
|
||||||
existPlaceholderPosition &&
|
|
||||||
existPlaceholderPosition.filter(
|
|
||||||
(data) => data.xPosition !== currentPlaceholder.xPosition
|
|
||||||
);
|
|
||||||
//copy all page placeholder at requested position except first page
|
|
||||||
if (newPageNumber === 1 && type === "first") {
|
|
||||||
if (filterPosition && filterPosition.length > 0) {
|
|
||||||
return {
|
|
||||||
pageNumber: newPageNumber,
|
|
||||||
pos: [...filterPosition]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//copy all page placeholder at requested position except last page
|
|
||||||
else if (newPageNumber === props.allPages && type === "last") {
|
|
||||||
if (existPlaceholderPosition) {
|
|
||||||
return {
|
|
||||||
pageNumber: newPageNumber,
|
|
||||||
pos: [...filterPosition]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//copy all page placeholder at requested position with existing placeholder position
|
|
||||||
else if (existPlaceholderPosition) {
|
|
||||||
return {
|
|
||||||
pageNumber: newPageNumber,
|
|
||||||
pos: [...filterPosition, currentPlaceholder]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
//copy all page placeholder at requested position
|
|
||||||
else {
|
|
||||||
return {
|
|
||||||
pageNumber: newPageNumber,
|
|
||||||
pos: [currentPlaceholder]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//function for copy placeholder as per select copy type
|
|
||||||
const copyPlaceholder = (type) => {
|
|
||||||
let newPlaceholderPosition = [];
|
|
||||||
let newPageNumber = 1;
|
|
||||||
const signerPosition = props.xyPostion;
|
|
||||||
const signerId = props.signerObjId ? props.signerObjId : props.Id;
|
|
||||||
|
|
||||||
//handle placeholder array and copy for multiple signers placeholder at requested location
|
|
||||||
if (signerId) {
|
|
||||||
//get current signers data
|
|
||||||
let filterSignerPosition;
|
|
||||||
if (props?.signerObjId) {
|
|
||||||
filterSignerPosition = signerPosition.filter(
|
|
||||||
(data) => data.signerObjId === signerId
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
filterSignerPosition = signerPosition.filter(
|
|
||||||
(item) => item.Id === signerId
|
|
||||||
);
|
|
||||||
}
|
|
||||||
//get current pagenumber's all placeholder position data
|
|
||||||
const placeholderPosition = filterSignerPosition[0].placeHolder.filter(
|
|
||||||
(data) => data.pageNumber === props.pageNumber
|
|
||||||
);
|
|
||||||
//get current placeholder position data which user want to copy
|
|
||||||
const currentPlaceholder = placeholderPosition[0].pos.find(
|
|
||||||
(position) => position.key === props.signKey
|
|
||||||
);
|
|
||||||
|
|
||||||
for (let i = 0; i < props.allPages; i++) {
|
|
||||||
const newId = randomId();
|
|
||||||
currentPlaceholder.key = newId;
|
|
||||||
//get exist placeholder position for particular page
|
|
||||||
const existPlaceholder = filterSignerPosition[0].placeHolder.filter(
|
|
||||||
(data) => data.pageNumber === newPageNumber
|
|
||||||
);
|
|
||||||
const existPlaceholderPosition =
|
|
||||||
existPlaceholder[0] && existPlaceholder[0].pos;
|
|
||||||
|
|
||||||
//function for get copy to requested location of placeholder position
|
|
||||||
const getPlaceholderObj = getCopyPlaceholderPosition(
|
|
||||||
type,
|
|
||||||
currentPlaceholder,
|
|
||||||
newPageNumber,
|
|
||||||
existPlaceholderPosition
|
|
||||||
);
|
|
||||||
if (getPlaceholderObj) {
|
|
||||||
newPlaceholderPosition.push(getPlaceholderObj);
|
|
||||||
}
|
|
||||||
newPageNumber++;
|
|
||||||
}
|
|
||||||
let updatedSignerPlaceholder;
|
|
||||||
if (props?.signerObjId) {
|
|
||||||
updatedSignerPlaceholder = signerPosition.map((signersData) => {
|
|
||||||
if (signersData.signerObjId === props.signerObjId) {
|
|
||||||
return {
|
|
||||||
...signersData,
|
|
||||||
placeHolder: newPlaceholderPosition
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return signersData;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
updatedSignerPlaceholder = signerPosition.map((signersData) => {
|
|
||||||
if (signersData.Id === props.Id) {
|
|
||||||
return {
|
|
||||||
...signersData,
|
|
||||||
placeHolder: newPlaceholderPosition
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return signersData;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const signersData = signerPosition;
|
|
||||||
signersData.splice(0, signerPosition.length, ...updatedSignerPlaceholder);
|
|
||||||
props.setXyPostion(signersData);
|
|
||||||
}
|
|
||||||
//handle signyourself array and copy for single signers placeholder at requested location
|
|
||||||
else {
|
|
||||||
const xyPostion = props.xyPostion;
|
|
||||||
|
|
||||||
const placeholderPosition = xyPostion.filter(
|
|
||||||
(data) => data.pageNumber === props.pageNumber
|
|
||||||
);
|
|
||||||
//get current placeholder position data which user want to copy
|
|
||||||
const currentPlaceholder = placeholderPosition[0].pos.find(
|
|
||||||
(pos) => pos.key === props.signKey
|
|
||||||
);
|
|
||||||
|
|
||||||
for (let i = 0; i < props.allPages; i++) {
|
|
||||||
//get exist placeholder position for particular page
|
|
||||||
const existPlaceholder = xyPostion.filter(
|
|
||||||
(data) => data.pageNumber === newPageNumber
|
|
||||||
);
|
|
||||||
const existPlaceholderPosition =
|
|
||||||
existPlaceholder[0] && existPlaceholder[0].pos;
|
|
||||||
|
|
||||||
const newId = randomId();
|
|
||||||
currentPlaceholder.key = newId;
|
|
||||||
//function for get copy to requested location of placeholder position
|
|
||||||
const getPlaceholderObj = getCopyPlaceholderPosition(
|
|
||||||
type,
|
|
||||||
currentPlaceholder,
|
|
||||||
newPageNumber,
|
|
||||||
existPlaceholderPosition
|
|
||||||
);
|
|
||||||
if (getPlaceholderObj) {
|
|
||||||
newPlaceholderPosition.push(getPlaceholderObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
newPageNumber++;
|
|
||||||
}
|
|
||||||
props.setXyPostion(newPlaceholderPosition);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//function for getting selected type placeholder copy
|
|
||||||
const handleApplyCopy = () => {
|
|
||||||
if (selectCopyType === "All pages") {
|
|
||||||
copyPlaceholder("all");
|
|
||||||
} else if (selectCopyType === "All pages but last") {
|
|
||||||
copyPlaceholder("last");
|
|
||||||
} else if (selectCopyType === "All pages but first") {
|
|
||||||
copyPlaceholder("first");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleUniqueId = () => {
|
|
||||||
if (props.widgetType === textWidget) {
|
|
||||||
props.setUniqueId(props?.tempSignerId);
|
|
||||||
props.setTempSignerId("");
|
|
||||||
}
|
|
||||||
props.setIsPageCopy(false);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<ModalUi
|
|
||||||
isOpen={props.isPageCopy}
|
|
||||||
title={"Copy to all pages"}
|
|
||||||
handleClose={() => {
|
|
||||||
props.setIsPageCopy(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{ height: "100%", padding: 20 }}>
|
|
||||||
{copyType.map((data, key) => {
|
|
||||||
return (
|
|
||||||
<div key={key} style={{ display: "flex", flexDirection: "column" }}>
|
|
||||||
<label key={key} style={{ fontSize: "16px", fontWeight: "500" }}>
|
|
||||||
<input
|
|
||||||
style={{ accentColor: "red", marginRight: "10px" }}
|
|
||||||
type="radio"
|
|
||||||
value={data}
|
|
||||||
onChange={() => setSelectCopyType(data)}
|
|
||||||
checked={selectCopyType === data}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{data}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: "1px",
|
|
||||||
backgroundColor: "#9f9f9f",
|
|
||||||
width: "100%",
|
|
||||||
marginTop: "15px",
|
|
||||||
marginBottom: "15px"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
handleApplyCopy();
|
|
||||||
handleUniqueId();
|
|
||||||
}}
|
|
||||||
style={{ background: themeColor }}
|
|
||||||
type="button"
|
|
||||||
disabled={!selectCopyType}
|
|
||||||
className="finishBtn"
|
|
||||||
>
|
|
||||||
Apply
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="finishBtn cancelBtn"
|
|
||||||
onClick={() => {
|
|
||||||
handleUniqueId();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</ModalUi>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PlaceholderCopy;
|
|
||||||
@@ -1,819 +0,0 @@
|
|||||||
import React, { useEffect, useState, forwardRef, useRef } from "react";
|
|
||||||
import {
|
|
||||||
getMonth,
|
|
||||||
getYear,
|
|
||||||
isMobile,
|
|
||||||
onChangeHeightOfTextArea,
|
|
||||||
onChangeInput,
|
|
||||||
radioButtonWidget,
|
|
||||||
range,
|
|
||||||
textInputWidget,
|
|
||||||
textWidget
|
|
||||||
} from "../../constant/Utils";
|
|
||||||
import DatePicker from "react-datepicker";
|
|
||||||
import "react-datepicker/dist/react-datepicker.css";
|
|
||||||
import "../../styles/signature.css";
|
|
||||||
import RegexParser from "regex-parser";
|
|
||||||
|
|
||||||
function PlaceholderType(props) {
|
|
||||||
const type = props?.pos?.type;
|
|
||||||
const [selectOption, setSelectOption] = useState("");
|
|
||||||
const [validatePlaceholder, setValidatePlaceholder] = useState("");
|
|
||||||
const inputRef = useRef(null);
|
|
||||||
const [textValue, setTextValue] = useState();
|
|
||||||
const [selectedCheckbox, setSelectedCheckbox] = useState([]);
|
|
||||||
const years = range(1990, getYear(new Date()) + 16, 1);
|
|
||||||
const months = [
|
|
||||||
"January",
|
|
||||||
"February",
|
|
||||||
"March",
|
|
||||||
"April",
|
|
||||||
"May",
|
|
||||||
"June",
|
|
||||||
"July",
|
|
||||||
"August",
|
|
||||||
"September",
|
|
||||||
"October",
|
|
||||||
"November",
|
|
||||||
"December"
|
|
||||||
];
|
|
||||||
const validateExpression = (regexValidation) => {
|
|
||||||
let regexObject = regexValidation;
|
|
||||||
if (props.pos?.options.validation.type === "regex") {
|
|
||||||
regexObject = RegexParser(regexValidation);
|
|
||||||
}
|
|
||||||
// new RegExp(regexValidation);
|
|
||||||
let isValidate = regexObject.test(textValue);
|
|
||||||
if (!isValidate) {
|
|
||||||
props?.setValidateAlert(true);
|
|
||||||
inputRef.current.focus();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleInputBlur = () => {
|
|
||||||
props.setDraggingEnabled(true);
|
|
||||||
const validateType = props.pos?.options?.validation?.type;
|
|
||||||
let regexValidation;
|
|
||||||
if (validateType) {
|
|
||||||
switch (validateType) {
|
|
||||||
case "email":
|
|
||||||
regexValidation = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
||||||
validateExpression(regexValidation);
|
|
||||||
break;
|
|
||||||
case "number":
|
|
||||||
regexValidation = /^\d+$/;
|
|
||||||
validateExpression(regexValidation);
|
|
||||||
break;
|
|
||||||
case "text":
|
|
||||||
regexValidation = /^[a-zA-Z\s]+$/;
|
|
||||||
validateExpression(regexValidation);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
regexValidation = props.pos?.options.validation.pattern;
|
|
||||||
validateExpression(regexValidation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTextValid = (e) => {
|
|
||||||
const textInput = e.target.value;
|
|
||||||
setTextValue(textInput);
|
|
||||||
};
|
|
||||||
function checkRegularExpress(validateType) {
|
|
||||||
switch (validateType) {
|
|
||||||
case "email":
|
|
||||||
setValidatePlaceholder("demo@gmail.com");
|
|
||||||
break;
|
|
||||||
case "number":
|
|
||||||
setValidatePlaceholder("12345");
|
|
||||||
break;
|
|
||||||
case textInputWidget:
|
|
||||||
setValidatePlaceholder("enter text");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
setValidatePlaceholder("enter text");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (type && type === "checkbox" && props.isNeedSign) {
|
|
||||||
const isDefaultValue = props.pos.options?.defaultValue;
|
|
||||||
if (isDefaultValue) {
|
|
||||||
setSelectedCheckbox(isDefaultValue);
|
|
||||||
}
|
|
||||||
} else if (props.pos?.options?.hint) {
|
|
||||||
setValidatePlaceholder(props.pos?.options.hint);
|
|
||||||
} else if (props.pos?.options?.validation?.type) {
|
|
||||||
checkRegularExpress(props.pos?.options?.validation?.type);
|
|
||||||
}
|
|
||||||
setTextValue(
|
|
||||||
props.pos?.options?.response
|
|
||||||
? props.pos?.options?.response
|
|
||||||
: props.pos?.options?.defaultValue
|
|
||||||
? props.pos?.options?.defaultValue
|
|
||||||
: ""
|
|
||||||
);
|
|
||||||
setSelectOption(
|
|
||||||
props.pos?.options?.response
|
|
||||||
? props.pos?.options?.response
|
|
||||||
: props.pos?.options?.defaultValue
|
|
||||||
? props.pos?.options?.defaultValue
|
|
||||||
: ""
|
|
||||||
);
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (
|
|
||||||
["name", "email", "job title", "company"].includes(props.pos?.type) &&
|
|
||||||
props.isNeedSign &&
|
|
||||||
props.data?.signerObjId === props?.signerObjId
|
|
||||||
) {
|
|
||||||
const defaultData = props.pos?.options?.defaultValue;
|
|
||||||
if (defaultData) {
|
|
||||||
setTextValue(defaultData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [props.pos]);
|
|
||||||
|
|
||||||
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
|
|
||||||
<div
|
|
||||||
className="inputPlaceholder"
|
|
||||||
style={{ overflow: "hidden", fontSize: calculateFontSize() }}
|
|
||||||
onClick={onClick}
|
|
||||||
ref={ref}
|
|
||||||
>
|
|
||||||
{value}
|
|
||||||
<i className="fa-regular fa-calendar" style={{ marginLeft: "5px" }}></i>
|
|
||||||
</div>
|
|
||||||
));
|
|
||||||
ExampleCustomInput.displayName = "ExampleCustomInput";
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (
|
|
||||||
["name", "email", "job title", "company"].includes(type) &&
|
|
||||||
props.isNeedSign &&
|
|
||||||
props.data?.signerObjId === props.signerObjId
|
|
||||||
) {
|
|
||||||
const isDefault = true;
|
|
||||||
const senderUser = localStorage.getItem(`Extand_Class`);
|
|
||||||
const jsonSender = JSON.parse(senderUser);
|
|
||||||
onChangeInput(
|
|
||||||
jsonSender && jsonSender[0],
|
|
||||||
null,
|
|
||||||
props.xyPostion,
|
|
||||||
null,
|
|
||||||
props.setXyPostion,
|
|
||||||
props.data.Id,
|
|
||||||
isDefault
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [type]);
|
|
||||||
|
|
||||||
const calculateFontSize = () => {
|
|
||||||
const fontSize = 10 + Math.min(props.pos.Width, props.pos.Height) * 0.1;
|
|
||||||
const size = fontSize ? fontSize : 12;
|
|
||||||
return size + "px";
|
|
||||||
};
|
|
||||||
//function for show checked checkbox
|
|
||||||
const selectCheckbox = (ind) => {
|
|
||||||
const res = props.pos.options?.response;
|
|
||||||
const defaultCheck = props.pos.options?.defaultValue;
|
|
||||||
if (res && res?.length > 0) {
|
|
||||||
const isSelectIndex = res.indexOf(ind);
|
|
||||||
if (isSelectIndex > -1) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
} else if (defaultCheck) {
|
|
||||||
const isSelectIndex = defaultCheck.indexOf(ind);
|
|
||||||
if (isSelectIndex > -1) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRadioCheck = (data) => {
|
|
||||||
const defaultData = props.pos.options?.defaultValue;
|
|
||||||
if (textValue === data) {
|
|
||||||
return true;
|
|
||||||
} else if (defaultData === data) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//function for set checked and unchecked value of checkbox
|
|
||||||
const handleCheckboxValue = (isChecked, ind) => {
|
|
||||||
let updateSelectedCheckbox = [],
|
|
||||||
checkedList;
|
|
||||||
let isDefaultValue, isDefaultEmpty;
|
|
||||||
if (type === "checkbox") {
|
|
||||||
updateSelectedCheckbox = selectedCheckbox ? selectedCheckbox : [];
|
|
||||||
|
|
||||||
if (isChecked) {
|
|
||||||
updateSelectedCheckbox.push(ind);
|
|
||||||
setSelectedCheckbox(updateSelectedCheckbox);
|
|
||||||
} else {
|
|
||||||
checkedList = selectedCheckbox.filter((data) => data !== ind);
|
|
||||||
setSelectedCheckbox(checkedList);
|
|
||||||
}
|
|
||||||
if (props.isNeedSign) {
|
|
||||||
isDefaultValue = props.pos.options?.defaultValue;
|
|
||||||
}
|
|
||||||
if (isDefaultValue && isDefaultValue.length > 0) {
|
|
||||||
isDefaultEmpty = true;
|
|
||||||
}
|
|
||||||
onChangeInput(
|
|
||||||
checkedList ? checkedList : updateSelectedCheckbox,
|
|
||||||
props.pos.key,
|
|
||||||
props.xyPostion,
|
|
||||||
props.index,
|
|
||||||
props.setXyPostion,
|
|
||||||
props.data && props.data.Id,
|
|
||||||
false,
|
|
||||||
null,
|
|
||||||
isDefaultEmpty
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//function to handle select radio widget and set value seletced by user
|
|
||||||
const handleCheckRadio = (isChecked, data) => {
|
|
||||||
let isDefaultValue,
|
|
||||||
isDefaultEmpty,
|
|
||||||
isRadio = true;
|
|
||||||
if (props.isNeedSign) {
|
|
||||||
isDefaultValue = props.pos.options?.defaultValue;
|
|
||||||
}
|
|
||||||
if (isDefaultValue) {
|
|
||||||
isDefaultEmpty = true;
|
|
||||||
}
|
|
||||||
if (isChecked) {
|
|
||||||
setTextValue(data);
|
|
||||||
} else {
|
|
||||||
setTextValue("");
|
|
||||||
}
|
|
||||||
onChangeInput(
|
|
||||||
data,
|
|
||||||
props.pos.key,
|
|
||||||
props.xyPostion,
|
|
||||||
props.index,
|
|
||||||
props.setXyPostion,
|
|
||||||
props.data && props.data.Id,
|
|
||||||
false,
|
|
||||||
null,
|
|
||||||
isDefaultEmpty,
|
|
||||||
isRadio
|
|
||||||
);
|
|
||||||
};
|
|
||||||
//function to set onchange date
|
|
||||||
const handleOnDateChange = (date) => {
|
|
||||||
props.setStartDate(date);
|
|
||||||
const isDateChange = true;
|
|
||||||
const dateObj = {
|
|
||||||
date: date,
|
|
||||||
format: props.selectDate.format
|
|
||||||
};
|
|
||||||
props.handleSaveDate(dateObj, isDateChange);
|
|
||||||
};
|
|
||||||
//handle height on enter press in text area
|
|
||||||
const handleEnterPress = (e) => {
|
|
||||||
const height = 15;
|
|
||||||
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) {
|
|
||||||
case "signature":
|
|
||||||
return props.pos.SignUrl ? (
|
|
||||||
<img
|
|
||||||
alt="signimg"
|
|
||||||
draggable="false"
|
|
||||||
src={props.pos.SignUrl}
|
|
||||||
style={{
|
|
||||||
width: "99%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
|
|
||||||
{props?.handleUserName &&
|
|
||||||
props?.handleUserName(
|
|
||||||
props?.data?.Id,
|
|
||||||
props?.data?.Role,
|
|
||||||
props?.pos?.type
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "stamp":
|
|
||||||
return props.pos.SignUrl ? (
|
|
||||||
<img
|
|
||||||
alt="signimg"
|
|
||||||
draggable="false"
|
|
||||||
src={props.pos.SignUrl}
|
|
||||||
style={{
|
|
||||||
width: "99%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
|
|
||||||
{props?.handleUserName &&
|
|
||||||
props?.handleUserName(
|
|
||||||
props?.data?.Id,
|
|
||||||
props?.data?.Role,
|
|
||||||
props?.pos?.type
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "checkbox":
|
|
||||||
return (
|
|
||||||
<div style={{ zIndex: props.isSignYourself && "99" }}>
|
|
||||||
{props.pos.options?.values?.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<div key={ind} className="flex items-center text-center gap-0.5">
|
|
||||||
<input
|
|
||||||
style={{
|
|
||||||
// width: props.pos.Width,
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
marginTop: ind === 0 ? 0 : "5px"
|
|
||||||
}}
|
|
||||||
onBlur={handleInputBlur}
|
|
||||||
disabled={
|
|
||||||
props.isNeedSign &&
|
|
||||||
(props.pos.options?.isReadOnly ||
|
|
||||||
props.data?.signerObjId !== props.signerObjId)
|
|
||||||
}
|
|
||||||
type="checkbox"
|
|
||||||
checked={selectCheckbox(ind)}
|
|
||||||
onChange={(e) => {
|
|
||||||
if (e.target.checked) {
|
|
||||||
if (!props.isPlaceholder) {
|
|
||||||
const maxRequired =
|
|
||||||
props.pos.options?.validation?.maxRequiredCount;
|
|
||||||
const maxCountInt =
|
|
||||||
maxRequired && parseInt(maxRequired);
|
|
||||||
|
|
||||||
if (maxCountInt > 0) {
|
|
||||||
if (
|
|
||||||
selectedCheckbox &&
|
|
||||||
selectedCheckbox?.length <= maxCountInt - 1
|
|
||||||
) {
|
|
||||||
handleCheckboxValue(e.target.checked, ind);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
handleCheckboxValue(e.target.checked, ind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
handleCheckboxValue(e.target.checked, ind);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{!props.pos.options?.isHideLabel && (
|
|
||||||
<label className="text-xs mb-0 text-center">{data}</label>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case textInputWidget:
|
|
||||||
return props.isSignYourself ||
|
|
||||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
|
||||||
<input
|
|
||||||
className="inputPlaceholder"
|
|
||||||
ref={inputRef}
|
|
||||||
placeholder={validatePlaceholder}
|
|
||||||
style={{ fontSize: calculateFontSize() }}
|
|
||||||
value={textValue}
|
|
||||||
type="text"
|
|
||||||
tabIndex="0"
|
|
||||||
disabled={
|
|
||||||
props.isNeedSign && props.data?.signerObjId !== props.signerObjId
|
|
||||||
? true
|
|
||||||
: props.isPlaceholder
|
|
||||||
}
|
|
||||||
onBlur={handleInputBlur}
|
|
||||||
onChange={(e) => {
|
|
||||||
setTextValue(e.target.value);
|
|
||||||
onChangeInput(
|
|
||||||
e.target.value,
|
|
||||||
props.pos.key,
|
|
||||||
props.xyPostion,
|
|
||||||
props.index,
|
|
||||||
props.setXyPostion,
|
|
||||||
props.data && props.data?.Id,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
color: "black",
|
|
||||||
fontSize: calculateFontSize()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span>{type}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "dropdown":
|
|
||||||
return props.data?.signerObjId === props.signerObjId ? (
|
|
||||||
<select
|
|
||||||
className="inputPlaceholder"
|
|
||||||
id="myDropdown"
|
|
||||||
style={{ fontSize: "12px" }}
|
|
||||||
value={selectOption}
|
|
||||||
onChange={(e) => {
|
|
||||||
setSelectOption(e.target.value);
|
|
||||||
onChangeInput(
|
|
||||||
e.target.value,
|
|
||||||
props.pos.key,
|
|
||||||
props.xyPostion,
|
|
||||||
props.index,
|
|
||||||
props.setXyPostion,
|
|
||||||
props.data && props.data?.Id,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Default/Title option */}
|
|
||||||
<option value="" disabled hidden>
|
|
||||||
{props?.pos?.options?.name}
|
|
||||||
</option>
|
|
||||||
|
|
||||||
{props.pos?.options?.values.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<option key={ind} value={data}>
|
|
||||||
{data}
|
|
||||||
</option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</select>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
className="inputPlaceholder"
|
|
||||||
style={{ fontSize: calculateFontSize() }}
|
|
||||||
>
|
|
||||||
{props.pos?.options?.name ? props.pos.options.name : type}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "initials":
|
|
||||||
return props.pos.SignUrl ? (
|
|
||||||
<img
|
|
||||||
alt="signimg"
|
|
||||||
draggable="false"
|
|
||||||
src={props.pos.SignUrl}
|
|
||||||
style={{
|
|
||||||
width: "99%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
|
|
||||||
{props?.handleUserName &&
|
|
||||||
props?.handleUserName(
|
|
||||||
props?.data?.Id,
|
|
||||||
props?.data?.Role,
|
|
||||||
props?.pos?.type
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "name":
|
|
||||||
return props.isSignYourself ||
|
|
||||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
|
||||||
<input
|
|
||||||
tabIndex="0"
|
|
||||||
ref={inputRef}
|
|
||||||
placeholder={"name"}
|
|
||||||
style={{ fontSize: calculateFontSize() }}
|
|
||||||
className="inputPlaceholder"
|
|
||||||
type="text"
|
|
||||||
value={textValue}
|
|
||||||
onBlur={handleInputBlur}
|
|
||||||
onChange={(e) => {
|
|
||||||
const isDefault = false;
|
|
||||||
handleTextValid(e);
|
|
||||||
onChangeInput(
|
|
||||||
e.target.value,
|
|
||||||
props.pos.key,
|
|
||||||
props.xyPostion,
|
|
||||||
props.index,
|
|
||||||
props.setXyPostion,
|
|
||||||
props.data && props.data?.Id,
|
|
||||||
isDefault
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
color: "black",
|
|
||||||
fontSize: calculateFontSize()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span>{type}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "company":
|
|
||||||
return props.isSignYourself ||
|
|
||||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
|
||||||
<input
|
|
||||||
className="inputPlaceholder"
|
|
||||||
type="text"
|
|
||||||
ref={inputRef}
|
|
||||||
placeholder={"company"}
|
|
||||||
style={{ fontSize: calculateFontSize() }}
|
|
||||||
value={textValue}
|
|
||||||
onBlur={handleInputBlur}
|
|
||||||
onChange={(e) => {
|
|
||||||
handleTextValid(e);
|
|
||||||
onChangeInput(
|
|
||||||
e.target.value,
|
|
||||||
props.pos.key,
|
|
||||||
props.xyPostion,
|
|
||||||
props.index,
|
|
||||||
props.setXyPostion,
|
|
||||||
props.data && props.data?.Id,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
color: "black",
|
|
||||||
fontSize: calculateFontSize()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span>{type}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "job title":
|
|
||||||
return props.isSignYourself ||
|
|
||||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
|
||||||
<input
|
|
||||||
className="inputPlaceholder"
|
|
||||||
type="text"
|
|
||||||
ref={inputRef}
|
|
||||||
placeholder={"job title"}
|
|
||||||
style={{ fontSize: calculateFontSize() }}
|
|
||||||
value={textValue}
|
|
||||||
onBlur={handleInputBlur}
|
|
||||||
onChange={(e) => {
|
|
||||||
handleTextValid(e);
|
|
||||||
onChangeInput(
|
|
||||||
e.target.value,
|
|
||||||
props.pos.key,
|
|
||||||
props.xyPostion,
|
|
||||||
props.index,
|
|
||||||
props.setXyPostion,
|
|
||||||
props.data && props.data?.Id,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
color: "black",
|
|
||||||
fontSize: calculateFontSize()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span>{type}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "date":
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<DatePicker
|
|
||||||
renderCustomHeader={({ date, changeYear, changeMonth }) => (
|
|
||||||
<div className="flex justify-start ml-2 ">
|
|
||||||
<select
|
|
||||||
className="bg-transparent outline-none"
|
|
||||||
value={months[getMonth(date)]}
|
|
||||||
onChange={({ target: { value } }) =>
|
|
||||||
changeMonth(months.indexOf(value))
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{months.map((option) => (
|
|
||||||
<option key={option} value={option}>
|
|
||||||
{option}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
<select
|
|
||||||
className="bg-transparent outline-none"
|
|
||||||
value={getYear(date)}
|
|
||||||
onChange={({ target: { value } }) => changeYear(value)}
|
|
||||||
>
|
|
||||||
{years.map((option) => (
|
|
||||||
<option key={option} value={option}>
|
|
||||||
{option}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
disabled={
|
|
||||||
props.isPlaceholder ||
|
|
||||||
(props.isNeedSign &&
|
|
||||||
props.data?.signerObjId !== props.signerObjId)
|
|
||||||
}
|
|
||||||
onBlur={handleInputBlur}
|
|
||||||
closeOnScroll={true}
|
|
||||||
className="inputPlaceholder"
|
|
||||||
style={{ outlineColor: "#007bff" }}
|
|
||||||
selected={
|
|
||||||
props?.startDate
|
|
||||||
? props?.startDate
|
|
||||||
: props.pos.options?.response &&
|
|
||||||
new Date(props.pos.options.response)
|
|
||||||
}
|
|
||||||
onChange={(date) => handleOnDateChange(date)}
|
|
||||||
popperPlacement="top-end"
|
|
||||||
customInput={<ExampleCustomInput />}
|
|
||||||
dateFormat={
|
|
||||||
props.selectDate
|
|
||||||
? props.selectDate?.format
|
|
||||||
: props.pos?.options?.validation?.format
|
|
||||||
? props.pos?.options?.validation?.format
|
|
||||||
: "MM/dd/yyyy"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "image":
|
|
||||||
return props.pos.SignUrl ? (
|
|
||||||
<img
|
|
||||||
alt="signimg"
|
|
||||||
draggable="false"
|
|
||||||
src={props.pos.SignUrl}
|
|
||||||
style={{
|
|
||||||
width: "99%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
|
|
||||||
{props?.handleUserName &&
|
|
||||||
props?.handleUserName(
|
|
||||||
props?.data?.Id,
|
|
||||||
props?.data?.Role,
|
|
||||||
props?.pos?.type
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "email":
|
|
||||||
return props.isSignYourself ||
|
|
||||||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
|
|
||||||
<input
|
|
||||||
className="inputPlaceholder"
|
|
||||||
type="text"
|
|
||||||
ref={inputRef}
|
|
||||||
placeholder={"email"}
|
|
||||||
style={{ fontSize: calculateFontSize() }}
|
|
||||||
value={textValue}
|
|
||||||
onBlur={handleInputBlur}
|
|
||||||
onChange={(e) => {
|
|
||||||
handleTextValid(e);
|
|
||||||
onChangeInput(
|
|
||||||
e.target.value,
|
|
||||||
props.pos.key,
|
|
||||||
props.xyPostion,
|
|
||||||
props.index,
|
|
||||||
props.setXyPostion,
|
|
||||||
props.data && props.data?.Id,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
color: "black",
|
|
||||||
fontSize: calculateFontSize()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span>{type}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case radioButtonWidget:
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.pos.options?.values.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<div key={ind} className="flex items-center text-center gap-0.5">
|
|
||||||
<input
|
|
||||||
style={{
|
|
||||||
width: props.pos.Width,
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
marginTop: ind === 0 ? 0 : "5px"
|
|
||||||
}}
|
|
||||||
type="radio"
|
|
||||||
disabled={
|
|
||||||
props.isNeedSign &&
|
|
||||||
(props.pos.options?.isReadOnly ||
|
|
||||||
props.data?.signerObjId !== props.signerObjId)
|
|
||||||
}
|
|
||||||
checked={handleRadioCheck(data)}
|
|
||||||
onChange={(e) => {
|
|
||||||
if (!props.isPlaceholder) {
|
|
||||||
handleCheckRadio(e.target.checked, data);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{!props.pos.options?.isHideLabel && (
|
|
||||||
<label className="text-xs mb-0">{data}</label>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case textWidget:
|
|
||||||
return (
|
|
||||||
<textarea
|
|
||||||
placeholder="Enter label"
|
|
||||||
rows={1}
|
|
||||||
onKeyDown={handleEnterPress}
|
|
||||||
value={textValue}
|
|
||||||
onBlur={handleInputBlur}
|
|
||||||
onChange={(e) => {
|
|
||||||
setTextValue(e.target.value);
|
|
||||||
onChangeInput(
|
|
||||||
e.target.value,
|
|
||||||
props.pos.key,
|
|
||||||
props.xyPostion,
|
|
||||||
props.index,
|
|
||||||
props.setXyPostion,
|
|
||||||
props.data && props.data?.Id,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
className={
|
|
||||||
isMobile
|
|
||||||
? "labelTextArea labelWidthMobile"
|
|
||||||
: "labelTextArea labelWidthDesktop"
|
|
||||||
}
|
|
||||||
style={{ whiteSpace: "pre-wrap" }}
|
|
||||||
cols="50"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return props.pos.SignUrl ? (
|
|
||||||
<div style={{ pointerEvents: "none" }}>
|
|
||||||
<img
|
|
||||||
alt="signimg"
|
|
||||||
draggable="false"
|
|
||||||
src={props.pos.SignUrl}
|
|
||||||
style={{
|
|
||||||
width: "99%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "10px",
|
|
||||||
color: "black",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.pos.isStamp ? <div>stamp</div> : <div>signature</div>}
|
|
||||||
{props?.handleUserName &&
|
|
||||||
props?.handleUserName(props?.data?.Id, props?.data?.Role)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PlaceholderType;
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
|
|
||||||
function PrevNext({ pageNumber, allPages, changePage }) {
|
|
||||||
//for go to previous page
|
|
||||||
function previousPage() {
|
|
||||||
changePage(-1);
|
|
||||||
}
|
|
||||||
//for go to next page
|
|
||||||
function nextPage() {
|
|
||||||
changePage(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className="preBtn1">
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
padding: "3px 20px ",
|
|
||||||
fontSize: "10px",
|
|
||||||
background: "#d3edeb",
|
|
||||||
fontWeight: "600",
|
|
||||||
|
|
||||||
border: "0px",
|
|
||||||
marginRight: "5px"
|
|
||||||
}}
|
|
||||||
disabled={pageNumber <= 1}
|
|
||||||
onClick={previousPage}
|
|
||||||
>
|
|
||||||
Prev
|
|
||||||
</button>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: "600"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
|
|
||||||
</span>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
padding: "3px 20px ",
|
|
||||||
fontSize: "10px",
|
|
||||||
background: "#d3edeb",
|
|
||||||
fontWeight: "600",
|
|
||||||
marginLeft: "5px",
|
|
||||||
border: "0px"
|
|
||||||
}}
|
|
||||||
disabled={pageNumber >= allPages}
|
|
||||||
onClick={nextPage}
|
|
||||||
>
|
|
||||||
Next
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PrevNext;
|
|
||||||
@@ -1,291 +0,0 @@
|
|||||||
import React, { useRef, useState } from "react";
|
|
||||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
|
||||||
import {
|
|
||||||
color,
|
|
||||||
darkenColor,
|
|
||||||
getFirstLetter,
|
|
||||||
isMobile,
|
|
||||||
nameColor
|
|
||||||
} from "../../constant/Utils";
|
|
||||||
|
|
||||||
const RecipientList = (props) => {
|
|
||||||
const [animationParent] = useAutoAnimate();
|
|
||||||
const [isHover, setIsHover] = useState();
|
|
||||||
const [isEdit, setIsEdit] = useState(false);
|
|
||||||
//function for onhover signer name change background color
|
|
||||||
const inputRef = useRef(null);
|
|
||||||
const onHoverStyle = (ind, blockColor) => {
|
|
||||||
const style = {
|
|
||||||
background: blockColor ? blockColor : color[ind % color.length],
|
|
||||||
padding: "10px",
|
|
||||||
marginTop: "2px",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
borderBottom: "1px solid #e3e1e1",
|
|
||||||
alignItems: "center"
|
|
||||||
};
|
|
||||||
return style;
|
|
||||||
};
|
|
||||||
//function for onhover signer name remove background color
|
|
||||||
const nonHoverStyle = () => {
|
|
||||||
const style = {
|
|
||||||
padding: "10px",
|
|
||||||
marginTop: "2px",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
borderBottom: "1px solid #e3e1e1",
|
|
||||||
alignItems: "center"
|
|
||||||
};
|
|
||||||
return style;
|
|
||||||
};
|
|
||||||
const isWidgetExist = (Id) => {
|
|
||||||
return props.signerPos.some((x) => x.Id === Id);
|
|
||||||
};
|
|
||||||
|
|
||||||
//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 (
|
|
||||||
<>
|
|
||||||
{props.signersdata.length > 0 &&
|
|
||||||
props.signersdata.map((obj, ind) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
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="reactourFirst"
|
|
||||||
onMouseEnter={() => setIsHover(ind)}
|
|
||||||
onMouseLeave={() => setIsHover(null)}
|
|
||||||
className={
|
|
||||||
props.sendInOrder
|
|
||||||
? props.isMailSend
|
|
||||||
? "disabled"
|
|
||||||
: "dragCursor"
|
|
||||||
: props.isMailSend && "disabled"
|
|
||||||
}
|
|
||||||
style={
|
|
||||||
(!isMobile && isHover === ind) || props.isSelectListId === ind
|
|
||||||
? onHoverStyle(ind, obj?.blockColor)
|
|
||||||
: nonHoverStyle(ind)
|
|
||||||
}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
props.setSignerObjId(obj?.objectId || "");
|
|
||||||
props.setIsSelectId(ind);
|
|
||||||
props.setContractName(obj?.className || "");
|
|
||||||
props.setUniqueId(obj.Id);
|
|
||||||
props.setRoleName(obj.Role);
|
|
||||||
props.setBlockColor(obj?.blockColor);
|
|
||||||
if (props.handleModal) {
|
|
||||||
props.handleModal();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
width: "100%"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
background: obj?.blockColor
|
|
||||||
? darkenColor(obj?.blockColor, 0.4)
|
|
||||||
: nameColor[ind % nameColor.length],
|
|
||||||
width: 30,
|
|
||||||
height: 30,
|
|
||||||
display: "flex",
|
|
||||||
borderRadius: 30 / 2,
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
marginRight: "12px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className={props.sendInOrder && "dragCursor"}
|
|
||||||
style={{
|
|
||||||
fontSize: "12px",
|
|
||||||
textAlign: "center",
|
|
||||||
fontWeight: "bold",
|
|
||||||
color: "white",
|
|
||||||
textTransform: "uppercase"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isWidgetExist(obj.Id) ? (
|
|
||||||
<i className="fa-solid fa-check"></i>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{obj.Name
|
|
||||||
? getFirstLetter(obj.Name)
|
|
||||||
: getFirstLetter(obj.Role)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: obj.Name ? "column" : "row",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{obj.Name ? (
|
|
||||||
<span className={"userName"}>{obj.Name}</span>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<span
|
|
||||||
className="userName"
|
|
||||||
style={{ cursor: "pointer" }}
|
|
||||||
onClick={() => {
|
|
||||||
setIsEdit({ [obj.Id]: true });
|
|
||||||
props.setRoleName(obj.Role);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isEdit?.[obj.Id] && props.handleRoleChange ? (
|
|
||||||
<input
|
|
||||||
ref={inputRef}
|
|
||||||
style={{
|
|
||||||
backgroundColor: "transparent",
|
|
||||||
width: "inherit",
|
|
||||||
padding: "3px"
|
|
||||||
}}
|
|
||||||
value={obj.Role}
|
|
||||||
onChange={(e) => props.handleRoleChange(e, obj.Id)}
|
|
||||||
onBlur={() => {
|
|
||||||
setIsEdit({});
|
|
||||||
props.handleOnBlur(obj.Role, obj.Id);
|
|
||||||
}}
|
|
||||||
onKeyDown={(e) => {
|
|
||||||
if (e.key === "Enter") {
|
|
||||||
e.preventDefault();
|
|
||||||
inputRef.current.blur();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<span style={{ padding: "3px" }}>{obj.Role}</span>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{obj.Name && <span className={"useEmail"}>{obj.Role}</span>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{isMobile && props.sendInOrder && (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: 5
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
onClick={(e) => {
|
|
||||||
if (ind !== 0) {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleChangeSequence(e, ind, "up");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{ color: ind === 0 ? "gray" : "black" }}
|
|
||||||
>
|
|
||||||
▲
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
onClick={(e) => {
|
|
||||||
if (ind !== props.signersdata.length - 1) {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleChangeSequence(e, ind, null, "down");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
color:
|
|
||||||
ind === props.signersdata.length - 1 ? "gray" : "black"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
▼
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{props.handleDeleteUser && (
|
|
||||||
<div
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
props.handleDeleteUser(obj.Id);
|
|
||||||
}}
|
|
||||||
style={{ cursor: "pointer", marginLeft: "5px" }}
|
|
||||||
>
|
|
||||||
<i className="fa-regular fa-trash-can"></i>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<hr />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default RecipientList;
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import RSC from "react-scrollbars-custom";
|
|
||||||
import { Document, Page } from "react-pdf";
|
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
|
|
||||||
function RenderAllPdfPage({
|
|
||||||
pdfUrl,
|
|
||||||
signPdfUrl,
|
|
||||||
allPages,
|
|
||||||
setAllPages,
|
|
||||||
setPageNumber,
|
|
||||||
setSignBtnPosition,
|
|
||||||
pageNumber
|
|
||||||
}) {
|
|
||||||
//set all number of pages after load pdf
|
|
||||||
function onDocumentLoad({ numPages }) {
|
|
||||||
setAllPages(numPages);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="showPages">
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
|
|
||||||
backgroundColor: "white",
|
|
||||||
height: "100%"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{ width: "140px" }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
background: themeColor
|
|
||||||
// color:"white"
|
|
||||||
}}
|
|
||||||
className="signedStyle"
|
|
||||||
>
|
|
||||||
Pages
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<RSC
|
|
||||||
id="RSC-Example"
|
|
||||||
style={{
|
|
||||||
width: "135px",
|
|
||||||
height: window.innerHeight - 130 + "px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Document
|
|
||||||
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",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
contain: "content"
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
setPageNumber(index + 1);
|
|
||||||
if (setSignBtnPosition) {
|
|
||||||
setSignBtnPosition([]);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Page
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RenderAllPdfPage;
|
|
||||||
@@ -1,694 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import RSC from "react-scrollbars-custom";
|
|
||||||
import { Document, Page } from "react-pdf";
|
|
||||||
import {
|
|
||||||
defaultWidthHeight,
|
|
||||||
handleImageResize,
|
|
||||||
handleSignYourselfImageResize
|
|
||||||
} from "../../constant/Utils";
|
|
||||||
import Placeholder from "./Placeholder";
|
|
||||||
import Alert from "../../primitives/Alert";
|
|
||||||
|
|
||||||
function RenderPdf({
|
|
||||||
pageNumber,
|
|
||||||
pdfOriginalWidth,
|
|
||||||
pdfNewWidth,
|
|
||||||
drop,
|
|
||||||
signerPos,
|
|
||||||
successEmail,
|
|
||||||
handleTabDrag,
|
|
||||||
handleStop,
|
|
||||||
isDragging,
|
|
||||||
setIsSignPad,
|
|
||||||
setIsStamp,
|
|
||||||
handleDeleteSign,
|
|
||||||
setSignKey,
|
|
||||||
pdfDetails,
|
|
||||||
xyPostion,
|
|
||||||
pdfUrl,
|
|
||||||
numPages,
|
|
||||||
pageDetails,
|
|
||||||
pdfRequest,
|
|
||||||
setCurrentSigner,
|
|
||||||
signerObjectId,
|
|
||||||
signedSigners,
|
|
||||||
setPdfLoadFail,
|
|
||||||
placeholder,
|
|
||||||
pdfLoadFail,
|
|
||||||
setSignerPos,
|
|
||||||
setXyPostion,
|
|
||||||
index,
|
|
||||||
containerWH,
|
|
||||||
setIsResize,
|
|
||||||
handleLinkUser,
|
|
||||||
setUniqueId,
|
|
||||||
signersdata,
|
|
||||||
setIsPageCopy,
|
|
||||||
setSignerObjId,
|
|
||||||
setShowDropdown,
|
|
||||||
setIsInitial,
|
|
||||||
setIsValidate,
|
|
||||||
setWidgetType,
|
|
||||||
setValidateAlert,
|
|
||||||
setIsRadio,
|
|
||||||
setCurrWidgetsDetails,
|
|
||||||
setSelectWidgetId,
|
|
||||||
selectWidgetId,
|
|
||||||
unSignedWidgetId,
|
|
||||||
setIsCheckbox,
|
|
||||||
handleNameModal,
|
|
||||||
setTempSignerId,
|
|
||||||
uniqueId
|
|
||||||
}) {
|
|
||||||
const isMobile = window.innerWidth < 767;
|
|
||||||
const newWidth = containerWH.width;
|
|
||||||
const scale = isMobile ? pdfOriginalWidth / newWidth : 1;
|
|
||||||
//check isGuestSigner is present in local if yes than handle login flow header in mobile view
|
|
||||||
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
|
||||||
|
|
||||||
// handle signature block width and height according to screen
|
|
||||||
const posWidth = (pos, signYourself) => {
|
|
||||||
const defaultWidth = defaultWidthHeight(pos.type).width;
|
|
||||||
const posWidth = pos.Width ? pos.Width : defaultWidth;
|
|
||||||
let width;
|
|
||||||
if (signYourself) {
|
|
||||||
width = posWidth;
|
|
||||||
return width;
|
|
||||||
} else {
|
|
||||||
if (isMobile) {
|
|
||||||
if (!pos.isMobile) {
|
|
||||||
if (pos.IsResize) {
|
|
||||||
width = posWidth ? posWidth : defaultWidth;
|
|
||||||
return width;
|
|
||||||
} else {
|
|
||||||
width = (posWidth || defaultWidth) / scale;
|
|
||||||
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
width = posWidth;
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (pos.isMobile) {
|
|
||||||
if (pos.IsResize) {
|
|
||||||
width = posWidth ? posWidth : defaultWidth;
|
|
||||||
return width;
|
|
||||||
} else {
|
|
||||||
width = (posWidth || defaultWidth) * pos.scale;
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
width = posWidth ? posWidth : defaultWidth;
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const posHeight = (pos, signYourself) => {
|
|
||||||
let height;
|
|
||||||
const posHeight = pos.Height;
|
|
||||||
const defaultHeight = defaultWidthHeight(pos.type).height;
|
|
||||||
|
|
||||||
if (signYourself) {
|
|
||||||
height = posHeight ? posHeight : defaultHeight;
|
|
||||||
|
|
||||||
return height;
|
|
||||||
} else {
|
|
||||||
if (isMobile) {
|
|
||||||
if (!pos.isMobile) {
|
|
||||||
if (pos.IsResize) {
|
|
||||||
height = posHeight ? posHeight : defaultHeight;
|
|
||||||
return height;
|
|
||||||
} else {
|
|
||||||
height = (posHeight || defaultHeight) / scale;
|
|
||||||
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
height = posHeight ? posHeight : defaultHeight;
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (pos.isMobile) {
|
|
||||||
if (pos.IsResize) {
|
|
||||||
height = posHeight ? posHeight : defaultHeight;
|
|
||||||
return height;
|
|
||||||
} else {
|
|
||||||
height = (posHeight || defaultHeight) * pos.scale;
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
height = posHeight ? posHeight : defaultHeight;
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const xPos = (pos, signYourself) => {
|
|
||||||
const resizePos = pos.xPosition;
|
|
||||||
if (signYourself) {
|
|
||||||
return resizePos;
|
|
||||||
} else {
|
|
||||||
//checking both condition mobile and desktop view
|
|
||||||
if (isMobile) {
|
|
||||||
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
|
|
||||||
if (!pos.isMobile) {
|
|
||||||
return resizePos / scale;
|
|
||||||
}
|
|
||||||
//pos.isMobile true -- placeholder save from mobile view(small device) handle position in mobile view(small screen) view divided by scale
|
|
||||||
else {
|
|
||||||
return resizePos * (pos.scale / scale);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale
|
|
||||||
|
|
||||||
if (pos.isMobile) {
|
|
||||||
return pos.scale && resizePos * pos.scale;
|
|
||||||
}
|
|
||||||
//else placeholder save from desktop(bigscreen) and show in desktop(bigscreen)
|
|
||||||
else {
|
|
||||||
return resizePos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const yPos = (pos, signYourself) => {
|
|
||||||
const resizePos = pos.yPosition;
|
|
||||||
if (signYourself) {
|
|
||||||
return resizePos;
|
|
||||||
} else {
|
|
||||||
//checking both condition mobile and desktop view
|
|
||||||
if (isMobile) {
|
|
||||||
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
|
|
||||||
if (!pos.isMobile) {
|
|
||||||
return resizePos / scale;
|
|
||||||
}
|
|
||||||
//pos.isMobile true -- placeholder save from mobile view(small device) handle position in mobile view(small screen) view divided by scale
|
|
||||||
else {
|
|
||||||
return resizePos * (pos.scale / scale);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale
|
|
||||||
|
|
||||||
if (pos.isMobile) {
|
|
||||||
return pos.scale && resizePos * pos.scale;
|
|
||||||
}
|
|
||||||
//else placeholder save from desktop(bigscreen) and show in desktop(bigscreen)
|
|
||||||
else {
|
|
||||||
return resizePos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//function for render placeholder block over pdf document
|
|
||||||
const checkSignedSignes = (data) => {
|
|
||||||
const checkSign = signedSigners.filter(
|
|
||||||
(sign) => sign.objectId === data.signerObjId
|
|
||||||
);
|
|
||||||
if (data.signerObjId === signerObjectId) {
|
|
||||||
setCurrentSigner(true);
|
|
||||||
}
|
|
||||||
const handleAllUserName = (Id, Role, type) => {
|
|
||||||
return pdfDetails[0].Signers.map((signerData, key) => {
|
|
||||||
return (
|
|
||||||
signerData.objectId === data.signerObjId && (
|
|
||||||
<React.Fragment key={key}>
|
|
||||||
{signerData?.Name && (
|
|
||||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
|
||||||
{signerData.Name}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{type && (
|
|
||||||
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
|
||||||
)}
|
|
||||||
{Role && (
|
|
||||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
|
||||||
{`(${Role})`}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
checkSign.length === 0 &&
|
|
||||||
data.placeHolder.map((placeData, key) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={key}>
|
|
||||||
{placeData.pageNumber === pageNumber &&
|
|
||||||
placeData.pos.map((pos) => {
|
|
||||||
return (
|
|
||||||
pos && (
|
|
||||||
<React.Fragment key={pos.key}>
|
|
||||||
<Placeholder
|
|
||||||
pos={pos}
|
|
||||||
setSignKey={setSignKey}
|
|
||||||
setIsSignPad={setIsSignPad}
|
|
||||||
setIsStamp={setIsStamp}
|
|
||||||
handleSignYourselfImageResize={handleImageResize}
|
|
||||||
index={pageNumber}
|
|
||||||
xyPostion={signerPos}
|
|
||||||
setXyPostion={setSignerPos}
|
|
||||||
data={data}
|
|
||||||
setIsResize={setIsResize}
|
|
||||||
isShowBorder={false}
|
|
||||||
signerObjId={signerObjectId}
|
|
||||||
isShowDropdown={true}
|
|
||||||
isNeedSign={true}
|
|
||||||
isSignYourself={false}
|
|
||||||
xPos={xPos}
|
|
||||||
yPos={yPos}
|
|
||||||
posWidth={posWidth}
|
|
||||||
posHeight={posHeight}
|
|
||||||
handleUserName={handleAllUserName}
|
|
||||||
isDragging={false}
|
|
||||||
pdfDetails={pdfDetails}
|
|
||||||
setIsInitial={setIsInitial}
|
|
||||||
setValidateAlert={setValidateAlert}
|
|
||||||
unSignedWidgetId={unSignedWidgetId}
|
|
||||||
setSelectWidgetId={setSelectWidgetId}
|
|
||||||
selectWidgetId={selectWidgetId}
|
|
||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUserName = (Id, Role, type) => {
|
|
||||||
if (Id) {
|
|
||||||
const checkSign = signersdata.find((sign) => sign.Id === Id);
|
|
||||||
if (checkSign?.Name) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
|
||||||
{checkSign?.Name}
|
|
||||||
</div>
|
|
||||||
{type && (
|
|
||||||
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
|
||||||
)}
|
|
||||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
|
||||||
{`(${Role})`}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{type && (
|
|
||||||
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
|
||||||
)}
|
|
||||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
|
||||||
{Role}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{type && (
|
|
||||||
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
|
|
||||||
)}
|
|
||||||
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
|
|
||||||
{Role}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{successEmail && <Alert type={"success"}>Email sent successfully!</Alert>}
|
|
||||||
{isMobile && scale ? (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border: "0.1px solid #ebe8e8",
|
|
||||||
marginTop: isGuestSigner && "30px"
|
|
||||||
}}
|
|
||||||
ref={drop}
|
|
||||||
id="container"
|
|
||||||
>
|
|
||||||
{pdfLoadFail.status &&
|
|
||||||
(pdfRequest
|
|
||||||
? signerPos.map((data, key) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={key}>
|
|
||||||
{checkSignedSignes(data)}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: placeholder // placeholder mobile
|
|
||||||
? signerPos.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={ind}>
|
|
||||||
{data.placeHolder.map((placeData, index) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={index}>
|
|
||||||
{placeData.pageNumber === pageNumber &&
|
|
||||||
placeData.pos.map((pos) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={pos.key}>
|
|
||||||
<Placeholder
|
|
||||||
pos={pos}
|
|
||||||
setIsPageCopy={setIsPageCopy}
|
|
||||||
setSignKey={setSignKey}
|
|
||||||
handleDeleteSign={handleDeleteSign}
|
|
||||||
setIsStamp={setIsStamp}
|
|
||||||
handleTabDrag={handleTabDrag}
|
|
||||||
handleStop={handleStop}
|
|
||||||
handleSignYourselfImageResize={
|
|
||||||
handleImageResize
|
|
||||||
}
|
|
||||||
index={pageNumber}
|
|
||||||
xyPostion={signerPos}
|
|
||||||
setXyPostion={setSignerPos}
|
|
||||||
setSignerObjId={setSignerObjId}
|
|
||||||
data={data}
|
|
||||||
setIsResize={setIsResize}
|
|
||||||
setShowDropdown={setShowDropdown}
|
|
||||||
isShowBorder={true}
|
|
||||||
isPlaceholder={true}
|
|
||||||
setUniqueId={setUniqueId}
|
|
||||||
handleLinkUser={handleLinkUser}
|
|
||||||
handleUserName={handleUserName}
|
|
||||||
isSignYourself={false}
|
|
||||||
xPos={xPos}
|
|
||||||
yPos={yPos}
|
|
||||||
posWidth={posWidth}
|
|
||||||
posHeight={posHeight}
|
|
||||||
isDragging={isDragging}
|
|
||||||
setIsValidate={setIsValidate}
|
|
||||||
setWidgetType={setWidgetType}
|
|
||||||
setIsRadio={setIsRadio}
|
|
||||||
setIsCheckbox={setIsCheckbox}
|
|
||||||
setCurrWidgetsDetails={
|
|
||||||
setCurrWidgetsDetails
|
|
||||||
}
|
|
||||||
setSelectWidgetId={setSelectWidgetId}
|
|
||||||
selectWidgetId={selectWidgetId}
|
|
||||||
handleNameModal={handleNameModal}
|
|
||||||
setTempSignerId={setTempSignerId}
|
|
||||||
uniqueId={uniqueId}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: xyPostion.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={ind}>
|
|
||||||
{data.pageNumber === pageNumber &&
|
|
||||||
data.pos.map((pos) => {
|
|
||||||
return (
|
|
||||||
pos && (
|
|
||||||
<Placeholder
|
|
||||||
pos={pos}
|
|
||||||
setIsPageCopy={setIsPageCopy}
|
|
||||||
setSignKey={setSignKey}
|
|
||||||
handleDeleteSign={handleDeleteSign}
|
|
||||||
setIsStamp={setIsStamp}
|
|
||||||
handleTabDrag={handleTabDrag}
|
|
||||||
handleStop={handleStop}
|
|
||||||
handleSignYourselfImageResize={
|
|
||||||
handleSignYourselfImageResize
|
|
||||||
}
|
|
||||||
index={index}
|
|
||||||
xyPostion={xyPostion}
|
|
||||||
setXyPostion={setXyPostion}
|
|
||||||
pdfOriginalWidth={pdfOriginalWidth}
|
|
||||||
containerWH={containerWH}
|
|
||||||
setIsSignPad={setIsSignPad}
|
|
||||||
isShowBorder={true}
|
|
||||||
isSignYourself={true}
|
|
||||||
xPos={xPos}
|
|
||||||
yPos={yPos}
|
|
||||||
posWidth={posWidth}
|
|
||||||
posHeight={posHeight}
|
|
||||||
pdfDetails={pdfDetails[0]}
|
|
||||||
isDragging={isDragging}
|
|
||||||
setIsInitial={setIsInitial}
|
|
||||||
setWidgetType={setWidgetType}
|
|
||||||
setSelectWidgetId={setSelectWidgetId}
|
|
||||||
selectWidgetId={selectWidgetId}
|
|
||||||
handleUserName={handleUserName}
|
|
||||||
setIsCheckbox={setIsCheckbox}
|
|
||||||
setValidateAlert={setValidateAlert}
|
|
||||||
setCurrWidgetsDetails={setCurrWidgetsDetails}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}))}
|
|
||||||
|
|
||||||
{/* this component for render pdf document is in middle of the component */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Document
|
|
||||||
onLoadError={() => {
|
|
||||||
setPdfLoadFail(true);
|
|
||||||
}}
|
|
||||||
loading={"Loading Document.."}
|
|
||||||
onLoadSuccess={pageDetails}
|
|
||||||
// ref={pdfRef}'
|
|
||||||
onClick={() => {
|
|
||||||
if (setSelectWidgetId) {
|
|
||||||
setSelectWidgetId("");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
file={
|
|
||||||
pdfUrl
|
|
||||||
? pdfUrl
|
|
||||||
: pdfDetails[0] && pdfDetails[0].SignedUrl
|
|
||||||
? pdfDetails[0].SignedUrl
|
|
||||||
: pdfDetails[0].URL
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{Array.from(new Array(numPages), (el, index) => (
|
|
||||||
<Page
|
|
||||||
key={index}
|
|
||||||
pageNumber={pageNumber}
|
|
||||||
width={containerWH.width}
|
|
||||||
height={containerWH.height}
|
|
||||||
renderAnnotationLayer={false}
|
|
||||||
renderTextLayer={false}
|
|
||||||
onGetAnnotationsError={(error) => {
|
|
||||||
console.log("annotation error", error);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Document>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<RSC
|
|
||||||
style={{
|
|
||||||
position: "relative",
|
|
||||||
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
|
|
||||||
width:
|
|
||||||
pdfOriginalWidth > pdfNewWidth ? pdfNewWidth : pdfOriginalWidth,
|
|
||||||
height: window.innerHeight - 110 + "px"
|
|
||||||
}}
|
|
||||||
noScrollY={false}
|
|
||||||
noScrollX={pdfNewWidth < pdfOriginalWidth ? false : true}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border: "0.1px solid #ebe8e8",
|
|
||||||
width: pdfOriginalWidth
|
|
||||||
}}
|
|
||||||
ref={drop}
|
|
||||||
id="container"
|
|
||||||
>
|
|
||||||
{pdfLoadFail.status &&
|
|
||||||
(pdfRequest
|
|
||||||
? signerPos.map((data, key) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={key}>
|
|
||||||
{checkSignedSignes(data)}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: placeholder
|
|
||||||
? signerPos.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={ind}>
|
|
||||||
{data.placeHolder.map((placeData, index) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={index}>
|
|
||||||
{placeData.pageNumber === pageNumber &&
|
|
||||||
placeData.pos.map((pos) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={pos.key}>
|
|
||||||
<Placeholder
|
|
||||||
pos={pos}
|
|
||||||
setIsPageCopy={setIsPageCopy}
|
|
||||||
setSignKey={setSignKey}
|
|
||||||
handleDeleteSign={handleDeleteSign}
|
|
||||||
setIsStamp={setIsStamp}
|
|
||||||
handleTabDrag={handleTabDrag}
|
|
||||||
handleStop={handleStop}
|
|
||||||
handleSignYourselfImageResize={
|
|
||||||
handleImageResize
|
|
||||||
}
|
|
||||||
index={pageNumber}
|
|
||||||
xyPostion={signerPos}
|
|
||||||
setXyPostion={setSignerPos}
|
|
||||||
setSignerObjId={setSignerObjId}
|
|
||||||
data={data}
|
|
||||||
setIsResize={setIsResize}
|
|
||||||
setShowDropdown={setShowDropdown}
|
|
||||||
isShowBorder={true}
|
|
||||||
isPlaceholder={true}
|
|
||||||
setUniqueId={setUniqueId}
|
|
||||||
handleLinkUser={handleLinkUser}
|
|
||||||
handleUserName={handleUserName}
|
|
||||||
isSignYourself={false}
|
|
||||||
xPos={xPos}
|
|
||||||
yPos={yPos}
|
|
||||||
posWidth={posWidth}
|
|
||||||
posHeight={posHeight}
|
|
||||||
isDragging={isDragging}
|
|
||||||
setIsValidate={setIsValidate}
|
|
||||||
setWidgetType={setWidgetType}
|
|
||||||
setIsRadio={setIsRadio}
|
|
||||||
setIsCheckbox={setIsCheckbox}
|
|
||||||
setCurrWidgetsDetails={
|
|
||||||
setCurrWidgetsDetails
|
|
||||||
}
|
|
||||||
setSelectWidgetId={setSelectWidgetId}
|
|
||||||
selectWidgetId={selectWidgetId}
|
|
||||||
handleNameModal={handleNameModal}
|
|
||||||
setTempSignerId={setTempSignerId}
|
|
||||||
uniqueId={uniqueId}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: xyPostion.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<React.Fragment key={ind}>
|
|
||||||
{data.pageNumber === pageNumber &&
|
|
||||||
data.pos.map((pos) => {
|
|
||||||
return (
|
|
||||||
pos && (
|
|
||||||
<React.Fragment key={pos.key}>
|
|
||||||
<Placeholder
|
|
||||||
pos={pos}
|
|
||||||
setIsPageCopy={setIsPageCopy}
|
|
||||||
setSignKey={setSignKey}
|
|
||||||
handleDeleteSign={handleDeleteSign}
|
|
||||||
setIsStamp={setIsStamp}
|
|
||||||
handleTabDrag={handleTabDrag}
|
|
||||||
handleStop={(event, dragElement) =>
|
|
||||||
handleStop(event, dragElement, pos.type)
|
|
||||||
}
|
|
||||||
handleSignYourselfImageResize={
|
|
||||||
handleSignYourselfImageResize
|
|
||||||
}
|
|
||||||
index={index}
|
|
||||||
xyPostion={xyPostion}
|
|
||||||
setXyPostion={setXyPostion}
|
|
||||||
pdfOriginalWidth={pdfOriginalWidth}
|
|
||||||
containerWH={containerWH}
|
|
||||||
setIsSignPad={setIsSignPad}
|
|
||||||
isShowBorder={true}
|
|
||||||
isSignYourself={true}
|
|
||||||
xPos={xPos}
|
|
||||||
yPos={yPos}
|
|
||||||
posWidth={posWidth}
|
|
||||||
posHeight={posHeight}
|
|
||||||
pdfDetails={pdfDetails[0]}
|
|
||||||
isDragging={isDragging}
|
|
||||||
setIsInitial={setIsInitial}
|
|
||||||
setWidgetType={setWidgetType}
|
|
||||||
setSelectWidgetId={setSelectWidgetId}
|
|
||||||
selectWidgetId={selectWidgetId}
|
|
||||||
handleUserName={handleUserName}
|
|
||||||
setIsCheckbox={setIsCheckbox}
|
|
||||||
setValidateAlert={setValidateAlert}
|
|
||||||
setCurrWidgetsDetails={
|
|
||||||
setCurrWidgetsDetails
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}))}
|
|
||||||
|
|
||||||
{/* this component for render pdf document is in middle of the component */}
|
|
||||||
<Document
|
|
||||||
onLoadError={() => {
|
|
||||||
const load = {
|
|
||||||
status: false,
|
|
||||||
type: "failed"
|
|
||||||
};
|
|
||||||
setPdfLoadFail(load);
|
|
||||||
}}
|
|
||||||
loading={"Loading Document.."}
|
|
||||||
onLoadSuccess={pageDetails}
|
|
||||||
onClick={() => {
|
|
||||||
if (setSelectWidgetId) {
|
|
||||||
setSelectWidgetId("");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
// ref={pdfRef}
|
|
||||||
file={
|
|
||||||
pdfUrl
|
|
||||||
? pdfUrl
|
|
||||||
: pdfDetails[0] && pdfDetails[0].SignedUrl
|
|
||||||
? pdfDetails[0].SignedUrl
|
|
||||||
: pdfDetails[0].URL
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{Array.from(new Array(numPages), (el, index) => (
|
|
||||||
<Page
|
|
||||||
key={index}
|
|
||||||
pageNumber={pageNumber}
|
|
||||||
renderAnnotationLayer={false}
|
|
||||||
renderTextLayer={false}
|
|
||||||
onGetAnnotationsError={(error) => {
|
|
||||||
console.log("annotation error", error);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Document>
|
|
||||||
</div>
|
|
||||||
</RSC>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RenderPdf;
|
|
||||||
@@ -1,712 +0,0 @@
|
|||||||
import React, { useRef, useState, useEffect } from "react";
|
|
||||||
import SignatureCanvas from "react-signature-canvas";
|
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
|
|
||||||
function SignPad({
|
|
||||||
isSignPad,
|
|
||||||
isStamp,
|
|
||||||
setIsImageSelect,
|
|
||||||
onSaveSign,
|
|
||||||
setIsSignPad,
|
|
||||||
setImage,
|
|
||||||
isImageSelect,
|
|
||||||
imageRef,
|
|
||||||
onImageChange,
|
|
||||||
onSaveImage,
|
|
||||||
image,
|
|
||||||
defaultSign,
|
|
||||||
setSignature,
|
|
||||||
myInitial,
|
|
||||||
isInitial,
|
|
||||||
setIsInitial,
|
|
||||||
setIsStamp,
|
|
||||||
widgetType,
|
|
||||||
currWidgetsDetails,
|
|
||||||
setCurrWidgetsDetails
|
|
||||||
}) {
|
|
||||||
const [penColor, setPenColor] = useState("blue");
|
|
||||||
const allColor = ["blue", "red", "black"];
|
|
||||||
const canvasRef = useRef(null);
|
|
||||||
const [isDefaultSign, setIsDefaultSign] = useState(false);
|
|
||||||
const [isTab, setIsTab] = useState("draw");
|
|
||||||
const [isSignImg, setIsSignImg] = useState("");
|
|
||||||
const [signValue, setSignValue] = useState("");
|
|
||||||
const [textWidth, setTextWidth] = useState(null);
|
|
||||||
const [textHeight, setTextHeight] = useState(null);
|
|
||||||
const [signatureType, setSignatureType] = useState("draw");
|
|
||||||
const fontOptions = [
|
|
||||||
{ value: "Fasthand" },
|
|
||||||
{ value: "Dancing Script" },
|
|
||||||
{ value: "Cedarville Cursive" },
|
|
||||||
{ value: "Delicious Handrawn" }
|
|
||||||
// Add more font options as needed
|
|
||||||
];
|
|
||||||
const [fontSelect, setFontSelect] = useState(fontOptions[0].value);
|
|
||||||
|
|
||||||
const senderUser =
|
|
||||||
localStorage.getItem(
|
|
||||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
|
||||||
) &&
|
|
||||||
localStorage.getItem(
|
|
||||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
|
||||||
);
|
|
||||||
const jsonSender = JSON.parse(senderUser);
|
|
||||||
const currentUserName = jsonSender && jsonSender.name;
|
|
||||||
|
|
||||||
//function for clear signature image
|
|
||||||
const handleClear = () => {
|
|
||||||
setCurrWidgetsDetails({});
|
|
||||||
if (isTab === "draw") {
|
|
||||||
if (canvasRef.current) {
|
|
||||||
canvasRef.current.clear();
|
|
||||||
} else if (isStamp) {
|
|
||||||
setImage("");
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsSignImg("");
|
|
||||||
} else if (isTab === "uploadImage") {
|
|
||||||
setImage("");
|
|
||||||
}
|
|
||||||
// setIsInitial(false);
|
|
||||||
};
|
|
||||||
//function for set signature url
|
|
||||||
const handleSignatureChange = () => {
|
|
||||||
setSignature(canvasRef.current.toDataURL());
|
|
||||||
setIsSignImg(canvasRef.current.toDataURL());
|
|
||||||
};
|
|
||||||
|
|
||||||
//save button component
|
|
||||||
const SaveBtn = () => {
|
|
||||||
return (
|
|
||||||
<div style={{ marginTop: "2px" }}>
|
|
||||||
{(isTab === "draw" || isTab === "uploadImage") && (
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
color: "black",
|
|
||||||
border: "1px solid #ccc"
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
className="finishBtn saveBtn"
|
|
||||||
onClick={() => handleClear()}
|
|
||||||
>
|
|
||||||
Clear
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
setCurrWidgetsDetails({});
|
|
||||||
if (!image) {
|
|
||||||
if (isTab === "mysignature") {
|
|
||||||
setIsSignImg("");
|
|
||||||
if (isInitial) {
|
|
||||||
onSaveSign(signatureType, "initials");
|
|
||||||
} else {
|
|
||||||
onSaveSign(null, "default");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (isTab === "type") {
|
|
||||||
setIsSignImg("");
|
|
||||||
onSaveSign(null, false, textWidth, textHeight);
|
|
||||||
} else {
|
|
||||||
onSaveSign(signatureType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setPenColor("blue");
|
|
||||||
} else {
|
|
||||||
setIsSignImg("");
|
|
||||||
onSaveImage(signatureType);
|
|
||||||
}
|
|
||||||
setIsSignPad(false);
|
|
||||||
setIsInitial(false);
|
|
||||||
setIsImageSelect(false);
|
|
||||||
setIsDefaultSign(false);
|
|
||||||
setImage();
|
|
||||||
setIsTab("draw");
|
|
||||||
setSignValue("");
|
|
||||||
setIsStamp(false);
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
disabled={
|
|
||||||
isSignImg || image || isDefaultSign || textWidth ? false : true
|
|
||||||
}
|
|
||||||
type="button"
|
|
||||||
className={
|
|
||||||
isSignImg || image || isDefaultSign || textWidth
|
|
||||||
? "finishBtn saveBtn"
|
|
||||||
: "disabledFinish saveBtn"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</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(() => {
|
|
||||||
const loadFont = async () => {
|
|
||||||
try {
|
|
||||||
await document.fonts.load(`20px ${fontSelect}`);
|
|
||||||
const selectFontSTyle = fontOptions.find(
|
|
||||||
(font) => font.value === fontSelect
|
|
||||||
);
|
|
||||||
setFontSelect(selectFontSTyle?.value || fontOptions[0].value);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error loading font:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
loadFont();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [fontSelect]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Load the default signature after the component mounts
|
|
||||||
if (canvasRef.current) {
|
|
||||||
canvasRef.current.fromDataURL(isSignImg);
|
|
||||||
}
|
|
||||||
if (isTab === "type") {
|
|
||||||
const trimmedName = signValue ? signValue.trim() : currentUserName.trim();
|
|
||||||
const firstCharacter = trimmedName.charAt(0);
|
|
||||||
const userName = isInitial ? firstCharacter : signValue;
|
|
||||||
setSignValue(userName);
|
|
||||||
convertToImg(fontSelect, userName);
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [isTab]);
|
|
||||||
|
|
||||||
//function for convert input text value in image
|
|
||||||
const convertToImg = async (fontStyle, text, color) => {
|
|
||||||
//get text content to convert in image
|
|
||||||
const textContent = text;
|
|
||||||
const fontfamily = fontStyle
|
|
||||||
? fontStyle
|
|
||||||
: fontSelect
|
|
||||||
? fontSelect
|
|
||||||
: "Fasthand";
|
|
||||||
|
|
||||||
//creating span for getting text content width
|
|
||||||
const span = document.createElement("span");
|
|
||||||
span.textContent = textContent;
|
|
||||||
span.style.font = `20px ${fontfamily}`; // here put your text size and font family
|
|
||||||
span.style.color = color ? color : penColor;
|
|
||||||
span.style.display = "hidden";
|
|
||||||
document.body.appendChild(span); // Replace 'container' with the ID of the container element
|
|
||||||
|
|
||||||
//create canvas to render text in canvas and convert in image
|
|
||||||
const canvasElement = document.createElement("canvas");
|
|
||||||
// Draw the text content on the canvas
|
|
||||||
const ctx = canvasElement.getContext("2d");
|
|
||||||
const pixelRatio = window.devicePixelRatio || 1;
|
|
||||||
const width = span.offsetWidth;
|
|
||||||
const height = span.offsetHeight;
|
|
||||||
setTextWidth(width);
|
|
||||||
setTextHeight(height);
|
|
||||||
const font = span.style["font"];
|
|
||||||
// Set the canvas dimensions to match the span
|
|
||||||
canvasElement.width = width * pixelRatio;
|
|
||||||
canvasElement.height = height * pixelRatio;
|
|
||||||
|
|
||||||
// You can customize text styles if needed
|
|
||||||
ctx.font = font;
|
|
||||||
ctx.fillStyle = color ? color : penColor; // Set the text color
|
|
||||||
ctx.textAlign = "center";
|
|
||||||
ctx.textBaseline = "middle";
|
|
||||||
ctx.scale(pixelRatio, pixelRatio);
|
|
||||||
// Draw the content of the span onto the canvas
|
|
||||||
ctx.fillText(span.textContent, width / 2, height / 2); // Adjust the x,y-coordinate as needed
|
|
||||||
//remove span tag
|
|
||||||
document.body.removeChild(span);
|
|
||||||
// Convert the canvas to image data
|
|
||||||
const dataUrl = canvasElement.toDataURL("image/png");
|
|
||||||
setSignature(dataUrl);
|
|
||||||
};
|
|
||||||
|
|
||||||
const PenColorComponent = (props) => {
|
|
||||||
return (
|
|
||||||
<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={() => {
|
|
||||||
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 solid fa-pen-nib"
|
|
||||||
width={20}
|
|
||||||
height={20}
|
|
||||||
></i>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{isSignPad && (
|
|
||||||
<div className="modaloverlay">
|
|
||||||
<div className="modalcontainer">
|
|
||||||
<div
|
|
||||||
className="modalheader"
|
|
||||||
style={{ padding: "0 13px", marginTop: "5px" }}
|
|
||||||
>
|
|
||||||
<div className="modaltitle">
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
background: "white",
|
|
||||||
marginTop: "3px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-around",
|
|
||||||
alignItems: "end",
|
|
||||||
gap: 10
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isStamp ? (
|
|
||||||
<span style={{ color: themeColor }} className="signTab">
|
|
||||||
{widgetType === "image"
|
|
||||||
? "Upload image"
|
|
||||||
: "Upload stamp image"}
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<div>
|
|
||||||
<span
|
|
||||||
onClick={() => {
|
|
||||||
setIsDefaultSign(false);
|
|
||||||
setIsImageSelect(false);
|
|
||||||
setIsTab("draw");
|
|
||||||
setImage();
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
color: isTab === "draw" ? themeColor : "#515252",
|
|
||||||
marginLeft: "2px"
|
|
||||||
}}
|
|
||||||
className="signTab"
|
|
||||||
>
|
|
||||||
Draw
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border:
|
|
||||||
isTab === "draw"
|
|
||||||
? "1.5px solid #108783"
|
|
||||||
: "1.5px solid #ffffff"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span
|
|
||||||
onClick={() => {
|
|
||||||
setIsDefaultSign(false);
|
|
||||||
setIsImageSelect(true);
|
|
||||||
setIsTab("uploadImage");
|
|
||||||
setSignatureType("");
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
color:
|
|
||||||
isTab === "uploadImage" ? themeColor : "#515252"
|
|
||||||
}}
|
|
||||||
className="signTab"
|
|
||||||
>
|
|
||||||
Upload Image
|
|
||||||
</span>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border:
|
|
||||||
isTab === "uploadImage"
|
|
||||||
? "1.5px solid #108783"
|
|
||||||
: "1.5px solid #ffffff"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span
|
|
||||||
onClick={() => {
|
|
||||||
setIsDefaultSign(false);
|
|
||||||
setIsImageSelect(false);
|
|
||||||
setIsTab("type");
|
|
||||||
setSignatureType("");
|
|
||||||
setImage();
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
color: isTab === "type" ? themeColor : "#515252",
|
|
||||||
marginLeft: "2px"
|
|
||||||
}}
|
|
||||||
className="signTab"
|
|
||||||
>
|
|
||||||
Type
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border:
|
|
||||||
isTab === "type"
|
|
||||||
? "1.5px solid #108783"
|
|
||||||
: "1.5px solid #ffffff"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
{!isInitial && defaultSign ? (
|
|
||||||
<div>
|
|
||||||
<span
|
|
||||||
onClick={() => {
|
|
||||||
setIsDefaultSign(true);
|
|
||||||
setIsImageSelect(true);
|
|
||||||
setIsTab("mysignature");
|
|
||||||
setSignatureType("");
|
|
||||||
setImage();
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
color:
|
|
||||||
isTab === "mysignature"
|
|
||||||
? themeColor
|
|
||||||
: "#515252"
|
|
||||||
}}
|
|
||||||
className="signTab"
|
|
||||||
>
|
|
||||||
My Signature
|
|
||||||
</span>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border:
|
|
||||||
isTab === "mysignature"
|
|
||||||
? "1.5px solid #108783"
|
|
||||||
: "1.5px solid #ffffff"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
isInitial &&
|
|
||||||
myInitial && (
|
|
||||||
<div>
|
|
||||||
<span
|
|
||||||
onClick={() => {
|
|
||||||
setIsDefaultSign(true);
|
|
||||||
setIsImageSelect(true);
|
|
||||||
setIsTab("mysignature");
|
|
||||||
setSignatureType("");
|
|
||||||
setImage();
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
color:
|
|
||||||
isTab === "mysignature"
|
|
||||||
? themeColor
|
|
||||||
: "#515252"
|
|
||||||
}}
|
|
||||||
className="signTab"
|
|
||||||
>
|
|
||||||
My Initials
|
|
||||||
</span>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border:
|
|
||||||
isTab === "mysignature"
|
|
||||||
? "1.5px solid #108783"
|
|
||||||
: "1.5px solid #ffffff"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="closebtn"
|
|
||||||
style={{ color: "black" }}
|
|
||||||
onClick={() => {
|
|
||||||
setPenColor("blue");
|
|
||||||
setIsSignPad(false);
|
|
||||||
setIsInitial(false);
|
|
||||||
setIsImageSelect(false);
|
|
||||||
setIsDefaultSign(false);
|
|
||||||
setImage();
|
|
||||||
setIsTab("draw");
|
|
||||||
setSignatureType("draw");
|
|
||||||
setSignValue("");
|
|
||||||
setIsStamp(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ height: "100%", padding: 20 }}>
|
|
||||||
{isDefaultSign ? (
|
|
||||||
<>
|
|
||||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border: "1.3px solid #007bff",
|
|
||||||
borderRadius: "2px",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
marginBottom: 6,
|
|
||||||
cursor: "pointer"
|
|
||||||
}}
|
|
||||||
className={
|
|
||||||
isInitial ? "intialSignatureCanvas" : "signatureCanvas"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="stamp img"
|
|
||||||
style={{
|
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
background: "rgb(255, 255, 255)",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
draggable="false"
|
|
||||||
src={isInitial ? myInitial : defaultSign}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: "flex", justifyContent: "flex-end" }}>
|
|
||||||
<SaveBtn />
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : isImageSelect || isStamp ? (
|
|
||||||
!image ? (
|
|
||||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border: "1.3px solid #007bff",
|
|
||||||
borderRadius: "2px",
|
|
||||||
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
marginBottom: 6,
|
|
||||||
cursor: "pointer"
|
|
||||||
}}
|
|
||||||
className={
|
|
||||||
isInitial ? "intialSignatureCanvas" : "signatureCanvas"
|
|
||||||
}
|
|
||||||
onClick={() => imageRef.current.click()}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
onChange={onImageChange}
|
|
||||||
className="filetype"
|
|
||||||
accept="image/*"
|
|
||||||
ref={imageRef}
|
|
||||||
hidden
|
|
||||||
/>
|
|
||||||
<i className="fas fa-cloud-upload-alt uploadImgLogo"></i>
|
|
||||||
<div className="uploadImg">Upload</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border: "1.3px solid #007bff",
|
|
||||||
borderRadius: "2px",
|
|
||||||
marginBottom: 6,
|
|
||||||
overflow: "hidden"
|
|
||||||
}}
|
|
||||||
className={
|
|
||||||
isInitial
|
|
||||||
? "intialSignatureCanvas"
|
|
||||||
: "signatureCanvas"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="print img"
|
|
||||||
ref={imageRef}
|
|
||||||
src={image.src}
|
|
||||||
draggable="false"
|
|
||||||
style={{
|
|
||||||
objectFit: "contain",
|
|
||||||
height: "100%",
|
|
||||||
width: "100%"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{ display: "flex", justifyContent: "flex-end" }}
|
|
||||||
>
|
|
||||||
<SaveBtn />
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
) : isTab === "type" ? (
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="signatureText">
|
|
||||||
{isInitial ? "Initials" : "Signature"}:
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<input
|
|
||||||
maxLength={isInitial ? 3 : 30}
|
|
||||||
style={{ fontFamily: fontSelect, color: penColor }}
|
|
||||||
type="text"
|
|
||||||
className="signatureInput"
|
|
||||||
placeholder="Your signature"
|
|
||||||
value={signValue}
|
|
||||||
onChange={(e) => {
|
|
||||||
setSignValue(e.target.value);
|
|
||||||
convertToImg(fontSelect, e.target.value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="fontOptionContainer">
|
|
||||||
{fontOptions.map((font, ind) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={ind}
|
|
||||||
style={{
|
|
||||||
cursor: "pointer",
|
|
||||||
fontFamily: font.value,
|
|
||||||
backgroundColor:
|
|
||||||
fontSelect === font.value && "rgb(206 225 247)"
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
setFontSelect(font.value);
|
|
||||||
convertToImg(font.value, signValue);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
padding: "5px 10px 5px 10px",
|
|
||||||
fontSize: "20px",
|
|
||||||
color: penColor
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{signValue ? signValue : "Your signature"}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
marginTop: "10px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<PenColorComponent convertToImg={convertToImg} />
|
|
||||||
<SaveBtn />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
|
||||||
<SignatureCanvas
|
|
||||||
ref={canvasRef}
|
|
||||||
penColor={penColor}
|
|
||||||
canvasProps={{
|
|
||||||
className: isInitial
|
|
||||||
? "intialSignatureCanvas"
|
|
||||||
: "signatureCanvas",
|
|
||||||
style: {
|
|
||||||
border: "1.6px solid #007bff",
|
|
||||||
borderRadius: "2px"
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
backgroundColor="rgb(255, 255, 255)"
|
|
||||||
onEnd={() =>
|
|
||||||
handleSignatureChange(canvasRef.current.toDataURL())
|
|
||||||
}
|
|
||||||
dotSize={1}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
marginTop: "10px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<PenColorComponent />
|
|
||||||
<SaveBtn />
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SignPad;
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
import "../../styles/signature.css";
|
|
||||||
function Signedby({ pdfDetails }) {
|
|
||||||
const getFirstLetter = (name) => {
|
|
||||||
const firstLetter = name.charAt(0);
|
|
||||||
return firstLetter;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="signerComponent">
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
className="signedStyle"
|
|
||||||
>
|
|
||||||
Signed By
|
|
||||||
</div>
|
|
||||||
<div style={{ marginTop: "2px", background: "white" }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
padding: "10px",
|
|
||||||
background: "#93a3db"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="signerStyle"
|
|
||||||
style={{
|
|
||||||
background: "#abd1d0",
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
display: "flex",
|
|
||||||
borderRadius: 30 / 2,
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
marginRight: "20px",
|
|
||||||
marginTop: "5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: "8px",
|
|
||||||
textAlign: "center",
|
|
||||||
fontWeight: "bold"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{getFirstLetter(pdfDetails.ExtUserPtr.Name)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
|
||||||
<span className="userName">{pdfDetails.ExtUserPtr.Name}</span>
|
|
||||||
<span className="useEmail">{pdfDetails.ExtUserPtr.Email}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Signedby;
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
import RecipientList from "./RecipientList";
|
|
||||||
import { Tooltip } from "react-tooltip";
|
|
||||||
|
|
||||||
function SignerListPlace(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
padding: "5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="signedStyle">
|
|
||||||
{props.title ? props.title : "Recipients"}
|
|
||||||
<span className="absolute text-xs z-[30] mt-1 ml-0.5">
|
|
||||||
{props?.title === "Roles" && (
|
|
||||||
<>
|
|
||||||
<a data-tooltip-id="my-tooltip">
|
|
||||||
<sup>
|
|
||||||
<i
|
|
||||||
className="fa-solid fa-question rounded-full"
|
|
||||||
style={{
|
|
||||||
borderColor: "white",
|
|
||||||
color: "white",
|
|
||||||
fontSize: 11,
|
|
||||||
borderWidth: 1.5,
|
|
||||||
padding: "1px 3px"
|
|
||||||
}}
|
|
||||||
></i>
|
|
||||||
</sup>
|
|
||||||
</a>
|
|
||||||
<Tooltip id="my-tooltip">
|
|
||||||
<div className="max-w-[450px]">
|
|
||||||
<p className="font-bold">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>
|
|
||||||
</div>
|
|
||||||
<div className="signerList">
|
|
||||||
<RecipientList {...props} />
|
|
||||||
</div>
|
|
||||||
{props.handleAddSigner && (
|
|
||||||
<div
|
|
||||||
data-tut="reactourAddbtn"
|
|
||||||
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
|
|
||||||
onClick={() => props.handleAddSigner()}
|
|
||||||
style={{
|
|
||||||
opacity: props.isMailSend && "0.5",
|
|
||||||
pointerEvents: props.isMailSend && "none"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-plus"></i>
|
|
||||||
<span style={{ marginLeft: 2 }}>Add role</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SignerListPlace;
|
|
||||||
@@ -1,436 +0,0 @@
|
|||||||
import React, { useState, useRef, useEffect } from "react";
|
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
|
||||||
import RecipientList from "./RecipientList";
|
|
||||||
import { useDrag } from "react-dnd";
|
|
||||||
import WidgetList from "./WidgetList";
|
|
||||||
import {
|
|
||||||
radioButtonWidget,
|
|
||||||
textInputWidget,
|
|
||||||
textWidget,
|
|
||||||
widgets
|
|
||||||
} from "../../constant/Utils";
|
|
||||||
import { themeColor } from "../../constant/const";
|
|
||||||
function WidgetComponent({
|
|
||||||
dragSignature,
|
|
||||||
signRef,
|
|
||||||
handleDivClick,
|
|
||||||
handleMouseLeave,
|
|
||||||
dragStamp,
|
|
||||||
isSignYourself,
|
|
||||||
addPositionOfSignature,
|
|
||||||
signersdata,
|
|
||||||
isSelectListId,
|
|
||||||
setSignerObjId,
|
|
||||||
setIsSelectId,
|
|
||||||
setContractName,
|
|
||||||
isSigners,
|
|
||||||
dataTut,
|
|
||||||
isMailSend,
|
|
||||||
handleAddSigner,
|
|
||||||
setUniqueId,
|
|
||||||
setRoleName,
|
|
||||||
handleDeleteUser,
|
|
||||||
signerPos,
|
|
||||||
handleRoleChange,
|
|
||||||
handleOnBlur,
|
|
||||||
title,
|
|
||||||
setSignersData,
|
|
||||||
sendInOrder,
|
|
||||||
isTemplateFlow,
|
|
||||||
setBlockColor,
|
|
||||||
blockColor
|
|
||||||
}) {
|
|
||||||
const [isSignersModal, setIsSignersModal] = useState(false);
|
|
||||||
|
|
||||||
const [, dropdown] = useDrag({
|
|
||||||
type: "BOX",
|
|
||||||
item: {
|
|
||||||
type: "BOX",
|
|
||||||
id: 5,
|
|
||||||
text: "dropdown"
|
|
||||||
},
|
|
||||||
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragDropdown: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const [, checkbox] = useDrag({
|
|
||||||
type: "BOX",
|
|
||||||
item: {
|
|
||||||
type: "BOX",
|
|
||||||
id: 6,
|
|
||||||
text: "checkbox"
|
|
||||||
},
|
|
||||||
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragCheck: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const [, textInput] = useDrag({
|
|
||||||
type: "BOX",
|
|
||||||
item: {
|
|
||||||
type: "BOX",
|
|
||||||
id: 7,
|
|
||||||
text: textInputWidget
|
|
||||||
},
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragTextInput: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const [, initials] = useDrag({
|
|
||||||
type: "BOX",
|
|
||||||
item: {
|
|
||||||
type: "BOX",
|
|
||||||
id: 8,
|
|
||||||
text: "initials"
|
|
||||||
},
|
|
||||||
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragInitial: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const [, name] = useDrag({
|
|
||||||
type: "BOX",
|
|
||||||
item: {
|
|
||||||
type: "BOX",
|
|
||||||
id: 9,
|
|
||||||
text: "name"
|
|
||||||
},
|
|
||||||
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragName: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const [, company] = useDrag({
|
|
||||||
type: "BOX",
|
|
||||||
item: {
|
|
||||||
type: "BOX",
|
|
||||||
id: 10,
|
|
||||||
text: "company"
|
|
||||||
},
|
|
||||||
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragCompany: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const [, jobTitle] = useDrag({
|
|
||||||
type: "BOX",
|
|
||||||
item: {
|
|
||||||
type: "BOX",
|
|
||||||
id: 11,
|
|
||||||
text: "job title"
|
|
||||||
},
|
|
||||||
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragJobtitle: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const [, date] = useDrag({
|
|
||||||
type: "BOX",
|
|
||||||
item: {
|
|
||||||
type: "BOX",
|
|
||||||
id: 12,
|
|
||||||
text: "date"
|
|
||||||
},
|
|
||||||
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragDate: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const [, image] = useDrag({
|
|
||||||
type: "BOX",
|
|
||||||
item: {
|
|
||||||
type: "BOX",
|
|
||||||
id: 13,
|
|
||||||
text: "image"
|
|
||||||
},
|
|
||||||
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragImage: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const [, email] = useDrag({
|
|
||||||
type: "BOX",
|
|
||||||
item: {
|
|
||||||
type: "BOX",
|
|
||||||
id: 14,
|
|
||||||
text: "email"
|
|
||||||
},
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragEmail: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const [, radioButton] = useDrag({
|
|
||||||
type: "BOX",
|
|
||||||
|
|
||||||
item: {
|
|
||||||
type: "BOX",
|
|
||||||
id: 15,
|
|
||||||
text: radioButtonWidget
|
|
||||||
},
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragRadiotton: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const [, text] = useDrag({
|
|
||||||
type: "BOX",
|
|
||||||
|
|
||||||
item: {
|
|
||||||
type: "BOX",
|
|
||||||
id: 16,
|
|
||||||
text: textWidget
|
|
||||||
},
|
|
||||||
collect: (monitor) => ({
|
|
||||||
isDragText: !!monitor.isDragging()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const isMobile = window.innerWidth < 767;
|
|
||||||
const scrollContainerRef = useRef(null);
|
|
||||||
const [widget, setWidget] = useState([]);
|
|
||||||
|
|
||||||
const color = [
|
|
||||||
"#93a3db",
|
|
||||||
"#e6c3db",
|
|
||||||
"#c0e3bc",
|
|
||||||
"#bce3db",
|
|
||||||
"#b8ccdb",
|
|
||||||
"#ceb8db",
|
|
||||||
"#ffccff",
|
|
||||||
"#99ffcc",
|
|
||||||
"#cc99ff",
|
|
||||||
"#ffcc99",
|
|
||||||
"#66ccff",
|
|
||||||
"#ffffcc"
|
|
||||||
];
|
|
||||||
const handleModal = () => {
|
|
||||||
setIsSignersModal(!isSignersModal);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const widgetRef = [
|
|
||||||
dragSignature,
|
|
||||||
dragStamp,
|
|
||||||
initials,
|
|
||||||
name,
|
|
||||||
jobTitle,
|
|
||||||
company,
|
|
||||||
date,
|
|
||||||
text,
|
|
||||||
textInput,
|
|
||||||
checkbox,
|
|
||||||
dropdown,
|
|
||||||
radioButton,
|
|
||||||
image,
|
|
||||||
email
|
|
||||||
];
|
|
||||||
const getWidgetArray = widgets;
|
|
||||||
const newUpdateSigner = getWidgetArray.map((obj, ind) => {
|
|
||||||
return { ...obj, ref: widgetRef[ind] };
|
|
||||||
});
|
|
||||||
|
|
||||||
setWidget(newUpdateSigner);
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const filterWidgets = widget.filter(
|
|
||||||
(data) =>
|
|
||||||
data.type !== "dropdown" &&
|
|
||||||
data.type !== radioButtonWidget &&
|
|
||||||
data.type !== textInputWidget
|
|
||||||
);
|
|
||||||
const textWidgetData = widget.filter((data) => data.type !== textWidget);
|
|
||||||
const updateWidgets = isSignYourself
|
|
||||||
? filterWidgets
|
|
||||||
: isTemplateFlow
|
|
||||||
? textWidgetData
|
|
||||||
: widget;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{isMobile ? (
|
|
||||||
!isMailSend && (
|
|
||||||
<div
|
|
||||||
data-tut={dataTut}
|
|
||||||
id="navbar"
|
|
||||||
className="stickyfooter"
|
|
||||||
style={{ width: window.innerWidth + "px" }}
|
|
||||||
>
|
|
||||||
{isSigners && (
|
|
||||||
<div
|
|
||||||
data-tut={dataTut}
|
|
||||||
style={{
|
|
||||||
background: blockColor
|
|
||||||
? blockColor
|
|
||||||
: isSelectListId
|
|
||||||
? color[isSelectListId % color.length]
|
|
||||||
: color[0],
|
|
||||||
padding: "10px 20px",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center"
|
|
||||||
}}
|
|
||||||
onClick={() => handleModal()}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: "700",
|
|
||||||
textAlign: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{title ? title : "Recipient"}
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: "700",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{signersdata[isSelectListId]?.Role && (
|
|
||||||
<div>
|
|
||||||
{signersdata[isSelectListId]?.Name ? (
|
|
||||||
<>
|
|
||||||
:{" "}
|
|
||||||
{signersdata[isSelectListId]?.Name?.length > 12
|
|
||||||
? `${signersdata[isSelectListId].Name.slice(
|
|
||||||
0,
|
|
||||||
12
|
|
||||||
)}...`
|
|
||||||
: signersdata[isSelectListId]?.Name}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
:{" "}
|
|
||||||
{signersdata[isSelectListId]?.Role?.length > 12
|
|
||||||
? `${signersdata[isSelectListId].Role.slice(
|
|
||||||
0,
|
|
||||||
12
|
|
||||||
)}...`
|
|
||||||
: signersdata[isSelectListId]?.Role}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div style={{ marginLeft: 6, fontSize: 16 }}>
|
|
||||||
<i className="fa-solid fa-angle-down"></i>
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{handleAddSigner && (
|
|
||||||
<div
|
|
||||||
data-tut="reactourAddbtn"
|
|
||||||
style={{
|
|
||||||
margin: "5px 0 5px 0",
|
|
||||||
backgroundColor: themeColor,
|
|
||||||
color: "white"
|
|
||||||
}}
|
|
||||||
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
|
|
||||||
onClick={() => handleAddSigner()}
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-plus"></i>
|
|
||||||
<span style={{ marginLeft: 2 }}>Add role</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div
|
|
||||||
ref={scrollContainerRef}
|
|
||||||
style={{
|
|
||||||
background: "white",
|
|
||||||
borderTop: `2px solid ${themeColor}`
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
overflowX: "scroll",
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
padding: "10px 5px 10px 1px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<WidgetList
|
|
||||||
updateWidgets={updateWidgets}
|
|
||||||
handleDivClick={handleDivClick}
|
|
||||||
handleMouseLeave={handleMouseLeave}
|
|
||||||
signRef={signRef}
|
|
||||||
marginLeft={5}
|
|
||||||
addPositionOfSignature={addPositionOfSignature}
|
|
||||||
isMobile={isMobile}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
data-tut={dataTut}
|
|
||||||
className={
|
|
||||||
isMailSend ? "disabled signerComponent " : "signerComponent"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
background: themeColor,
|
|
||||||
padding: "5px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="signedStyle">Fields</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="signLayoutContainer1">
|
|
||||||
<WidgetList
|
|
||||||
updateWidgets={updateWidgets}
|
|
||||||
handleDivClick={handleDivClick}
|
|
||||||
handleMouseLeave={handleMouseLeave}
|
|
||||||
signRef={signRef}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{isSignersModal && (
|
|
||||||
<ModalUi
|
|
||||||
title={"Roles"}
|
|
||||||
isOpen={isSignersModal}
|
|
||||||
handleClose={handleModal}
|
|
||||||
>
|
|
||||||
{signersdata.length > 0 ? (
|
|
||||||
<div style={{ maxHeight: "600px", overflow: "auto" }}>
|
|
||||||
<RecipientList
|
|
||||||
signerPos={signerPos}
|
|
||||||
signersdata={signersdata}
|
|
||||||
isSelectListId={isSelectListId}
|
|
||||||
setSignerObjId={setSignerObjId}
|
|
||||||
setIsSelectId={setIsSelectId}
|
|
||||||
setContractName={setContractName}
|
|
||||||
setUniqueId={setUniqueId}
|
|
||||||
setRoleName={setRoleName}
|
|
||||||
handleDeleteUser={handleDeleteUser}
|
|
||||||
handleRoleChange={handleRoleChange}
|
|
||||||
handleOnBlur={handleOnBlur}
|
|
||||||
handleModal={handleModal}
|
|
||||||
sendInOrder={sendInOrder}
|
|
||||||
setSignersData={setSignersData}
|
|
||||||
setBlockColor={setBlockColor}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
padding: 20,
|
|
||||||
fontSize: 15,
|
|
||||||
fontWeight: "500",
|
|
||||||
textAlign: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Please add a role
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</ModalUi>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default WidgetComponent;
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { getWidgetType } from "../../constant/Utils";
|
|
||||||
|
|
||||||
function WidgetList(props) {
|
|
||||||
return props.updateWidgets.map((item, ind) => {
|
|
||||||
return (
|
|
||||||
<div key={ind} style={{ marginBottom: "5px" }}>
|
|
||||||
<div
|
|
||||||
className="widgets"
|
|
||||||
onClick={() => {
|
|
||||||
props.addPositionOfSignature &&
|
|
||||||
props.addPositionOfSignature("onclick", item);
|
|
||||||
}}
|
|
||||||
ref={(element) => {
|
|
||||||
if (!props.isMobile) {
|
|
||||||
item.ref(element);
|
|
||||||
if (element) {
|
|
||||||
if (props?.signRef) {
|
|
||||||
props.signRef.current = element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onMouseMove={props?.handleDivClick}
|
|
||||||
onMouseDown={() => {
|
|
||||||
props?.handleMouseLeave();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.ref && getWidgetType(item, props?.marginLeft)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default WidgetList;
|
|
||||||
@@ -1,304 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
|
||||||
import "../../styles/AddUser.css";
|
|
||||||
import RegexParser from "regex-parser";
|
|
||||||
import { textInputWidget } from "../../constant/Utils";
|
|
||||||
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
|
|
||||||
import Upgrade from "../../primitives/Upgrade";
|
|
||||||
import { isEnableSubscription } from "../../constant/const";
|
|
||||||
|
|
||||||
const WidgetNameModal = (props) => {
|
|
||||||
const [formdata, setFormdata] = useState({
|
|
||||||
name: "",
|
|
||||||
defaultValue: "",
|
|
||||||
status: "required",
|
|
||||||
hint: "",
|
|
||||||
textvalidate: "text"
|
|
||||||
});
|
|
||||||
const [isValid, setIsValid] = useState(true);
|
|
||||||
const statusArr = ["Required", "Optional"];
|
|
||||||
const inputOpt = ["text", "email", "number"];
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (props.defaultdata) {
|
|
||||||
setFormdata({
|
|
||||||
name: props.defaultdata?.options?.name || props?.widgetName || "",
|
|
||||||
defaultValue: props.defaultdata?.options?.defaultValue || "",
|
|
||||||
status: props.defaultdata?.options?.status || "required",
|
|
||||||
hint: props.defaultdata?.options?.hint || "",
|
|
||||||
textvalidate:
|
|
||||||
props.defaultdata?.options?.validation?.type === "regex"
|
|
||||||
? props.defaultdata?.options?.validation?.pattern
|
|
||||||
: props.defaultdata?.options?.validation?.type || ""
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setFormdata({
|
|
||||||
...formdata,
|
|
||||||
name: props.defaultdata?.options?.name || props?.widgetName || ""
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [props.defaultdata, props.widgetName]);
|
|
||||||
const handleSubmit = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (props.handleData) {
|
|
||||||
props.handleData(formdata);
|
|
||||||
setFormdata({
|
|
||||||
name: "",
|
|
||||||
defaultValue: "",
|
|
||||||
status: "required",
|
|
||||||
hint: "",
|
|
||||||
textvalidate: "text"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleChange = (e) => {
|
|
||||||
setFormdata({ ...formdata, [e.target.name]: e.target.value });
|
|
||||||
};
|
|
||||||
|
|
||||||
const handledefaultChange = (e) => {
|
|
||||||
if (formdata.textvalidate) {
|
|
||||||
const regexObject = RegexParser(handleValidation(formdata.textvalidate));
|
|
||||||
const isValidate = regexObject?.test(e.target.value);
|
|
||||||
setIsValid(isValidate);
|
|
||||||
} else {
|
|
||||||
setIsValid(true);
|
|
||||||
}
|
|
||||||
setFormdata({ ...formdata, [e.target.name]: e.target.value });
|
|
||||||
};
|
|
||||||
|
|
||||||
function handleValidation(type) {
|
|
||||||
switch (type) {
|
|
||||||
case "email":
|
|
||||||
return "/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/";
|
|
||||||
case "number":
|
|
||||||
return "/^\\d+$/";
|
|
||||||
case "text":
|
|
||||||
return "/^[a-zA-Zs]+$/";
|
|
||||||
default:
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleBlurRegex() {
|
|
||||||
if (!formdata.textvalidate) {
|
|
||||||
setFormdata({ ...formdata, textvalidate: "text" });
|
|
||||||
} else {
|
|
||||||
if (formdata.defaultValue) {
|
|
||||||
const regexObject = RegexParser(
|
|
||||||
handleValidation(formdata.textvalidate)
|
|
||||||
);
|
|
||||||
const isValidate = regexObject?.test(formdata.defaultValue);
|
|
||||||
if (isValidate === false) {
|
|
||||||
setFormdata({ ...formdata, defaultValue: "" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<ModalUi
|
|
||||||
isOpen={props.isOpen}
|
|
||||||
handleClose={props.handleClose && props.handleClose}
|
|
||||||
title={"Widget info"}
|
|
||||||
>
|
|
||||||
{(props.defaultdata?.type === textInputWidget ||
|
|
||||||
props.widgetName === textInputWidget) &&
|
|
||||||
!isEnableSubscription && (
|
|
||||||
<PremiumAlertHeader
|
|
||||||
message={
|
|
||||||
"Field validations are free in beta, this feature will incur a fee later."
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<form
|
|
||||||
onSubmit={handleSubmit}
|
|
||||||
className={`${
|
|
||||||
props.defaultdata?.type === textInputWidget ||
|
|
||||||
props.widgetName === textInputWidget
|
|
||||||
? "pt-0"
|
|
||||||
: ""
|
|
||||||
} p-[20px]`}
|
|
||||||
>
|
|
||||||
<div className="form-section">
|
|
||||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
|
||||||
Name
|
|
||||||
<span style={{ color: "red", fontSize: 13 }}> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
className="addUserInput"
|
|
||||||
name="name"
|
|
||||||
value={formdata.name}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{(props.defaultdata?.type === textInputWidget ||
|
|
||||||
props.widgetName === textInputWidget) && (
|
|
||||||
<>
|
|
||||||
<div className="form-section">
|
|
||||||
<label
|
|
||||||
htmlFor="textvalidate"
|
|
||||||
className={
|
|
||||||
!props.isSubscribe && isEnableSubscription && "disabled"
|
|
||||||
}
|
|
||||||
style={{ fontSize: 13 }}
|
|
||||||
>
|
|
||||||
Validation
|
|
||||||
</label>
|
|
||||||
{!props.isSubscribe && isEnableSubscription && <Upgrade />}
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
!props.isSubscribe && isEnableSubscription && "disabled"
|
|
||||||
}
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
gap: 10,
|
|
||||||
marginBottom: "0.5rem"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{ width: "100%", position: "relative" }}>
|
|
||||||
<input
|
|
||||||
className="relative z-20 w-[87%] md:w-[92%] p-2.5 border-[1px] border-[#d1d5db] rounded-l-md outline-none text-xs"
|
|
||||||
name="textvalidate"
|
|
||||||
placeholder="Enter custom expression"
|
|
||||||
value={formdata.textvalidate}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
// onBlur={() => handleBlurRegex()}
|
|
||||||
/>
|
|
||||||
<select
|
|
||||||
className="validationlist addUserInput"
|
|
||||||
name="textvalidate"
|
|
||||||
value={formdata.textvalidate}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
onBlur={() => handleBlurRegex()}
|
|
||||||
>
|
|
||||||
<option disabled style={{ fontSize: "13px" }}>
|
|
||||||
Select...
|
|
||||||
</option>
|
|
||||||
{inputOpt.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<option
|
|
||||||
style={{ fontSize: "13px" }}
|
|
||||||
key={ind}
|
|
||||||
value={data}
|
|
||||||
>
|
|
||||||
{data}
|
|
||||||
</option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-section">
|
|
||||||
<label htmlFor="name" style={{ fontSize: 13 }}>
|
|
||||||
Default value
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
className="addUserInput"
|
|
||||||
name="defaultValue"
|
|
||||||
value={formdata.defaultValue}
|
|
||||||
onChange={(e) => handledefaultChange(e)}
|
|
||||||
autoComplete="off"
|
|
||||||
onBlur={() => {
|
|
||||||
if (isValid === false) {
|
|
||||||
setFormdata({ ...formdata, defaultValue: "" });
|
|
||||||
setIsValid(true);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{isValid === false && (
|
|
||||||
<div
|
|
||||||
className="warning defaultvalueWarning"
|
|
||||||
style={{ fontSize: 12 }}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className="fas fa-exclamation-circle"
|
|
||||||
style={{ color: "#fab005", fontSize: 15 }}
|
|
||||||
></i>{" "}
|
|
||||||
invalid default value
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<div className="form-section">
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
gap: 10,
|
|
||||||
marginBottom: "0.5rem"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{statusArr.map((data, ind) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={ind}
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
gap: 5,
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
style={{ accentColor: "red", marginRight: "10px" }}
|
|
||||||
type="radio"
|
|
||||||
name="status"
|
|
||||||
onChange={() =>
|
|
||||||
setFormdata({ ...formdata, status: data.toLowerCase() })
|
|
||||||
}
|
|
||||||
checked={
|
|
||||||
formdata.status.toLowerCase() === data.toLowerCase()
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<div style={{ fontSize: "13px", fontWeight: "500" }}>
|
|
||||||
{data}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{(props.defaultdata?.type === textInputWidget ||
|
|
||||||
props?.widgetName === textInputWidget) && (
|
|
||||||
<div className="form-section">
|
|
||||||
<label htmlFor="hint" style={{ fontSize: 13 }}>
|
|
||||||
Hint
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
className="addUserInput"
|
|
||||||
name="hint"
|
|
||||||
value={formdata.hint}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: 1,
|
|
||||||
backgroundColor: "#b7b3b3",
|
|
||||||
width: "100%",
|
|
||||||
marginBottom: "16px"
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
color: "white",
|
|
||||||
padding: "5px 20px",
|
|
||||||
backgroundColor: "#32a3ac"
|
|
||||||
}}
|
|
||||||
type="submit"
|
|
||||||
className="finishBtn"
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</ModalUi>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default WidgetNameModal;
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import Parse from "parse";
|
|
||||||
import Alert from "../../../primitives/Alert";
|
|
||||||
|
|
||||||
const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
|
|
||||||
const folderPtr = {
|
|
||||||
__type: "Pointer",
|
|
||||||
className: folderCls,
|
|
||||||
objectId: parentFolderId
|
|
||||||
};
|
|
||||||
const [name, setName] = useState("");
|
|
||||||
const [folderList, setFolderList] = useState([]);
|
|
||||||
const [isAlert, setIsAlert] = useState(false);
|
|
||||||
const [isLoader, setIsLoader] = useState(false);
|
|
||||||
const [selectedParent, setSelectedParent] = useState();
|
|
||||||
const [alert, setAlert] = useState({ type: "info", message: "" });
|
|
||||||
useEffect(() => {
|
|
||||||
fetchFolder();
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const fetchFolder = async () => {
|
|
||||||
try {
|
|
||||||
const FolderQuery = new Parse.Query(folderCls);
|
|
||||||
if (parentFolderId) {
|
|
||||||
FolderQuery.equalTo("Folder", folderPtr);
|
|
||||||
FolderQuery.equalTo("Type", "Folder");
|
|
||||||
} else {
|
|
||||||
FolderQuery.doesNotExist("Folder");
|
|
||||||
FolderQuery.equalTo("Type", "Folder");
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await FolderQuery.find();
|
|
||||||
if (res) {
|
|
||||||
const result = JSON.parse(JSON.stringify(res));
|
|
||||||
if (result) {
|
|
||||||
setFolderList(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Err ", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleCreateFolder = async (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
handleLoader(true);
|
|
||||||
if (name) {
|
|
||||||
const currentUser = Parse.User.current();
|
|
||||||
const exsitQuery = new Parse.Query(folderCls);
|
|
||||||
exsitQuery.equalTo("Name", name);
|
|
||||||
exsitQuery.equalTo("Type", "Folder");
|
|
||||||
if (parentFolderId) {
|
|
||||||
exsitQuery.equalTo("Folder", folderPtr);
|
|
||||||
}
|
|
||||||
const templExist = await exsitQuery.first();
|
|
||||||
if (templExist) {
|
|
||||||
setAlert({ type: "danger", message: "Folder already exist!" });
|
|
||||||
setIsAlert(true);
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsAlert(false);
|
|
||||||
}, 1000);
|
|
||||||
} else {
|
|
||||||
const template = new Parse.Object(folderCls);
|
|
||||||
template.set("Name", name);
|
|
||||||
template.set("Type", "Folder");
|
|
||||||
|
|
||||||
if (selectedParent) {
|
|
||||||
template.set("Folder", {
|
|
||||||
__type: "Pointer",
|
|
||||||
className: folderCls,
|
|
||||||
objectId: selectedParent
|
|
||||||
});
|
|
||||||
} else if (parentFolderId) {
|
|
||||||
template.set("Folder", folderPtr);
|
|
||||||
}
|
|
||||||
template.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
|
|
||||||
const res = await template.save();
|
|
||||||
if (res) {
|
|
||||||
handleLoader(false);
|
|
||||||
setAlert({
|
|
||||||
type: "success",
|
|
||||||
message: "Folder created successfully!"
|
|
||||||
});
|
|
||||||
setIsAlert(true);
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsAlert(false);
|
|
||||||
}, 1000);
|
|
||||||
if (onSuccess) {
|
|
||||||
onSuccess(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
handleLoader(false);
|
|
||||||
setAlert({ type: "info", message: "Please fill folder name" });
|
|
||||||
setIsAlert(true);
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsAlert(false);
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleOptions = (e) => {
|
|
||||||
setSelectedParent(e.target.value);
|
|
||||||
};
|
|
||||||
const handleLoader = (status) => {
|
|
||||||
setIsLoader(status);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{isAlert && <Alert type={alert.type}>{alert.message}</Alert>}
|
|
||||||
<div id="createFolder" className="relative">
|
|
||||||
{isLoader && (
|
|
||||||
<div className="absolute h-full w-full flex justify-center items-center ">
|
|
||||||
<div
|
|
||||||
style={{ fontSize: "45px", color: "#3dd3e0" }}
|
|
||||||
className="loader-37"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<h1 className="text-base font-semibold">Create Folder</h1>
|
|
||||||
<div className="text-xs mt-2">
|
|
||||||
<label className="block">
|
|
||||||
Name<span className="text-red-500 text-[13px]">*</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
|
||||||
value={name}
|
|
||||||
onChange={(e) => setName(e.target.value)}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="text-xs mt-2">
|
|
||||||
<label className="block">Parent Folder</label>
|
|
||||||
<select
|
|
||||||
value={selectedParent}
|
|
||||||
onChange={handleOptions}
|
|
||||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
|
||||||
>
|
|
||||||
<option>select</option>
|
|
||||||
{folderList.length > 0 &&
|
|
||||||
folderList.map((x) => (
|
|
||||||
<option key={x.objectId} value={x.objectId}>
|
|
||||||
{x.Name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
onClick={handleCreateFolder}
|
|
||||||
disabled={isLoader}
|
|
||||||
className="flex items-center rounded p-2 bg-[#32a3ac] text-white mt-3"
|
|
||||||
>
|
|
||||||
<i className="fa-solid fa-plus mr-1"></i>
|
|
||||||
<span>Create</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CreateFolder;
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
import React, { useCallback, useMemo } from "react";
|
|
||||||
import { useDropScript } from "../../../hook/useScript";
|
|
||||||
|
|
||||||
const DROPBOX_APP_KEY = process.env.REACT_APP_DROPBOX_API_KEY; // App key
|
|
||||||
const DROPBOX_SDK_URL = "https://www.dropbox.com/static/api/2/dropins.js";
|
|
||||||
const DROPBOX_SCRIPT_ID = "dropboxjs";
|
|
||||||
|
|
||||||
export default function DropboxChooser({ children, onSuccess, onCancel }) {
|
|
||||||
useDropScript(DROPBOX_SDK_URL, {
|
|
||||||
attrs: {
|
|
||||||
id: DROPBOX_SCRIPT_ID,
|
|
||||||
"data-app-key": DROPBOX_APP_KEY
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const options = useMemo(
|
|
||||||
() => ({
|
|
||||||
// Required. Called when a user selects an item in the Chooser.
|
|
||||||
success: (files) => {
|
|
||||||
// console.log("success", files);
|
|
||||||
onSuccess && onSuccess(files);
|
|
||||||
},
|
|
||||||
// Optional. Called when the user closes the dialog without selecting a file
|
|
||||||
// and does not include any parameters.
|
|
||||||
cancel: () => {
|
|
||||||
console.log("cancel");
|
|
||||||
onCancel && onCancel();
|
|
||||||
},
|
|
||||||
|
|
||||||
// Optional. "preview" (default) is a preview link to the document for sharing,
|
|
||||||
// "direct" is an expiring link to download the contents of the file. For more
|
|
||||||
linkType: "direct", // or "preview"
|
|
||||||
multiselect: false, // 是否支持多选
|
|
||||||
extensions: [".pdf"],
|
|
||||||
|
|
||||||
// Optional. A value of false (default) limits selection to files,
|
|
||||||
// while true allows the user to select both folders and files.
|
|
||||||
// You cannot specify `linkType: "direct"` when using `folderselect: true`.
|
|
||||||
folderselect: false // or true
|
|
||||||
}),
|
|
||||||
[onSuccess, onCancel]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleChoose = useCallback(
|
|
||||||
(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (window.Dropbox) {
|
|
||||||
window.Dropbox.choose(options);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[options]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div onClick={handleChoose}>
|
|
||||||
{children || (
|
|
||||||
<button className="px-2 py-[2px] text-2xl rounded border-[1px] text-blue-400 border-gray-300 w-full">
|
|
||||||
<i className="fa-brands fa-dropbox"></i>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
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.equalTo("Type", "Folder");
|
|
||||||
} else {
|
|
||||||
FolderQuery.doesNotExist("Folder");
|
|
||||||
FolderQuery.equalTo("Type", "Folder");
|
|
||||||
}
|
|
||||||
|
|
||||||
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="py-2 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 />
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 mb-3">
|
|
||||||
<div className="max-h-[210px] overflow-auto">
|
|
||||||
{!isAdd &&
|
|
||||||
folderList.length > 0 &&
|
|
||||||
folderList.map((folder) => (
|
|
||||||
<div
|
|
||||||
key={folder.Name}
|
|
||||||
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer "
|
|
||||||
onClick={() => handleSelect(folder)}
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<i
|
|
||||||
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
<span className="font-semibold">{folder.Name}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
{isAdd && (
|
|
||||||
<CreateFolder
|
|
||||||
parentFolderId={clickFolder && clickFolder.ObjectId}
|
|
||||||
folderCls={props.folderCls}
|
|
||||||
onSuccess={handleAddFolder}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isLoader && (
|
|
||||||
<div className="flex justify-center">
|
|
||||||
<i className="fa-solid 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="text-[30px] cursor-pointer text-[#32a3ac]"
|
|
||||||
title="Save Here"
|
|
||||||
onClick={handleCreate}
|
|
||||||
>
|
|
||||||
{isAdd ? (
|
|
||||||
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
|
|
||||||
) : (
|
|
||||||
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-[30px] cursor-pointer"
|
|
||||||
title="Save Here"
|
|
||||||
onClick={handleSubmit}
|
|
||||||
>
|
|
||||||
<i className="fas fa-save" aria-hidden="true"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ModalUi>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FolderModal;
|
|
||||||
@@ -1,296 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import Parse from "parse";
|
|
||||||
import CreateFolder from "./CreateFolder";
|
|
||||||
import ModalUi from "../../../primitives/ModalUi";
|
|
||||||
import Tooltip from "../../../primitives/Tooltip";
|
|
||||||
|
|
||||||
const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
|
||||||
const [isOpen, SetIsOpen] = useState(false);
|
|
||||||
const [clickFolder, setClickFolder] = useState("");
|
|
||||||
const [selectFolder, setSelectedFolder] = useState({});
|
|
||||||
const [folderList, setFolderList] = useState([]);
|
|
||||||
const [tabList, setTabList] = useState([]);
|
|
||||||
const [isLoader, setIsLoader] = useState(false);
|
|
||||||
const [folderPath, setFolderPath] = useState("");
|
|
||||||
const [isAdd, setIsAdd] = useState(false);
|
|
||||||
useEffect(() => {
|
|
||||||
if (isOpen) {
|
|
||||||
setIsAdd(false);
|
|
||||||
setClickFolder({});
|
|
||||||
setFolderList([]);
|
|
||||||
setTabList([]);
|
|
||||||
fetchFolder();
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [isOpen]);
|
|
||||||
// below useEffect is used to reset folder selection if user pass isReset = true from parent component
|
|
||||||
useEffect(() => {
|
|
||||||
if (isReset == true) {
|
|
||||||
handleReset();
|
|
||||||
}
|
|
||||||
}, [isReset]);
|
|
||||||
const handleReset = () => {
|
|
||||||
setFolderPath({});
|
|
||||||
setSelectedFolder("");
|
|
||||||
setClickFolder("");
|
|
||||||
setIsAdd(false);
|
|
||||||
setFolderList([]);
|
|
||||||
setTabList([]);
|
|
||||||
};
|
|
||||||
// `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(folderCls);
|
|
||||||
if (folderPtr) {
|
|
||||||
FolderQuery.equalTo("Folder", folderPtr);
|
|
||||||
FolderQuery.equalTo("Type", "Folder");
|
|
||||||
} else {
|
|
||||||
FolderQuery.doesNotExist("Folder");
|
|
||||||
FolderQuery.equalTo("Type", "Folder");
|
|
||||||
}
|
|
||||||
|
|
||||||
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: folderCls,
|
|
||||||
objectId: item.objectId
|
|
||||||
};
|
|
||||||
fetchFolder(folderPtr);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setTabList((tabs) => [...tabs, item]);
|
|
||||||
const folderPtr = {
|
|
||||||
__type: "Pointer",
|
|
||||||
className: 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;
|
|
||||||
});
|
|
||||||
setFolderPath(url);
|
|
||||||
setSelectedFolder(clickFolder);
|
|
||||||
if (onSuccess) {
|
|
||||||
onSuccess(clickFolder);
|
|
||||||
}
|
|
||||||
SetIsOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// `handleCancel` is used to clear list of folder, close popup and folderUrl
|
|
||||||
const handleCancel = () => {
|
|
||||||
SetIsOpen(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: folderCls,
|
|
||||||
objectId: list[_len].objectId
|
|
||||||
};
|
|
||||||
setTabList(list);
|
|
||||||
} else {
|
|
||||||
setClickFolder({});
|
|
||||||
setSelectedFolder({});
|
|
||||||
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 = () => {
|
|
||||||
setFolderList([]);
|
|
||||||
if (clickFolder && clickFolder.ObjectId) {
|
|
||||||
fetchFolder({
|
|
||||||
__type: "Pointer",
|
|
||||||
className: folderCls,
|
|
||||||
objectId: clickFolder.ObjectId
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
fetchFolder();
|
|
||||||
}
|
|
||||||
handleCreate();
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className="text-xs mt-2 ">
|
|
||||||
<div>
|
|
||||||
<label className="block">
|
|
||||||
Select Folder
|
|
||||||
{required && <span className="text-red-500 text-[13px]">*</span>}
|
|
||||||
</label>
|
|
||||||
</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>
|
|
||||||
<i
|
|
||||||
className="far fa-folder-open text-[40px] text-[#33bbff]"
|
|
||||||
style={{ fontSize: "40px" }}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
</div>
|
|
||||||
<div className="font-semibold ">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<p>
|
|
||||||
{selectFolder && selectFolder.Name
|
|
||||||
? selectFolder.Name
|
|
||||||
: "OpenSign™ Drive"}
|
|
||||||
</p>
|
|
||||||
<div className="text-black text-sm" onClick={() => SetIsOpen(true)}>
|
|
||||||
<i
|
|
||||||
className="fa fa-pencil"
|
|
||||||
title="Select Folder"
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p className="text-[10px] text-gray-400">
|
|
||||||
{selectFolder && selectFolder.Name ? `(${folderPath})` : ""}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="absolute top-2 right-1 cursor-pointer">
|
|
||||||
<Tooltip
|
|
||||||
message={
|
|
||||||
"If you do not select a folder, your signed document will be saved in the Main OpenSign drive folder."
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ModalUi
|
|
||||||
title={"Select Folder"}
|
|
||||||
isOpen={isOpen}
|
|
||||||
handleClose={handleCancel}
|
|
||||||
>
|
|
||||||
<div className="w-full min-w-[300px] md:min-w-[500px] max-w-[500px] px-3">
|
|
||||||
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
|
|
||||||
<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 />
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 mb-3">
|
|
||||||
<div className="max-h-[210px] overflow-auto">
|
|
||||||
{!isAdd &&
|
|
||||||
folderList.length > 0 &&
|
|
||||||
folderList.map((folder) => (
|
|
||||||
<div
|
|
||||||
key={folder.Name}
|
|
||||||
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer "
|
|
||||||
onClick={() => handleSelect(folder)}
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<i
|
|
||||||
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
<span className="font-semibold">{folder.Name}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
{isAdd && (
|
|
||||||
<CreateFolder
|
|
||||||
parentFolderId={clickFolder && clickFolder.ObjectId}
|
|
||||||
folderCls={folderCls}
|
|
||||||
onSuccess={handleAddFolder}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isLoader && (
|
|
||||||
<div className="flex justify-center">
|
|
||||||
<i className="fa-solid 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="text-[30px] cursor-pointer text-[#32a3ac]"
|
|
||||||
title="Save Here"
|
|
||||||
onClick={handleCreate}
|
|
||||||
>
|
|
||||||
{isAdd ? (
|
|
||||||
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
|
|
||||||
) : (
|
|
||||||
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-[30px] cursor-pointer"
|
|
||||||
title="Save Here"
|
|
||||||
onClick={handleSubmit}
|
|
||||||
>
|
|
||||||
<i className="fas fa-save" aria-hidden="true"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ModalUi>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SelectFolder;
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import Parse from "parse";
|
|
||||||
import "../../../styles/AddUser.css";
|
|
||||||
import AsyncSelect from "react-select/async";
|
|
||||||
|
|
||||||
const customStyles = {
|
|
||||||
control: (provided) => ({
|
|
||||||
...provided,
|
|
||||||
fontSize: "13px" // Font size for the control
|
|
||||||
}),
|
|
||||||
option: (provided) => ({
|
|
||||||
...provided,
|
|
||||||
fontSize: "13px" // Font size for the options
|
|
||||||
})
|
|
||||||
};
|
|
||||||
const SelectSigners = (props) => {
|
|
||||||
const [userList, setUserList] = useState([]);
|
|
||||||
const [selected, setSelected] = useState();
|
|
||||||
const [userData, setUserData] = useState({});
|
|
||||||
const [isError, setIsError] = useState(false);
|
|
||||||
// `handleOptions` is used to set just save from quick form to selected option in dropdown
|
|
||||||
const handleOptions = (item) => {
|
|
||||||
setSelected(item);
|
|
||||||
const userData = userList.find((x) => x.objectId === item.value);
|
|
||||||
if (userData) {
|
|
||||||
setUserData(userData);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleAdd = () => {
|
|
||||||
if (userData && userData.objectId) {
|
|
||||||
props.details(userData);
|
|
||||||
if (props.closePopup) {
|
|
||||||
props.closePopup();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setIsError(true);
|
|
||||||
setTimeout(() => setIsError(false), 1000);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const loadOptions = async (inputValue) => {
|
|
||||||
try {
|
|
||||||
const currentUser = Parse.User.current();
|
|
||||||
const contactbook = new Parse.Query("contracts_Contactbook");
|
|
||||||
contactbook.equalTo(
|
|
||||||
"CreatedBy",
|
|
||||||
Parse.User.createWithoutData(currentUser.id)
|
|
||||||
);
|
|
||||||
if (inputValue.length > 1) {
|
|
||||||
contactbook.matches("Name", new RegExp(inputValue, "i"));
|
|
||||||
}
|
|
||||||
contactbook.notEqualTo("IsDeleted", true);
|
|
||||||
const contactRes = await contactbook.find();
|
|
||||||
if (contactRes) {
|
|
||||||
const res = JSON.parse(JSON.stringify(contactRes));
|
|
||||||
// console.log("userList ", res);
|
|
||||||
setUserList(res);
|
|
||||||
return await res.map((item) => ({
|
|
||||||
label: item.Email,
|
|
||||||
value: item.objectId
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log("err", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="addusercontainer">
|
|
||||||
<div className="form-wrapper">
|
|
||||||
<div className="form-section" style={{ marginBottom: 0 }}>
|
|
||||||
<label style={{ fontSize: 14, fontWeight: "700" }}>Choose User</label>
|
|
||||||
<AsyncSelect
|
|
||||||
cacheOptions
|
|
||||||
defaultOptions
|
|
||||||
value={selected}
|
|
||||||
loadingMessage={() => "Loading..."}
|
|
||||||
noOptionsMessage={() => "User not Found"}
|
|
||||||
loadOptions={loadOptions}
|
|
||||||
onChange={handleOptions}
|
|
||||||
styles={customStyles}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{isError ? (
|
|
||||||
<p style={{ color: "red", fontSize: "12px", margin: "5px" }}>
|
|
||||||
Please select signer
|
|
||||||
</p>
|
|
||||||
) : (
|
|
||||||
<p style={{ color: "transparent", fontSize: "12px", margin: "5px" }}>
|
|
||||||
.
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
<div>
|
|
||||||
<button className="submitbutton" onClick={() => handleAdd()}>
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SelectSigners;
|
|
||||||
@@ -1,201 +0,0 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
|
||||||
import Select from "react-select";
|
|
||||||
import AddSigner from "../../AddSigner";
|
|
||||||
import Modal from "react-modal";
|
|
||||||
import Parse from "parse";
|
|
||||||
import Tooltip from "../../../primitives/Tooltip";
|
|
||||||
function arrayMove(array, from, to) {
|
|
||||||
array = array.slice();
|
|
||||||
array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]);
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* react-sortable-hoc is depcreated not usable from react 18.x.x
|
|
||||||
* need to replace it with @dnd-kit
|
|
||||||
* code changes required
|
|
||||||
*/
|
|
||||||
|
|
||||||
const SignersInput = (props) => {
|
|
||||||
Modal.setAppElement("body");
|
|
||||||
const [state, setState] = useState(undefined);
|
|
||||||
// const [editFormData, setEditFormData] = useState([]);
|
|
||||||
const [selected, setSelected] = useState([]);
|
|
||||||
const [isModal, setIsModel] = useState(false);
|
|
||||||
const onChange = (selectedOptions) => setSelected(selectedOptions);
|
|
||||||
const [modalIsOpen, setModalIsOpen] = useState(false);
|
|
||||||
|
|
||||||
const onSortEnd = ({ oldIndex, newIndex }) => {
|
|
||||||
const newValue = arrayMove(selected, oldIndex, newIndex);
|
|
||||||
setSelected(newValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
const GetSelectListData = async () => {
|
|
||||||
try {
|
|
||||||
const currentUser = Parse.User.current();
|
|
||||||
const contactbook = new Parse.Query("contracts_Contactbook");
|
|
||||||
contactbook.equalTo(
|
|
||||||
"CreatedBy",
|
|
||||||
Parse.User.createWithoutData(currentUser.id)
|
|
||||||
);
|
|
||||||
contactbook.notEqualTo("IsDeleted", true);
|
|
||||||
const contactRes = await contactbook.find();
|
|
||||||
if (contactRes) {
|
|
||||||
const res = JSON.parse(JSON.stringify(contactRes));
|
|
||||||
let list = [];
|
|
||||||
|
|
||||||
// let _selected = [];
|
|
||||||
res.forEach((x) => {
|
|
||||||
let obj = {
|
|
||||||
label: x.Name,
|
|
||||||
value: x.objectId,
|
|
||||||
isChecked: true
|
|
||||||
};
|
|
||||||
|
|
||||||
list.push(obj);
|
|
||||||
});
|
|
||||||
setState(list);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log("err", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
GetSelectListData();
|
|
||||||
}, []);
|
|
||||||
useEffect(() => {
|
|
||||||
if (props.isReset && props.isReset === true) {
|
|
||||||
setSelected([]);
|
|
||||||
}
|
|
||||||
}, [props.isReset]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (selected && selected.length) {
|
|
||||||
let newData = [];
|
|
||||||
selected.forEach((x) => {
|
|
||||||
newData.push(x.value);
|
|
||||||
});
|
|
||||||
if (props.onChange) {
|
|
||||||
props.onChange(newData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [selected]);
|
|
||||||
|
|
||||||
const handleModalCloseClick = () => {
|
|
||||||
setIsModel(false);
|
|
||||||
setModalIsOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const openModal = () => {
|
|
||||||
setModalIsOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
// `handleNewDetails` is used to set just save from quick form to selected option in dropdown
|
|
||||||
const handleNewDetails = (data) => {
|
|
||||||
setState([...state, data]);
|
|
||||||
if (selected.length > 0) {
|
|
||||||
setSelected([...selected, data]);
|
|
||||||
} else {
|
|
||||||
setSelected([data]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="text-xs mt-2 ">
|
|
||||||
<label className="block relative">
|
|
||||||
Signers
|
|
||||||
{props.required && <span className="text-red-500 text-[13px]">*</span>}
|
|
||||||
<span className="absolute ml-1 text-xs z-50">
|
|
||||||
<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>
|
|
||||||
<div style={{ display: "flex", gap: 5 }}>
|
|
||||||
<div style={{ flexWrap: "wrap", width: "100%" }}>
|
|
||||||
<Select
|
|
||||||
onSortEnd={onSortEnd}
|
|
||||||
distance={4}
|
|
||||||
isMulti
|
|
||||||
options={state || []}
|
|
||||||
value={selected}
|
|
||||||
onChange={onChange}
|
|
||||||
closeMenuOnSelect={false}
|
|
||||||
required={props.required}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
setIsModel(true);
|
|
||||||
openModal();
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
cursor: "pointer",
|
|
||||||
borderRadius: 4,
|
|
||||||
border: "1px solid #ccc",
|
|
||||||
minHeight: 38,
|
|
||||||
minWidth: 48,
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i className="fas fa-plus"></i>
|
|
||||||
</div>
|
|
||||||
<Modal
|
|
||||||
isOpen={modalIsOpen}
|
|
||||||
onRequestClose={handleModalCloseClick}
|
|
||||||
shouldCloseOnOverlayClick={false}
|
|
||||||
id="modal1"
|
|
||||||
contentLabel="Modal"
|
|
||||||
style={{
|
|
||||||
content: {
|
|
||||||
top: "50%",
|
|
||||||
left: "50%",
|
|
||||||
right: "auto",
|
|
||||||
bottom: "auto",
|
|
||||||
transform: "translate(-50%, -50%)",
|
|
||||||
border: "1px transparent",
|
|
||||||
padding: 0
|
|
||||||
},
|
|
||||||
overlay: {
|
|
||||||
width: "100%",
|
|
||||||
backgroundColor: "rgba(0, 0, 0, 0.75)",
|
|
||||||
zIndex: 50
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="min-w-full md:min-w-[500px]">
|
|
||||||
<div
|
|
||||||
className="flex justify-between rounded-t items-center py-[10px] px-[20px] text-white"
|
|
||||||
style={{ background: "#32a3ac" }}
|
|
||||||
>
|
|
||||||
<div className="text-[1.2rem] font-normal">Add Signer</div>
|
|
||||||
<button
|
|
||||||
onClick={handleModalCloseClick}
|
|
||||||
className="text-[1.5rem] cursor-pointer focus:outline-none"
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{isModal && (
|
|
||||||
<AddSigner
|
|
||||||
valueKey={"objectId"}
|
|
||||||
displayKey={"Name"}
|
|
||||||
details={handleNewDetails}
|
|
||||||
closePopup={handleModalCloseClick}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SignersInput;
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { NavLink } from "react-router-dom";
|
|
||||||
|
|
||||||
const Menu = ({ item, isOpen, closeSidebar }) => {
|
|
||||||
return (
|
|
||||||
<li key={item.title} role="none">
|
|
||||||
<NavLink
|
|
||||||
to={
|
|
||||||
item.pageType
|
|
||||||
? `/${item.pageType}/${item.objectId}`
|
|
||||||
: `/${item.objectId}`
|
|
||||||
}
|
|
||||||
className="mx-auto flex items-center hover:bg-[#eef1f5] p-3 lg:p-4 cursor-pointer focus:text-[#0056b3] focus:bg-[#eef1f5]"
|
|
||||||
onClick={closeSidebar}
|
|
||||||
tabIndex={isOpen ? 0 : -1}
|
|
||||||
role="menuitem"
|
|
||||||
>
|
|
||||||
<i className={`${item.icon} text-[18px]`} aria-hidden="true"></i>
|
|
||||||
<span className="ml-3 lg:ml-4">{item.title}</span>
|
|
||||||
</NavLink>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Menu;
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
|
||||||
|
|
||||||
import Menu from "./Menu";
|
|
||||||
import Submenu from "./SubMenu";
|
|
||||||
import SocialMedia from "./SocialMedia";
|
|
||||||
|
|
||||||
import Parse from "parse";
|
|
||||||
import dp from "../../assets/images/dp.png";
|
|
||||||
|
|
||||||
const Sidebar = ({ isOpen, closeSidebar }) => {
|
|
||||||
const [menuList, setmenuList] = useState([]);
|
|
||||||
let username = localStorage.getItem("username");
|
|
||||||
const image = localStorage.getItem("profileImg") || dp;
|
|
||||||
const tenantname = localStorage.getItem("TenantName");
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (localStorage.getItem("accesstoken")) {
|
|
||||||
menuItem();
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const menuItem = async () => {
|
|
||||||
try {
|
|
||||||
var sideMenu = Parse.Object.extend("w_menu");
|
|
||||||
var query = new Parse.Query(sideMenu);
|
|
||||||
query.equalTo("objectId", localStorage.getItem("defaultmenuid"));
|
|
||||||
const results = await query.first();
|
|
||||||
const resultjson = results.toJSON();
|
|
||||||
let result = resultjson;
|
|
||||||
setmenuList(result.menuItems);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Problem", e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<aside
|
|
||||||
className={`bg-white text-[#444] h-screen w-full md:w-[300px] overflow-y-auto transform transition-transform z-40 md:translate-x-0
|
|
||||||
${isOpen ? "translate-x-0 block" : "-translate-x-full hidden"}`}
|
|
||||||
>
|
|
||||||
<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">
|
|
||||||
<img
|
|
||||||
className="w-full h-full object-cover"
|
|
||||||
src={image}
|
|
||||||
alt="Profile"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-[14px] font-bold">{username}</p>
|
|
||||||
<p className={`text-[12px] ${tenantname ? "mt-2" : ""}`}>
|
|
||||||
{tenantname}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<nav aria-label="OpenSign Sidebar Navigation">
|
|
||||||
<ul
|
|
||||||
className="text-sm"
|
|
||||||
role="menubar"
|
|
||||||
aria-label="OpenSign Sidebar Navigation"
|
|
||||||
>
|
|
||||||
{menuList.map((item) =>
|
|
||||||
!item.children ? (
|
|
||||||
<Menu
|
|
||||||
key={item.title}
|
|
||||||
item={item}
|
|
||||||
isOpen={isOpen}
|
|
||||||
closeSidebar={closeSidebar}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Submenu
|
|
||||||
key={item.title}
|
|
||||||
item={item}
|
|
||||||
closeSidebar={closeSidebar}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
<footer className="mt-4 flex justify-center items-center text-[25px] text-black gap-3">
|
|
||||||
<SocialMedia />
|
|
||||||
</footer>
|
|
||||||
</aside>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Sidebar;
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { NavLink } from "react-router-dom";
|
|
||||||
|
|
||||||
const SocialMedia = () => {
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<NavLink to="https://github.com/opensignlabs/opensign" target="_blank" rel="noopener noreferrer">
|
|
||||||
<i aria-hidden="true" className="fa-brands fa-github"></i>
|
|
||||||
<span className="fa-sr-only">OpenSign's Github</span>
|
|
||||||
</NavLink>
|
|
||||||
<NavLink to="https://www.linkedin.com/company/opensign%E2%84%A2/" target="_blank" rel="noopener noreferrer">
|
|
||||||
<i aria-hidden="true" className="fa-brands fa-linkedin"></i>
|
|
||||||
<span className="fa-sr-only">OpenSign's LinkedIn</span>
|
|
||||||
</NavLink>
|
|
||||||
<NavLink to="https://www.twitter.com/opensignlabs" target="_blank" rel="noopener noreferrer">
|
|
||||||
<i aria-hidden="true" className="fa-brands fa-square-x-twitter"></i>
|
|
||||||
<span className="fa-sr-only">OpenSign's Twitter</span>
|
|
||||||
</NavLink>
|
|
||||||
<NavLink to="https://discord.com/invite/xe9TDuyAyj" target="_blank" rel="noopener noreferrer">
|
|
||||||
<i aria-hidden="true" className="fa-brands fa-discord"></i>
|
|
||||||
<span className="fa-sr-only">OpenSign's Discord</span>
|
|
||||||
</NavLink>
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SocialMedia;
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import { NavLink } from "react-router-dom";
|
|
||||||
|
|
||||||
const Submenu = ({ item, closeSidebar }) => {
|
|
||||||
const [submenuOpen, setSubmenuOpen] = useState(false);
|
|
||||||
const { title, icon, children } = item;
|
|
||||||
|
|
||||||
const toggleSubmenu = () => {
|
|
||||||
setSubmenuOpen(!submenuOpen);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li role="none">
|
|
||||||
<button
|
|
||||||
onClick={toggleSubmenu}
|
|
||||||
className="w-full flex items-center text-left text-[#444] p-3 lg:p-4 hover:bg-[#eef1f5] focus:outline-none focus:text-[#0056b3] focus:bg-[#eef1f5]"
|
|
||||||
aria-expanded={submenuOpen}
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-controls={`submenu-${title}`}
|
|
||||||
>
|
|
||||||
<i className={`${icon} text-[18px]`}></i>
|
|
||||||
<div className="flex justify-between items-center w-full">
|
|
||||||
<span className="ml-3 lg:ml-4">{title}</span>
|
|
||||||
<i
|
|
||||||
className={`${
|
|
||||||
submenuOpen ? "fa-solid fa-angle-down" : "fa-solid fa-angle-right"
|
|
||||||
}`}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
{submenuOpen && (
|
|
||||||
<ul id={`submenu-${title}`} role="menu" aria-label={`${title} submenu`}>
|
|
||||||
{children.map((childItem) => (
|
|
||||||
<li key={childItem.title} role="none">
|
|
||||||
<NavLink
|
|
||||||
to={
|
|
||||||
childItem.pageType
|
|
||||||
? `/${childItem.pageType}/${childItem.objectId}`
|
|
||||||
: `/${childItem.objectId}`
|
|
||||||
}
|
|
||||||
className="block pl-6 md:pl-8 py-2 text-sm text-gray-700 hover:bg-blue-500 hover:text-white focus:text-[#0056b3] focus:bg-[#eef1f5] cursor-pointer"
|
|
||||||
onClick={closeSidebar}
|
|
||||||
role="menuitem"
|
|
||||||
tabIndex={submenuOpen ? 0 : -1}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className={`${childItem.icon} text-[18px]`}
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
<span className="ml-3 lg:ml-4">{childItem.title}</span>
|
|
||||||
</NavLink>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
)}
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Submenu;
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import logo from "../assets/images/logo.png";
|
|
||||||
export const appInfo = {
|
|
||||||
appTitle: "contracts",
|
|
||||||
applogo: logo,
|
|
||||||
appname: "contracts",
|
|
||||||
appId: process.env.REACT_APP_APPID ? process.env.REACT_APP_APPID : "opensign",
|
|
||||||
baseUrl: process.env.REACT_APP_SERVERURL
|
|
||||||
? process.env.REACT_APP_SERVERURL
|
|
||||||
: window.location.origin + "/api/app",
|
|
||||||
defaultRole: "contracts_User",
|
|
||||||
fbAppId: process.env.REACT_APP_FBAPPID
|
|
||||||
? `${process.env.REACT_APP_FBAPPID}`
|
|
||||||
: "",
|
|
||||||
fev_Icon:
|
|
||||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC",
|
|
||||||
googleClietId: process.env.REACT_APP_GOOGLECLIENTID
|
|
||||||
? `${process.env.REACT_APP_GOOGLECLIENTID}`
|
|
||||||
: "",
|
|
||||||
metaDescription:
|
|
||||||
"The fastest way to sign PDFs & request signatures from others.",
|
|
||||||
objectId: "aIPmIvMzGM",
|
|
||||||
settings: [
|
|
||||||
{
|
|
||||||
role: "contracts_User",
|
|
||||||
menuId: "H9vRfEYKhT",
|
|
||||||
pageType: "dashboard",
|
|
||||||
pageId: "35KBoSgoAK",
|
|
||||||
extended_class: "contracts_Users"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: "contracts_Admin",
|
|
||||||
menuId: "VPh91h0ZHk",
|
|
||||||
pageType: "dashboard",
|
|
||||||
pageId: "35KBoSgoAK",
|
|
||||||
extended_class: "contracts_Users"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
version: "0.1"
|
|
||||||
};
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
export const contactCls = "contracts_Contactbook";
|
|
||||||
export const templateCls = "contracts_Template";
|
|
||||||
export const documentCls = "contracts_Document";
|
|
||||||
export const rejectBtn =
|
|
||||||
"bg-[#ffffff] rounded-sm shadow-md text-[12px] font-semibold uppercase text-black py-1.5 px-4 focus:outline-none text-center border-[1px] border-[#b4b4b4]";
|
|
||||||
export const submitBtn =
|
|
||||||
"bg-[#32a3ac] rounded-sm shadow-md text-[12px] font-semibold uppercase text-white py-1.5 px-4 focus:outline-none text-center";
|
|
||||||
export const modalSubmitBtnColor = "#17a2b8";
|
|
||||||
export const modalCancelBtnColor = "white";
|
|
||||||
export const themeColor = "#47a3ad";
|
|
||||||
export const iconColor = "#686968";
|
|
||||||
export const isEnableSubscription = process.env.REACT_APP_ENABLE_SUBSCRIPTION;
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
import Parse from "parse";
|
|
||||||
/**
|
|
||||||
* Function returning the queryString in which multiple hash replaced with actual values
|
|
||||||
* @param str query string
|
|
||||||
* @param json localstroage data in json
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default function getReplacedHashQuery(str, json) {
|
|
||||||
// eslint-disable-next-line
|
|
||||||
let reg = /(\#.*?\#)/gi;
|
|
||||||
const currentUser = Parse.User.current();
|
|
||||||
const multiHash = str.match(reg);
|
|
||||||
|
|
||||||
let values = {};
|
|
||||||
let key = "";
|
|
||||||
multiHash.forEach((x) => {
|
|
||||||
key = x;
|
|
||||||
key = key.substring(1, key.length - 1);
|
|
||||||
key = key.split(".");
|
|
||||||
if (key.length > 1) {
|
|
||||||
key = x.replace(reg, json[key[0]][key[1]]);
|
|
||||||
} else if (json[key[0]]) {
|
|
||||||
key = x.replace(reg, json[key[0]]);
|
|
||||||
} else if (key[0] === "Date") {
|
|
||||||
key = x.replace(reg, "Date");
|
|
||||||
} else if (key[0] === "today") {
|
|
||||||
key = x.replace(reg, new Date().toISOString());
|
|
||||||
} else {
|
|
||||||
key = x.replace(reg, currentUser.id);
|
|
||||||
}
|
|
||||||
values = { ...values, [x]: key };
|
|
||||||
});
|
|
||||||
const querySplit = str.split(reg);
|
|
||||||
const replacedHashWithValuesArr = querySplit.map((hash) =>
|
|
||||||
values[hash] ? values[hash] : hash
|
|
||||||
);
|
|
||||||
const HashFreeQuery = replacedHashWithValuesArr.join("");
|
|
||||||
// console.log("HashFreeQuery ", HashFreeQuery);
|
|
||||||
return HashFreeQuery;
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
export default function linkURL(url) {
|
|
||||||
let newURL = (url && decodeURIComponent(url)) || "";
|
|
||||||
return newURL.substring(newURL.indexOf(".com/") + 5, newURL.indexOf("_"));
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
import axios from "axios";
|
|
||||||
const parseAppId = localStorage.getItem("parseAppId");
|
|
||||||
const serverUrl = localStorage.getItem("baseUrl");
|
|
||||||
|
|
||||||
export const SaveFileSize = async (size, imageUrl, tenantId) => {
|
|
||||||
//checking server url and save file's size
|
|
||||||
const tenantPtr = {
|
|
||||||
__type: "Pointer",
|
|
||||||
className: "partners_Tenant",
|
|
||||||
objectId: tenantId
|
|
||||||
};
|
|
||||||
const _tenantPtr = JSON.stringify(tenantPtr);
|
|
||||||
try {
|
|
||||||
const res = await axios.get(
|
|
||||||
`${serverUrl}classes/partners_TenantCredits?where={"PartnersTenant":${_tenantPtr}}`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const response = res.data.results;
|
|
||||||
let data;
|
|
||||||
// console.log("response", response);
|
|
||||||
if (response && response.length > 0) {
|
|
||||||
data = {
|
|
||||||
usedStorage: response[0].usedStorage
|
|
||||||
? response[0].usedStorage + size
|
|
||||||
: size
|
|
||||||
};
|
|
||||||
await axios.put(
|
|
||||||
`${serverUrl}classes/partners_TenantCredits/${response[0].objectId}`,
|
|
||||||
data,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
data = { usedStorage: size, PartnersTenant: tenantPtr };
|
|
||||||
await axios.post(`${serverUrl}classes/partners_TenantCredits`, data, {
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log("err in save usage", err);
|
|
||||||
}
|
|
||||||
saveDataFile(size, imageUrl, tenantPtr);
|
|
||||||
};
|
|
||||||
|
|
||||||
//function for save fileUrl and file size in particular client db class partners_DataFiles
|
|
||||||
const saveDataFile = async (size, imageUrl, tenantPtr) => {
|
|
||||||
const data = {
|
|
||||||
FileUrl: imageUrl,
|
|
||||||
FileSize: size,
|
|
||||||
TenantPtr: tenantPtr
|
|
||||||
};
|
|
||||||
|
|
||||||
// console.log("data save",file, data)
|
|
||||||
try {
|
|
||||||
await axios.post(`${serverUrl}classes/partners_DataFiles`, data, {
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Parse-Application-Id": parseAppId
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
console.log("err in save usage ", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import { useEffect } from "react";
|
|
||||||
|
|
||||||
/**`useScript` hook is generated scripte for google sign in button */
|
|
||||||
export const useScript = (url, onload) => {
|
|
||||||
useEffect(() => {
|
|
||||||
const script = document.createElement("script");
|
|
||||||
//add url parameter to the script src, for load and it will remove after load in return
|
|
||||||
script.src = url;
|
|
||||||
script.async = true;
|
|
||||||
script.defer = true;
|
|
||||||
script.onload = onload;
|
|
||||||
document.head.appendChild(script);
|
|
||||||
return () => {
|
|
||||||
document.head.removeChild(script);
|
|
||||||
};
|
|
||||||
}, [url, onload]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**`useScript` hook is generated scripte for google sign in button */
|
|
||||||
export const useDropScript = (url, onload) => {
|
|
||||||
useEffect(() => {
|
|
||||||
const script = document.createElement("script");
|
|
||||||
//add url parameter to the script src, for load and it will remove after load in return
|
|
||||||
script.src = url;
|
|
||||||
script.async = true;
|
|
||||||
script.defer = true;
|
|
||||||
script.id = "dropboxjs";
|
|
||||||
script.setAttribute("data-app-key", "8k0thg9r1t7asqg");
|
|
||||||
document.head.appendChild(script);
|
|
||||||
return () => {
|
|
||||||
document.head.removeChild(script);
|
|
||||||
};
|
|
||||||
}, [url, onload]);
|
|
||||||
};
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { useEffect, useState } from "react";
|
|
||||||
|
|
||||||
export function useWindowSize() {
|
|
||||||
const [size, setSize] = useState({
|
|
||||||
width: 0,
|
|
||||||
height: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
const onResize = () => {
|
|
||||||
setSize({
|
|
||||||
width: window.innerWidth,
|
|
||||||
height: window.innerHeight
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
onResize();
|
|
||||||
window.addEventListener("resize", onResize);
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener("resize", onResize);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
body{
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Custom CSS to hide scrollbar */
|
|
||||||
.hide-scrollbar::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hide-scrollbar {
|
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
|
||||||
scrollbar-width: none; /* Firefox */
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import ReactDOM from "react-dom/client";
|
|
||||||
import "./index.css";
|
|
||||||
import App from "./App";
|
|
||||||
import { Provider } from "react-redux";
|
|
||||||
import { store } from "./redux/store";
|
|
||||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
|
||||||
import { TouchBackend } from "react-dnd-touch-backend";
|
|
||||||
import {
|
|
||||||
DndProvider,
|
|
||||||
TouchTransition,
|
|
||||||
MouseTransition,
|
|
||||||
Preview
|
|
||||||
} from "react-dnd-multi-backend";
|
|
||||||
import DragElement from "./components/pdf/DragElement";
|
|
||||||
import TagManager from "react-gtm-module";
|
|
||||||
import Parse from "parse";
|
|
||||||
const appId = process.env.REACT_APP_APPID
|
|
||||||
? process.env.REACT_APP_APPID
|
|
||||||
: "opensign";
|
|
||||||
const serverUrl = process.env.REACT_APP_SERVERURL
|
|
||||||
? process.env.REACT_APP_SERVERURL
|
|
||||||
: window.location.origin + "/api/app";
|
|
||||||
Parse.initialize(appId);
|
|
||||||
Parse.serverURL = serverUrl;
|
|
||||||
|
|
||||||
const HTML5toTouch = {
|
|
||||||
backends: [
|
|
||||||
{
|
|
||||||
id: "html5",
|
|
||||||
backend: HTML5Backend,
|
|
||||||
transition: MouseTransition
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "touch",
|
|
||||||
backend: TouchBackend,
|
|
||||||
options: { enableMouseEvents: true },
|
|
||||||
preview: true,
|
|
||||||
transition: TouchTransition
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
const generatePreview = (props) => {
|
|
||||||
const { item, style } = props;
|
|
||||||
const newStyle = {
|
|
||||||
...style
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={newStyle}>
|
|
||||||
<DragElement {...item} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (process.env.REACT_APP_GTM) {
|
|
||||||
const tagManagerArgs = {
|
|
||||||
gtmId: process.env.REACT_APP_GTM
|
|
||||||
};
|
|
||||||
TagManager.initialize(tagManagerArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById("root"));
|
|
||||||
root.render(
|
|
||||||
<Provider store={store}>
|
|
||||||
<DndProvider options={HTML5toTouch}>
|
|
||||||
<Preview>{generatePreview}</Preview>
|
|
||||||
<App />
|
|
||||||
</DndProvider>
|
|
||||||
</Provider>
|
|
||||||
);
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import { documentCls, templateCls } from "../constant/const";
|
|
||||||
export const formJson = {
|
|
||||||
//json form for signYourself
|
|
||||||
sHAnZphf69: {
|
|
||||||
title: "Sign Yourself",
|
|
||||||
redirectRoute: "signaturePdf",
|
|
||||||
msgVar: "Document",
|
|
||||||
Cls: documentCls
|
|
||||||
},
|
|
||||||
|
|
||||||
//json form for request signatures
|
|
||||||
"8mZzFxbG1z": {
|
|
||||||
title: "Request Signatures",
|
|
||||||
msgVar: "Document",
|
|
||||||
redirectRoute: "placeHolderSign",
|
|
||||||
Cls: documentCls,
|
|
||||||
signers: true
|
|
||||||
},
|
|
||||||
//json form for template
|
|
||||||
template: {
|
|
||||||
title: "New Template",
|
|
||||||
redirectRoute: "template",
|
|
||||||
msgVar: "Template",
|
|
||||||
Cls: templateCls
|
|
||||||
}
|
|
||||||
};
|
|
||||||