Compare commits

...
248 Commits
Author SHA1 Message Date
AmolandGitHub f3a1c74a45 Merge pull request #254 from OpenSignLabs/fix_action_btn
fix: continuous loader on action btn in report
2023-12-04 18:14:39 +05:30
prafull-opensignlabsandGitHub 2544651ff1 fix: continuous loader on action btn in report 2023-12-04 18:13:35 +05:30
AmolandGitHub 93297b972a Merge pull request #253 from OpenSignLabs/update_appname
Update app name
2023-12-04 17:56:14 +05:30
prafull-opensignlabsandGitHub 7165ed82f5 Update_appname 2023-12-04 17:55:16 +05:30
prafull-opensignlabsandGitHub 17422427a8 Update index.html 2023-12-04 17:33:33 +05:30
AmolandGitHub 9ef2bc9ee2 Merge pull request #238 from OpenSignLabs/feat-dropbox-fileupload
feat: add dropbox fileupload
2023-12-04 17:31:10 +05:30
AmolandGitHub 12ec1bad0f Merge pull request #248 from OpenSignLabs/contactbook-validation
update query for contact
2023-12-04 17:07:53 +05:30
AmolandGitHub fd552cedec Merge pull request #251 from OpenSignLabs/folder-update
update folder component
2023-12-04 17:06:36 +05:30
prafull-opensignlabsandGitHub 5784378073 Update TreeWidget.js 2023-12-04 16:17:28 +05:30
prafull-opensignlabsandGitHub e0448cd4fa Merge pull request #252 from OpenSignLabs/staging
Merge pull request #250 from OpenSignLabs/folder-update
2023-12-04 16:10:55 +05:30
RaktimaNXG 9ae0334249 update folder component 2023-12-04 16:06:00 +05:30
AndrewandGitHub eb355f562b Merge pull request #250 from OpenSignLabs/folder-update 2023-12-04 13:13:27 +05:30
RaktimaNXG 92dc13185b update folder creation query 2023-12-04 12:16:06 +05:30
RaktimaNXG 65ec4e78ad update folder creation 2023-12-04 11:56:56 +05:30
prafull-opensignlabs 944370134a add validation for contactbook 2023-12-01 19:14:36 +05:30
prafull-opensignlabsandGitHub c1621f64e6 Merge pull request #247 from OpenSignLabs/feat-password-validation
add password validation
2023-12-01 10:50:24 +05:30
prafull-opensignlabsandGitHub e8c06d0836 Merge pull request #246 from OpenSignLabs/guest-signers-download
fix:  #227 download button throws error in guest signer flow issue
2023-12-01 10:50:08 +05:30
prafull-opensignlabs a6295a6e56 add password validation 2023-11-30 18:08:32 +05:30
RaktimaNXG 47ae52c881 fix: download button throws error in guest signer flow 2023-11-30 18:01:37 +05:30
prafull-opensignlabsandGitHub f2f0b55596 Merge pull request #245 from raktima-opensignlabs/horizontal-pdf-issue
fix: horizontal pdf or large size pdf's scrollbar issue in signyourself & placeholder flow
2023-11-30 15:43:09 +05:30
RaktimaNXG 0c415de598 remove unecessary times call getDocumentsDetails function 2023-11-30 14:15:50 +05:30
RaktimaNXG 411941d9f7 fix: horizontal pdf or large size pdf's scrollbar issue in signyourself and placeholder flow 2023-11-30 14:12:25 +05:30
RaktimaandGitHub 3c54f2287c Merge pull request #28 from OpenSignLabs/staging
update
2023-11-30 13:37:28 +05:30
AndrewandGitHub dfa121fe57 Merge pull request #234 from raktima-opensignlabs/default-signature 2023-11-30 13:17:52 +05:30
prafull-opensignlabsandGitHub 52b17730ef feat: migration of contactbook report (#243) 2023-11-30 13:17:35 +05:30
AndrewandGitHub 346d69124c chore: Add issue and feature request template (#244) 2023-11-29 16:34:26 +05:30
AndrewandGitHub 7f35074acd Merge pull request #241 from OpenSignLabs/all-contributors/add-crediblebilal 2023-11-28 19:49:19 +05:30
allcontributors[bot]andGitHub b9e9694d61 docs: update .all-contributorsrc 2023-11-28 14:19:00 +00:00
allcontributors[bot]andGitHub ee4a787b81 docs: update README.md 2023-11-28 14:18:59 +00:00
AndrewandGitHub d801680846 Merge pull request #239 from crediblebilal/fix-automatic-sidebar-opening 2023-11-28 19:47:59 +05:30
prafull-opensignlabsandAndrew d84ab89a9b fix: smtp mail issue resolve 2023-11-28 19:40:08 +05:30
prafull-opensignlabs 26d38f4ca2 change color of cancel btn test in file-upload 2023-11-28 15:52:26 +05:30
Bilal Ahmad Bhat 745e519eec fix automatic sidebar opening on window resize 2023-11-28 14:04:51 +05:30
prafull-opensignlabs 45b3e739d7 make changes UI in file upload 2023-11-28 12:22:13 +05:30
prafull-opensignlabs 5ce50db001 add dropbox in file upload field 2023-11-28 10:14:41 +05:30
AndrewandGitHub a8c7b60c1b Docs: Add SMTP config 2023-11-28 04:17:05 +05:30
AndrewandGitHub 16860bc7b8 Docs: Add SMTP CONFIG 2023-11-28 04:15:26 +05:30
AndrewandGitHub 57f20ae1c0 Docs: Add USE_LOCAL variable 2023-11-28 03:45:22 +05:30
allcontributors[bot]andAndrew d3b0c614ff docs: update .all-contributorsrc 2023-11-27 23:55:22 +05:30
allcontributors[bot]andAndrew e28f929ffc docs: update README.md 2023-11-27 23:55:22 +05:30
AndrewandGitHub 9f8f9a0992 Merge pull request #235 from Govinda04/feature/fix-delete-btn
fix: Delete button issue
2023-11-27 23:53:58 +05:30
Govinda KocharekarandGitHub 60857638ba Proper style for the delete button(cross) on "email documents" popup 2023-11-27 23:14:31 +05:30
Govinda KocharekarandGitHub 8041151243 show cursor pointer for select email list cancel button/img 2023-11-27 23:13:12 +05:30
AmolandGitHub 7faed512b8 Merge pull request #226 from prafull-opensignlabs/auth_user
feat:add contactbook report & updated version of app in footer
2023-11-27 17:01:23 +05:30
RaktimaNXG 5d99a4a9c8 fix: multiple default signature error,sign-yourself placeholder location issue in mobile view 2023-11-27 16:29:19 +05:30
prafull-opensignlabs 25c50d5387 change subscipiton urls 2023-11-27 12:48:20 +05:30
prafull-opensignlabsandGitHub 5719dcca79 Merge pull request #51 from OpenSignLabs/staging
sync fork
2023-11-27 11:01:53 +05:30
RaktimaandGitHub db1e81a249 Merge pull request #27 from OpenSignLabs/staging
update
2023-11-26 15:04:58 +05:30
AndrewandGitHub ecd3395453 Docs: fix duplicate values in INSTALLATION.md 2023-11-26 11:15:41 +05:30
AmolandGitHub 06e8140be4 Merge pull request #228 from OpenSignLabs/fix-additionalinfo-popup
fix: correct typo
2023-11-24 19:24:38 +05:30
prafull-opensignlabsandGitHub 14e9330651 replace destination to Jobtitle in additional info popup 2023-11-24 19:21:51 +05:30
prafull-opensignlabs 636910a78e feat:add contactbook report & updated version of app in footer 2023-11-24 17:12:38 +05:30
prafull-opensignlabsandGitHub e4f9152de8 Merge pull request #49 from OpenSignLabs/staging
sync fork
2023-11-24 16:56:41 +05:30
RaktimaandGitHub e0b9df9ba5 Merge pull request #26 from OpenSignLabs/staging
update
2023-11-24 10:54:28 +05:30
AmolandGitHub a20bd407a8 Merge pull request #224 from prafull-opensignlabs/auth_user
chore:code refactor
2023-11-23 19:25:11 +05:30
prafull-opensignlabs 5630dd45a7 chore:code refactor 2023-11-23 19:23:35 +05:30
AmolandGitHub 20220dd8c9 Merge pull request #223 from raktima-opensignlabs/horizontal-pdf2
fix: two modal overlap at a time in signyourself flow
2023-11-23 19:23:17 +05:30
RaktimaNXG db4b8ec0ee fix two modal overlap during signyourself flow 2023-11-23 19:19:57 +05:30
RaktimaandGitHub 2ee9ae16fb Merge pull request #25 from OpenSignLabs/staging
update
2023-11-23 18:18:24 +05:30
prafull-opensignlabsandGitHub e50a55403d Merge pull request #48 from OpenSignLabs/staging
sync fork
2023-11-23 18:10:28 +05:30
AmolandGitHub 23ae72738d chore: syntax issue 2023-11-23 18:07:22 +05:30
AmolandGitHub 8619021f30 chore: syntax issue 2023-11-23 17:57:00 +05:30
AmolandGitHub 6c579178c0 chore: syntax issue 2023-11-23 17:51:10 +05:30
AmolandGitHub 01e19632a9 fix: syntax issue 2023-11-23 17:49:43 +05:30
AmolandGitHub 79ff8fd71d Merge pull request #191 from raktima-opensignlabs/transparent-img
fix:  #165 - transparent PNG signature issue
2023-11-23 17:36:30 +05:30
AmolandGitHub 8700fd837d Merge branch 'staging' into transparent-img 2023-11-23 17:36:10 +05:30
AmolandGitHub cdc8eb5bf6 Merge pull request #189 from rishabjasrotia/issue/126
#126 - Fix UI layout issue after signing a document from mobile
2023-11-23 17:27:43 +05:30
AmolandGitHub 95200e234f Merge pull request #216 from rishabjasrotia/issue/204
#204 - Fix issue due to Signature URL validation
2023-11-23 17:26:44 +05:30
AmolandGitHub d94527e31a Merge branch 'staging' into issue/204 2023-11-23 17:26:35 +05:30
prafull-opensignlabsandGitHub 903066e6fa Merge pull request #47 from OpenSignLabs/staging
sync fork
2023-11-23 17:25:16 +05:30
AmolandGitHub 8c8015fe4a Merge pull request #188 from rishabjasrotia/issue/168
#168 - Align Modal to Center of PDF if Signed
2023-11-23 17:19:01 +05:30
AmolandGitHub a002ac779c Merge pull request #222 from prafull-opensignlabs/auth_user 2023-11-23 13:47:12 +05:30
prafull-opensignlabs 5c9bfbbdfe fix: signature slighty move from top and bottom 2023-11-23 13:36:35 +05:30
RishabandGitHub 4a1e6d1318 Merge branch 'OpenSignLabs:staging' into issue/168 2023-11-23 12:56:50 +05:30
RaktimaandGitHub 90dc7c738a Merge pull request #24 from OpenSignLabs/staging
update
2023-11-23 11:14:50 +05:30
prafull-opensignlabsandGitHub 777028f3a7 Merge pull request #46 from OpenSignLabs/staging
Merge pull request #221 from prafull-opensignlabs/auth_user
2023-11-22 20:46:57 +05:30
AmolandGitHub c5a0ff4021 Merge pull request #221 from prafull-opensignlabs/auth_user
change sequence in add signer form
2023-11-22 20:42:58 +05:30
prafull-opensignlabs bf9f42e94d change sequence in add signer form 2023-11-22 20:41:55 +05:30
prafull-opensignlabsandGitHub 5556de2ef5 Merge pull request #45 from OpenSignLabs/staging
sync fork
2023-11-22 20:32:28 +05:30
rishabjasrotia 1b3508a9ef Replace npm package with manual valiadation 2023-11-22 18:57:18 +05:30
RishabandGitHub 3992a9be94 Merge branch 'OpenSignLabs:staging' into issue/204 2023-11-22 18:54:53 +05:30
AmolandGitHub eaf875be06 Merge pull request #220 from OpenSignLabs/add-verificaiton-branding
Add "OpenSign" branding to verification email
2023-11-22 17:27:53 +05:30
AmolandGitHub e62897e729 Add "OpenSign" branding to verification email 2023-11-22 16:57:44 +05:30
AmolandGitHub 4c58fe2040 Merge pull request #219 from prafull-opensignlabs/auth_user
add parameter verifyUserEmails in server
2023-11-22 16:34:26 +05:30
prafull-opensignlabs 298068207e add parameter verifyUserEmails in server 2023-11-22 16:33:18 +05:30
prafull-opensignlabsandGitHub d0abe615cb Merge pull request #44 from OpenSignLabs/staging
Merge pull request #215 from prafull-opensignlabs/auth_user
2023-11-22 16:32:06 +05:30
Rishab 87c65e4bea #204 - Fix issue due to Signature URL validation 2023-11-22 06:20:02 +00:00
RishabandGitHub be49cb9d6d Merge branch 'staging' into issue/168 2023-11-22 08:52:17 +05:30
AmolandGitHub 2b73087b7e Merge pull request #215 from prafull-opensignlabs/auth_user 2023-11-22 00:13:04 +05:30
prafull-opensignlabs d11dff2987 fix: google sign in mobile & add progress in profile pic upload 2023-11-22 00:09:28 +05:30
prafull-opensignlabsandGitHub 8ac82b1214 Merge pull request #43 from OpenSignLabs/staging
Merge pull request #214 from prafull-opensignlabs/auth_user
2023-11-21 23:07:08 +05:30
RaktimaandGitHub c46fa19bbb Merge pull request #23 from OpenSignLabs/staging
update
2023-11-21 20:56:29 +05:30
AmolandGitHub 2fa2f56bac Merge pull request #214 from prafull-opensignlabs/auth_user 2023-11-21 19:35:42 +05:30
prafull-opensignlabs ef50aaa417 fix google sign in 2023-11-21 19:34:11 +05:30
prafull-opensignlabsandGitHub a1d7275fcd Merge pull request #42 from OpenSignLabs/staging
sync fork
2023-11-21 19:17:55 +05:30
AmolandGitHub 080acc9ed6 Merge pull request #213 from raktima-opensignlabs/signer-login
fix:  no data found issue on signers login page
2023-11-21 16:36:10 +05:30
prafull-opensignlabsandGitHub 30b888f3a0 Merge pull request #41 from OpenSignLabs/staging
sync fork
2023-11-21 15:35:30 +05:30
prafull-opensignlabs df11a77971 Merge branch 'auth_user' of https://github.com/prafull-opensignlabs/OpenSign into auth_user 2023-11-21 15:28:41 +05:30
prafull-opensignlabs 03e660527d security improvement 2023-11-21 15:23:26 +05:30
RaktimaNXG f7bd439df5 remove contracts_contactbook class query from placeholderSign.js 2023-11-21 14:14:01 +05:30
RaktimaNXG 2a55c03788 fix no data found on signers login page 2023-11-21 13:36:42 +05:30
RaktimaandGitHub f712532793 Merge pull request #22 from OpenSignLabs/staging
update
2023-11-21 10:27:00 +05:30
AmolandGitHub cbdeaf8cc9 Merge pull request #212 from raktima-opensignlabs/email-message 2023-11-21 10:24:29 +05:30
RaktimaNXG 6bb353fd1f fix spelling mistake of email message beeen to been after signed by all parties 2023-11-21 10:22:16 +05:30
RaktimaandGitHub 523dd43b4d Merge pull request #21 from OpenSignLabs/staging
update
2023-11-21 09:55:49 +05:30
AmolandGitHub bd0216fc39 Merge pull request #197 from rishabjasrotia/issue/170 2023-11-21 03:09:16 +05:30
prafull-opensignlabsandGitHub 50c40bfec1 Merge pull request #40 from OpenSignLabs/staging
Merge pull request #211 from prafull-opensignlabs/auth_user
2023-11-20 23:03:35 +05:30
AmolandGitHub 0e2b6ee180 Merge pull request #211 from prafull-opensignlabs/auth_user 2023-11-20 23:01:49 +05:30
prafull-opensignlabs 359d86e17b fix: sendmail functionality not working 2023-11-20 23:00:07 +05:30
prafull-opensignlabsandGitHub 0b19c87a50 Merge pull request #37 from OpenSignLabs/staging
sync fork
2023-11-20 22:25:28 +05:30
AmolandGitHub 4a35eab7c6 Merge pull request #209 from raktima-opensignlabs/cloud-function 2023-11-20 22:14:20 +05:30
RaktimaNXG b178a3c91e handle condition of no data for contracts_Document and contracts_ContactBook classes 2023-11-20 21:57:26 +05:30
prafull-opensignlabsandGitHub 9fb0fecba4 Merge pull request #36 from OpenSignLabs/staging
sync fork
2023-11-20 20:18:32 +05:30
AmolandGitHub cfc7408a52 Merge pull request #210 from prafull-opensignlabs/auth_user
add getReport cloud function
2023-11-20 19:21:19 +05:30
prafull-opensignlabs aed0b8a3db add getReport cloud function 2023-11-20 19:11:46 +05:30
RaktimaNXG 910bd801ac remove contracts_Document & contracts_Users query from frontend and call cloud function 2023-11-20 16:46:27 +05:30
AmolandGitHub 22dad33b2e Merge pull request #208 from prafull-opensignlabs/auth_user
security changes in getDocument function & add getDrive cloud function
2023-11-20 14:14:31 +05:30
prafull-opensignlabs 4d3ed0232e security changes in getDocument function & add getDrive function 2023-11-20 14:11:32 +05:30
prafull-opensignlabsandGitHub 6d83f05b13 Merge pull request #34 from OpenSignLabs/staging
sync fork
2023-11-20 12:51:41 +05:30
AmolandGitHub 66cc2e1f2f Merge pull request #203 from rishabjasrotia/feature/certificate_update 2023-11-20 12:36:32 +05:30
AmolandGitHub f773fc6e3c Merge pull request #207 from prafull-opensignlabs/auth_user 2023-11-20 12:33:34 +05:30
prafull-opensignlabs dc83f21f5e Merge branch 'auth_user' of https://github.com/prafull-opensignlabs/OpenSign into auth_user 2023-11-20 12:04:06 +05:30
prafull-opensignlabsandGitHub 0186c48d59 Update getDocument.js 2023-11-20 12:00:41 +05:30
prafull-opensignlabs 43f20508ae Merge branch 'auth_user' of https://github.com/prafull-opensignlabs/OpenSign into auth_user 2023-11-20 11:54:18 +05:30
prafull-opensignlabs f678dd02cb change in getDoucment cloud function 2023-11-20 11:54:04 +05:30
prafull-opensignlabsandGitHub 5c2d6cddcb Merge pull request #33 from OpenSignLabs/staging
Merge pull request #205 from prafull-opensignlabs/auth_user
2023-11-20 11:53:02 +05:30
AmolandGitHub 1bbf64fe83 Merge pull request #205 from prafull-opensignlabs/auth_user
create getDocument cloud function & minor UI changes
2023-11-20 11:14:21 +05:30
prafull-opensignlabs 296f43101e comment getinProgessReport 2023-11-20 11:13:24 +05:30
prafull-opensignlabs ed6f44fd62 create getDocument cloud function & minor UI changes 2023-11-20 10:42:20 +05:30
prafull-opensignlabsandGitHub 776b1a7b43 Merge pull request #32 from OpenSignLabs/staging
sync fork
2023-11-20 10:25:08 +05:30
RaktimaandGitHub 06cdb660b3 Merge pull request #20 from OpenSignLabs/staging
update
2023-11-20 10:22:25 +05:30
rishabjasrotia db9268e1af Include the Signer Email Address 2023-11-18 20:21:17 +05:30
nxglabs 83ce3a1c21 update local cert setup 2023-11-18 01:52:20 +05:30
prafull-opensignlabsandGitHub bda31de345 add parse-dbtool package (#201) 2023-11-17 20:12:51 +05:30
prafull-opensignlabs cdfc952a3f add parse-dbtool package 2023-11-17 20:00:43 +05:30
prafull-opensignlabsandGitHub 9434315775 migration db changes (#200) 2023-11-17 19:58:01 +05:30
prafull-opensignlabsandGitHub 47bb4cac38 migration db changes (#200) 2023-11-17 19:37:44 +05:30
prafull-opensignlabs 11d3e6c696 migration db changes 2023-11-17 19:36:11 +05:30
prafull-opensignlabsandGitHub 0173727bc5 Merge branch 'OpenSignLabs:staging' into auth_user 2023-11-17 19:35:13 +05:30
prafull-opensignlabsandGitHub 3cfa2639e5 migrate db changes (#199) 2023-11-17 18:29:41 +05:30
prafull-opensignlabs 502400ee56 rename file from create_setclp to update_setclp 2023-11-17 18:27:34 +05:30
prafull-opensignlabs 4a3276f4e3 check migration functionality in staging app 2023-11-17 18:07:26 +05:30
prafull-opensignlabsandGitHub 750e48ca2e Merge pull request #27 from OpenSignLabs/staging
sync fork
2023-11-17 16:21:37 +05:30
prafull-opensignlabsandGitHub 823e6a9e2f update schema of contracts_users (#196) 2023-11-17 15:39:18 +05:30
Rishab 642ef334f6 #170 - Fix While dragging sign placeholder in mobile view the drawbox pops up unexpectedly 2023-11-17 09:21:31 +00:00
prafull-opensignlabsandGitHub 939a67b2c5 fix: resolve user not able to login/signup (#195) 2023-11-17 14:03:33 +05:30
prafull-opensignlabsandGitHub e1f8481aa2 Merge pull request #24 from prafull-opensignlabs/staging
sync fork'
2023-11-17 10:08:55 +05:30
rishabjasrotia b8e8cd127a Remove duplicate code 2023-11-16 20:14:32 +05:30
rishabjasrotia 876a2d78d5 enhancement 2023-11-16 20:06:57 +05:30
rishabjasrotia 16f287fdc0 Added backdrop to modal 2023-11-16 20:03:59 +05:30
prafull-opensignlabsandGitHub d396a4f71d Merge pull request #22 from OpenSignLabs/staging
fix: sendmail cloud function is not working (#194)
2023-11-16 19:57:02 +05:30
prafull-opensignlabsandGitHub 6bee566d8d fix: sendmail cloud function is not working (#194) 2023-11-16 19:25:57 +05:30
RaktimaandGitHub 79acd8ae13 Merge pull request #19 from OpenSignLabs/staging
update
2023-11-16 17:04:03 +05:30
prafull-opensignlabsandGitHub 01666b49cf Merge pull request #21 from OpenSignLabs/staging
change in in class level permission of contracts_User class (#192)
2023-11-16 11:24:18 +05:30
prafull-opensignlabsandGitHub a20ebbf08f change in in class level permission of contracts_User class (#192) 2023-11-16 11:19:34 +05:30
prafull-opensignlabsandGitHub 26cf9c5310 Merge pull request #20 from OpenSignLabs/staging
security improvement (#190)
2023-11-16 11:18:44 +05:30
prafull-opensignlabs 3ad58ee52b update url of migrate 2023-11-16 11:16:28 +05:30
prafull-opensignlabs 2b67af6097 change create, update clp of contracts_Users class 2023-11-16 11:09:56 +05:30
prafull-opensignlabsandGitHub f61dae35ff Merge pull request #19 from OpenSignLabs/staging
security improvement (#190)
2023-11-16 11:08:57 +05:30
prafull-opensignlabsandGitHub dead3088d6 security improvement (#190) 2023-11-16 11:02:38 +05:30
prafull-opensignlabs 45d65cfbe2 change cloud function name getContractUser to getUserDetails 2023-11-16 11:00:49 +05:30
RaktimaNXG 6d2010facb fix transparent PNG signature issue 2023-11-16 10:59:26 +05:30
prafull-opensignlabsandGitHub 48d3166049 Merge pull request #18 from prafull-opensignlabs/staging
sync fork
2023-11-16 10:52:47 +05:30
prafull-opensignlabsandGitHub 82992d324d Merge pull request #17 from OpenSignLabs/staging
sync fork
2023-11-16 10:51:50 +05:30
prafull-opensignlabs 9a549fa35d Merge branch 'auth_user' of https://github.com/prafull-opensignlabs/OpenSign into auth_user 2023-11-16 10:50:01 +05:30
prafull-opensignlabs 93a891c8b6 feat: add migration code for contracts_users class 2023-11-16 10:47:11 +05:30
RaktimaandGitHub 2ede742b10 Merge pull request #18 from OpenSignLabs/staging
update
2023-11-16 10:32:15 +05:30
Rishab c43690faa8 #126 - Fix UI layout issue after signing a document from mobile 2023-11-16 04:08:12 +00:00
Rishab a482a92d34 #168 - Align Modal to Center of PDF if Signed 2023-11-16 04:02:34 +00:00
prafull-opensignlabsandGitHub 1d429cbe36 Merge pull request #16 from OpenSignLabs/staging
sync fork
2023-11-15 17:14:46 +05:30
AmolandGitHub 0a36550907 Update README.md 2023-11-15 02:21:26 +05:30
Mathieu VigneandGitHub 09610112fc Feature/use smtp to send email (#182) 2023-11-14 20:55:45 +05:30
RaktimaandGitHub a14454227c fix Completion certificate issues (#184) 2023-11-14 20:31:19 +05:30
AmolandGitHub 0d8767ee98 Revert "fix: #172 - Location of requested signature placeholders shift to slight right on mobile view in "Request Signatures" flow (#185)" (#186)
This reverts commit f463dc7af7.
2023-11-14 20:30:40 +05:30
RaktimaandGitHub f463dc7af7 fix: #172 - Location of requested signature placeholders shift to slight right on mobile view in "Request Signatures" flow (#185) 2023-11-14 20:09:51 +05:30
RaktimaandGitHub 407b01565a Merge pull request #17 from OpenSignLabs/staging
Update main
2023-11-14 15:50:20 +05:30
RaktimaandGitHub 6c565a144a fix need your sign report document signature issue (#183) 2023-11-14 15:29:00 +05:30
RaktimaandGitHub 141351de49 Merge pull request #16 from OpenSignLabs/staging
update main branch
2023-11-14 10:14:48 +05:30
nxglabs edecf3ea23 chore: configure husky & prettier 2023-11-13 18:21:49 +05:30
prafull-opensignlabsandGitHub e708dad596 add shipping country code param in subscriptions url (#181) 2023-11-13 16:17:40 +05:30
prafull-opensignlabsandGitHub 48012c9343 Merge pull request #13 from OpenSignLabs/staging
sync fork
2023-11-13 16:00:03 +05:30
prafull-opensignlabsandGitHub 009a24e943 Merge pull request #15 from OpenSignLabs/staging
sync fork
2023-11-13 15:59:51 +05:30
RaktimaandGitHub 04a3251968 fix issue of mulitple annotation in signyourself (#174) 2023-11-13 14:29:14 +05:30
prafull-opensignlabsandGitHub 82694a24f2 replace modal title login with additional info and verification mail alert (#179) 2023-11-13 13:22:10 +05:30
prafull-opensignlabsandGitHub 748cc042dd Merge pull request #14 from OpenSignLabs/staging
sync fork
2023-11-13 10:59:43 +05:30
RishabandGitHub 6b8bca0802 #167 - Sanitize Output filename (#176) 2023-11-11 13:25:04 +05:30
AmolandGitHub fed1cff0cb Update features in README.md 2023-11-11 02:45:53 +05:30
AmolandGitHub b2eba6409f Main (#175) 2023-11-10 20:12:35 +05:30
RaktimaandGitHub 81af6a6c61 Merge pull request #15 from OpenSignLabs/staging
update
2023-11-10 10:28:02 +05:30
AmolandGitHub c326849b8d Merge pull request #162 from rishabjasrotia/issue/146 2023-11-09 21:18:53 +05:30
prafull-opensignlabsandGitHub a92188d8e2 change variable name 2023-11-09 21:18:36 +05:30
prafull-opensignlabsandGitHub b5dbc69188 Merge pull request #12 from OpenSignLabs/staging
sync fork
2023-11-09 20:54:17 +05:30
prafull-opensignlabsandGitHub 4055574785 sanitize File Name in upload file 2023-11-09 20:48:53 +05:30
AmolandGitHub 9b295f784a Merge pull request #158 from raktima-opensignlabs/placeholder-mobile-view2 2023-11-09 20:37:49 +05:30
prafull-opensignlabsandGitHub bfae7f236c Merge branch 'staging' into placeholder-mobile-view2 2023-11-09 20:36:33 +05:30
AmolandGitHub fe907116e2 Merge pull request #156 from raktima-opensignlabs/login-header3 2023-11-09 20:27:04 +05:30
rishabjasrotia ade39c2f46 Doc Updated 2023-11-09 18:36:18 +05:30
AndrewandGitHub 31baefcce3 Merge pull request #161 from rishabjasrotia/issue/32 2023-11-09 18:32:23 +05:30
RishabandGitHub 59eb4eb9c7 #32 - Change the title of popup that appears after sending out emails from "Request signatures" flow
#32 - Change the title of popup that appears after sending out emails from "Request signatures" flow
2023-11-09 18:30:37 +05:30
rishabjasrotia 3b93f96479 Fix makefile 2023-11-09 18:05:34 +05:30
rishabjasrotia dbff436bc2 #146 - Fix issue of build & Add local File upload support 2023-11-09 17:53:34 +05:30
AmolandGitHub c3cf9c891e Merge pull request #160 from maoo/patch-1 2023-11-09 17:47:54 +05:30
Maurizio PillituandGitHub 4e7c8c63bb CORS configuration instructions
See https://github.com/OpenSignLabs/OpenSign/issues/159
2023-11-09 12:57:58 +01:00
prafull-opensignlabs db4494c463 security improvment 2023-11-09 17:08:57 +05:30
RaktimaandGitHub d208a90107 Merge pull request #14 from OpenSignLabs/staging
update
2023-11-09 15:48:38 +05:30
RaktimaNXG 450a971ca9 remove isSigner exist checking from local storage 2023-11-09 14:30:17 +05:30
RaktimaNXG 5ba1f79f3b replce isSigner variable name to isGuestSigner 2023-11-09 14:23:56 +05:30
prafull-opensignlabsandGitHub f81f72a147 Merge pull request #11 from OpenSignLabs/staging
sync fork
2023-11-09 12:28:51 +05:30
AndrewandGitHub d255d5bfb2 Merge pull request #151 from prafull-opensignlabs/mf_header 2023-11-09 12:01:41 +05:30
AndrewandGitHub f5e835cbc4 Merge pull request #148 from prafull-opensignlabs/fix_signup 2023-11-09 12:01:20 +05:30
AmolandGitHub b40eb7119d Merge branch 'issue/119' into staging 2023-11-08 22:36:01 +05:30
RaktimaNXG f56faf3afd handle placeholder block position and size on mobile view 2023-11-08 21:01:09 +05:30
RaktimaNXG 5fa60d8135 solved overflow header on logiin page 2023-11-08 20:42:35 +05:30
AmolandGitHub 695345d911 Merge pull request #144 from raktima-opensignlabs/main
fix: blocking popup on view expired and declined document screens
2023-11-08 20:11:16 +05:30
prafull-opensignlabs 3f60509254 remove header from report microapp 2023-11-08 16:55:30 +05:30
RaktimaandGitHub 6bd9ac0b8f Merge pull request #12 from OpenSignLabs/staging
Update
2023-11-08 16:55:09 +05:30
prafull-opensignlabs 2022df000e fix: user sign up issue for user existing in contact list 2023-11-08 13:56:28 +05:30
prafull-opensignlabsandGitHub ec6e037422 Merge pull request #10 from OpenSignLabs/staging
sync fork
2023-11-07 18:35:15 +05:30
AndrewandGitHub d4be4aec2c Merge pull request #143 from rishabjasrotia/issue/81 2023-11-07 18:09:08 +05:30
prafull-opensignlabsandGitHub 4b11fe77e0 Merge pull request #9 from OpenSignLabs/staging
sync fork
2023-11-07 17:40:34 +05:30
RishabandGitHub 4caf7b8c1a Update header.js 2023-11-07 17:31:50 +05:30
AmolandGitHub c736bbce55 Merge pull request #145 from prafull-opensignlabs/staging
remove hardcoded pfx passphrase
2023-11-07 16:30:35 +05:30
prafull-opensignlabsandGitHub 4bbf0d05d5 Merge pull request #147 from lsprr/accessibility/login
Improve accessibility of the login form
2023-11-07 16:14:40 +05:30
RaktimaNXG d42e11c5c1 fix: blocking screen by warning for expired and decline document 2023-11-07 11:32:25 +05:30
prafull-opensignlabs f227b79316 change prod and dev command 2023-11-07 11:29:08 +05:30
lsprr d4b4e02b62 Improve accessibility of the login form
- Add ARIA labels to input fields for better screen reader support
- Implement keyboard navigation for the login form elements
- Fix semantic HTML issues for assistive technologies
2023-11-06 15:57:49 -05:00
prafull-opensignlabs 1e76cf5253 fix: login url in mail change to current host 2023-11-06 20:48:01 +05:30
prafull-opensignlabs 4b9088b252 docs: update pass_phrase variable in env files 2023-11-06 20:00:10 +05:30
prafull-opensignlabs 820d6378f9 fix: add loadmf route to load login flow of microapp, add pagenotfound microapp 2023-11-06 19:44:06 +05:30
prafull-opensignlabs dfc816bdac Merge branch 'staging' of https://github.com/prafull-opensignlabs/OpenSign into staging 2023-11-06 16:51:17 +05:30
prafull-opensignlabs 0f62419d99 remove confidential passphrase param 2023-11-06 16:48:06 +05:30
prafull-opensignlabsandGitHub 37af995aaa Merge pull request #8 from OpenSignLabs/staging
sync fork
2023-11-06 16:10:54 +05:30
RishabandGitHub 4c69971ba1 Update emailComponent.js 2023-11-06 14:52:23 +05:30
RaktimaNXG fe37f3e021 fix: expired and decline document block whole screeen 2023-11-06 14:51:33 +05:30
RishabandGitHub 9047aa7dc8 Fix Printing for mobile 2023-11-06 14:49:44 +05:30
RishabandGitHub d33df9b934 Fix Print for mobile 2023-11-06 14:49:25 +05:30
RaktimaandGitHub 95558d1407 Merge pull request #11 from OpenSignLabs/staging
update
2023-11-06 14:48:05 +05:30
AndrewandGitHub 3164ee5824 Merge pull request #142 from OpenSignLabs/all-contributors/add-lsprr
docs: add lsprr as a contributor for a11y
2023-11-06 13:56:42 +05:30
allcontributors[bot]andGitHub 6a98adebd2 docs: update .all-contributorsrc 2023-11-06 08:26:13 +00:00
allcontributors[bot]andGitHub 015b752f5b docs: update README.md 2023-11-06 08:26:12 +00:00
AndrewandGitHub 11164a716f Merge pull request #140 from lsprr/lsprr/accessibility/sidebar
Refactor Menu and Social Media Components for Improved Accessibility
2023-11-06 13:55:19 +05:30
AndrewandGitHub 64638acd43 Merge pull request #141 from prafull-opensignlabs/staging 2023-11-06 13:24:20 +05:30
prafull-opensignlabsandGitHub 133769d5fd Merge pull request #7 from OpenSignLabs/staging
Merge pull request #137 from prafull-opensignlabs/staging
2023-11-06 13:19:11 +05:30
prafull-opensignlabs e330285e24 add pagination in reports, fix navigation in signup 2023-11-06 13:17:01 +05:30
lsprr 2acf851852 Refactor: Split Sidebar into Menu and SocialMedia components for modularity
- Created separate Menu and SocialMedia components from the Sidebar.
- Enhanced accessibility features in Menu.js, Sidebar.js, SubMenu.js, and SocialMedia.js.
- Adjusted NavLink components to improve keyboard navigation accessibility.
- Cleaned up and isolated component responsibilities for clarity and maintenance.
2023-11-05 15:55:38 -05:00
rishabjasrotia 73978ebce4 Fix issue 2023-11-05 19:20:34 +05:30
rishabjasrotia 96ae95a97c Fix the generation of remoteentry.js for docker development 2023-11-05 19:13:54 +05:30
rishabjasrotia 356d2e81c5 Update Document & Self Signed Cert added 2023-11-05 19:09:15 +05:30
105 changed files with 7670 additions and 4944 deletions
+27
View File
@@ -169,6 +169,33 @@
"contributions": [ "contributions": [
"bug" "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"
]
} }
] ]
} }
+12 -2
View File
@@ -39,11 +39,21 @@ DO_ACCESS_KEY_ID=
DO_SECRET_ACCESS_KEY= DO_SECRET_ACCESS_KEY=
# Digital ocean spaces region or AWS s3 region # Digital ocean spaces region or AWS s3 region
DO_REGION=us-west DO_REGION=us-west
# Set this to true id you are using local storage instead of s3 compatible storage
# USE_LOCAL=TRUE
# Email mailgun config (The app will not initialize if any of these 3 variables are not set) ********************************************************************************************************************* # Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
MAILGUN_API_KEY= MAILGUN_API_KEY=XXXXX
MAILGUN_DOMAIN=mail.yourdomain.com MAILGUN_DOMAIN=mail.yourdomain.com
MAILGUN_SENDER=postmaster@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 ********************************************************************************************************************* # Base64 encoded PFX or p12 document signing certificate file *********************************************************************************************************************
PFX_BASE64= PFX_BASE64=
# Provide Pass pharse of above PFX or p12 document
PASS_PHRASE=
+64 -2
View File
@@ -44,10 +44,72 @@ DO_REGION=us-west
# local storage # local storage
USE_LOCAL=TRUE USE_LOCAL=TRUE
# Email mailgun config (The app will not initialize if any of these 3 variables are not set) ********************************************************************************************************************* # Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
MAILGUN_API_KEY=XXXXX MAILGUN_API_KEY=XXXXX
MAILGUN_DOMAIN=mail.yourdomain.com MAILGUN_DOMAIN=mail.yourdomain.com
MAILGUN_SENDER=postmaster@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 ********************************************************************************************************************* # Base64 encoded PFX or p12 document signing certificate file *********************************************************************************************************************
PFX_BASE64= 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
+73
View File
@@ -0,0 +1,73 @@
name: "Bug Report"
labels: ["bug","up-for-grabs"]
title: "[Bug]: "
assignees:
- andrew-opensignlabs
description: Create a bug report to help us make OpenSign™ the world's best document e-signature platform
body:
- type: textarea
attributes:
label: Issue Description
description: Please provide a clear & concise description of the problem.
- type: textarea
attributes:
label: Expected Behavior
description: Describe what you expected to happen.
- type: textarea
attributes:
label: Current Behavior
description: Describe what is happening instead.
- type: textarea
attributes:
label: Steps to reproduce
description: Please provide step-by-step instructions to reproduce the issue. Include code snippets, URLs, error messages and any other relevant information.
- type: textarea
attributes:
label: Screenshots of the issue(optional)
description: Add screenshots to better explain the issue.
- type: input
attributes:
label: Operating System [e.g. MacOS Sonoma 14.1, Windows 11]
- type: dropdown
id: browsers
attributes:
label: What browsers are you seeing the problem on?
multiple: true
options:
- Chrome
- Firefox
- Safari
- Microsoft Edge
default: 0
- type: input
attributes:
label: What version of OpenSign™ are you seeing this issue on? [e.g. 1.0.6]
validations:
required: true
- type: dropdown
id: environment
attributes:
label: What environment are you seeing the problem on?
multiple: true
options:
- Production (app.opensignlabs.com)
- Staging (staging-app.opensignlabs.com)
- Hosted (app.yourdomain.com)
- Dev (localhost or vercel)
- type: checkboxes
attributes:
label: Please check the boxes that apply to this issue report.
options:
- label: I have searched the existing issues & discussions to make sure that this is not a duplicate.
validations:
required: true
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://www.opensignlabs.com)
options:
- label: I agree to follow this project's Code of Conduct
required: true
- label: I have searched the existing issues & discussions to make sure that this is not a duplicate.
required: true
@@ -0,0 +1,70 @@
name: Feature Request
description: Suggest an idea for OpenSign™
title: "Feature Request: [Short Description]"
labels: [feature request, needs triage]
body:
- type: markdown
attributes:
value: |
## Thanks for taking the time to fill out this feature request!
- type: input
id: title
attributes:
label: Feature Title
description: What would you call this feature?
placeholder: e.g., Advanced Signature Verification
validations:
required: true
- type: textarea
id: feature-description
attributes:
label: Feature Description
description: |
Please provide a detailed description of the feature you're proposing.
placeholder: |
e.g., I'm proposing an advanced signature verification feature that...
validations:
required: true
- type: dropdown
id: featuretype
attributes:
label: What type of feature are you requesting?
multiple: true
options:
- UI/UX Improvement
- Security / Compliance
- Performance / Optimization
- 3rd party integration
- Other
- type: dropdown
id: importance
attributes:
label: Importance
description: How important is this feature to you?
options:
- Critical
- High
- Medium
- Low
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Any other context or screenshots about the feature request here.
placeholder: Additional details, examples, or screenshots...
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://www.opensignlabs.com)
options:
- label: I agree to follow this project's Code of Conduct
required: true
- label: I have searched the existing issues & discussions to make sure that this is not a duplicate.
required: true
+3
View File
@@ -22,3 +22,6 @@
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
apps/OpenSign/public/mfbuild/*
microfrontends/SignDocuments/build/*
apps/OpenSignServer/files/files/*
+3 -4
View File
@@ -1,5 +1,4 @@
#!/bin/sh #!/usr/bin/env sh
. "$(dirname "$0")/_/husky.sh" . "$(dirname -- "$0")/_/husky.sh"
npx eslint '**/*.{js,jsx}' npm run lint-staged-changes
npx pretty-quick --staged '**/*.{js,jsx}'
+3
View File
@@ -0,0 +1,3 @@
{
"*.js": "prettier --write"
}
+59 -2
View File
@@ -88,5 +88,62 @@ You can install all 3 components on digital ocean using the button below -
## Localhost(Docker) ## Localhost(Docker)
Below are the steps to follow - For local Setup we need to need following prerequisite:
- Execute `make build`
Environment Varaibles:
| Environment Varibale | Value | Description |
| ------------- | ------------- | ------------- |
| CI | false | Set CI to false while running the app locally |
| PUBLIC_URL | http://localhost:3000 | Set it to the URL form where the app home page will be accessed |
| GENERATE_SOURCEMAP | false | Set it to true if you want to generate the Sourcemap for debugging |
| REACT_APP_SERVERURL | http://localhost:8080/app | 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_APPID | opensignstgn | 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. |
| APP_ID | opensignstgn | 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. |
| appName | open_sign_server | Name of the app. It will be visible in the verification emails sent out. |
| MASTER_KEY | XnAadwKxxByMr | 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. |
| MONGODB_URI | mongodb://host.docker.internal:27017/OpenSignDB | Mongodb URI to connect to |
| PARSE_MOUNT |/app | 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. |
| SERVER_URL | http://127.0.0.1:8080/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) |
| DO_SPACE | DOSPACENAME | Digital ocean space name or AWS S3 bucket name for uploading documents |
| DO_ENDPOINT | ams3.digitaloceanspaces.com | Digital ocean spaces endpoint or AWS S3 endpoint for uploading documents |
| DO_BASEURL |https://DOSPACENAME.ams3.digitaloceanspaces.com | Digital ocean baseurl or AWS S3 base URL |
| DO_ACCESS_KEY_ID | YOUR_S3_ACCESS_ID | Digital ocean spaces access key ID or AWS s3 Access key ID for uploading the docs |
| DO_SECRET_ACCESS_KEY | YOUR_S3_ACCESS_KEY | Digital ocean spaces secret access key or AWS s3 secret access key for uploading the docs |
| DO_REGION | YOUR_S3_REGION | Digital ocean spaces region or AWS s3 region |
| USE_LOCAL | FALSE | To use local file storage to save file |
| MAILGUN_API_KEY | YOUR_MAILGUNAPI_KEY | Mailgun API Key |
| MAILGUN_DOMAIN | YOUR_MAILGUNAPI_DOMAIN | Mailgun API Domain |
| MAILGUN_SENDER | - | Mailgun Sender Mail ID |
| PFX_BASE64 | - | Base64 encoded PFX or p12 document signing certificate file. You can generate base64 encoded self sign certificate using the passphrase `emudhra` |
# Steps to Generate Self Sign Certificate
```
# execute below command and use passphrase emudhra
openssl genrsa -des3 -out ./cert/local_dev.key 2048
openssl req -key ./cert/local_dev.key -new -x509 -days 365 -out ./cert/local_dev.crt
openssl pkcs12 -inkey ./cert/local_dev.key -in ./cert/local_dev.crt -export -out ./cert/local_dev.pfx
openssl base64 -in ./cert/local_dev.pfx -out ./cert/base64_pfx
```
# CORS Configuration
As document storage is delegated to S3-compatible services that reside in a different host than the OpenSign one, document operations (loading, storing, deleting) are subject to [Cross-Origin Resource Sharing](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) restriction policies; as a consequence, OpenSign app may fail with (browser console) errors like the following:
```
Access to fetch at 'https://foo.nyc3.digitaloceanspaces.com/exported_file_4627_0000-00-00T00%3A45%3A43.344Z.pdf'
from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header
is present on the requested resource. If an opaque response serves your needs, set the request's mode to
'no-cors' to fetch the resource with CORS disabled.
```
In order to address this, your document storage system must be instructed to accept requests from other hosts; below the relevant documentation links:
- [How to Configure CORS on DigitalOcean Spaces](https://docs.digitalocean.com/products/spaces/how-to/configure-cors/)
- [Configuring cross-origin resource sharing on AWS S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/enabling-cors-examples.html)
# Build Local Environment
Command to build project -
- Execute `make build`
Command to run project -
- Execute `make run`
+6
View File
@@ -1,3 +1,9 @@
build: build:
cp .env.local_dev .env
rm -rf apps/OpenSign/public/mfbuild
cd microfrontends/SignDocuments && npm install && npm run build
docker compose up --build --force-recreate
run:
cp .env.local_dev .env cp .env.local_dev .env
docker compose up -d docker compose up -d
+19 -13
View File
@@ -1,8 +1,7 @@
<h1 align="center"><a href='https://www.opensignlabs.com'>OpenSign™</a></h1> <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">
<div align="center">
The free and open source alternative to DocuSign [The free and open source alternative to DocuSign](https://www.opensignlabs.com)
[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/opensignlabs/opensign.svg)](http://isitmaintained.com/project/opensignlabs/opensign "Average time to resolve an issue") [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/opensignlabs/opensign.svg)](http://isitmaintained.com/project/opensignlabs/opensign "Average time to resolve an issue")
[![All Contributors](https://img.shields.io/github/all-contributors/opensignlabs/opensign?color=ee8449&style=flat-square)](#contributors) [![All Contributors](https://img.shields.io/github/all-contributors/opensignlabs/opensign?color=ee8449&style=flat-square)](#contributors)
@@ -23,7 +22,7 @@ The free and open source alternative to DocuSign
<a href="https://www.linkedin.com/company/opensign%E2%84%A2/about/">LinkedIn</a> <a href="https://www.linkedin.com/company/opensign%E2%84%A2/about/">LinkedIn</a>
## An open-source document e-signing solution ## The open-source document e-signing solution
--- ---
</div> </div>
@@ -48,14 +47,18 @@ Welcome to OpenSign, an open-source document e-signing solution designed to prov
### Features ### Features
- **Secure Signing**: Utilizes state-of-the-art cryptographic algorithms to ensure the security & integrity of your documents. - **Secure PDF E-Signing:** With the help of Robust encryption algorithms, OpenSign™ ensures maximum security, privacy & compatibility.
- **User-Friendly Interface**: Designed with usability in mind, making it easy for both technical and non-technical users. - **Annotate Documents:** OpenSign™ allows you to annotate PDF documents with an advanced signing pad that comes with hand drawn signatures support as well as uploaded images & saved signatures for the simplest signing experience.
- **Multi-Platform Support**: Compatible with various browsers and devices. - **User-Friendly Interface:** OpenSign™ was built while keeping Intuitive design in mind for ease of use. Features like "Sign yourself", "One click signatures" and "OpenSign Drive" makes it stand out of the crowd and even makes it better than a lot of so-called industry leaders.
- **Invite & collaborate users**: Bring multiple people from your team into the signing process, all within your own infrastructure. - **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.
- **Secure**: Allows for the easy, secure and seamless organization of your documents using 'OpenSigDrive'. - **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. 
- **Audit Trails**: Keeps a detailed log of all activities related to the document signing process including IP addresses and access timings. - **"Expiring Docs" & "Rejection":** You can set documents to expire after certain number of days after which nobody will be able to sign it. Not just this, OpenSign also allows signers to reject signing a document.
- **Completion Certificate**: Generate secure completion certificate as soon as a document is signed by all participants. - **Beautiful email templates:** All document signing invitations, completion notifications & reminders are formatted using great looking email templates.
- **API Support**: Provides a robust API for integration into other software and services. - **PDF Template Creation(coming soon):** OpenSign™ allows you to create and store PDF document templates for repeated use thereby saving you a lot of time.
- **OpenSign™ Drive:** It is a centralised secure vault for your signed 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(coming soon):** OpenSign™ API allows seamless integration into existing systems and software. APIs will soon be available as a cloud hosted solution.
- **Integrations:** Seamless integrations with various Cloud storage systems, CRMs & enterprise platforms is coming soon.
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/b37ff443-7099-4273-9aeb-21c46d7154cf height='200'> <img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/b37ff443-7099-4273-9aeb-21c46d7154cf height='200'>
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/86db91b7-6c2f-4885-a33c-58f4fd35ec89 height='200'> <img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/86db91b7-6c2f-4885-a33c-58f4fd35ec89 height='200'>
@@ -124,6 +127,9 @@ We would like to thank all our contributors and users for their support and feed
<td align="center" valign="top" width="14.28%"><a href="https://github.com/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/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://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://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>
</tbody> </tbody>
</table> </table>
+1
View File
@@ -10,6 +10,7 @@
# production # production
/build /build
/mfbuild
# misc # misc
.env .env
+1 -1
View File
@@ -21,5 +21,5 @@ EXPOSE 3000
# ENV NODE_ENV production # ENV NODE_ENV production
# Run the application # Run the application
CMD ["npm", "start"] ENTRYPOINT npm run start-dev
+5 -4
View File
@@ -40,9 +40,10 @@
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"scripts": { "scripts": {
"start": "mf-cra start", "start": "serve -s build",
"start-prod": "serve -s build", "start-dev": "mf-cra start",
"build": "rm -rf public/mfbuild && npm run micro && CI=false && mf-cra build", "version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
"build": "npm run version && rm -rf public/mfbuild && npm run micro && CI=false && mf-cra build",
"micro": "cd ../../microfrontends/SignDocuments && npm install && npm run build", "micro": "cd ../../microfrontends/SignDocuments && npm install && npm run build",
"test": "react-scripts test", "test": "react-scripts test",
"eject": "react-scripts eject", "eject": "react-scripts eject",
@@ -85,4 +86,4 @@
"pretty-quick": "^3.1.3", "pretty-quick": "^3.1.3",
"tailwindcss": "^3.3.3" "tailwindcss": "^3.3.3"
} }
} }
+2 -2
View File
@@ -31,7 +31,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" /> integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" />
<title>Open sign</title> <title>OpenSign</title>
</head> </head>
<body> <body>
@@ -50,4 +50,4 @@
--> -->
</body> </body>
</html> </html>
+1
View File
@@ -0,0 +1 @@
v1.0.5-beta
+2
View File
@@ -14,6 +14,7 @@ import PageNotFound from "./routes/PageNotFound";
import ForgetPassword from "./routes/ForgetPassword"; import ForgetPassword from "./routes/ForgetPassword";
import ChangePassword from "./routes/ChangePassword"; import ChangePassword from "./routes/ChangePassword";
import ReportMicroapp from "./components/ReportMicroapp"; import ReportMicroapp from "./components/ReportMicroapp";
import LoadMf from "./routes/LoadMf";
function App() { function App() {
const [isloading, setIsLoading] = useState(true); const [isloading, setIsLoading] = useState(true);
@@ -59,6 +60,7 @@ function App() {
<Routes> <Routes>
<Route exact path="/" element={<Login />} /> <Route exact path="/" element={<Login />} />
<Route exact path="/signup" element={<Signup />} /> <Route exact path="/signup" element={<Signup />} />
<Route exact path="/loadmf/:remoteApp/*" element={<LoadMf />} />
<Route exact path="/forgetpassword" element={<ForgetPassword />} /> <Route exact path="/forgetpassword" element={<ForgetPassword />} />
{process.env.REACT_APP_ENABLE_SUBSCRIPTION && ( {process.env.REACT_APP_ENABLE_SUBSCRIPTION && (
<> <>
@@ -32,6 +32,7 @@ const AppendFormInForm = (props) => {
try { try {
const query = new Parse.Query("contracts_Contactbook"); const query = new Parse.Query("contracts_Contactbook");
query.equalTo("CreatedBy", user); query.equalTo("CreatedBy", user);
query.notEqualTo("IsDeleted", true);
query.equalTo("Email", user.getEmail()); query.equalTo("Email", user.getEmail());
const res = await query.first(); const res = await query.first();
// console.log(res); // console.log(res);
@@ -241,26 +242,6 @@ const AppendFormInForm = (props) => {
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
/> />
</div> </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="mb-3"> <div className="mb-3">
<label <label
htmlFor="email" htmlFor="email"
@@ -279,6 +260,24 @@ const AppendFormInForm = (props) => {
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
/> />
</div> </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"> <div className="mt-4 flex justify-start">
<button <button
+15 -7
View File
@@ -1,8 +1,20 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Package from "../../package.json"; import Package from "../../package.json";
import axios from "axios";
const Footer = () => { const Footer = () => {
const [showButton, setShowButton] = useState(false); 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 = () => { const handleScroll = () => {
if (window.pageYOffset >= 50) { if (window.pageYOffset >= 50) {
setShowButton(true); setShowButton(true);
@@ -25,16 +37,12 @@ const Footer = () => {
}, []); }, []);
const appName = "OpenSign™"; const appName = "OpenSign™";
return ( return (
<> <>
<div className="bg-[#222c3c] text-[#98a6ba] text-center text-[13px] py-3"> <div className="bg-[#222c3c] text-[#98a6ba] text-center text-[13px] py-3">
All Rights Reserved &copy; {new Date().getFullYear()} &nbsp; All Rights Reserved &copy; {new Date().getFullYear()} &nbsp;
{appName}{" "} {appName} ( version: {version ? version : `${Package.version} `})
(version:{" "}
{localStorage.getItem("appVersion") &&
`${Package.version}.${localStorage.getItem("appVersion")}`}
)
</div> </div>
<button <button
className={`${ className={`${
+15 -12
View File
@@ -27,14 +27,14 @@ const LoginFacebook = ({
setThirdpartyLoader(true); setThirdpartyLoader(true);
const details = { const details = {
Email: response.email, Email: response.email,
Name: response.name, Name: response.name
}; };
setUserDetails({ ...userDetails, ...details }); setUserDetails({ ...userDetails, ...details });
const fDetails = { const fDetails = {
Id: response.userID, Id: response.userID,
AccessToken: response.accessToken, AccessToken: response.accessToken,
Name: response.name, Name: response.name,
Email: response.email, Email: response.email
}; };
setFBDetails({ ...fBDetails, ...fDetails }); setFBDetails({ ...fBDetails, ...fDetails });
const res = await checkExtUser(fDetails); const res = await checkExtUser(fDetails);
@@ -42,9 +42,11 @@ const LoginFacebook = ({
}; };
const checkExtUser = async (details) => { const checkExtUser = async (details) => {
const extUser = new Parse.Query("contracts_Users"); // const extUser = new Parse.Query("contracts_Users");
extUser.equalTo("Email", details.Email); // extUser.equalTo("Email", details.Email);
const extRes = await extUser.first(); // const extRes = await extUser.first();
const params = { email: details.Email };
const extRes = await Parse.Cloud.run("getUserDetails", params);
// console.log("extRes ", extRes); // console.log("extRes ", extRes);
if (extRes) { if (extRes) {
const params = { ...details, Phone: extRes.get("Phone") }; const params = { ...details, Phone: extRes.get("Phone") };
@@ -209,18 +211,19 @@ const LoginFacebook = ({
<div> <div>
<button <button
type="button" type="button"
className="btn btn-secondary" onClick={() => handleSubmitbtn()}
onClick={() => setIsModal(false)} className="btn btn-info"
style={{ marginRight: 10, width: 90 }} style={{ marginRight: 10 }}
> >
Cancel Sign up
</button> </button>
<button <button
type="button" type="button"
onClick={() => handleSubmitbtn()} className="btn btn-secondary"
className="btn btn-info" onClick={() => setIsModal(false)}
style={{ width: 90 }}
> >
Sign up Cancel
</button> </button>
</div> </div>
</form> </form>
+77 -13
View File
@@ -42,7 +42,42 @@ const GoogleSignInBtn = ({
width: "187px" width: "187px"
}); });
}); });
const clearStorage = async () => {
if (Parse.User.current()) {
await Parse.User.logOut();
}
let baseUrl = localStorage.getItem("BaseUrl12");
let appid = localStorage.getItem("AppID12");
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("BaseUrl12", baseUrl);
localStorage.setItem("AppID12", 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) => { const responseGoogle = async (response) => {
clearStorage();
setThirdpartyLoader(true); setThirdpartyLoader(true);
// console.log("response ", response); // console.log("response ", response);
if (response.credential) { if (response.credential) {
@@ -66,9 +101,11 @@ const GoogleSignInBtn = ({
} }
}; };
const checkExtUser = async (details) => { const checkExtUser = async (details) => {
const extUser = new Parse.Query("contracts_Users"); // const extUser = new Parse.Query("contracts_Users");
extUser.equalTo("Email", details.Gmail); // extUser.equalTo("Email", details.Gmail);
const extRes = await extUser.first(); // const extRes = await extUser.first();
const params = { email: details.Gmail };
const extRes = await Parse.Cloud.run("getUserDetails", params);
// console.log("extRes ", extRes); // console.log("extRes ", extRes);
if (extRes) { if (extRes) {
const params = { ...details, Phone: extRes.get("Phone") }; const params = { ...details, Phone: extRes.get("Phone") };
@@ -141,6 +178,32 @@ const GoogleSignInBtn = ({
alert("Please fill required details!"); 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("BaseUrl12");
let appid = localStorage.getItem("AppID12");
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("BaseUrl12", baseUrl);
localStorage.setItem("AppID12", appid);
};
return ( return (
<div style={{ position: "relative" }}> <div style={{ position: "relative" }}>
{thirdpartyLoader && ( {thirdpartyLoader && (
@@ -235,17 +298,17 @@ const GoogleSignInBtn = ({
</div> </div>
<div className="form-group"> <div className="form-group">
<label <label
htmlFor="Destination" htmlFor="JobTitle"
style={{ display: "flex" }} style={{ display: "flex" }}
className="col-form-label" className="col-form-label"
> >
Destination{" "} Job Title{" "}
<span style={{ fontSize: 13, color: "red" }}>*</span> <span style={{ fontSize: 13, color: "red" }}>*</span>
</label> </label>
<input <input
type="text" type="text"
className="form-control" className="form-control"
id="Destination" id="JobTitle"
value={userDetails.Destination} value={userDetails.Destination}
onChange={(e) => onChange={(e) =>
setUserDetails({ setUserDetails({
@@ -259,18 +322,19 @@ const GoogleSignInBtn = ({
<div> <div>
<button <button
type="button" type="button"
className="btn btn-secondary" className="bg-[#17a2b8] p-2 text-white rounded"
onClick={() => setIsModal(false)} onClick={() => handleSubmitbtn()}
style={{ marginRight: 10, width: 90 }} style={{ marginRight: 10 }}
> >
Cancel Sign up
</button> </button>
<button <button
type="button" type="button"
onClick={() => handleSubmitbtn()} className="bg-[#6c757d] p-2 text-white rounded"
className="btn btn-info" onClick={handleCloseModal}
style={{ width: 90 }}
> >
Sign up Cancel
</button> </button>
</div> </div>
</form> </form>
+26 -50
View File
@@ -1,6 +1,6 @@
import useFederatedComponent from "mf-cra"; import useFederatedComponent from "mf-cra";
import React, { Suspense, useEffect } from "react"; import React, { Suspense, useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
const MicroappModal = () => { const MicroappModal = () => {
const { remoteApp } = useParams(); const { remoteApp } = useParams();
@@ -28,60 +28,36 @@ const MicroappModal = () => {
} }
// console.log("app ", remoteApp); // console.log("app ", remoteApp);
const { Component: RemoteComponent } = useFederatedComponent(obj); const { Component: RemoteComponent } = useFederatedComponent(obj);
const navigate = useNavigate();
// console.log("RemoteComponent ", RemoteComponent); // console.log("RemoteComponent ", RemoteComponent);
return ( return (
<div className="w-full h-full flex items-center justify-center "> <div className="w-full h-full flex items-center justify-center ">
{/* <!-- Modal Container --> */} <div className="w-full">
<div className="bg-white rounded-lg shadow-lg w-full"> <Suspense
{/* <!-- Modal Header --> */} fallback={
<div className="flex w-full items-center border-b-2 mb-2 p-2"> <div style={{ height: "300px" }}>
<button <div
className="focus:outline-none bg-blue-500 text-white text-sm shadow px-2.5 py-1 rounded" style={{
id="closeModal" marginLeft: "45%",
onClick={(e) => { marginTop: "150px",
e.preventDefault(); fontSize: "45px",
// setIsModal(false); color: "#3dd3e0"
navigate(-1); }}
className="loader-37"
></div>
</div>
}
>
<div
style={{
backgroundColor: "#ffffff",
width: "100%",
overflow: "hidden",
minHeight: "50vh"
}} }}
> >
Back {RemoteComponent && <RemoteComponent />}
</button> </div>
{localStorage.getItem("domain") && ( </Suspense>
<p className="flex-1 w-full text-sm md:text-base text-black text-center">
{localStorage.getItem("domain") === "contracts" ? "Document" : ""}
</p>
)}
</div>
{/* <!-- Modal Body --> */}
<div className="w-full">
<Suspense
fallback={
<div style={{ height: "300px" }}>
<div
style={{
marginLeft: "45%",
marginTop: "150px",
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
</div>
}
>
<div
style={{
backgroundColor: "#ffffff",
width: "100%",
overflow: "hidden",
minHeight: "50vh"
}}
>
{RemoteComponent && <RemoteComponent />}
</div>
</Suspense>
</div>
</div> </div>
</div> </div>
); );
+22 -21
View File
@@ -49,12 +49,9 @@ const TreeWidget = (props) => {
let data = JSON.parse(localStorage.getItem("Extand_Class")); let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0]; res = data[0];
} else { } else {
var emp = Parse.Object.extend( res = await Parse.Cloud.run("getUserDetails", {
localStorage.getItem("extended_class") email: currentUser.get("email")
); });
var q = new Parse.Query(emp);
q.equalTo("UserId", currentUser);
res = await q.first();
if (res) res = res.toJSON(); if (res) res = res.toJSON();
} }
if (res) { if (res) {
@@ -79,12 +76,9 @@ const TreeWidget = (props) => {
let data = JSON.parse(localStorage.getItem("Extand_Class")); let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0]; res = data[0];
} else { } else {
emp = Parse.Object.extend( res = await Parse.Cloud.run("getUserDetails", {
localStorage.getItem("extended_class") email: currentUser.get("email")
); });
q = new Parse.Query(emp);
q.equalTo("UserId", currentUser);
res = await q.first();
if (res) res = res.toJSON(); if (res) res = res.toJSON();
} }
@@ -121,10 +115,15 @@ const TreeWidget = (props) => {
let data = JSON.parse(localStorage.getItem("Extand_Class")); let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0]; res = data[0];
} else { } else {
emp = Parse.Object.extend(localStorage.getItem("extended_class")); // emp = Parse.Object.extend(localStorage.getItem("extended_class"));
q = new Parse.Query(emp); // q = new Parse.Query(emp);
q.equalTo("UserId", currentUser); // q.equalTo("UserId", currentUser);
res = await q.first(); // res = await q.first();
// if (res) res = res.toJSON();
const currentUser = Parse.User.current();
res = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
if (res) res = res.toJSON(); if (res) res = res.toJSON();
} }
@@ -473,6 +472,8 @@ const TreeWidget = (props) => {
props.schema.data.FolderTypeField, props.schema.data.FolderTypeField,
props.schema.data.FolderTypeValue props.schema.data.FolderTypeValue
); );
const currentUser = Parse.User.current();
folder.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
if (tabList.length > 0) { if (tabList.length > 0) {
let len = tabList.length - 1; let len = tabList.length - 1;
folder.set(props.schema.data.ParentFolderField, { folder.set(props.schema.data.ParentFolderField, {
@@ -532,7 +533,7 @@ const TreeWidget = (props) => {
padding: 0 padding: 0
}, },
overlay: { overlay: {
width:"100%", width: "100%",
backgroundColor: "rgba(0, 0, 0, 0.75)", backgroundColor: "rgba(0, 0, 0, 0.75)",
zIndex: 50 zIndex: 50
} }
@@ -699,7 +700,7 @@ const TreeWidget = (props) => {
))} ))}
<hr /> <hr />
</div> </div>
{editable && ( {/* {editable && (
<TreeEditForm <TreeEditForm
FormId={props.schema.data.FormId} FormId={props.schema.data.FormId}
objectId={editId} objectId={editId}
@@ -708,7 +709,7 @@ const TreeWidget = (props) => {
selectFolderHandle(); selectFolderHandle();
}} }}
/> />
)} )} */}
{isAddField && !loader && !editable && ( {isAddField && !loader && !editable && (
<TreeFormComponent <TreeFormComponent
Id={props.schema.data.FormId} Id={props.schema.data.FormId}
@@ -796,7 +797,7 @@ const TreeWidget = (props) => {
</a> </a>
</div> </div>
{fldr[props.schema.data.FolderTypeField] === {/* {fldr[props.schema.data.FolderTypeField] ===
props.schema.data.FolderTypeValue && ( props.schema.data.FolderTypeValue && (
<a <a
className="float-right" className="float-right"
@@ -816,7 +817,7 @@ const TreeWidget = (props) => {
aria-hidden="true" aria-hidden="true"
></i> ></i>
</a> </a>
)} )} */}
</li> </li>
) )
)} )}
@@ -1,7 +1,6 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import axios from "axios"; import axios from "axios";
import Parse from "parse"; import Parse from "parse";
import onSearchFilter from "../../constant/searchQuery";
import getReplacedHashQuery from "../../constant/getReplacedHashQuery"; import getReplacedHashQuery from "../../constant/getReplacedHashQuery";
import "../../styles/loader.css"; import "../../styles/loader.css";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@@ -35,14 +34,9 @@ const DashboardCard = (props) => {
let data = JSON.parse(localStorage.getItem("Extand_Class")); let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0]; res = data[0];
} else { } else {
var emp = Parse.Object.extend(localStorage.getItem("extended_class")); res = await Parse.Cloud.run("getUserDetails", {
var q = new Parse.Query(emp); email: currentUser.get("email")
q.equalTo("UserId", {
__type: "Pointer",
className: "_User",
objectId: currentUser
}); });
res = await q.first();
if (res) res = res.toJSON(); if (res) res = res.toJSON();
} }
if (res) { if (res) {
@@ -50,12 +44,7 @@ const DashboardCard = (props) => {
var reg = /(\#.*?\#)/gi; // eslint-disable-line var reg = /(\#.*?\#)/gi; // eslint-disable-line
var str = props.Data.query; var str = props.Data.query;
var test = ""; var test = "";
if (str.includes("#filterCondition#")) {
str = str.replace(
"#filterCondition#",
onSearchFilter(props.DefaultQuery)
);
}
if (props.Data.extendkey) { if (props.Data.extendkey) {
let a = props.Data.extendkey.split("."); let a = props.Data.extendkey.split(".");
if (a.length > 0) { if (a.length > 0) {
@@ -110,13 +99,10 @@ const DashboardCard = (props) => {
let data = JSON.parse(localStorage.getItem("Extand_Class")); let data = JSON.parse(localStorage.getItem("Extand_Class"));
resr = data[0]; resr = data[0];
} else { } else {
let emp = Parse.Object.extend( resr = await Parse.Cloud.run("getUserDetails", {
localStorage.getItem("extended_class") email: currentUser.get("email")
); });
let q = new Parse.Query(emp); if (resr) resr = resr.toJSON();
q.equalTo("UserId", currentUser);
let t = await q.first();
resr = t.toJSON();
} }
let json = resr; let json = resr;
@@ -150,47 +136,65 @@ const DashboardCard = (props) => {
"X-Parse-Application-Id": parseAppId, "X-Parse-Application-Id": parseAppId,
"X-Parse-Session-Token": localStorage.getItem("accesstoken") "X-Parse-Session-Token": localStorage.getItem("accesstoken")
}; };
await axios.get(url, { headers: headers }).then((res) => { // handle need your sign report count
if (res.data.results.length > 0) { if (props.Data.Redirect_id === "4Hhwbp482K") {
setLoading(false); const params = {
if (props.Data.key !== "count") { reportId: props.Data.Redirect_id,
setresponse(res.data.results[0][props.Data.key]); skip: 0,
} else { limit: 200
if (props.Label === "Need your Signature") { };
const listData = res.data?.results.filter( const url = `${parseBaseUrl}/functions/getReport`;
(x) => x.Signers.length > 0 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
); );
let arr = []; if (isSigner) {
for (const obj of listData) { let isRecord;
const isSigner = obj.Signers.some( if (obj?.AuditTrail && obj?.AuditTrail.length > 0) {
(item) => item.UserId.objectId === currentUser.id isRecord = obj?.AuditTrail.some(
); (item) =>
if (isSigner) { item?.UserPtr?.UserId?.objectId === currentUser.id &&
let isRecord; item.Activity === "Signed"
if (obj?.AuditTrail && obj?.AuditTrail.length > 0) { );
isRecord = obj?.AuditTrail.some( } else {
(item) => isRecord = false;
item?.UserPtr?.UserId?.objectId === currentUser.id && }
item.Activity === "Signed" if (isRecord === false) {
); arr.push(obj);
} else {
isRecord = false;
}
if (isRecord === false) {
arr.push(obj);
}
} }
} }
setresponse(arr.length); }
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 { } else {
setresponse(res.data[props.Data.key]); setresponse(res.data[props.Data.key]);
} }
} else {
setresponse(0);
setLoading(false);
} }
} else { });
setresponse(0); }
setLoading(false);
}
});
} catch (e) { } catch (e) {
console.error("Problem", e); console.error("Problem", e);
setLoading(false); setLoading(false);
@@ -227,13 +231,10 @@ const DashboardCard = (props) => {
let data = JSON.parse(localStorage.getItem("Extand_Class")); let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0]; res = data[0];
} else { } else {
var emp = Parse.Object.extend( let resr = await Parse.Cloud.run("getUserDetails", {
localStorage.getItem("extended_class") email: currentUser.get("email")
); });
var q = new Parse.Query(emp); if (res) res = resr.toJSON();
q.equalTo("UserId", currentUser);
let resr = await q.first();
res = resr.toJSON();
} }
let json = res; let json = res;
@@ -9,39 +9,60 @@ function DashboardReport(props) {
const [isLoader, setIsLoader] = useState(true); const [isLoader, setIsLoader] = useState(true);
const [reportName, setReportName] = useState(""); const [reportName, setReportName] = useState("");
const [actions, setActions] = 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(() => { useEffect(() => {
setReportName(""); setReportName("");
getReportData(props.Record.reportId); 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]); }, [props.Record.reportId]);
const getReportData = async (id) => { // 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); setIsLoader(true);
const json = reportJson(id); const json = reportJson(id);
if (json) { if (json) {
setActions(json.actions); setActions(json.actions);
setReportName(json.reportName); setReportName(json.reportName);
const { className, params, keys, orderBy } = json; setHeading(json.heading);
Parse.serverURL = localStorage.getItem("BaseUrl12"); Parse.serverURL = localStorage.getItem("BaseUrl12");
Parse.initialize(localStorage.getItem("AppID12")); Parse.initialize(localStorage.getItem("AppID12"));
const serverURL = const currentUser = Parse.User.current().id;
localStorage.getItem("BaseUrl12") + "classes/" + className;
const strParams = JSON.stringify(params);
const strKeys = keys.join();
const headers = { const headers = {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("AppID12"), "X-Parse-Application-Id": localStorage.getItem("AppID12"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken") sessiontoken: localStorage.getItem("accesstoken")
}; };
try { try {
const url = `${serverURL}?where=${strParams}&keys=${strKeys}&order=${orderBy}&include=AuditTrail.UserPtr`; const params = { reportId: id, skip: skipUserRecord, limit: limit };
const res = await axios.get(url, { headers: headers }); const url = `${localStorage.getItem("BaseUrl12")}/functions/getReport`;
// console.log("res ", res.data?.results); const res = await axios.post(url, params, {
headers: headers,
signal: abortController.signal // is used to cancel fetch query
});
if (id === "5Go51Q7T8r") { if (id === "5Go51Q7T8r") {
const currentUser = Parse.User.current().id; const listData = res.data?.result.filter((x) => x.Signers.length > 0);
const listData = res.data?.results.filter(
(x) => x.Signers.length > 0
);
let arr = []; let arr = [];
for (const obj of listData) { for (const obj of listData) {
const isSigner = obj.Signers.some( const isSigner = obj.Signers.some(
@@ -63,14 +84,34 @@ function DashboardReport(props) {
} }
} }
} }
setList(arr); if (arr.length === docPerPage) {
setIsMoreDocs(true);
} else {
setIsMoreDocs(false);
}
setList((prevRecord) =>
prevRecord.length > 0 ? [...prevRecord, ...arr] : arr
);
} else { } else {
setList(res.data?.results); 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); setIsLoader(false);
} catch (err) { } catch (err) {
console.log("err ", err); const isCancel = axios.isCancel(err);
setIsLoader(false); if (!isCancel) {
console.log("err ", err);
setIsLoader(false);
}
} }
} else { } else {
setIsLoader(false); setIsLoader(false);
@@ -101,8 +142,12 @@ function DashboardReport(props) {
<ReportTable <ReportTable
ReportName={reportName} ReportName={reportName}
List={List} List={List}
act={"Sign"} setList={setList}
actions={actions} 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="flex items-center justify-center h-[100px] w-full bg-white rounded">
@@ -1,5 +1,4 @@
import React, { useState, Suspense, lazy } from "react"; import React, { Suspense, lazy } from "react";
import moment from "moment";
import ErrorBoundary from "../ErrorBoundary"; import ErrorBoundary from "../ErrorBoundary";
const DashboardCard = lazy(() => import("./DashboardCard")); const DashboardCard = lazy(() => import("./DashboardCard"));
@@ -7,258 +6,6 @@ const DashboardCard = lazy(() => import("./DashboardCard"));
const DashboardReport = lazy(() => import("./DashboardReport")); const DashboardReport = lazy(() => import("./DashboardReport"));
const GetDashboard = (props) => { const GetDashboard = (props) => {
const [filter, setfilter] = useState("");
const [option, setoption] = useState("");
const onSearchFilter = (e) => {
let _search = e.target.value;
localStorage.setItem("DashboardDefaultFilter", _search);
switch (_search) {
case "Today": {
let d = new Date();
let formDate = new Date(
Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0)
).toISOString();
let Todate = new Date(
Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), 23, 59, 59)
).toISOString();
let Query = `'$gte':'${formDate}','$lte':'${Todate}'`;
setfilter(Query);
setoption(_search);
break;
}
case "Yesterday": {
let d1 = new Date();
d1.setDate(d1.getDate() - 1);
let yesFrDate = new Date(
Date.UTC(d1.getFullYear(), d1.getMonth(), d1.getDate(), 0, 0, 0)
).toISOString();
let YesTodate = new Date(
Date.UTC(d1.getFullYear(), d1.getMonth(), d1.getDate(), 23, 59, 59)
).toISOString();
let Query1 = `'$gte':'${yesFrDate}','$lte':'${YesTodate}'`;
setfilter(Query1);
setoption(_search);
break;
}
case "This week": {
let oneDay = 24 * 60 * 60 * 1000;
let curr = new Date(); // get current date
let first = curr.getDate() - curr.getDay(); // First day is the day of the month - the day of the week
let firstday = new Date(
new Date(
Date.UTC(
curr.getFullYear(),
curr.getMonth(),
curr.getDate(),
0,
0,
0
)
).setDate(first)
).toISOString();
let diffDays = Math.round(
Math.abs(
(new Date(
Date.UTC(
curr.getFullYear(),
curr.getMonth(),
curr.getDate(),
23,
59,
59
)
) -
new Date(firstday)) /
oneDay
)
); //Days since last week
let last = first + diffDays;
let lastday = new Date(
new Date(
Date.UTC(
curr.getFullYear(),
curr.getMonth(),
curr.getDate(),
23,
59,
59
)
).setDate(last)
).toISOString();
let Query2 = `'$gte':'${firstday}','$lte':'${lastday}'`;
setfilter(Query2);
setoption(_search);
break;
}
case "Last 7 days": {
let d7 = new Date();
let d7l = new Date();
d7.setDate(d7.getDate() - 7);
let l7t = new Date(
Date.UTC(d7l.getFullYear(), d7l.getMonth(), d7l.getDate(), 23, 59, 59)
).toISOString();
let date7 = new Date(
Date.UTC(d7.getFullYear(), d7.getMonth(), d7.getDate(), 0, 0, 0)
).toISOString();
let Query7 = `'$gte':'${date7}','$lte':'${l7t}'`;
setfilter(Query7);
setoption(_search);
break;
}
case "Last 14 days": {
let d14 = new Date();
let d14l = new Date();
let l14t = new Date(
Date.UTC(
d14l.getFullYear(),
d14l.getMonth(),
d14l.getDate(),
23,
59,
59
)
).toISOString();
d14.setDate(d14.getDate() - 14);
let date14 = new Date(
Date.UTC(d14.getFullYear(), d14.getMonth(), d14.getDate(), 0, 0, 0)
).toISOString();
let Query14 = `'$gte':'${date14}','$lte':'${l14t}'`;
setfilter(Query14);
setoption(_search);
break;
}
case "Last 30 days": {
let d30 = new Date();
let d30l = new Date();
let l30t = new Date(
Date.UTC(
d30l.getFullYear(),
d30l.getMonth(),
d30l.getDate(),
23,
59,
59
)
).toISOString();
d30.setDate(d30.getDate() - 30);
let date30 = new Date(
Date.UTC(d30.getFullYear(), d30.getMonth(), d30.getDate(), 0, 0, 0)
).toISOString();
let Query30 = `'$gte':'${date30}','$lte':'${l30t}'`;
setfilter(Query30);
setoption(_search);
break;
}
case "Last week": {
const from_date = moment().startOf("week").subtract(7, "days");
const to_date = moment().endOf("week").subtract(7, "days");
let Queryl = `'$gte':'${from_date.toISOString()}','$lte':'${to_date.toISOString()}'`;
setfilter(Queryl);
setoption(_search);
break;
}
case "This month": {
const tdate = new Date();
let tfirstDay = new Date(
tdate.getFullYear(),
tdate.getMonth(),
1
).toISOString();
let tlastDay = new Date(
tdate.getFullYear(),
tdate.getMonth() + 1,
0
).toISOString();
let Querylt = `'$gte':'${tfirstDay}','$lte':'${tlastDay}'`;
setfilter(Querylt);
setoption(_search);
break;
}
case "Last month": {
const ldate = new Date();
var lfirstDay = new Date(
ldate.getFullYear(),
ldate.getMonth() - 1,
2
).toISOString();
var llastDay = new Date(
ldate.getFullYear(),
ldate.getMonth(),
1
).toISOString();
let Queryltl = `'$gte':'${lfirstDay}','$lte':'${llastDay}'`;
setfilter(Queryltl);
setoption(_search);
break;
}
case "All": {
let fall = new Date(
new Date().getFullYear() - 100,
0,
1,
0,
0,
0
).toISOString();
let fall_year = `'$gte':'${fall}'`;
setfilter(fall_year);
setoption(_search);
break;
}
case "This year": {
let fcy = new Date(
new Date().getFullYear(),
0,
1,
0,
0,
0
).toISOString();
let lcy = new Date(
new Date().getFullYear(),
11,
31,
23,
59,
59
).toISOString();
let cur_year = `'$gte':'${fcy}','$lte':'${lcy}'`;
setfilter(cur_year);
setoption(_search);
break;
}
case "Last year": {
let fly = new Date(
new Date().getFullYear() - 1,
0,
1,
0,
0,
0
).toISOString();
let lly = new Date(
new Date().getFullYear() - 1,
11,
31,
23,
59,
59
).toISOString();
let last_year = `'$gte':'${fly}','$lte':'${lly}'`;
setfilter(last_year);
setoption(_search);
break;
}
default: {
setoption(_search);
break;
}
}
};
const renderSwitchWithTour = (col) => { const renderSwitchWithTour = (col) => {
switch (col.widget.type) { switch (col.widget.type) {
case "Card": case "Card":
@@ -272,7 +19,6 @@ const GetDashboard = (props) => {
<DashboardCard <DashboardCard
Icon={col.widget.icon} Icon={col.widget.icon}
Label={col.widget.label} Label={col.widget.label}
Filter={filter}
Format={col.widget.format && col.widget.format} Format={col.widget.format && col.widget.format}
Data={col.widget.data} Data={col.widget.data}
FilterData={col.widget.filter} FilterData={col.widget.filter}
@@ -281,50 +27,12 @@ const GetDashboard = (props) => {
</Suspense> </Suspense>
</div> </div>
); );
case "customeHtml":
return (
<div data-tut={col.widget.data.tourSection}>
<select
id="searchFiltr"
className="form-control"
value={
option ||
localStorage.getItem("DashboardDefaultFilter") ||
col.widget.data[0].default
}
onChange={onSearchFilter}
>
{col.widget.data[0].options.map((opt) => (
<option key={opt} value={opt}>
{opt}
</option>
))}
</select>
<br />
</div>
);
case "customeTag":
return (
<h3
data-tut={col.widget.data.tourSection}
style={{
marginBottom: "4px",
color: "currentColor",
marginLeft: "4px"
}}
>
{col.widget.label}
</h3>
);
case "report": { case "report": {
let _filter = `${col.widget.filterKey}:${filter}`;
return ( return (
<div data-tut={col.widget.data.tourSection}> <div data-tut={col.widget.data.tourSection}>
<Suspense fallback={<div>please wait</div>}> <Suspense fallback={<div>please wait</div>}>
<div className="mb-4 md:mb-0"> <div className="mb-4 md:mb-0">
<DashboardReport Filter={_filter} Record={col.widget} /> <DashboardReport Record={col.widget} />
</div> </div>
</Suspense> </Suspense>
</div> </div>
@@ -346,7 +54,6 @@ const GetDashboard = (props) => {
<DashboardCard <DashboardCard
Icon={col.widget.icon} Icon={col.widget.icon}
Label={col.widget.label} Label={col.widget.label}
Filter={filter}
Format={col.widget.format && col.widget.format} Format={col.widget.format && col.widget.format}
Data={col.widget.data} Data={col.widget.data}
FilterData={col.widget.filter} FilterData={col.widget.filter}
@@ -355,48 +62,11 @@ const GetDashboard = (props) => {
</Suspense> </Suspense>
</div> </div>
); );
case "customeHtml":
return (
<div>
<select
id="searchFiltr"
className="form-control"
value={
option ||
localStorage.getItem("DashboardDefaultFilter") ||
col.widget.data[0].default
}
onChange={onSearchFilter}
>
{col.widget.data[0].options.map((opt) => (
<option key={opt} value={opt}>
{opt}
</option>
))}
</select>
<br />
</div>
);
case "customeTag":
return (
<h3
style={{
marginBottom: "4px",
color: "currentColor",
marginLeft: "4px"
}}
>
{col.widget.label}
</h3>
);
case "report": { case "report": {
let _filter = `${col.widget.filterKey}:${filter}`;
return ( return (
<Suspense fallback={<div>please wait</div>}> <Suspense fallback={<div>please wait</div>}>
<div className="mb-4 md:mb-0"> <div className="mb-4 md:mb-0">
<DashboardReport Filter={_filter} Record={col.widget} /> <DashboardReport Record={col.widget} />
</div> </div>
</Suspense> </Suspense>
); );
@@ -0,0 +1,59 @@
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(() => {
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>
);
}
@@ -2,14 +2,12 @@ import React, { useState, useEffect } from "react";
import { SaveFileSize } from "../../constant/saveFileSize"; import { SaveFileSize } from "../../constant/saveFileSize";
import Parse from "parse"; import Parse from "parse";
import sanitizeFileName from "../../primitives/sanitizeFileName"; import sanitizeFileName from "../../primitives/sanitizeFileName";
import DropboxChooser from "./DropboxChoose";
const FileUpload = (props) => { const FileUpload = (props) => {
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId")); const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [_fileupload, setFileUpload] = useState(""); const [_fileupload, setFileUpload] = useState("");
const [fileload, setfileload] = useState(false); const [fileload, setfileload] = useState(false);
const [localValue, setLocalValue] = useState("");
const [Message] = useState(false); const [Message] = useState(false);
const [percentage, setpercentage] = useState(0); const [percentage, setpercentage] = useState(0);
@@ -25,7 +23,6 @@ const FileUpload = (props) => {
const onChange = (e) => { const onChange = (e) => {
try { try {
let files = e.target.files; let files = e.target.files;
setLocalValue(e.target.files);
if (typeof files[0] !== "undefined") { if (typeof files[0] !== "undefined") {
if (props.schema.filetypes && props.schema.filetypes.length > 0) { if (props.schema.filetypes && props.schema.filetypes.length > 0) {
var fileName = files[0].name; var fileName = files[0].name;
@@ -82,7 +79,7 @@ const FileUpload = (props) => {
progress: (progressValue, loaded, total, { type }) => { progress: (progressValue, loaded, total, { type }) => {
if (type === "upload" && progressValue !== null) { if (type === "upload" && progressValue !== null) {
const percentCompleted = Math.round((loaded * 100) / total); const percentCompleted = Math.round((loaded * 100) / total);
console.log("percentCompleted ", percentCompleted); // console.log("percentCompleted ", percentCompleted);
setpercentage(percentCompleted); setpercentage(percentCompleted);
} }
} }
@@ -106,6 +103,56 @@ const FileUpload = (props) => {
console.error("Error uploading file:", error); console.error("Error uploading file:", error);
} }
}; };
const dropboxSuccess = async (files) => {
// console.log("file ", files);
setfileload(true);
const file = files[0];
const url = file.link;
const size = file.bytes;
const mb = Math.round(file.bytes / Math.pow(1024, 2));
if (mb > 10) {
setTimeout(() => {
alert(
`The selected file size is too large. Please select a file less than 10 MB`
);
}, 500);
return;
} else {
const name = sanitizeFileName(file.name);
const parseFile = new Parse.File(name, { uri: url });
try {
const response = await parseFile.save({
progress: (progressValue, loaded, total, { type }) => {
if (type === "upload" && progressValue !== null) {
const percentCompleted = Math.round((loaded * 100) / total);
// console.log("percentCompleted ", percentCompleted);
setpercentage(percentCompleted);
}
}
});
// console.log("response.url() ", response.url());
setFileUpload(response.url());
props.onChange(response.url());
setfileload(false);
if (response.url()) {
SaveFileSize(size, response.url());
return response.url();
}
} catch (error) {
setfileload(false);
setpercentage(0);
console.error("Error uploading file:", error);
}
}
};
const dropboxCancel = async () => {
console.log("cancel clicked ");
};
let fileView = let fileView =
props.formData && props.formData &&
props.schema.uploadtype === "s3viajw" ? null : props.formData && props.schema.uploadtype === "s3viajw" ? null : props.formData &&
@@ -207,55 +254,51 @@ const FileUpload = (props) => {
</div> </div>
<> <>
{localValue ? ( {props.formData ? (
<input <div className="flex gap-2 justify-center items-center">
type="file" <div className="flex justify-between items-center px-2 py-[3px] w-full font-bold rounded border-[1px] border-[#ccc] text-gray-500 bg-white text-[13px]">
id="hashfile" <div className="break-all">
style={{ file selected : {props.formData.split("/")[3]}
border: "1px solid #ccc", </div>
color: "gray", <div
backgroundColor: "white", onClick={() => {
padding: "5px 10px", console.log("clicked");
borderRadius: "4px", setFileUpload([]);
fontSize: "13px", props.onChange(undefined);
width: "100%", }}
fontWeight: "bold" className="cursor-pointer px-[10px] text-[20px] font-bold bg-white text-red-500"
}} >
accept="application/pdf,application/vnd.ms-excel" <i className="fa-solid fa-xmark"></i>
onChange={onChange} </div>
/> </div>
) : props.formData ? ( <DropboxChooser
<div onSuccess={dropboxSuccess}
style={{ onCancel={dropboxCancel}
border: "1px solid #ccc", />
color: "gray",
backgroundColor: "white",
padding: "5px 10px",
borderRadius: "4px",
fontSize: "13px",
width: "100%",
fontWeight: "bold"
}}
>
file selected : {props.formData.split("/")[3]}
</div> </div>
) : ( ) : (
<input <div className="flex gap-2 justify-center items-center">
type="file" <input
id="hashfile" type="file"
style={{ id="hashfile"
border: "1px solid #ccc", style={{
color: "gray", border: "1px solid #ccc",
backgroundColor: "white", color: "gray",
padding: "5px 10px", backgroundColor: "white",
borderRadius: "4px", padding: "5px 10px",
fontSize: "13px", borderRadius: "4px",
width: "100%", fontSize: "13px",
fontWeight: "bold" width: "100%",
}} fontWeight: "bold"
accept="application/pdf,application/vnd.ms-excel" }}
onChange={onChange} accept="application/pdf,application/vnd.ms-excel"
/> onChange={onChange}
/>
<DropboxChooser
onSuccess={dropboxSuccess}
onCancel={dropboxCancel}
/>
</div>
)} )}
</> </>
</React.Fragment> </React.Fragment>
@@ -1,6 +1,6 @@
import React, { Component } from "react"; import React, { Component } from "react";
import Parse from "parse"; import Parse from "parse";
import axios from "axios"; // import axios from "axios";
export class HiddenField extends Component { export class HiddenField extends Component {
state = { state = {
@@ -37,31 +37,46 @@ export class HiddenField extends Component {
this.setState({ _fields: custome_Filed }); this.setState({ _fields: custome_Filed });
} else { } else {
if (currentUser) { if (currentUser) {
let url = `${this.state.baseUrl}classes/${localStorage.getItem( // let url = `${this.state.baseUrl}classes/${localStorage.getItem(
"extended_class" // "extended_class"
)}?where={"UserId":{"__type":"Pointer","className":"_User","objectId":"${ // )}?where={"UserId":{"__type":"Pointer","className":"_User","objectId":"${
currentUser.id // currentUser.id
}"}}&keys=${this.props.schema.data.valueKey}`; // }"}}&keys=${this.props.schema.data.valueKey}`;
const headers = { // const headers = {
"Content-Type": "application/json", // "Content-Type": "application/json",
"X-Parse-Application-Id": this.state.parseAppId // "X-Parse-Application-Id": this.state.parseAppId
}; // };
await axios.get(url, { headers: headers }).then((res) => { // await axios.get(url, { headers: headers }).then((res) => {
let custome_Filed = ""; // let custome_Filed = "";
let _rdata = res.data.results; // let _rdata = res.data.results;
let splitArray = this.props.schema.data.valueKey.split("."); // let splitArray = this.props.schema.data.valueKey.split(".");
if (splitArray.length > 1) { // if (splitArray.length > 1) {
custome_Filed = _rdata[0][splitArray[0]][splitArray[1]]; // custome_Filed = _rdata[0][splitArray[0]][splitArray[1]];
} else { // } else {
console.log(_rdata[0][splitArray[0]]); // console.log(_rdata[0][splitArray[0]]);
custome_Filed = _rdata[0][splitArray[0]]; // custome_Filed = _rdata[0][splitArray[0]];
} // }
this.setState({ _fields: custome_Filed }); // this.setState({ _fields: custome_Filed });
// });
const res = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
}); });
let custome_Filed = "";
const result = res.toJSON();
let _rdata = [result];
let splitArray = this.props.schema.data.valueKey.split(".");
if (splitArray.length > 1) {
custome_Filed = _rdata[0][splitArray[0]][splitArray[1]];
} else {
console.log(_rdata[0][splitArray[0]]);
custome_Filed = _rdata[0][splitArray[0]];
}
this.setState({ _fields: custome_Filed });
} }
} }
} catch (error) { } catch (error) {
console.log('err', error) console.log("err", error);
} }
} }
}; };
@@ -120,12 +120,10 @@ const Level1Dropdown = (props) => {
let data = JSON.parse(localStorage.getItem("Extand_Class")); let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0]; res = data[0];
} else { } else {
var emp = Parse.Object.extend( const currentUser = Parse.User.current();
localStorage.getItem("extended_class") res = await Parse.Cloud.run("getUserDetails", {
); email: currentUser.get("email")
var q = new Parse.Query(emp); });
q.equalTo("UserId", currentUser);
res = await q.first();
if (res) res = res.toJSON(); if (res) res = res.toJSON();
} }
@@ -339,7 +337,7 @@ const Level1Dropdown = (props) => {
x.className = x.className.replace("show", ""); x.className = x.className.replace("show", "");
}, 5000); }, 5000);
} catch (error) { } catch (error) {
console.log("Err", error) console.log("Err", error);
} }
} }
}; };
@@ -0,0 +1,21 @@
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.objectId}`}
className="mx-auto flex items-center hover:bg-[#eef1f5] p-3 lg:p-4"
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;
+33 -72
View File
@@ -1,115 +1,76 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Link, NavLink } from "react-router-dom";
import Menu from './Menu';
import Submenu from "./SubMenu"; import Submenu from "./SubMenu";
import dp from "../../assets/images/dp.png"; import SocialMedia from './SocialMedia';
import Parse from "parse"; import Parse from "parse";
import dp from "../../assets/images/dp.png";
const Sidebar = ({ isOpen, closeSidebar }) => { const Sidebar = ({ isOpen, closeSidebar }) => {
const [menuList, setmenuList] = useState([]);
let username = localStorage.getItem("username"); let username = localStorage.getItem("username");
const image = localStorage.getItem("profileImg") || dp; const image = localStorage.getItem("profileImg") || dp;
const tenantname = localStorage.getItem("TenantName"); const tenantname = localStorage.getItem("TenantName");
const [menuList, setmenuList] = useState([]);
useEffect(() => { useEffect(() => {
if (localStorage.getItem("accesstoken")) { if (localStorage.getItem("accesstoken")) {
menuItem(); menuItem();
} }
}, []); }, []);
const menuItem = async () => { const menuItem = async () => {
const parseBaseUrl = localStorage.getItem("baseUrl"); const parseBaseUrl = localStorage.getItem("baseUrl");
const parseAppId = localStorage.getItem("parseAppId"); const parseAppId = localStorage.getItem("parseAppId");
try { try {
Parse.serverURL = parseBaseUrl; Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId); Parse.initialize(parseAppId);
var sideMenu = Parse.Object.extend("w_menu"); var sideMenu = Parse.Object.extend("w_menu");
var query = new Parse.Query(sideMenu); var query = new Parse.Query(sideMenu);
query.equalTo("objectId", localStorage.getItem("defaultmenuid")); query.equalTo("objectId", localStorage.getItem("defaultmenuid"));
const results = await query.first(); const results = await query.first();
const resultjson = results.toJSON(); const resultjson = results.toJSON();
// console.log("resultjson ", resultjson);
let result = resultjson; let result = resultjson;
setmenuList(result.menuItems); setmenuList(result.menuItems);
} catch (e) { } catch (e) {
console.error("Problem", e); console.error("Problem", e);
} }
}; };
return ( return (
<div <aside
className={`${ 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 ? "block" : "hidden" ${isOpen ? "translate-x-0 block" : "-translate-x-full hidden"}`}
} bg-white text-[#444] h-screen w-full md:w-[300px] overflow-y-auto transform transition-transform z-40 ${
isOpen ? "translate-x-0" : "-translate-x-full"
}`}
> >
<div className="flex px-2 py-3 gap-2 items-center shadow-md"> <div className="flex px-2 py-3 gap-2 items-center shadow-md">
<div className="w-[75px] h-[75px] rounded-full ring-[2px] ring-offset-2 ring-gray-400 overflow-hidden"> <div className="w-[75px] h-[75px] rounded-full ring-[2px] ring-offset-2 ring-gray-400 overflow-hidden">
<img className="w-full h-full object-contain" src={image} alt="img" /> <img className="w-full h-full object-cover" src={image} alt="Profile" />
</div> </div>
<div> <div>
<p className="text-[14px] font-bold">{username && username}</p> <p className="text-[14px] font-bold">{username}</p>
<p <p className={`text-[12px] ${tenantname ? "mt-2" : ""}`}>
className={`text-[12px] ${tenantname && tenantname ? "mt-2" : ""}`} {tenantname}
>
{tenantname && tenantname}
</p> </p>
</div> </div>
</div> </div>
<ul className="text-sm"> <nav aria-label="OpenSign Sidebar Navigation">
{menuList.length > 0 && ( <ul className="text-sm" role="menubar" aria-label="OpenSign Sidebar Navigation">
<> {menuList.map((item) => (
{menuList.map((item) => !item.children ? (
!item.children ? ( <Menu key={item.title} item={item} isOpen={isOpen} closeSidebar={closeSidebar} />
<li key={item.title} onClick={() => closeSidebar()}> ) : (
<Link <Submenu key={item.title} item={item} closeSidebar={closeSidebar} />
className={`mx-auto flex items-center hover:bg-[#eef1f5] p-3 lg:p-4 hover:no-underline cursor-pointer`} )
to={`/${item.pageType}/${item.objectId}`} ))}
> </ul>
<i className={item.icon + " text-[18px]"}></i> </nav>
<span title={item.description} className="ml-3 lg:ml-4"> <footer className="mt-4 flex justify-center items-center text-[25px] text-black gap-3">
{item.title} <SocialMedia />
</span> </footer>
</Link> </aside>
</li>
) : (
<Submenu key={item.title} icon={item.icon} title={item.title}>
{item.children.map((item) => (
<li key={item.title} onClick={() => closeSidebar()} className="pl-6 md:pl-8 hover:bg-[#eef1f5] cursor-pointer">
<Link
className={`mx-auto flex items-center p-2 lg:p-3 hover:no-underline`}
to={`/${item.pageType}/${item.objectId}`}
>
<i className={item.icon + " text-[18px]"}></i>
<span title={item.description} className="ml-3 lg:ml-4">
{item.title}
</span>
</Link>
</li>
))}
</Submenu>
)
)}
</>
)}
</ul>
<div className="mt-4 flex justify-center items-center text-[25px] text-black gap-3">
<NavLink to="https://github.com/opensignlabs/opensign" target="_blank">
<i className="fa-brands fa-github"></i>
</NavLink>
<NavLink
to="https://www.linkedin.com/company/opensign%E2%84%A2/"
target="_blank"
>
<i className="fa-brands fa-linkedin"></i>
</NavLink>
<NavLink to="https://www.twitter.com/opensignlabs" target="_blank">
<i className="fa-brands fa-square-x-twitter"></i>
</NavLink>
<NavLink to="https://discord.com/invite/xe9TDuyAyj" target="_blank">
<i className="fa-brands fa-discord"></i>
</NavLink>
</div>
</div>
); );
}; };
@@ -0,0 +1,27 @@
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&apos;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&apos;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&apos;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&apos;s Discord</span>
</NavLink>
</React.Fragment>
)
}
export default SocialMedia;
+33 -11
View File
@@ -1,30 +1,52 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { NavLink } from "react-router-dom";
const Submenu = ({ icon, title, children }) => { const Submenu = ({ item, closeSidebar }) => {
const [isOpen, setIsOpen] = useState(false); const [submenuOpen, setSubmenuOpen] = useState(false);
const { title, icon, children } = item;
const toggleSubmenu = () => { const toggleSubmenu = () => {
setIsOpen(!isOpen); setSubmenuOpen(!submenuOpen);
}; };
return ( return (
<div> <li role="none">
<button <button
onClick={toggleSubmenu} onClick={toggleSubmenu}
className="w-full mx-auto flex items-center text-left text-[#444] p-3 lg:p-4 hover:bg-[#eef1f5] focus:outline-none" className="w-full flex items-center text-left text-[#444] p-3 lg:p-4 hover:bg-[#eef1f5] focus:ring-2 focus:ring-blue-600"
aria-expanded={submenuOpen}
aria-haspopup="true"
aria-controls={`submenu-${title}`}
> >
<i className={icon + " text-[18px]"}></i> <i className={`${icon} text-[18px]`}></i>
<div className="flex justify-between items-center w-full"> <div className="flex justify-between items-center w-full">
<span className="ml-3 lg:ml-4">{title}</span> <span className="ml-3 lg:ml-4">{title}</span>
<i <i
className={ className={`${submenuOpen ? "fa-solid fa-angle-down" : "fa-solid fa-angle-right"
isOpen ? "fa-solid fa-angle-down" : "fa-solid fa-angle-right" }`}
} aria-hidden="true"
></i> ></i>
</div> </div>
</button> </button>
{isOpen && <ul>{children}</ul>} {submenuOpen && (
</div> <ul id={`submenu-${title}`} role="menu" aria-label={`${title} submenu`}>
{children.map((childItem) => (
<li key={childItem.title} role="none">
<NavLink
to={`/${childItem.pageType}/${childItem.objectId}`}
className="block pl-6 md:pl-8 py-2 text-sm text-gray-700 hover:bg-blue-500 hover:text-white"
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>
); );
}; };
-210
View File
@@ -1,210 +0,0 @@
import moment from "moment";
export default function onSearchFilter(_search) {
switch (_search) {
case "Today": {
let d = new Date();
let formDate = new Date(
Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0)
).toISOString();
let Todate = new Date(
Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), 23, 59, 59)
).toISOString();
let Query = `'$gte':'${formDate}','$lte':'${Todate}'`;
return Query;
}
case "Yesterday": {
let d1 = new Date();
d1.setDate(d1.getDate() - 1);
let yesFrDate = new Date(
Date.UTC(d1.getFullYear(), d1.getMonth(), d1.getDate(), 0, 0, 0)
).toISOString();
let YesTodate = new Date(
Date.UTC(d1.getFullYear(), d1.getMonth(), d1.getDate(), 23, 59, 59)
).toISOString();
let Query1 = `'$gte':'${yesFrDate}','$lte':'${YesTodate}'`;
return Query1;
}
case "This week": {
let oneDay = 24 * 60 * 60 * 1000;
let curr = new Date(); // get current date
let first = curr.getDate() - curr.getDay(); // First day is the day of the month - the day of the week
let firstday = new Date(
new Date(
Date.UTC(curr.getFullYear(), curr.getMonth(), curr.getDate(), 0, 0, 0)
).setDate(first)
).toISOString();
let diffDays = Math.round(
Math.abs(
(new Date(
Date.UTC(
curr.getFullYear(),
curr.getMonth(),
curr.getDate(),
23,
59,
59
)
) -
new Date(firstday)) /
oneDay
)
); //Days since last week
let last = first + diffDays;
let lastday = new Date(
new Date(
Date.UTC(
curr.getFullYear(),
curr.getMonth(),
curr.getDate(),
23,
59,
59
)
).setDate(last)
).toISOString();
let Query2 = `'$gte':'${firstday}','$lte':'${lastday}'`;
return Query2;
}
case "Last 7 days": {
let d7 = new Date();
let d7l = new Date();
d7.setDate(d7.getDate() - 7);
let l7t = new Date(
Date.UTC(d7l.getFullYear(), d7l.getMonth(), d7l.getDate(), 23, 59, 59)
).toISOString();
let date7 = new Date(
Date.UTC(d7.getFullYear(), d7.getMonth(), d7.getDate(), 0, 0, 0)
).toISOString();
let Query7 = `'$gte':'${date7}','$lte':'${l7t}'`;
return Query7;
}
case "Last 14 days": {
let d14 = new Date();
let d14l = new Date();
let l14t = new Date(
Date.UTC(
d14l.getFullYear(),
d14l.getMonth(),
d14l.getDate(),
23,
59,
59
)
).toISOString();
d14.setDate(d14.getDate() - 14);
let date14 = new Date(
Date.UTC(d14.getFullYear(), d14.getMonth(), d14.getDate(), 0, 0, 0)
).toISOString();
let Query14 = `'$gte':'${date14}','$lte':'${l14t}'`;
return Query14;
}
case "Last 30 days": {
let d30 = new Date();
let d30l = new Date();
let l30t = new Date(
Date.UTC(
d30l.getFullYear(),
d30l.getMonth(),
d30l.getDate(),
23,
59,
59
)
).toISOString();
d30.setDate(d30.getDate() - 30);
let date30 = new Date(
Date.UTC(d30.getFullYear(), d30.getMonth(), d30.getDate(), 0, 0, 0)
).toISOString();
return `'$gte':'${date30}','$lte':'${l30t}'`;
}
case "Last week": {
const from_date = moment().startOf("week").subtract(7, "days");
const to_date = moment().endOf("week").subtract(7, "days");
return `'$gte':'${from_date.toISOString()}','$lte':'${to_date.toISOString()}'`;
}
case "This month": {
var tdate = new Date();
var tfirstDay = new Date(
tdate.getFullYear(),
tdate.getMonth(),
1
).toISOString();
var tlastDay = new Date(
tdate.getFullYear(),
tdate.getMonth() + 1,
0
).toISOString();
let Querylt = `'$gte':'${tfirstDay}','$lte':'${tlastDay}'`;
return Querylt;
}
case "Last month": {
var ldate = new Date();
var lfirstDay = new Date(
ldate.getFullYear(),
ldate.getMonth() - 1,
2
).toISOString();
var llastDay = new Date(
ldate.getFullYear(),
ldate.getMonth(),
1
).toISOString();
let Queryltl = `'$gte':'${lfirstDay}','$lte':'${llastDay}'`;
return Queryltl;
}
case "All": {
let fall = new Date(
new Date().getFullYear() - 100,
0,
1,
0,
0,
0
).toISOString();
let fall_year = `'$gte':'${fall}'`;
return fall_year;
}
case "This year": {
let fcy = new Date(new Date().getFullYear(), 0, 1, 0, 0, 0).toISOString();
let lcy = new Date(
new Date().getFullYear(),
11,
31,
23,
59,
59
).toISOString();
let cur_year = `'$gte':'${fcy}','$lte':'${lcy}'`;
return cur_year;
}
case "Last year": {
let fly = new Date(
new Date().getFullYear() - 1,
0,
1,
0,
0,
0
).toISOString();
let lly = new Date(
new Date().getFullYear() - 1,
11,
31,
23,
59,
59
).toISOString();
let last_year = `'$gte':'${fly}','$lte':'${lly}'`;
return last_year;
}
default:
return "";
}
}
+17
View File
@@ -15,3 +15,20 @@ export const useScript = (url, onload) => {
}; };
}, [url, onload]); }, [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]);
};
+2 -3
View File
@@ -14,7 +14,7 @@ export const formJson = (id) => {
type: "string", type: "string",
title: "Select Document", title: "Select Document",
filetypes: [], filetypes: [],
maxfilesizeKB: "5000", maxfilesizeKB: "10000",
uploadtype: "regular", uploadtype: "regular",
helpbody: "", helpbody: "",
helplink: "" helplink: ""
@@ -147,7 +147,7 @@ export const formJson = (id) => {
class: "contracts_Contactbook", class: "contracts_Contactbook",
displayKey: "Name", displayKey: "Name",
valueKey: "objectId", valueKey: "objectId",
query: `where={"CreatedBy":${userPtr}}&keys=Name`, query: `where={"CreatedBy":${userPtr},"IsDeleted":{"$ne":true}}&keys=Name`,
isPointer: true, isPointer: true,
helpbody: "", helpbody: "",
helplink: "", helplink: "",
@@ -582,4 +582,3 @@ export const formJson = (id) => {
return formData; return formData;
} }
}; };
+25 -246
View File
@@ -1,35 +1,13 @@
import Parse from "parse";
export default function reportJson(id) { export default function reportJson(id) {
const currentUserId = Parse.User.current().id;
// console.log("json ", json); // console.log("json ", json);
const head = ["Sr.No", "Name", "Note", "Folder", "File", "Owner", "Signers"];
const contactbook = ["Sr.No", "Name", "Email", "Phone"];
switch (id) { switch (id) {
// draft documents report // draft documents report
case "ByHuevtCFY": case "ByHuevtCFY":
return { return {
reportName: "Draft Documents", reportName: "Draft Documents",
className: "contracts_Document", heading: head,
params: {
Type: null,
$or: [
{ Signers: null, SignedUrl: null },
{ Signers: { $exists: true }, Placeholders: null }
],
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
}
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
actions: [ actions: [
{ {
btnLabel: "sign", btnLabel: "sign",
@@ -45,27 +23,7 @@ export default function reportJson(id) {
case "4Hhwbp482K": case "4Hhwbp482K":
return { return {
reportName: "Need your sign", reportName: "Need your sign",
className: "contracts_Document", heading: head,
params: {
Type: { $ne: "Folder" },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
ExpiryDate: {
$gt: { __type: "Date", iso: new Date().toISOString() }
},
Placeholders: { $ne: null }
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name",
"Signers.UserId",
"AuditTrail"
],
orderBy: "-updatedAt",
actions: [ actions: [
{ {
btnLabel: "sign", btnLabel: "sign",
@@ -81,31 +39,7 @@ export default function reportJson(id) {
case "1MwEuxLEkF": case "1MwEuxLEkF":
return { return {
reportName: "In-progress documents", reportName: "In-progress documents",
className: "contracts_Document", heading: head,
params: {
Type: { $ne: "Folder" },
Signers: { $ne: null },
Placeholders: { $ne: null },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
},
ExpiryDate: {
$gt: { __type: "Date", iso: new Date().toISOString() }
}
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
actions: [ actions: [
{ {
btnLabel: "View", btnLabel: "View",
@@ -121,27 +55,7 @@ export default function reportJson(id) {
case "kQUoW4hUXz": case "kQUoW4hUXz":
return { return {
reportName: "Completed Documents", reportName: "Completed Documents",
className: "contracts_Document", heading: head,
params: {
Type: null,
IsCompleted: true,
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
},
IsDeclined: { $ne: true }
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name",
"TimeToCompleteDays"
],
orderBy: "-updatedAt",
actions: [ actions: [
{ {
btnLabel: "View", btnLabel: "View",
@@ -153,63 +67,11 @@ export default function reportJson(id) {
} }
] ]
}; };
// OpenSignDrive™ documents Drafts
case "VRFDmUmw5B":
return {
reportName: "OpenSignDrive™ Drafts",
className: "contracts_Document",
params: {
Type: "AIDoc",
$or: [
{ Signers: null, SignedUrl: null },
{ Signers: { $exists: true }, Placeholders: null }
],
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
}
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
actions: [
{
btnLabel: "edit",
btnColor: "#3ac9d6",
textColor: "white",
btnIcon: "fa fa-plus",
redirectUrl:
"remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9MZWdhR2VuaWUtTWljcm9hcHBWMi9yZW1vdGVFbnRyeS5qcw==&moduleToLoad=AppRoutes&remoteName=legageniemicroapp/legagenie"
}
]
};
// declined documents report // declined documents report
case "UPr2Fm5WY3": case "UPr2Fm5WY3":
return { return {
reportName: "Declined Documents", reportName: "Declined Documents",
className: "contracts_Document", heading: head,
params: { Type: null, IsDeclined: true },
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
actions: [ actions: [
{ {
btnLabel: "View", btnLabel: "View",
@@ -225,39 +87,7 @@ export default function reportJson(id) {
case "zNqBHXHsYH": case "zNqBHXHsYH":
return { return {
reportName: "Expired Documents", reportName: "Expired Documents",
className: "contracts_Document", heading: head,
params: {
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
Type: { $ne: "Folder" },
$and: [
{
$or: [
{ Signers: { $ne: null }, SignedUrl: { $ne: null } },
{ Placeholders: { $ne: null } }
]
},
{
ExpiryDate: {
$lt: { __type: "Date", iso: new Date().toISOString() }
}
}
],
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
}
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
actions: [ actions: [
{ {
btnLabel: "View", btnLabel: "View",
@@ -273,31 +103,7 @@ export default function reportJson(id) {
case "d9k3UfYHBc": case "d9k3UfYHBc":
return { return {
reportName: "Recently sent for signatures", reportName: "Recently sent for signatures",
className: "contracts_Document", heading: head,
params: {
Type: { $ne: "Folder" },
Signers: { $ne: null },
Placeholders: { $ne: null },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
},
ExpiryDate: {
$gt: { __type: "Date", iso: new Date().toISOString() }
}
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
actions: [ actions: [
{ {
btnLabel: "View", btnLabel: "View",
@@ -313,27 +119,7 @@ export default function reportJson(id) {
case "5Go51Q7T8r": case "5Go51Q7T8r":
return { return {
reportName: "Recent signature requests", reportName: "Recent signature requests",
className: "contracts_Document", heading: head,
params: {
Type: { $ne: "Folder" },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
ExpiryDate: {
$gt: { __type: "Date", iso: new Date().toISOString() }
},
Placeholders: { $ne: null }
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name",
"Signers.UserId",
"AuditTrail"
],
orderBy: "-updatedAt",
actions: [ actions: [
{ {
btnLabel: "Sign", btnLabel: "Sign",
@@ -349,28 +135,7 @@ export default function reportJson(id) {
case "kC5mfynCi4": case "kC5mfynCi4":
return { return {
reportName: "Drafts", reportName: "Drafts",
className: "contracts_Document", heading: head,
params: {
Type: null,
$or: [
{ Signers: null, SignedUrl: null },
{ Signers: { $exists: true }, Placeholders: null }
],
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: currentUserId
}
},
keys: [
"Name",
"Note",
"Folder.Name",
"URL",
"ExtUserPtr.Name",
"Signers.Name"
],
orderBy: "-updatedAt",
actions: [ actions: [
{ {
btnLabel: "sign", btnLabel: "sign",
@@ -382,6 +147,20 @@ export default function reportJson(id) {
} }
] ]
}; };
// contactbook report
case "5KhaPr482K":
return {
reportName: "Contactbook",
heading: contactbook,
actions: [
{
btnLabel: "",
btnColor: "#f55a42",
textColor: "white",
btnIcon: "fa-solid fa-trash"
}
]
};
default: default:
return null; return null;
} }
+4 -1
View File
@@ -6,6 +6,7 @@
"subtitle": "Free for life One click install.", "subtitle": "Free for life One click install.",
"btnText": "Visit github", "btnText": "Visit github",
"url": "https://github.com/opensignlabs/opensign", "url": "https://github.com/opensignlabs/opensign",
"target": "_blank",
"benefits": [ "benefits": [
"Sign Unlimited Documents", "Sign Unlimited Documents",
"S3 Doc Storage", "S3 Doc Storage",
@@ -26,9 +27,10 @@
"planName": "THANKS PLAN", "planName": "THANKS PLAN",
"currency": "$", "currency": "$",
"price": "29.99", "price": "29.99",
"subtitle": "Use code 'FREEBETA' to get this for free(First 100 users)", "subtitle": "Use code 'FREEBETA' to get this for free(First 1000 users)",
"btnText": "Subscribe", "btnText": "Subscribe",
"url": "https://subscriptions.zoho.in/subscribe/ef798486e6a0a11ea65f2bae8f2af901dbadf3175d495584fd25b9af5d2f2b9e/thanks", "url": "https://subscriptions.zoho.in/subscribe/ef798486e6a0a11ea65f2bae8f2af901dbadf3175d495584fd25b9af5d2f2b9e/thanks",
"target": "_self",
"benefits": [ "benefits": [
"Sign Unlimited Documents", "Sign Unlimited Documents",
"Unlimited Secure Doc Storage with OpenSignDrive", "Unlimited Secure Doc Storage with OpenSignDrive",
@@ -50,6 +52,7 @@
"subtitle": "Customization available Priority support.", "subtitle": "Customization available Priority support.",
"btnText": "Contact us", "btnText": "Contact us",
"url": "https://www.opensignlabs.com/contact-us", "url": "https://www.opensignlabs.com/contact-us",
"target": "_blank",
"benefits": [ "benefits": [
"All features", "All features",
"Custom domain", "Custom domain",
+8 -19
View File
@@ -6,10 +6,10 @@ import { useWindowSize } from "../hook/useWindowSize";
import Tour from "reactour"; import Tour from "reactour";
import axios from "axios"; import axios from "axios";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import Parse from "parse";
const HomeLayout = ({ children }) => { const HomeLayout = ({ children }) => {
const { width } = useWindowSize(); const { width } = useWindowSize();
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(true);
const arr = useSelector((state) => state.TourSteps); const arr = useSelector((state) => state.TourSteps);
// reactour state // reactour state
@@ -19,13 +19,11 @@ const HomeLayout = ({ children }) => {
const [tourConfigs, setTourConfigs] = useState([]); const [tourConfigs, setTourConfigs] = useState([]);
const showSidebar = () => { const showSidebar = () => {
setIsOpen(!isOpen); setIsOpen(value => !value);
}; };
useEffect(() => { useEffect(() => {
if (width && width <= 768) { if (width && width <= 768) {
setIsOpen(false); setIsOpen(false);
} else {
setIsOpen(true);
} }
}, [width]); }, [width]);
@@ -124,20 +122,11 @@ const HomeLayout = ({ children }) => {
}; };
async function checkTourStatus() { async function checkTourStatus() {
const serverUrl = localStorage.getItem("baseUrl"); const currentUser = Parse.User.current();
const appId = localStorage.getItem("AppID12"); const cloudRes = await Parse.Cloud.run("getUserDetails", {
const extUserClass = localStorage.getItem("extended_class"); email: currentUser.get("email")
const json = JSON.parse(localStorage.getItem("Extand_Class")); });
const extUserId = json && json.length > 0 && json[0].objectId; const res = { data: cloudRes.toJSON() };
// console.log("extUserId ", extUserId);
const res = await axios.get(
serverUrl + "classes/" + extUserClass + "/" + extUserId,
{
headers: {
"X-Parse-Application-Id": appId
}
}
);
if (res.data && res.data.TourStatus && res.data.TourStatus.length > 0) { if (res.data && res.data.TourStatus && res.data.TourStatus.length > 0) {
const tourStatus = res.data.TourStatus; const tourStatus = res.data.TourStatus;
// console.log("res ", res.data.TourStatus); // console.log("res ", res.data.TourStatus);
+247 -83
View File
@@ -1,9 +1,41 @@
import React from "react"; import React, { useState, useEffect, useMemo } from "react";
import pad from "../assets/images/pad.svg"; import pad from "../assets/images/pad.svg";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import axios from "axios";
const ReportTable = ({ ReportName, List, actions }) => { import "../styles/report.css";
const ReportTable = ({
ReportName,
List,
setList,
actions,
heading,
setIsNextRecord,
isMoreDocs,
docPerPage
}) => {
const navigate = useNavigate(); const navigate = useNavigate();
const [currentPage, setCurrentPage] = useState(1);
const [actLoader, setActLoader] = useState({});
const [isAlert, setIsAlert] = useState(false);
const [isErr, setIsErr] = useState(false);
// For loop is used to calculate page numbers visible below table
// Initialize pageNumbers using useMemo to avoid unnecessary re-creation
const pageNumbers = useMemo(() => {
const calculatedPageNumbers = [];
for (let i = 1; i <= Math.ceil(List.length / docPerPage); i++) {
calculatedPageNumbers.push(i);
}
return calculatedPageNumbers;
}, [List, docPerPage]);
// below useEffect reset currenpage to 1 if user change route
useEffect(() => {
return () => setCurrentPage(1);
}, []);
// `formatRow` is used to show data in poper manner like
// if data is of array type then it will join array items with ","
// if data is of object type then it Name values will be show in row
// if no data available it will show hyphen "-"
const formatRow = (row) => { const formatRow = (row) => {
if (Array.isArray(row)) { if (Array.isArray(row)) {
let updateArr = row.map((x) => x.Name); let updateArr = row.map((x) => x.Name);
@@ -14,44 +46,84 @@ const ReportTable = ({ ReportName, List, actions }) => {
return "-"; return "-";
} }
}; };
// below useEffect is used to render next record if IsMoreDoc is true
// second last value of pageNumber array is same as currentPage
useEffect(() => {
if (isMoreDocs && pageNumbers[pageNumbers.length - 1] === currentPage) {
setIsNextRecord(true);
}
}, [isMoreDocs, pageNumbers, currentPage, setIsNextRecord]);
// `handlemicroapp` is used to open microapp
const handlemicroapp = (item, url) => { const handlemicroapp = (item, url) => {
localStorage.removeItem("rowlevel"); localStorage.removeItem("rowlevel");
// const params = new URLSearchParams(url);
// let arr = [];
// for (let [key, value] of params.entries()) {
// if (key === "remoteUrl") {
// arr.push(
// `${key}=${window.btoa(
// window.location.origin + "/mfbuild/remoteEntry.js"
// )}`
// );
// } else {
// arr.push(`${key}=${value}`);
// }
// }
// const remoteUrl = arr.join("&");
// console.log("arr", remoteUrl);
navigate("/rpmf/" + url); navigate("/rpmf/" + url);
localStorage.setItem("rowlevel", JSON.stringify(item)); localStorage.setItem("rowlevel", JSON.stringify(item));
// localStorage.setItem("rowlevelMicro"); // localStorage.setItem("rowlevelMicro");
}; };
const handlebtn = () => { const handlebtn = async (item) => {
console.log("clicked"); if (ReportName === "Contactbook") {
setActLoader({ [item.objectId]: true });
try {
const url =
process.env.REACT_APP_SERVERURL + "/classes/contracts_Contactbook/";
const body = { IsDeleted: true };
const res = await axios.put(url + item.objectId, body, {
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("AppID12"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
});
// console.log("Res ", res.data);
if (res.data && res.data.updatedAt) {
setActLoader({});
setIsAlert(true);
const upldatedList = List.filter((x) => x.objectId !== item.objectId);
setList(upldatedList);
}
} catch (err) {
console.log("err", err);
setIsAlert(true);
setIsErr(true);
setActLoader({});
}
}
}; };
// Get current list
const indexOfLastDoc = currentPage * docPerPage;
const indexOfFirstDoc = indexOfLastDoc - docPerPage;
// `currentLists` is total record render on current page
const currentLists = List.slice(indexOfFirstDoc, indexOfLastDoc);
// Change page
const paginateFront = () => setCurrentPage(currentPage + 1);
const paginateBack = () => setCurrentPage(currentPage - 1);
return ( return (
<div className="p-2 overflow-x-scroll w-full bg-white rounded-md"> <div className="p-2 overflow-x-scroll w-full bg-white rounded-md">
{isAlert && (
<div
className={`alert alert-${isErr ? "danger" : "success"} alertBox`}
role="alert"
onAnimationEnd={() => setIsAlert(false)}
>
{isErr
? "Something went wrong, Please try again later!"
: "Record deleted successfully!"}
</div>
)}
<h2 className="text-[23px] font-light my-2">{ReportName}</h2> <h2 className="text-[23px] font-light my-2">{ReportName}</h2>
<table className="table-auto w-full border-collapse"> <table className="table-auto w-full border-collapse">
<thead className="text-[14px]"> <thead className="text-[14px]">
<tr className="border-y-[1px]"> <tr className="border-y-[1px]">
<th className="px-4 py-2 font-thin">Sr.No</th> {heading?.map((item, index) => (
<th className="px-4 py-2 font-thin">Name</th> <React.Fragment key={index}>
<th className="px-4 py-2 font-thin">Note</th> <th className="px-4 py-2 font-thin">{item}</th>
<th className="px-4 py-2 font-thin">Folder</th> </React.Fragment>
<th className="px-4 py-2 font-thin">File</th> ))}
<th className="px-4 py-2 font-thin">Owner</th>
<th className="px-4 py-2 font-thin">Signers</th>
{actions?.length > 0 && ( {actions?.length > 0 && (
<th className="px-4 py-2 font-thin">Action</th> <th className="px-4 py-2 font-thin">Action</th>
)} )}
@@ -60,69 +132,161 @@ const ReportTable = ({ ReportName, List, actions }) => {
<tbody className="text-[12px]"> <tbody className="text-[12px]">
{List?.length > 0 ? ( {List?.length > 0 ? (
<> <>
{List.map((item, index) => ( {currentLists.map((item, index) =>
<tr className="border-t-[1px]" key={index}> ReportName === "Contactbook" ? (
<td className="px-4 py-2">{index + 1}</td> <tr className="border-y-[1px]" key={index}>
<td className="px-4 py-2 font-semibold">{item?.Name} </td> <td className="px-4 py-2">{index + 1}</td>
<td className="px-4 py-2">{item?.Note || "-"}</td> <td className="px-4 py-2 font-semibold">{item?.Name} </td>
<td className="px-4 py-2"> <td className="px-4 py-2">{item?.Email || "-"}</td>
{item?.Folder?.Name || "OpenSignDrive"} <td className="px-4 py-2">{item?.Phone || "-"}</td>
</td> <td className="px-4 py-2 flex flex-col justify-center items-center gap-2 text-white">
<td className="px-4 py-2"> {actions?.length > 0 &&
<a actions.map((act, index) => (
target="_blank" <button
rel="noopener noreferrer" key={index}
title={item?.URL} onClick={() =>
href={item?.URL} act?.redirectUrl
download={item?.URL} ? handlemicroapp(item, act.redirectUrl)
className="text-[blue] hover:text-[blue] hover:underline" : handlebtn(item)
> }
{item?.URL ? "Download" : "-"} className={`flex justify-center items-center gap-1 px-2 py-1 rounded shadow`}
</a> style={{
</td> backgroundColor: act.btnColor
? act.btnColor
: "#3ac9d6",
color: act?.textColor ? act?.textColor : "white"
}}
>
<span>
{act?.btnIcon && (
<i
className={
actLoader[item.objectId]
? "fa-solid fa-spinner fa-spin-pulse"
: act.btnIcon
}
></i>
)}
</span>
{act?.btnLabel && (
<span className="uppercase">
{act?.btnLabel ? act.btnLabel : "View"}
</span>
)}
</button>
))}
</td>
</tr>
) : (
<tr className="border-y-[1px]" key={index}>
<td className="px-4 py-2">{index + 1}</td>
<td className="px-4 py-2 font-semibold">{item?.Name} </td>
<td className="px-4 py-2">{item?.Note || "-"}</td>
<td className="px-4 py-2">
{item?.Folder?.Name || "OpenSignDrive"}
</td>
<td className="px-4 py-2">
<a
target="_blank"
rel="noopener noreferrer"
title={item?.URL}
href={item?.URL}
download={item?.URL}
className="text-[blue] hover:text-[blue] hover:underline"
>
{item?.URL ? "Download" : "-"}
</a>
</td>
<td className="px-4 py-2">{formatRow(item?.ExtUserPtr)}</td> <td className="px-4 py-2">{formatRow(item?.ExtUserPtr)}</td>
<td className="px-4 py-2"> <td className="px-4 py-2">
{item?.Signers ? formatRow(item?.Signers) : "-"} {item?.Signers ? formatRow(item?.Signers) : "-"}
</td> </td>
<td className="px-4 py-2 flex flex-col justify-center items-center gap-2 text-white"> <td className="px-4 py-2 flex flex-col justify-center items-center gap-2 text-white">
{actions?.length > 0 && {actions?.length > 0 &&
actions.map((act, index) => ( actions.map((act, index) => (
<button <button
key={index} key={index}
onClick={() => onClick={() =>
act?.redirectUrl act?.redirectUrl
? handlemicroapp(item, act.redirectUrl) ? handlemicroapp(item, act.redirectUrl)
: handlebtn(item) : handlebtn(item)
} }
className={`flex justify-center items-center w-full gap-1 px-2 py-1 rounded shadow`} className={`flex justify-center items-center w-full gap-1 px-2 py-1 rounded shadow`}
style={{ style={{
backgroundColor: act.btnColor backgroundColor: act.btnColor
? act.btnColor ? act.btnColor
: "#3ac9d6", : "#3ac9d6",
color: act?.textColor ? act?.textColor : "white" color: act?.textColor ? act?.textColor : "white"
}} }}
> >
<span> <span>
{act?.btnIcon && <i className={act.btnIcon}></i>} {act?.btnIcon && (
</span> <i
<span className="uppercase"> className={
{act?.btnLabel ? act.btnLabel : "view"} actLoader[item.objectId]
</span> ? "fa-solid fa-spinner fa-spin-pulse"
</button> : act.btnIcon
// ) }
))} ></i>
</td> )}
</tr> </span>
))} <span className="uppercase">
{act?.btnLabel ? act.btnLabel : "view"}
</span>
</button>
// )
))}
</td>
</tr>
)
)}
</> </>
) : ( ) : (
<></> <></>
)} )}
</tbody> </tbody>
</table> </table>
<div className="flex flex-wrap items-center gap-2 p-2 ">
{List.length > docPerPage && (
<>
{currentPage > 1 && (
<button
onClick={() => paginateBack()}
className="bg-blue-400 text-white rounded px-3 py-2 focus:outline-none"
>
Prev
</button>
)}
</>
)}
{pageNumbers.map((x) => (
<button
key={x}
onClick={() => setCurrentPage(x)}
className=" bg-sky-400 text-white rounded px-3 py-2 focus:outline-none"
>
{x}
</button>
))}
{isMoreDocs && (
<button className="text-black rounded px-1 py-2">...</button>
)}
{List.length > docPerPage && (
<>
{pageNumbers.includes(currentPage + 1) && (
<button
onClick={() => paginateFront()}
className="bg-blue-400 text-white rounded px-3 py-2 focus:outline-none"
>
Next
</button>
)}
</>
)}
</div>
{List?.length <= 0 && ( {List?.length <= 0 && (
<div className="flex flex-col items-center justify-center w-full bg-white roundedm py-4"> <div className="flex flex-col items-center justify-center w-full bg-white rounded py-4">
<div className="w-[60px] h-[60px] overflow-hidden"> <div className="w-[60px] h-[60px] overflow-hidden">
<img className="w-full h-full object-contain" src={pad} alt="img" /> <img className="w-full h-full object-contain" src={pad} alt="img" />
</div> </div>
+8 -12
View File
@@ -11,7 +11,8 @@ export const fetchAppInfo = (str, burl, app_id) => async (dispatch) => {
let _base = ""; // Define _base here and initialize it to an empty string let _base = ""; // Define _base here and initialize it to an empty string
if (response && response.baseurl) { if (response && response.baseurl) {
_base = response.baseurl.charAt(response.baseurl.length - 1); _base = response.baseurl.charAt(response.baseurl.length - 1);
} localStorage.removeItem("baseUrl"); }
localStorage.removeItem("baseUrl");
localStorage.setItem("_appName", response.appname); localStorage.setItem("_appName", response.appname);
localStorage.setItem("_app_objectId", response.objectId); localStorage.setItem("_app_objectId", response.objectId);
if (_base === "/") { if (_base === "/") {
@@ -120,16 +121,11 @@ export const login = (username, password) => async (dispatch) => {
localStorage.setItem("_user_role", _role); localStorage.setItem("_user_role", _role);
} }
try { try {
const tour = Parse.Object.extend( const currentUser = Parse.User.current();
localStorage.getItem("extended_class") await Parse.Cloud.run("getUserDetails", {
); email: currentUser.get("email")
let _tour = new Parse.Query(tour); })
_tour.equalTo("UserId", { .then(
__type: "Pointer",
className: "_User",
objectId: resultjson.objectId
});
await _tour.first().then(
(results) => { (results) => {
let userinfo = results.toJSON(); let userinfo = results.toJSON();
if (userinfo.TenantId) { if (userinfo.TenantId) {
@@ -142,7 +138,7 @@ export const login = (username, password) => async (dispatch) => {
} }
); );
} catch (error) { } catch (error) {
console.log("err ", error) console.log("err ", error);
} }
} }
}); });
+15 -15
View File
@@ -2,11 +2,12 @@ import React, { useState, useEffect } from "react";
import Parse from "parse"; import Parse from "parse";
import "../styles/loader.css"; import "../styles/loader.css";
import GetDashboard from "../components/dashboard/GetDashboard"; import GetDashboard from "../components/dashboard/GetDashboard";
import { Navigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import Title from "../components/Title"; import Title from "../components/Title";
import { save_tourSteps } from "../redux/actions"; import { save_tourSteps } from "../redux/actions";
import { connect } from "react-redux"; import { connect } from "react-redux";
const Dashboard = (props) => { const Dashboard = (props) => {
const navigate = useNavigate();
const { id } = useParams(); const { id } = useParams();
const [dashboard, setdashboard] = useState([]); const [dashboard, setdashboard] = useState([]);
const [classnameArray, setclassnameArray] = useState([]); const [classnameArray, setclassnameArray] = useState([]);
@@ -15,6 +16,19 @@ const Dashboard = (props) => {
const [parseAppId] = useState(localStorage.getItem("parseAppId")); const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [defaultQuery, setDefaultQuery] = useState(""); const [defaultQuery, setDefaultQuery] = useState("");
useEffect(() => {
if (localStorage.getItem("accesstoken")) {
if (id !== undefined) {
getDashboard(id);
} else {
getDashboard(localStorage.getItem("PageLanding"));
}
} else {
navigate("/", { replace: true });
}
// eslint-disable-next-line
}, [id]);
const getDashboard = async (id) => { const getDashboard = async (id) => {
setloading(true); setloading(true);
try { try {
@@ -93,20 +107,6 @@ const Dashboard = (props) => {
} }
}; };
useEffect(() => {
if (id !== undefined) {
getDashboard(id);
} else {
getDashboard(localStorage.getItem("PageLanding"));
}
// eslint-disable-next-line
}, [id]);
if (localStorage.getItem("accesstoken") === "" || null) {
return <Navigate to="/" />;
}
let _dash = ( let _dash = (
<GetDashboard <GetDashboard
dashboard={dashboard} dashboard={dashboard}
+84
View File
@@ -0,0 +1,84 @@
import { Suspense } from "react";
import { useParams } from "react-router-dom";
import useFederatedComponent from "mf-cra";
import React from "react";
import Title from "../components/Title";
function RemoteApp({ app }) {
// console.log("app ", app);
const { Component: RemoteComponent } = useFederatedComponent(app);
// console.log("RemoteComponent ", RemoteComponent);
return (
<>
<Title title={app.remoteName} />
<Suspense
fallback={
<div style={{ height: "300px" }}>
<div
style={{
marginLeft: "45%",
marginTop: "150px",
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
</div>
}
>
<div
style={{
boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.33)",
backgroundColor: "#ffffff",
width: "100%",
overflow: "hidden",
borderRadius: 3,
minHeight: "70vh"
}}
>
{RemoteComponent && <RemoteComponent />}
</div>
</Suspense>
</>
);
}
function checkObjectProperties(obj) {
// Check if all three properties exist in the object
if (
obj &&
obj.remoteName !== undefined &&
obj.remoteUrl !== undefined &&
obj.moduleToLoad !== undefined
) {
return true; // All properties are present
} else {
return false; // At least one property is missing
}
}
export default function RemoteAppContainer() {
const { remoteApp } = useParams();
const obj = {
remoteUrl: window.location.origin + "/mfbuild/remoteEntry.js",
moduleToLoad: "./AppRoutes",
remoteName: remoteApp
};
// console.log("obj ", obj);
const isMf = checkObjectProperties(obj);
if (isMf) {
const appToLoad = obj;
return <RemoteApp app={appToLoad} />;
} else {
return (
<div className="flex items-center justify-center h-screen w-full bg-white rounded">
<div className="text-center">
<h1 className="text-[60px] lg:text-[120px] font-semibold text-black">
404
</h1>
<p className="text-[30px] lg:text-[50px] text-black">
Page Not Found
</p>
</div>
</div>
);
}
}
File diff suppressed because it is too large Load Diff
+67 -35
View File
@@ -21,6 +21,9 @@ const PgSignUp = (props) => {
}); });
const [validationMessage, setValidationMessage] = useState(""); const [validationMessage, setValidationMessage] = useState("");
const [isLoader, setIsLoader] = useState(true); const [isLoader, setIsLoader] = useState(true);
const [lengthValid, setLengthValid] = useState(false);
const [caseDigitValid, setCaseDigitValid] = useState(false);
const [specialCharValid, setSpecialCharValid] = useState(false);
// below useEffect is used to fetch App data and save to redux state // below useEffect is used to fetch App data and save to redux state
useEffect(() => { useEffect(() => {
@@ -67,9 +70,8 @@ const PgSignUp = (props) => {
const userSettings = JSON.parse(localStorage.getItem("userSettings")); const userSettings = JSON.parse(localStorage.getItem("userSettings"));
const extClass = userSettings[0].extended_class; const extClass = userSettings[0].extended_class;
// console.log("extClass ", extClass); // console.log("extClass ", extClass);
const checkUser = new Parse.Query(extClass); const params = { email: userDetails.email };
checkUser.equalTo("Email", userDetails.email); const res = await Parse.Cloud.run("getUserDetails", params);
const res = await checkUser.first();
// console.log("res", res); // console.log("res", res);
if (res) { if (res) {
const checkUser = new Parse.Query(extClass); const checkUser = new Parse.Query(extClass);
@@ -105,21 +107,23 @@ const PgSignUp = (props) => {
// "handleSubmit" is used to save user details signup him/her who come from plan-pricing page // "handleSubmit" is used to save user details signup him/her who come from plan-pricing page
const handleSubmit = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
setIsLoader(true); if (lengthValid && caseDigitValid && specialCharValid) {
if (formData.password === formData.confirmPassword) { setIsLoader(true);
const url = window.location.href; if (formData.password === formData.confirmPassword) {
let paramString = url.split("?")[1]; const url = window.location.href;
let queryString = new URLSearchParams(paramString); let paramString = url.split("?")[1];
// console.log("url ", queryString); let queryString = new URLSearchParams(paramString);
// console.log("url ", queryString);
let obj = { ...formData }; let obj = { ...formData };
for (let pair of queryString.entries()) { for (let pair of queryString.entries()) {
// console.log("Key is: " + pair[0]); // console.log("Key is: " + pair[0]);
// console.log("Value is: " + pair[1]); // console.log("Value is: " + pair[1]);
obj = { ...obj, [pair[0]]: pair[1] }; obj = { ...obj, [pair[0]]: pair[1] };
}
saveUser(obj);
// console.log("obj ", obj);}
} }
saveUser(obj);
// console.log("obj ", obj);}
} }
}; };
const saveUser = async (obj) => { const saveUser = async (obj) => {
@@ -152,6 +156,7 @@ const PgSignUp = (props) => {
if (res) { if (res) {
const params = { const params = {
userDetails: { userDetails: {
jobTitle: zohoRes.data.result.jobTitle,
company: zohoRes.data.result.company, company: zohoRes.data.result.company,
name: zohoRes.data.result.name, name: zohoRes.data.result.name,
email: zohoRes.data.result.email, email: zohoRes.data.result.email,
@@ -194,6 +199,15 @@ const PgSignUp = (props) => {
const newPassword = e.target.value; const newPassword = e.target.value;
setFormData({ ...formData, [e.target.name]: e.target.value }); setFormData({ ...formData, [e.target.name]: e.target.value });
validatePasswords(newPassword, formData.confirmPassword); validatePasswords(newPassword, formData.confirmPassword);
// Check conditions separately
setLengthValid(newPassword.length >= 8);
setCaseDigitValid(
/[a-z]/.test(newPassword) &&
/[A-Z]/.test(newPassword) &&
/\d/.test(newPassword)
);
setSpecialCharValid(/[!@#$%^&*()\-_=+{};:,<.>]/.test(newPassword));
}; };
const handleConFirmPassowordChange = (e) => { const handleConFirmPassowordChange = (e) => {
const newConfirmPassword = e.target.value; const newConfirmPassword = e.target.value;
@@ -279,13 +293,6 @@ const PgSignUp = (props) => {
"" ""
); );
localStorage.setItem("_user_role", _role); localStorage.setItem("_user_role", _role);
if (element.enableCart) {
localStorage.setItem("EnableCart", element.enableCart);
props.setEnableCart(element.enableCart);
} else {
localStorage.removeItem("EnableCart");
}
// Get TenentID from Extendend Class // Get TenentID from Extendend Class
localStorage.setItem( localStorage.setItem(
"extended_class", "extended_class",
@@ -293,14 +300,12 @@ const PgSignUp = (props) => {
); );
localStorage.setItem("userpointer", element.userpointer); localStorage.setItem("userpointer", element.userpointer);
const extendedClass = Parse.Object.extend( const currentUser = Parse.User.current();
element.extended_class await Parse.Cloud.run("getUserDetails", {
); email: currentUser.get("email")
let query = new Parse.Query(extendedClass); }).then(
query.equalTo("UserId", Parse.User.current()); (result) => {
query.include("TenantId"); const results = [result];
await query.find().then(
(results) => {
let tenentInfo = []; let tenentInfo = [];
if (results) { if (results) {
let extendedInfo_stringify = let extendedInfo_stringify =
@@ -415,7 +420,7 @@ const PgSignUp = (props) => {
} }
}) })
.catch((err) => { .catch((err) => {
console.log('err', err) console.log("err", err);
setIsLoader(false); setIsLoader(false);
}); });
} }
@@ -448,10 +453,10 @@ const PgSignUp = (props) => {
) : ( ) : (
<form id="signup" className="pgsignup-content" onSubmit={handleSubmit}> <form id="signup" className="pgsignup-content" onSubmit={handleSubmit}>
<div className="pgsignup-container"> <div className="pgsignup-container">
<h1 className="text-4xl font-bold">Choose Password</h1> <h1 className="text-2xl md:text-3xl font-bold">Choose Password</h1>
<hr className="hrt" /> <hr className="hrt" />
<label htmlFor="password"> <label htmlFor="password">
<b>Password</b> <b className="text-[13px]">Password</b>
</label> </label>
<input <input
type="password" type="password"
@@ -464,7 +469,7 @@ const PgSignUp = (props) => {
/> />
<label htmlFor="confirmPassword"> <label htmlFor="confirmPassword">
<b>Confirm Password</b> <b className="text-[13px]">Confirm Password</b>
</label> </label>
<input <input
type="password" type="password"
@@ -494,6 +499,33 @@ const PgSignUp = (props) => {
> >
{validationMessage} {validationMessage}
</div> </div>
{formData.password.length > 0 && (
<div className="mt-1 text-[11px]">
<p
className={`${
lengthValid ? "text-green-600" : "text-red-600"
}`}
>
{lengthValid ? "✓" : "✗"} Password should be 8 characters long
</p>
<p
className={`${
caseDigitValid ? "text-green-600" : "text-red-600"
}`}
>
{caseDigitValid ? "✓" : "✗"} Password should contain uppercase
letter, lowercase letter, digit
</p>
<p
className={`${
specialCharValid ? "text-green-600" : "text-red-600"
}`}
>
{specialCharValid ? "✓" : "✗"} Password should contain special
character
</p>
</div>
)}
<div className="clearfix"> <div className="clearfix">
<button type="submit" className="signupbtn"> <button type="submit" className="signupbtn">
Submit Submit
+25 -17
View File
@@ -2,14 +2,14 @@ import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
import checkmark from "../assets/images/checkmark.png"; import checkmark from "../assets/images/checkmark.png";
import plansArr from '../json/plansArr.json' import plansArr from "../json/plansArr.json";
import Title from "../components/Title"; import Title from "../components/Title";
const listItemStyle = { const listItemStyle = {
paddingLeft: '20px', // Add padding to create space for the image paddingLeft: "20px", // Add padding to create space for the image
backgroundImage: `url(${checkmark})`, // Set your image as the list style image backgroundImage: `url(${checkmark})`, // Set your image as the list style image
backgroundPosition: 'left', backgroundPosition: "left",
backgroundRepeat: 'no-repeat', backgroundRepeat: "no-repeat",
backgroundSize: '16px 16px', // Adjust the size of the image backgroundSize: "16px 16px" // Adjust the size of the image
}; };
const PlanSubscriptions = () => { const PlanSubscriptions = () => {
@@ -28,7 +28,12 @@ const PlanSubscriptions = () => {
: ""; : "";
const phone = const phone =
userDetails && userDetails.phone ? "&mobile=" + userDetails.phone : ""; userDetails && userDetails.phone ? "&mobile=" + userDetails.phone : "";
const details = "?" + name + email + company + phone; const details =
"?shipping_country_code=US&billing_country_code=US&billing_state_code=CA&" +
name +
email +
company +
phone;
useEffect(() => { useEffect(() => {
if (localStorage.getItem("accesstoken")) { if (localStorage.getItem("accesstoken")) {
setIsLoader(false); setIsLoader(false);
@@ -41,7 +46,7 @@ const PlanSubscriptions = () => {
return ( return (
<> <>
<Title title={"Subscriptions"} /> <Title title={"Subscriptions"} />
{isLoader ? ( {isLoader ? (
<div <div
style={{ style={{
@@ -64,7 +69,7 @@ const PlanSubscriptions = () => {
style={{ style={{
backgroundColor: "white", backgroundColor: "white",
overflowY: "auto", overflowY: "auto",
maxHeight: "600px", maxHeight: "100%",
"--theme-color": "#7952b3", "--theme-color": "#7952b3",
"--plan-width": 30 "--plan-width": 30
}} }}
@@ -131,15 +136,18 @@ const PlanSubscriptions = () => {
<p>{item.subtitle}</p> <p>{item.subtitle}</p>
</div> </div>
</div> </div>
<div className="bg-[#002862] w-full text-white py-2 rounded">
<NavLink <NavLink
to={item.url + details} to={
className="rounded uppercase hover:no-underline hover:text-white" item.btnText === "Subscribe"
target="_self" ? item.url + details
> : item.url
{item.btnText} }
</NavLink> className="bg-[#002862] w-full text-white py-2 rounded uppercase hover:no-underline hover:text-white"
</div> target={item.target}
>
{item.btnText}
</NavLink>
</div> </div>
<hr className="w-full bg-gray-300 p-[.5px]" /> <hr className="w-full bg-gray-300 p-[.5px]" />
<ul className="mx-1 p-3 text-left break-words text-sm list-none"> <ul className="mx-1 p-3 text-left break-words text-sm list-none">
+65 -17
View File
@@ -12,39 +12,62 @@ const Report = () => {
const [isLoader, setIsLoader] = useState(true); const [isLoader, setIsLoader] = useState(true);
const [reportName, setReportName] = useState(""); const [reportName, setReportName] = useState("");
const [actions, setActions] = 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 = 10;
// below useEffect is call when id param change
useEffect(() => { useEffect(() => {
setReportName(""); setReportName("");
setList([]);
getReportData(); getReportData();
// 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 // eslint-disable-next-line
}, [id]); }, [id]);
const getReportData = async () => { // below useEffect call when isNextRecord state is true and fetch next record
setIsLoader(true); useEffect(() => {
if (isNextRecord) {
getReportData(List.length, 200);
}
// eslint-disable-next-line
}, [isNextRecord]);
const getReportData = async (skipUserRecord = 0, limit = 200) => {
// setIsLoader(true);
const json = reportJson(id); const json = reportJson(id);
if (json) { if (json) {
setActions(json.actions); setActions(json.actions);
setHeading(json.heading);
setReportName(json.reportName); setReportName(json.reportName);
const { className, params, keys, orderBy } = json;
Parse.serverURL = localStorage.getItem("BaseUrl12"); Parse.serverURL = localStorage.getItem("BaseUrl12");
Parse.initialize(localStorage.getItem("AppID12")); Parse.initialize(localStorage.getItem("AppID12"));
const currentUser = Parse.User.current().id; const currentUser = Parse.User.current().id;
const serverURL =
localStorage.getItem("BaseUrl12") + "classes/" + className;
const strParams = JSON.stringify(params);
const strKeys = keys.join();
const headers = { const headers = {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("AppID12"), "X-Parse-Application-Id": localStorage.getItem("AppID12"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken") sessiontoken: localStorage.getItem("accesstoken")
}; };
try { try {
const url = `${serverURL}?where=${strParams}&keys=${strKeys}&order=${orderBy}&include=AuditTrail.UserPtr`; const params = { reportId: id, skip: skipUserRecord, limit: limit };
const res = await axios.get(url, { headers: headers }); const url = `${localStorage.getItem("BaseUrl12")}/functions/getReport`;
const res = await axios.post(url, params, {
headers: headers,
signal: abortController.signal // is used to cancel fetch query
});
if (id === "4Hhwbp482K") { if (id === "4Hhwbp482K") {
const listData = res.data?.results.filter( const listData = res.data?.result.filter((x) => x.Signers.length > 0);
(x) => x.Signers.length > 0
);
let arr = []; let arr = [];
for (const obj of listData) { for (const obj of listData) {
const isSigner = obj.Signers.some( const isSigner = obj.Signers.some(
@@ -66,14 +89,34 @@ const Report = () => {
} }
} }
} }
setList(arr); if (arr.length === docPerPage) {
setIsMoreDocs(true);
} else {
setIsMoreDocs(false);
}
setList((prevRecord) =>
prevRecord.length > 0 ? [...prevRecord, ...arr] : arr
);
} else { } else {
setList(res.data?.results); 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); setIsLoader(false);
} catch (err) { } catch (err) {
console.log("err ", err); const isCancel = axios.isCancel(err);
setIsLoader(false); if (!isCancel) {
console.log("err ", err);
setIsLoader(false);
}
} }
} else { } else {
setIsLoader(false); setIsLoader(false);
@@ -105,7 +148,12 @@ const Report = () => {
<ReportTable <ReportTable
ReportName={reportName} ReportName={reportName}
List={List} List={List}
setList={setList}
actions={actions} actions={actions}
heading={heading}
setIsNextRecord={setIsNextRecord}
isMoreDocs={isMoreDocs}
docPerPage={docPerPage}
/> />
) : ( ) : (
<div className="flex items-center justify-center h-screen w-full bg-white rounded"> <div className="flex items-center justify-center h-screen w-full bg-white rounded">
+187 -113
View File
@@ -6,8 +6,10 @@ import Title from "../components/Title";
import { fetchAppInfo, showTenantName } from "../redux/actions"; import { fetchAppInfo, showTenantName } from "../redux/actions";
import { useNavigate, NavLink } from "react-router-dom"; import { useNavigate, NavLink } from "react-router-dom";
import login_img from "../assets/images/login_img.svg"; import login_img from "../assets/images/login_img.svg";
import { useWindowSize } from "../hook/useWindowSize";
const Signup = (props) => { const Signup = (props) => {
const { width } = useWindowSize();
const navigate = useNavigate(); const navigate = useNavigate();
const [name, setName] = useState(""); const [name, setName] = useState("");
const [phone, setPhone] = useState(""); const [phone, setPhone] = useState("");
@@ -18,93 +20,143 @@ const Signup = (props) => {
const [company, setCompany] = useState(""); const [company, setCompany] = useState("");
const [jobTitle, setJobTitle] = useState(""); const [jobTitle, setJobTitle] = useState("");
const [state, setState] = useState({ const [state, setState] = useState({
hideNav: "",
loading: false, loading: false,
toastColor: "#5cb85c", toastColor: "#5cb85c",
toastDescription: "" toastDescription: ""
}); });
const [showPassword, setShowPassword] = useState(false); const [showPassword, setShowPassword] = useState(false);
const [lengthValid, setLengthValid] = useState(false);
const [caseDigitValid, setCaseDigitValid] = useState(false);
const [specialCharValid, setSpecialCharValid] = useState(false);
const togglePasswordVisibility = () => setShowPassword(!showPassword); const togglePasswordVisibility = () => setShowPassword(!showPassword);
const image = props.appInfo.applogo; const image = props.appInfo.applogo;
const handleSubmit = (event) => { const clearStorage = async () => {
setState({ loading: true }); if (Parse.User.current()) {
const userDetails = { await Parse.User.logOut();
name: name, }
email: email, let baseUrl = localStorage.getItem("BaseUrl12");
phone: phone, let appid = localStorage.getItem("AppID12");
company: company, let applogo = localStorage.getItem("appLogo");
jobTitle: jobTitle let domain = localStorage.getItem("domain");
}; let appversion = localStorage.getItem("appVersion");
localStorage.setItem("userDetails", JSON.stringify(userDetails)); let appTitle = localStorage.getItem("appTitle");
try { let defaultmenuid = localStorage.getItem("defaultmenuid");
event.preventDefault(); let PageLanding = localStorage.getItem("PageLanding");
Parse.serverURL = parseBaseUrl; let _appName = localStorage.getItem("_appName");
Parse.initialize(parseAppId); let _app_objectId = localStorage.getItem("_app_objectId");
event.preventDefault(); let appName = localStorage.getItem("appName");
var user = new Parse.User(); let userSettings = localStorage.getItem("userSettings");
user.set("name", name);
user.set("email", email);
user.set("password", password);
user.set("phone", phone);
user.set("username", email);
let res = user.save();
res
.then(async (r) => {
if (r) {
let roleurl = `${parseBaseUrl}functions/AddUserToRole`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessionToken:
r.getSessionToken() || localStorage.getItem("accesstoken")
};
let body = {
appName: props.appInfo.appname,
roleName: props.appInfo.defaultRole,
userId: r.id
};
await axios.post(roleurl, body, { headers: headers });
let roleData = props.appInfo.settings; localStorage.clear();
if (roleData && roleData.length > 0) {
roleData.forEach((rld) => { localStorage.setItem("BaseUrl12", baseUrl);
if (rld.role === props.appInfo.defaultRole) { localStorage.setItem("AppID12", appid);
const extCls = Parse.Object.extend(rld.extended_class); localStorage.setItem("appLogo", applogo);
const newObj = new extCls(); localStorage.setItem("domain", domain);
newObj.set("UserId", { localStorage.setItem("appversion", appversion);
__type: "Pointer", localStorage.setItem("appTitle", appTitle);
className: "_User", localStorage.setItem("defaultmenuid", defaultmenuid);
objectId: r.id localStorage.setItem("PageLanding", PageLanding);
}); localStorage.setItem("_appName", _appName);
newObj.set("UserRole", props.appInfo.defaultRole); localStorage.setItem("_app_objectId", _app_objectId);
newObj.set("Email", email); localStorage.setItem("appName", appName);
newObj.set("Name", name); localStorage.setItem("userSettings", userSettings);
newObj.set("Phone", phone); localStorage.setItem("baseUrl", baseUrl);
newObj.set("Company", company); localStorage.setItem("parseAppId", appid);
newObj.set("JobTitle", jobTitle); };
newObj const handleSubmit = (event) => {
.save() event.preventDefault();
.then((ex) => { if (lengthValid && caseDigitValid && specialCharValid) {
if (ex) { clearStorage();
handleNavigation(r.getSessionToken()); setState({ loading: true });
} const userDetails = {
}) name: name,
.catch((err) => { email: email,
alert(err.message); phone: phone,
setState({ loading: false }); company: company,
}); jobTitle: jobTitle
};
localStorage.setItem("userDetails", JSON.stringify(userDetails));
try {
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
event.preventDefault();
var user = new Parse.User();
user.set("name", name);
user.set("email", email);
user.set("password", password);
user.set("phone", phone);
user.set("username", email);
let res = user.save();
res
.then(async (r) => {
if (r) {
let roleData = props.appInfo.settings;
if (roleData && roleData.length > 0) {
const params = {
userDetails: {
jobTitle: jobTitle,
company: company,
name: name,
email: email,
phone: phone,
role: props.appInfo.defaultRole
}
};
try {
const usersignup = await Parse.Cloud.run(
"usersignup",
params
);
if (usersignup) {
handleNavigation(r.getSessionToken());
}
} catch (err) {
alert(err.message);
setState({ loading: false });
} }
}); }
} }
} })
}) .catch(async (err) => {
.catch((err) => { if (err.code === 202) {
alert(err.message); const params = { email: email };
setState({ loading: false }); const res = await Parse.Cloud.run("getUserDetails", params);
}); // console.log("Res ", res);
} catch (error) { if (res) {
console.log("err ", error); alert("User already exists with this username!");
setState({ loading: false });
} else {
let baseUrl = localStorage.getItem("BaseUrl12");
let parseAppId = localStorage.getItem("AppID12");
// console.log("state.email ", email);
try {
Parse.serverURL = baseUrl;
Parse.initialize(parseAppId);
await Parse.User.requestPasswordReset(email).then(
async function (res1) {
if (res1.data === undefined) {
alert(
"Verification mail has been sent to your E-mail!"
);
}
}
);
} catch (err) {
console.log(err);
}
setState({ loading: false });
}
} else {
alert(err.message);
setState({ loading: false });
}
});
} catch (error) {
console.log("err ", error);
}
} }
}; };
@@ -179,13 +231,6 @@ const Signup = (props) => {
"" ""
); );
localStorage.setItem("_user_role", _role); localStorage.setItem("_user_role", _role);
if (element.enableCart) {
localStorage.setItem("EnableCart", element.enableCart);
props.setEnableCart(element.enableCart);
} else {
localStorage.removeItem("EnableCart");
}
// Get TenentID from Extendend Class // Get TenentID from Extendend Class
localStorage.setItem( localStorage.setItem(
"extended_class", "extended_class",
@@ -193,15 +238,12 @@ const Signup = (props) => {
); );
localStorage.setItem("userpointer", element.userpointer); localStorage.setItem("userpointer", element.userpointer);
const extendedClass = Parse.Object.extend( await Parse.Cloud.run("getUserDetails", {
element.extended_class email: email
); }).then(
let query = new Parse.Query(extendedClass); (result) => {
query.equalTo("UserId", Parse.User.current());
query.include("TenantId");
await query.find().then(
(results) => {
let tenentInfo = []; let tenentInfo = [];
const results = [result];
if (results) { if (results) {
let extendedInfo_stringify = let extendedInfo_stringify =
JSON.stringify(results); JSON.stringify(results);
@@ -251,7 +293,7 @@ const Signup = (props) => {
element.pageType element.pageType
); );
setState({ loading: false }); setState({ loading: false });
navigate("/login"); navigate("/");
} else { } else {
extendedInfo.forEach((x) => { extendedInfo.forEach((x) => {
if (x.TenantId) { if (x.TenantId) {
@@ -289,7 +331,7 @@ const Signup = (props) => {
); );
setState({ loading: false }); setState({ loading: false });
if (process.env.REACT_APP_ENABLE_SUBSCRIPTION) { if (process.env.REACT_APP_ENABLE_SUBSCRIPTION) {
navigate("/subscription"); navigate(`/subscription`, { replace: true });
} else { } else {
alert("Registered user successfully"); alert("Registered user successfully");
navigate( navigate(
@@ -307,7 +349,7 @@ const Signup = (props) => {
localStorage.setItem("pageType", element.pageType); localStorage.setItem("pageType", element.pageType);
setState({ loading: false }); setState({ loading: false });
if (process.env.REACT_APP_ENABLE_SUBSCRIPTION) { if (process.env.REACT_APP_ENABLE_SUBSCRIPTION) {
navigate("/subscription"); navigate(`/subscription`, { replace: true });
} else { } else {
navigate( navigate(
`/${element.pageType}/${element.pageId}` `/${element.pageType}/${element.pageId}`
@@ -392,23 +434,26 @@ const Signup = (props) => {
} }
}; };
useEffect(() => { useEffect(() => {
window.addEventListener("resize", resize);
props.fetchAppInfo( props.fetchAppInfo(
localStorage.getItem("domain"), localStorage.getItem("domain"),
localStorage.getItem("BaseUrl12"), localStorage.getItem("BaseUrl12"),
localStorage.getItem("AppID12") localStorage.getItem("AppID12")
); );
return () => {
window.removeEventListener("resize", resize);
};
// eslint-disable-next-line // eslint-disable-next-line
}, []); }, []);
const resize = () => { const handlePasswordChange = (e) => {
let currentHideNav = window.innerWidth <= 760; const newPassword = e.target.value;
if (currentHideNav !== state.hideNav) { setPassword(newPassword);
setState({ hideNav: currentHideNav });
} // Check conditions separately
setLengthValid(newPassword.length >= 8);
setCaseDigitValid(
/[a-z]/.test(newPassword) &&
/[A-Z]/.test(newPassword) &&
/\d/.test(newPassword)
);
setSpecialCharValid(/[!@#$%^&*()\-_=+{};:,<.>]/.test(newPassword));
}; };
return ( return (
<div className="bg-white"> <div className="bg-white">
@@ -443,17 +488,13 @@ const Signup = (props) => {
<div> <div>
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 "> <div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
<div className="w-[250px] h-[66px] inline-block"> <div className="w-[250px] h-[66px] inline-block">
{state.hideNav ? ( <img src={image} width="100%" alt="" />
<img src={image} width="100%" alt="" />
) : (
<img src={image} width="100%" alt="" />
)}
</div> </div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-2"> <div className="grid grid-cols-1 md:grid-cols-2 gap-x-2">
<div className=""> <div className="">
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<h2 className="text-[30px] mt-6">Create Account !</h2> <h2 className="text-[30px] mt-6">Create Account !</h2>
<div className="shadow-md rounded my-4"> <div className="outline outline-1 outline-slate-300/50 shadow-md rounded my-4">
<div className="px-6 py-4 text-xs"> <div className="px-6 py-4 text-xs">
<label className="block "> <label className="block ">
Name{" "} Name{" "}
@@ -472,6 +513,7 @@ const Signup = (props) => {
<span style={{ color: "red", fontSize: 13 }}>*</span> <span style={{ color: "red", fontSize: 13 }}>*</span>
</label> </label>
<input <input
id="email"
type="text" type="text"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
value={email} value={email}
@@ -525,7 +567,7 @@ const Signup = (props) => {
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs" className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
name="password" name="password"
value={password} value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(e) => handlePasswordChange(e)}
required required
/> />
<span <span
@@ -541,6 +583,38 @@ const Signup = (props) => {
)} )}
</span> </span>
</div> </div>
{password.length > 0 && (
<div className="mt-1 text-[11px]">
<p
className={`${
lengthValid ? "text-green-600" : "text-red-600"
}`}
>
{lengthValid ? "✓" : "✗"} Password should be 8
characters long
</p>
<p
className={`${
caseDigitValid ? "text-green-600" : "text-red-600"
}`}
>
{caseDigitValid ? "✓" : "✗"} Password should contain
uppercase letter, lowercase letter, digit
</p>
<p
className={`${
specialCharValid
? "text-green-600"
: "text-red-600"
}`}
>
{specialCharValid ? "✓" : "✗"} Password should
contain special character
</p>
{/* </>
)} */}
</div>
)}
</div> </div>
</div> </div>
<div className="flex flex-col md:flex-row justify-between items-stretch gap-8 text-center text-xs font-bold mt-2"> <div className="flex flex-col md:flex-row justify-between items-stretch gap-8 text-center text-xs font-bold mt-2">
@@ -554,16 +628,16 @@ const Signup = (props) => {
<NavLink <NavLink
className="rounded-sm cursor-pointer bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] w-full py-3 shadow uppercase" className="rounded-sm cursor-pointer bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] w-full py-3 shadow uppercase"
to="/" to="/"
style={state.hideNav ? { textAlign: "center" } : {}} style={width < 768 ? { textAlign: "center" } : {}}
> >
Login Login
</NavLink> </NavLink>
</div> </div>
</form> </form>
</div> </div>
{!state.hideNav && ( {width >= 768 && (
<div className="self-center"> <div className="self-center">
<div className="mx-auto md:w-[300px] lg:w-[500px]"> <div className="mx-auto md:w-[300px] lg:w-[400px] xl:w-[500px]">
<img src={login_img} alt="bisec" width="100%" /> <img src={login_img} alt="bisec" width="100%" />
</div> </div>
</div> </div>
+59 -31
View File
@@ -5,7 +5,7 @@ import { SaveFileSize } from "../constant/saveFileSize";
import dp from "../assets/images/dp.png"; import dp from "../assets/images/dp.png";
import Title from "../components/Title"; import Title from "../components/Title";
import sanitizeFileName from "../primitives/sanitizeFileName"; import sanitizeFileName from "../primitives/sanitizeFileName";
import axios from "axios";
function UserProfile() { function UserProfile() {
const navigate = useNavigate(); const navigate = useNavigate();
let UserProfile = JSON.parse(localStorage.getItem("UserInformation")); let UserProfile = JSON.parse(localStorage.getItem("UserInformation"));
@@ -16,6 +16,8 @@ function UserProfile() {
const [Phone, SetPhone] = useState(UserProfile && UserProfile.phone); const [Phone, SetPhone] = useState(UserProfile && UserProfile.phone);
const [Image, setImage] = useState(localStorage.getItem("profileImg")); const [Image, setImage] = useState(localStorage.getItem("profileImg"));
const [isLoader, setIsLoader] = useState(false); const [isLoader, setIsLoader] = useState(false);
const [percentage, setpercentage] = useState(0);
Parse.serverURL = parseBaseUrl; Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId); Parse.initialize(parseAppId);
const handleSubmit = async (e) => { const handleSubmit = async (e) => {
@@ -44,7 +46,7 @@ function UserProfile() {
await updateExtUser({ Name: res.name, Phone: res.phone }); await updateExtUser({ Name: res.name, Phone: res.phone });
alert("Profile updated successfully."); alert("Profile updated successfully.");
setEditMode(false); setEditMode(false);
navigate("/"); navigate("/dashboard/35KBoSgoAK");
} }
}, },
(error) => { (error) => {
@@ -64,18 +66,24 @@ function UserProfile() {
const extClass = localStorage.getItem("extended_class"); const extClass = localStorage.getItem("extended_class");
const extData = JSON.parse(localStorage.getItem("Extand_Class")); const extData = JSON.parse(localStorage.getItem("Extand_Class"));
const ExtUserId = extData[0].objectId; const ExtUserId = extData[0].objectId;
// console.log("extData ", extData);
// console.log("UserId ", ExtUserId); // console.log("UserId ", ExtUserId);
const body = { Phone: obj.Phone, Name: obj.Name };
await axios.put(
parseBaseUrl + "classes/" + extClass + "/" + ExtUserId,
body,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
);
const res = await Parse.Cloud.run("getUserDetails", {
email: extData[0].Email
});
const extQuery = new Parse.Query(extClass); const json = JSON.parse(JSON.stringify([res]));
const update = await extQuery.get(ExtUserId);
// console.log("update ", update);
update.set("Phone", obj.Phone);
update.set("Name", obj.Name);
const updateRes = await update.save();
const json = JSON.parse(JSON.stringify([updateRes]));
const extRes = JSON.stringify(json); const extRes = JSON.stringify(json);
localStorage.setItem("Extand_Class", extRes); localStorage.setItem("Extand_Class", extRes);
@@ -96,7 +104,15 @@ function UserProfile() {
const parseFile = new Parse.File(name, pdfFile); const parseFile = new Parse.File(name, pdfFile);
try { try {
const response = await parseFile.save(); const response = await parseFile.save({
progress: (progressValue, loaded, total, { type }) => {
if (type === "upload" && progressValue !== null) {
const percentCompleted = Math.round((loaded * 100) / total);
// console.log("percentCompleted ", percentCompleted);
setpercentage(percentCompleted);
}
}
});
// // The response object will contain information about the uploaded file // // The response object will contain information about the uploaded file
// console.log("File uploaded:", response); // console.log("File uploaded:", response);
@@ -105,6 +121,7 @@ function UserProfile() {
if (response.url()) { if (response.url()) {
setImage(response.url()); setImage(response.url());
localStorage.setItem("profileImg", response.url()); localStorage.setItem("profileImg", response.url());
setpercentage(0);
SaveFileSize(size, response.url()); SaveFileSize(size, response.url());
return response.url(); return response.url();
} }
@@ -154,14 +171,25 @@ function UserProfile() {
<input <input
type="file" type="file"
className="max-w-[270px] text-sm py-1 px-2 mt-4 border-[1px] border-[#15b4e9] text-black rounded" className="max-w-[270px] text-sm py-1 px-2 mt-4 border-[1px] border-[#15b4e9] text-black rounded"
accept="image/png, image/gif, image/jpeg"
onChange={(e) => { onChange={(e) => {
let files = e.target.files; let files = e.target.files;
fileUpload(files[0]); fileUpload(files[0]);
}} }}
/> />
)} )}
{percentage !== 0 && (
<div className="flex items-center gap-x-2">
<div className="h-2 rounded-full w-[200px] md:w-[400px] bg-gray-200">
<div
className="h-2 rounded-full bg-blue-500"
style={{ width: `${percentage}%` }}
></div>
</div>
<span className="text-black text-sm">{percentage}%</span>
</div>
)}
<div className="text-base font-semibold pt-4"> <div className="text-base font-semibold pt-4">
{" "}
{localStorage.getItem("_user_role")} {localStorage.getItem("_user_role")}
</div> </div>
</div> </div>
@@ -214,26 +242,11 @@ function UserProfile() {
</li> </li>
</ul> </ul>
<div className="flex justify-center pb-4"> <div className="flex justify-center pb-4">
<button
type="button"
onClick={() => {
if (editmode) {
setEditMode(false);
} else {
navigate("/changepassword");
}
}}
className={`rounded shadow text-white bg-[#3598dc] mr-4 ${
editmode ? "px-4 py-2 " : "p-2"
}`}
>
{editmode ? "Cancel" : "Change Password"}
</button>
{editmode ? ( {editmode ? (
<button <button
type="button" type="button"
onClick={handleSubmit} onClick={handleSubmit}
className="rounded bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] px-4 py-2" className="rounded bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] px-4 py-2 mr-4"
> >
Save Save
</button> </button>
@@ -243,11 +256,26 @@ function UserProfile() {
onClick={() => { onClick={() => {
setEditMode(true); setEditMode(true);
}} }}
className="rounded shadow text-white bg-[#e7505a] px-4 py-2" className="rounded shadow text-white bg-[#e7505a] px-4 py-2 mr-4"
> >
Edit Edit
</button> </button>
)} )}
<button
type="button"
onClick={() => {
if (editmode) {
setEditMode(false);
} else {
navigate("/changepassword");
}
}}
className={`rounded shadow text-white bg-[#3598dc] ${
editmode ? "px-4 py-2 " : "p-2"
}`}
>
{editmode ? "Cancel" : "Change Password"}
</button>
</div> </div>
</div> </div>
)} )}
+29 -9
View File
@@ -1,12 +1,14 @@
/* Full-width input fields */ /* Full-width input fields */
.inputt { .inputt {
width: 100%; width: 100%;
padding: 15px; padding: 8px;
margin: 5px 0 22px 0; margin-bottom: 10px;
/* margin: 5px 0 14px 0; */
display: inline-block; display: inline-block;
border: none; border: none;
background: #f1f1f1; background: #f1f1f1;
color: black; color: black;
font-size: 12px;
} }
/* Add a background color when the inputs get focus */ /* Add a background color when the inputs get focus */
@@ -18,11 +20,12 @@
.confirmInputt { .confirmInputt {
width: 100%; width: 100%;
padding: 15px; padding: 8px;
margin: 5px 0 1px 0; /* margin: 5px 0 14px 0; */
display: inline-block; display: inline-block;
background: #f1f1f1; background: #f1f1f1;
color: black; color: black;
font-size: 12px;
} }
.inputt::placeholder, .inputt::placeholder,
@@ -42,11 +45,10 @@
.signupbtn { .signupbtn {
background-color: #15b4e9; background-color: #15b4e9;
color: white; color: white;
padding: 14px 20px; padding: 12px 12px;
margin: 8px 0; margin: 8px 0;
border: none; border: none;
cursor: pointer; cursor: pointer;
width: 100%;
opacity: 0.9; opacity: 0.9;
float: left; float: left;
width: 50%; width: 50%;
@@ -87,7 +89,7 @@
margin: 5% auto 15% auto; margin: 5% auto 15% auto;
/* 5% from the top, 15% from the bottom and centered */ /* 5% from the top, 15% from the bottom and centered */
border: 1px solid #888; border: 1px solid #888;
width: 80%; width: 50%;
/* Could be more or less, depending on screen size */ /* Could be more or less, depending on screen size */
} }
@@ -111,8 +113,26 @@
} }
/* Change styles for cancel button and signup button on extra small screens */ /* Change styles for cancel button and signup button on extra small screens */
@media screen and (max-width: 300px) { @media screen and (max-width: 768px) {
/* pgsignup Content/Box */
.pgsignup-content {
background-color: #fefefe;
margin: 5% auto 15% auto;
/* 5% from the top, 15% from the bottom and centered */
border: 1px solid #888;
width: 90%;
/* Could be more or less, depending on screen size */
}
.signupbtn { .signupbtn {
width: 100%; width: 100%;
font-size: 16px;
} }
}
/* Style the horizontal ruler */
.hrt {
border: 1px solid #f1f1f1;
margin-bottom: 16px;
}
}
+36
View File
@@ -0,0 +1,36 @@
.alertBox {
z-index: 1;
position: absolute;
top: 10%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 13px;
animation: inAnimation 2s ease-in-out;
}
@keyframes inAnimation {
0% {
opacity: 0;
visibility: hidden;
}
25% {
opacity: 1;
visibility: visible;
}
50% {
opacity: 1;
visibility: visible;
}
75% {
opacity: 1;
visibility: visible;
}
100% {
opacity: 0;
visibility: hidden;
}
}
@@ -4,6 +4,12 @@ import multerS3 from 'multer-s3';
import aws from 'aws-sdk'; import aws from 'aws-sdk';
import dotenv from 'dotenv'; import dotenv from 'dotenv';
dotenv.config(); dotenv.config();
function sanitizeFileName(fileName) {
// Remove spaces and invalid characters
return fileName.replace(/[^a-zA-Z0-9._-]/g, '');
}
async function uploadFile(req, res) { async function uploadFile(req, res) {
try { try {
//--size extended to 100 mb //--size extended to 100 mb
@@ -50,16 +56,28 @@ async function uploadFile(req, res) {
region: process.env.DO_REGION, region: process.env.DO_REGION,
}); });
// const s3 = new aws.S3(); const parseBaseUrl = process.env.SERVER_URL;
const upload = multer({ const parseAppId = process.env.APP_ID;
fileFilter: function (req, file, cb) {
if (accepted_extensions.some(ext => file.originalname.toLowerCase().endsWith('.' + ext))) { if (process.env.USE_LOCAL == "TRUE") {
return cb(null, true); var fileStorage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, "files/files");
},
metadata: function (req, file, cb) {
cb(null, { fieldName: 'OPENSIGN_METADATA' });
},
filename: function(req, file, cb) {
let filename = file.originalname;
let newFileName = filename.split('.')[0];
let extension = filename.split('.')[1];
newFileName = sanitizeFileName(newFileName + '_' + new Date().toISOString() + '.' + extension)
console.log(newFileName);
cb(null, newFileName);
} }
// otherwise, return error });
return cb('Only ' + accepted_extensions.join(', ') + ' files are allowed!'); } else {
}, var fileStorage = multerS3({
storage: multerS3({
acl: 'public-read', acl: 'public-read',
s3, s3,
bucket: DO_SPACE, bucket: DO_SPACE,
@@ -69,14 +87,25 @@ async function uploadFile(req, res) {
key: function (req, file, cb) { key: function (req, file, cb) {
//console.log(file); //console.log(file);
let filename = file.originalname; let filename = file.originalname;
let filenam = filename.split('.')[0]; let newFileName = filename.split('.')[0];
let extension = filename.split('.')[1]; let extension = filename.split('.')[1];
filenam = filenam + '_' + new Date().toISOString() + '.' + extension; newFileName = sanitizeFileName(newFileName + '_' + new Date().toISOString() + '.' + extension)
console.log(filenam); console.log(newFileName);
cb(null, filenam); cb(null, newFileName);
}, }
}), });
}
// const s3 = new aws.S3();
const upload = multer({
fileFilter: function (req, file, cb) {
if (accepted_extensions.some(ext => file.originalname.toLowerCase().endsWith('.' + ext))) {
return cb(null, true);
}
// otherwise, return error
return cb('Only ' + accepted_extensions.join(', ') + ' files are allowed!');
},
storage: fileStorage,
limits: { fileSize: size }, limits: { fileSize: size },
}).single('file'); }).single('file');
@@ -93,7 +122,14 @@ async function uploadFile(req, res) {
const status = 'Success'; const status = 'Success';
//res.header("Access-Control-Allow-Headers", "Content-Type"); //res.header("Access-Control-Allow-Headers", "Content-Type");
//res.setHeader("Access-Control-Allow-Origin", "*"); //res.setHeader("Access-Control-Allow-Origin", "*");
return res.json({ status, imageUrl: req.file.location }); if (process.env.USE_LOCAL == "TRUE") {
console.log(req.file);
var fileUrl = `${parseBaseUrl}/files/${parseAppId}/${req.file.filename}`;
} else {
var fileUrl = req.file.location;
}
return res.json({ status, imageUrl: fileUrl });
}); });
} catch (err) { } catch (err) {
console.log('Exeption in query ' + err.stack); console.log('Exeption in query ' + err.stack);
+8
View File
@@ -13,6 +13,10 @@ import sendMailOTPv1 from './parsefunction/SendMailOTPv1.js';
import SendMailv1 from './parsefunction/SendMailv1.js'; import SendMailv1 from './parsefunction/SendMailv1.js';
import AuthLoginAsMail from './parsefunction/AuthLoginAsMail.js'; import AuthLoginAsMail from './parsefunction/AuthLoginAsMail.js';
import getUserId from './parsefunction/getUserId.js'; import getUserId from './parsefunction/getUserId.js';
import getUserDetails from './parsefunction/getUserDetails.js';
import getDocument from './parsefunction/getDocument.js';
import getDrive from './parsefunction/getDrive.js';
import getReport from './parsefunction/getReport.js';
Parse.Cloud.define('AddUserToRole', addUserToGroups); Parse.Cloud.define('AddUserToRole', addUserToGroups);
Parse.Cloud.define('UserGroups', getUserGroups); Parse.Cloud.define('UserGroups', getUserGroups);
@@ -29,3 +33,7 @@ Parse.Cloud.define('SendOTPMailV1', sendMailOTPv1);
Parse.Cloud.define('sendmail', SendMailv1); Parse.Cloud.define('sendmail', SendMailv1);
Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail); Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail);
Parse.Cloud.define('getUserId', getUserId); Parse.Cloud.define('getUserId', getUserId);
Parse.Cloud.define('getUserDetails', getUserDetails);
Parse.Cloud.define('getDocument', getDocument);
Parse.Cloud.define('getDrive', getDrive)
Parse.Cloud.define('getReport', getReport)
@@ -16,6 +16,7 @@ async function ContactbookAftersave(request) {
acl.setWriteAccess(object.get('UserId'), true); acl.setWriteAccess(object.get('UserId'), true);
object.setACL(acl); object.setACL(acl);
object.set('IsDeleted', false)
// Continue saving the object // Continue saving the object
return object.save(null, { useMasterKey: true }); return object.save(null, { useMasterKey: true });
} }
@@ -5,7 +5,7 @@ async function SendMailv1(request) {
const recipient = request.params.email; const recipient = request.params.email;
const otp = request.params.otp; const otp = request.params.otp;
const res = await Parse.Cloud.sendEmail({ const res = await Parse.Cloud.sendEmail({
from: 'Test user' + ' <' + process.env.MAILGUN_SENDER + '>', from: 'Test user' + ' <' + process.env.SMTP_ENABLE ? process.env.SMTP_USER_EMAIL : process.env.MAILGUN_SENDER + '>',
recipient: recipient, recipient: recipient,
subject: 'Your OpenSign™ OTP', subject: 'Your OpenSign™ OTP',
text: 'This email is a test.', text: 'This email is a test.',
@@ -46,15 +46,20 @@ export default async function ZohoDetails(request) {
(userData.data.data.subscription.customer && (userData.data.data.subscription.customer &&
userData.data.data.subscription.customer.company_name) || userData.data.data.subscription.customer.company_name) ||
''; '';
const jobTitle =
(userData.data.data.subscription.customer &&
userData.data.data.subscription.customer.cd_job_title) ||
'';
const resData = { const resData = {
phone: userData.data.data.subscription.contactpersons[0].mobile, phone: userData.data.data.subscription.contactpersons[0].mobile,
name: first_name + ' ' + last_name, name: first_name + ' ' + last_name,
email: userData.data.data.subscription.contactpersons[0].email, email: userData.data.data.subscription.contactpersons[0].email,
nextBillingDate: userData.data.expiring_time, nextBillingDate: userData.data.data.subscription.next_billing_at,
company: company_name, company: company_name,
plan: userData.data.data.subscription.plan, plan: userData.data.data.subscription.plan,
customer_id: userData.data.data.subscription.customer_id, customer_id: userData.data.data.subscription.customer_id,
subscription_id: userData.data.data.subscription.subscription_id, subscription_id: userData.data.data.subscription.subscription_id,
jobTitle: jobTitle,
}; };
return resData; return resData;
} }
@@ -0,0 +1,50 @@
import axios from 'axios';
export default async function getDocument(request) {
const serverUrl = process.env.SERVER_URL;
const docId = request.params.docId;
try {
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
const userId = userRes.data && userRes.data.objectId;
if (docId && userId) {
try {
const query = new Parse.Query('contracts_Document');
query.equalTo('objectId', docId);
query.include('ExtUserPtr');
query.include('CreatedBy');
query.include('Signers');
query.include('AuditTrail.UserPtr');
query.include('Placeholders');
const res = await query.first({ useMasterKey: true });
if (res) {
const acl = res.getACL();
if (acl && acl.getReadAccess(userId)) {
return res;
} else {
return { error: "You don't have access of this document!" };
}
} else {
return { error: "You don't have access of this document!" };
}
} catch (err) {
console.log('err', err);
return err;
}
} else {
return { error: 'Please pass required parameters!' };
}
} catch (err) {
console.log('err');
if (err.code == 209) {
return { error: 'Invalid session token' };
} else {
return { error: "You don't have access of this document!" };
}
}
}
@@ -0,0 +1,51 @@
import axios from 'axios';
export default async function getDrive(request) {
const serverUrl = process.env.SERVER_URL;
const appId = process.env.APP_ID;
const classUrl = serverUrl + '/classes/contracts_Document';
const docId = request.params.docId;
try {
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': appId,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
const userId = userRes.data && userRes.data.objectId;
if (userId) {
let url;
if (docId) {
url = `${classUrl}?where={"Folder":{"__type":"Pointer","className":"contracts_Document","objectId":"${docId}"},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"}}&include=ExtUserPtr,Signers,Folder`;
} else {
url = `${classUrl}?where={"Folder":{"$exists":false},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"}}&include=ExtUserPtr,Signers`;
}
try {
const res = await axios.get(url, {
headers: {
'X-Parse-Application-Id': appId,
'X-Parse-Master-key': process.env.MASTER_KEY,
},
});
// console.log('res.data.results ', res.data.results);
if (res.data && res.data.results) {
return res.data.results;
} else {
return [];
}
} catch (err) {
console.log('err', err);
return { error: "You don't have access to drive" };
}
} else {
return { error: 'Please provide required parameter!' };
}
} catch (err) {
console.log('err', err);
if (err.code == 209) {
return { error: 'Invalid session token' };
} else {
return { error: "You don't have access!" };
}
}
}
@@ -0,0 +1,52 @@
import reportJson from './reportsJson.js';
import axios from 'axios';
export default async function getReport(request) {
const reportId = request.params.reportId;
const limit = request.params.limit;
const skip = request.params.skip;
const serverUrl = process.env.SERVER_URL;
const appId = process.env.APP_ID;
try {
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': appId,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
const userId = userRes.data && userRes.data.objectId;
if (userId) {
const json = reportId && reportJson(reportId, userId);
const clsName = reportId === '5KhaPr482K' ? 'contracts_Contactbook' : 'contracts_Document';
if (json) {
const { params, keys } = json;
const orderBy = '-updatedAt';
const strParams = JSON.stringify(params);
const strKeys = keys.join();
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': appId,
'X-Parse-Master-Key': process.env.MASTER_KEY,
};
const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`;
const res = await axios.get(url, { headers: headers });
if (res.data && res.data.results) {
return res.data.results;
} else {
return [];
}
} else {
return { error: 'Report is not available!' };
}
}
} catch (err) {
console.log('err', err);
if (err.code == 209) {
return { error: 'Invalid session token' };
} else {
return { error: "You don't have access!" };
}
}
}
@@ -0,0 +1,14 @@
async function getUserDetails(request) {
try {
const userQuery = new Parse.Query('contracts_Users');
userQuery.equalTo('Email', request.params.email);
userQuery.include('TenantId');
userQuery.include('UserId')
const res = await userQuery.first({ useMasterKey: true });
return res;
} catch (err) {
console.log('Err ', err);
return err;
}
}
export default getUserDetails;
+4 -4
View File
@@ -79,7 +79,7 @@ async function sendCompletedMail(e) {
url: a, url: a,
from: 'OpenSign™', from: 'OpenSign™',
recipient: e.receiver, recipient: e.receiver,
subject: `Document ${s} has beeen signed by all parties`, subject: `Document ${s} has been signed by all parties`,
pdfName: s, pdfName: s,
html: html:
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=https://qikinnovation.ams3.digitaloceanspaces.com/logo.png height='50' style='padding:20px'/> </div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document sign successfully</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>All parties have successfully signed the document" + "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=https://qikinnovation.ams3.digitaloceanspaces.com/logo.png height='50' style='padding:20px'/> </div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document sign successfully</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>All parties have successfully signed the document" +
@@ -105,7 +105,7 @@ async function PDF(s, r) {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-Parse-Application-Id': APPID, 'X-Parse-Application-Id': APPID,
'X-Parse-Session-Token': s.headers.sessiontoken, 'X-Parse-Master-Key': masterKEY,
}, },
}), }),
d = await axios.get(serverUrl + '/users/me', { d = await axios.get(serverUrl + '/users/me', {
@@ -132,7 +132,7 @@ async function PDF(s, r) {
: ((a = await axios.get(serverUrl + '/classes/contracts_Users?where=' + m, { : ((a = await axios.get(serverUrl + '/classes/contracts_Users?where=' + m, {
headers: { headers: {
'X-Parse-Application-Id': APPID, 'X-Parse-Application-Id': APPID,
'X-Parse-Session-Token': s.headers.sessiontoken, 'X-Parse-Master-Key': masterKEY,
}, },
})), })),
'contracts_Users') 'contracts_Users')
@@ -142,7 +142,7 @@ async function PDF(s, r) {
(c = await axios.get(serverUrl + '/classes/contracts_Users?where=' + p, { (c = await axios.get(serverUrl + '/classes/contracts_Users?where=' + p, {
headers: { headers: {
'X-Parse-Application-Id': APPID, 'X-Parse-Application-Id': APPID,
'X-Parse-Session-Token': s.headers.sessiontoken, 'X-Parse-Master-Key': masterKEY,
}, },
})).data && 0 < c.data.results.length })).data && 0 < c.data.results.length
? ((a = c), 'contracts_Users') ? ((a = c), 'contracts_Users')
@@ -1 +1 @@
const signer=require("node-signpdf").default;class SignPDF{constructor(e,t){this.pdfDoc=e,this.certificate=t}async signPDF(){return signer.sign(this.pdfDoc,this.certificate,{passphrase:"emudhra"})}static unit8ToBuffer(e){var t=Buffer.alloc(e.byteLength),r=new Uint8Array(e);for(let e=0;e<t.length;++e)t[e]=r[e];return t}}module.exports=SignPDF; const signer=require("node-signpdf").default;class SignPDF{constructor(e,t){this.pdfDoc=e,this.certificate=t}async signPDF(){return signer.sign(this.pdfDoc,this.certificate, process.env.PASS_PHRASE ? {passphrase : process.env.PASS_PHRASE}: null)}static unit8ToBuffer(e){var t=Buffer.alloc(e.byteLength),r=new Uint8Array(e);for(let e=0;e<t.length;++e)t[e]=r[e];return t}}module.exports=SignPDF;
@@ -1,28 +1,28 @@
import{DEFAULT_BYTE_RANGE_PLACEHOLDER,DEFAULT_SIGNATURE_LENGTH,SUBFILTER_ADOBE_PKCS7_DETACHED}from"./const.min.js";import PDFKitReferenceMock from"./PDFKitReferenceMock.min.js";import PNG from"png-js";import zlib from"zlib";import fs from"node:fs";const specialCharacters=["á","Á","é","É","í","Í","ó","Ó","ö","Ö","ő","Ő","ú","Ú","ű","Ű"],MARKERS=[65472,65473,65474,65475,65477,65478,65479,65480,65481,65482,65483,65484,65485,65486,65487],COLOR_SPACE_MAP={1:"DeviceGray",3:"DeviceRGB",4:"DeviceCMYK"};function getImage(e,t){let n;if(255===e[0]&&216===e[1])n=getJpgImage(t,e);else{if(137!==e[0]||"PNG"!==e.toString("ascii",1,4))throw new Error("Unknown image format.");n=getPngImage(t,e)}return n}function getAnnotationApparance(e,t,n){return e.ref({CropBox:[0,0,197,70],Type:"XObject",FormType:1,BBox:[0,0,197,70],Resources:`<</XObject << import{DEFAULT_BYTE_RANGE_PLACEHOLDER,DEFAULT_SIGNATURE_LENGTH,SUBFILTER_ADOBE_PKCS7_DETACHED}from"./const.min.js";import PDFKitReferenceMock from"./PDFKitReferenceMock.min.js";import PNG from"png-js";import zlib from"zlib";const specialCharacters=["á","Á","é","É","í","Í","ó","Ó","ö","Ö","ő","Ő","ú","Ú","ű","Ű"],MARKERS=[65472,65473,65474,65475,65477,65478,65479,65480,65481,65482,65483,65484,65485,65486,65487],COLOR_SPACE_MAP={1:"DeviceGray",3:"DeviceRGB",4:"DeviceCMYK"};function getImage(e,t){let n;if(255===e[0]&&216===e[1])n=getJpgImage(t,e);else{if(137!==e[0]||"PNG"!==e.toString("ascii",1,4))throw new Error("Unknown image format.");n=getPngImage(t,e)}return n}function getAnnotationApparance(e,t,n){return e.ref({CropBox:[0,10,200,60],Type:"XObject",FormType:1,BBox:[0,10,200,60],Resources:`<</XObject <<
/Img${t.index} ${t.index} 0 R /Img${t.index} ${t.index} 0 R
>> >>
/Font << /Font <<
/f1 ${n.index} 0 R /f1 ${n.index} 0 R
>> >>
>>`,MediaBox:[0,0,197,70],Subtype:"Form"},null,getStream(t.index))}const getStream=e=>getConvertedText(` >>`,MediaBox:[0,10,200,60],Subtype:"Form"},null,getStream(t.index))}const getStream=e=>getConvertedText(`
1.0 1.0 1.0 rg 1.0 1.0 1.0 rg
0.0 0.0 0.0 RG 0.0 0.0 0.0 RG
q q
q q
200 0 0 50 0 10 cm 200 0 0 50 0 10 cm
/Img${e} Do /Img${e} Do
Q Q
0 0 0 rg 0 0 0 rg
BT BT
0 Tr 0 Tr
/f1 10.0 Tf /f1 10.0 Tf
1.4 0 0 1 20 45.97412 Tm 1.4 0 0 1 20 45.97412 Tm
ET ET
BT BT
0 Tr 0 Tr
/f1 10.0 Tf /f1 10.0 Tf
1.4 0 0 1 20 33.56006 Tm 1.4 0 0 1 20 33.56006 Tm
ET ET
Q`),getFont=(e,t)=>e.ref({Type:"Font",BaseFont:t,Encoding:"WinAnsiEncoding",Subtype:"Type1"}),getJpgImage=(e,t)=>{if(65496!==t.readUInt16BE(0))throw"SOI not found in JPEG";let n=2,a;for(;n<t.length&&(a=t.readUInt16BE(n),n+=2,!MARKERS.includes(a));)n+=t.readUInt16BE(n);if(!MARKERS.includes(a))throw"Invalid JPEG.";n+=2;var r=t[n++],o=t.readUInt16BE(n),i=(n+=2,t.readUInt16BE(n)),l=(n+=2,t[n++]),l=COLOR_SPACE_MAP[l],r={Type:"XObject",Subtype:"Image",BitsPerComponent:r,Width:i,Height:o,ColorSpace:l,Filter:"DCTDecode"},i=("DeviceCMYK"===l&&(r.Decode=[1,0,1,0,1,0,1,0]),e.ref(r,null,t));return i},getPngImage=(e,t)=>{var t=new PNG(t),n=t.hasAlphaChannel,a={Type:"XObject",Subtype:"Image",BitsPerComponent:n?8:t.bits,Width:t.width,Height:t.height,Filter:"FlateDecode"};if(n||(r=e.ref({Predictor:15,Colors:t.colors,BitsPerComponent:t.bits,Columns:t.width}),a.DecodeParms=r),0===t.palette.length?a.ColorSpace=t.colorSpace:(r=e.ref({stream:new Buffer(t.palette)}),a.ColorSpace=["Indexed","DeviceRGB",t.palette.length/3-1,r]),null!=t.transparency.grayscale){var r=t.transparency.grayscale;a.Mask=[r,r]}else if(t.transparency.rgb){var o,r=t.transparency["rgb"],i=[];for(o of r)i.push(o,o);a.Mask=i}else t.transparency.indexed?loadIndexedAlphaChannel(t):n&&(splitAlphaChannel(t),r=getSmask(e,t),a.Mask=r);return e.ref(a,null,t.imgData)},loadIndexedAlphaChannel=e=>{const o=e.transparency.indexed;return e.decodePixels(n=>{var a=new Buffer(e.width*e.height);let r=0;for(let e=0,t=n.length;e<t;e++)a[r++]=o[n[e]];e.alphaChannel=zlib.deflateSync(a)})},splitAlphaChannel=d=>{d.decodePixels(t=>{let e,n;var a=d.colors,r=d.width*d.height,o=new Buffer(r*a),i=new Buffer(r);let l=n=e=0;for(var g=t.length,c=16===d.bits?1:0;l<g;){for(let e=0;e<a;e++)o[n++]=t[l++],l+=c;i[e++]=t[l++],l+=c}d.imgData=zlib.deflateSync(o),d.alphaChannel=zlib.deflateSync(i)})},getSmask=(e,t)=>{let n;return console.log("image.hasAlphaChannel ",t.hasAlphaChannel),t.hasAlphaChannel&&(console.log("image.alphaChannel ",t.alphaChannel),n=e.ref({Type:"XObject",Subtype:"Image",Height:t.height,Width:t.width,BitsPerComponent:8,Filter:"FlateDecode",ColorSpace:"DeviceGray",Decode:[0,1],stream:t.alphaChannel})),n},getConvertedText=e=>e.split("").map(e=>specialCharacters.includes(e)?getOctalCodeFromCharacter(e):e).join(""),getOctalCodeFromCharacter=e=>"\\"+e.charCodeAt(0).toString(8),pdfkitAddPlaceholder=({pdf:e,pdfBuffer:a,reason:r,contactInfo:t="emailfromp1289@gmail.com",name:n="Name from p12",location:o="Location from p12",signatureLength:i=DEFAULT_SIGNATURE_LENGTH,byteRangePlaceholder:l=DEFAULT_BYTE_RANGE_PLACEHOLDER,subFilter:g=SUBFILTER_ADOBE_PKCS7_DETACHED,sign:c})=>{var d=getFont(e,"Helvetica"),s=getFont(e,"ZapfDingbats"),f=getFont(e,"Helvetica"),p=c.Base64,p=getAnnotationApparance(e,getImage(Buffer.from(p,"base64"),e),f),f=e.ref({Type:"Sig",Filter:"Adobe.PPKLite",SubFilter:g,ByteRange:[0,l,l,l],Contents:Buffer.from(String.fromCharCode(0).repeat(i)),Reason:new String(r),M:new Date,ContactInfo:new String(t),Name:new String(n),Location:new String(o)}),h=a.lastIndexOf("/Type /AcroForm"),g=-1!==h;let m=[],C;if(g){let e=h;var S=h-10;let t="",n=11;for(n;n<22;n+=1){var A=a.slice(h-n,S).toString();if("\n"===A[0])break;t=A,e=h-n}l=a.slice(e),i=l.slice(0,l.indexOf("endobj")).toString(),r=(C=parseInt(t),i.slice(i.indexOf("/Fields [")+9,i.indexOf("]")));m=r.split(" ").filter((e,t)=>t%3==0).map(e=>new PDFKitReferenceMock(e))}m.length;t=c.Left,n=c.Bottom,o=t+c.Width,l=n+c.Height,i=e.ref({Type:"Annot",Subtype:"Widget",FT:"Sig",Rect:[t,n,o,l],V:f,T:new String("Signature"+(m.length+1)),F:4,P:e.page.dictionary,AP:`<</N ${p.index} 0 R>>`,DA:new String("/Helvetica 0 Tf 0 g")});e.page.dictionary.data.Annots=[i];let T;return T=g?e.ref({Type:"AcroForm",SigFlags:3,Fields:[...m,i],DR:`<</Font Q`),getFont=(e,t)=>e.ref({Type:"Font",BaseFont:t,Encoding:"WinAnsiEncoding",Subtype:"Type1"}),getJpgImage=(e,t)=>{if(65496!==t.readUInt16BE(0))throw"SOI not found in JPEG";let n=2,a;for(;n<t.length&&(a=t.readUInt16BE(n),n+=2,!MARKERS.includes(a));)n+=t.readUInt16BE(n);if(!MARKERS.includes(a))throw"Invalid JPEG.";n+=2;var r=t[n++],o=t.readUInt16BE(n),i=(n+=2,t.readUInt16BE(n)),l=(n+=2,t[n++]),l=COLOR_SPACE_MAP[l],r={Type:"XObject",Subtype:"Image",BitsPerComponent:r,Width:i,Height:o,ColorSpace:l,Filter:"DCTDecode"},i=("DeviceCMYK"===l&&(r.Decode=[1,0,1,0,1,0,1,0]),e.ref(r,null,t));return i},getPngImage=(e,t)=>{var t=new PNG(t),n=t.hasAlphaChannel,a={Type:"XObject",Subtype:"Image",BitsPerComponent:n?8:t.bits,Width:t.width,Height:t.height,Filter:"FlateDecode"};if(n||(r=e.ref({Predictor:15,Colors:t.colors,BitsPerComponent:t.bits,Columns:t.width}),a.DecodeParms=r),0===t.palette.length?a.ColorSpace=t.colorSpace:(r=e.ref({stream:new Buffer(t.palette)}),a.ColorSpace=["Indexed","DeviceRGB",t.palette.length/3-1,r]),null!=t.transparency.grayscale){var r=t.transparency.grayscale;a.Mask=[r,r]}else if(t.transparency.rgb){var o,r=t.transparency["rgb"],i=[];for(o of r)i.push(o,o);a.Mask=i}else t.transparency.indexed?loadIndexedAlphaChannel(t):n&&(splitAlphaChannel(t),r=getSmask(e,t),a.Mask=r);return e.ref(a,null,t.imgData)},loadIndexedAlphaChannel=e=>{const o=e.transparency.indexed;return e.decodePixels(n=>{var a=new Buffer(e.width*e.height);let r=0;for(let e=0,t=n.length;e<t;e++)a[r++]=o[n[e]];e.alphaChannel=zlib.deflateSync(a)})},splitAlphaChannel=d=>{d.decodePixels(t=>{let e,n;var a=d.colors,r=d.width*d.height,o=new Buffer(r*a),i=new Buffer(r);let l=n=e=0;for(var c=t.length,g=16===d.bits?1:0;l<c;){for(let e=0;e<a;e++)o[n++]=t[l++],l+=g;i[e++]=t[l++],l+=g}d.imgData=zlib.deflateSync(o),d.alphaChannel=zlib.deflateSync(i)})},getSmask=(e,t)=>{let n;return console.log("image.hasAlphaChannel ",t.hasAlphaChannel),t.hasAlphaChannel&&(console.log("image.alphaChannel ",t.alphaChannel),n=e.ref({Type:"XObject",Subtype:"Image",Height:t.height,Width:t.width,BitsPerComponent:8,Filter:"FlateDecode",ColorSpace:"DeviceGray",Decode:[0,1],stream:t.alphaChannel})),n},getConvertedText=e=>e.split("").map(e=>specialCharacters.includes(e)?getOctalCodeFromCharacter(e):e).join(""),getOctalCodeFromCharacter=e=>"\\"+e.charCodeAt(0).toString(8),pdfkitAddPlaceholder=({pdf:e,pdfBuffer:a,reason:r,contactInfo:t="emailfromp1289@gmail.com",name:n="Name from p12",location:o="Location from p12",signatureLength:i=DEFAULT_SIGNATURE_LENGTH,byteRangePlaceholder:l=DEFAULT_BYTE_RANGE_PLACEHOLDER,subFilter:c=SUBFILTER_ADOBE_PKCS7_DETACHED,sign:g})=>{var d=getFont(e,"Helvetica"),s=getFont(e,"ZapfDingbats"),p=getFont(e,"Helvetica"),f=g.Base64,f=getAnnotationApparance(e,getImage(Buffer.from(f,"base64"),e),p,g),p=e.ref({Type:"Sig",Filter:"Adobe.PPKLite",SubFilter:c,ByteRange:[0,l,l,l],Contents:Buffer.from(String.fromCharCode(0).repeat(i)),Reason:new String(r),M:new Date,ContactInfo:new String(t),Name:new String(n),Location:new String(o)}),h=a.lastIndexOf("/Type /AcroForm"),c=-1!==h;let m=[],C;if(c){let e=h;var S=h-10;let t="",n=11;for(n;n<22;n+=1){var A=a.slice(h-n,S).toString();if("\n"===A[0])break;t=A,e=h-n}l=a.slice(e),i=l.slice(0,l.indexOf("endobj")).toString(),r=(C=parseInt(t),i.slice(i.indexOf("/Fields [")+9,i.indexOf("]")));m=r.split(" ").filter((e,t)=>t%3==0).map(e=>new PDFKitReferenceMock(e))}t=g.Left,n=g.Bottom,o=t+g.Width,l=n+g.Height,i=e.ref({Type:"Annot",Subtype:"Widget",FT:"Sig",Rect:[t,n,o,l],V:p,T:new String("Signature"+(m.length+1)),F:4,P:e.page.dictionary,AP:`<</N ${f.index} 0 R>>`,DA:new String("/Helvetica 0 Tf 0 g")});e.page.dictionary.data.Annots=[i];let T;return T=c?e.ref({Type:"AcroForm",SigFlags:3,Fields:[...m,i],DR:`<</Font
<</Helvetica ${d.index} 0 R/ZapfDingbats ${s.index} 0 R>> <</Helvetica ${d.index} 0 R/ZapfDingbats ${s.index} 0 R>>
>>`},C):e.ref({Type:"AcroForm",SigFlags:3,Fields:[...m,i]}),{signature:f,form:e._root.data.AcroForm=T,widget:i}};export default pdfkitAddPlaceholder; >>`},C):e.ref({Type:"AcroForm",SigFlags:3,Fields:[...m,i]}),{signature:p,form:e._root.data.AcroForm=T,widget:i}};export default pdfkitAddPlaceholder;
@@ -0,0 +1,218 @@
export default function reportJson(id, userId) {
const currentUserId = userId;
switch (id) {
// draft documents report
case 'ByHuevtCFY':
return {
reportName: 'Draft Documents',
params: {
Type: null,
$or: [
{ Signers: null, SignedUrl: null },
{ Signers: { $exists: true }, Placeholders: null },
],
CreatedBy: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
},
keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'],
};
// Need your sign report
case '4Hhwbp482K':
return {
reportName: 'Need your sign',
params: {
Type: { $ne: 'Folder' },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
ExpiryDate: {
$gt: { __type: 'Date', iso: new Date().toISOString() },
},
Placeholders: { $ne: null },
},
keys: [
'Name',
'Note',
'Folder.Name',
'URL',
'ExtUserPtr.Name',
'Signers.Name',
'Signers.UserId',
'AuditTrail',
],
};
// In progess report
case '1MwEuxLEkF':
return {
reportName: 'In-progress documents',
params: {
Type: { $ne: 'Folder' },
Signers: { $ne: null },
Placeholders: { $ne: null },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
CreatedBy: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
ExpiryDate: {
$gt: { __type: 'Date', iso: new Date().toISOString() },
},
},
keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'],
};
// completed documents report
case 'kQUoW4hUXz':
return {
reportName: 'Completed Documents',
params: {
Type: null,
IsCompleted: true,
CreatedBy: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
IsDeclined: { $ne: true },
},
keys: [
'Name',
'Note',
'Folder.Name',
'URL',
'ExtUserPtr.Name',
'Signers.Name',
'TimeToCompleteDays',
],
};
// declined documents report
case 'UPr2Fm5WY3':
return {
reportName: 'Declined Documents',
params: {
Type: null,
IsDeclined: true,
CreatedBy: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
},
keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'],
};
// Expired Documents report
case 'zNqBHXHsYH':
return {
reportName: 'Expired Documents',
params: {
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
Type: { $ne: 'Folder' },
$and: [
{
$or: [
{ Signers: { $ne: null }, SignedUrl: { $ne: null } },
{ Placeholders: { $ne: null } },
],
},
{
ExpiryDate: {
$lt: { __type: 'Date', iso: new Date().toISOString() },
},
},
],
CreatedBy: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
},
keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'],
};
// Recently sent for signatures report show on dashboard
case 'd9k3UfYHBc':
return {
reportName: 'Recently sent for signatures',
params: {
Type: { $ne: 'Folder' },
Signers: { $ne: null },
Placeholders: { $ne: null },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
CreatedBy: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
ExpiryDate: {
$gt: { __type: 'Date', iso: new Date().toISOString() },
},
},
keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'],
};
// Recent signature requests report show on dashboard
case '5Go51Q7T8r':
return {
reportName: 'Recent signature requests',
params: {
Type: { $ne: 'Folder' },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
ExpiryDate: {
$gt: { __type: 'Date', iso: new Date().toISOString() },
},
Placeholders: { $ne: null },
},
keys: [
'Name',
'Note',
'Folder.Name',
'URL',
'ExtUserPtr.Name',
'Signers.Name',
'Signers.UserId',
'AuditTrail',
],
};
// Drafts report show on dashboard
case 'kC5mfynCi4':
return {
reportName: 'Drafts',
params: {
Type: null,
$or: [
{ Signers: null, SignedUrl: null },
{ Signers: { $exists: true }, Placeholders: null },
],
CreatedBy: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
},
keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'],
};
// contact book report
case '5KhaPr482K':
return {
reportName: 'Contactbook',
params: {
CreatedBy: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
IsDeleted: { $ne: true },
},
keys: ['Name', 'Email', 'Phone'],
};
default:
return null;
}
}
@@ -1,14 +1,30 @@
import fs from 'node:fs'; import fs from 'node:fs';
import https from 'https';
import formData from 'form-data'; import formData from 'form-data';
import Mailgun from 'mailgun.js'; import Mailgun from 'mailgun.js';
import https from 'https'; import { createTransport } from 'nodemailer';
const mailgun = new Mailgun(formData); let transporterSMTP;
const mailgunClient = mailgun.client({ let mailgunClient;
username: 'api', let mailgunDomain;
key: process.env.MAILGUN_API_KEY, if (process.env.SMTP_ENABLE) {
}); transporterSMTP = createTransport({
const mailgunDomain = process.env.MAILGUN_DOMAIN; host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT || 465,
secure: process.env.SMTP_SECURE || true,
auth: {
user: process.env.SMTP_USER_EMAIL,
pass: process.env.SMTP_PASS,
},
});
} else {
const mailgun = new Mailgun(formData);
mailgunClient = mailgun.client({
username: 'api',
key: process.env.MAILGUN_API_KEY,
});
mailgunDomain = process.env.MAILGUN_DOMAIN;
}
async function sendmail(req) { async function sendmail(req) {
try { try {
@@ -38,22 +54,67 @@ async function sendmail(req) {
const pdfName = req.params.pdfName && `${req.params.pdfName}.pdf`; const pdfName = req.params.pdfName && `${req.params.pdfName}.pdf`;
const file = { const file = {
filename: pdfName || 'exported.pdf', filename: pdfName || 'exported.pdf',
data: PdfBuffer, //fs.readFileSync('./exports/exported_file_1223.pdf'), content: process.env.SMTP_ENABLE ? PdfBuffer : undefined, //fs.readFileSync('./exports/exported_file_1223.pdf'),
data: process.env.SMTP_ENABLE ? undefined : PdfBuffer,
}; };
// const html = "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body style='text-align: center;'> <p style='font-weight: bolder; font-size: large;'>Hello!</p> <p>This is a html checking mail</p><p><button style='background-color: lightskyblue; cursor: pointer; border-radius: 5px; padding: 10px; border-style: solid; border-width: 2px; text-decoration: none; font-weight: bolder; color:blue'>Verify email</button></p></body></html>" // const html = "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body style='text-align: center;'> <p style='font-weight: bolder; font-size: large;'>Hello!</p> <p>This is a html checking mail</p><p><button style='background-color: lightskyblue; cursor: pointer; border-radius: 5px; padding: 10px; border-style: solid; border-width: 2px; text-decoration: none; font-weight: bolder; color:blue'>Verify email</button></p></body></html>"
const from = req.params.from || ''; const from = req.params.from || '';
const mailsender = process.env.SMTP_ENABLE
? process.env.SMTP_USER_EMAIL
: process.env.MAILGUN_SENDER;
const messageParams = { const messageParams = {
from: from + ' <' + process.env.MAILGUN_SENDER + '>', from: from + ' <' + mailsender + '>',
to: req.params.recipient, to: req.params.recipient,
subject: req.params.subject, subject: req.params.subject,
text: req.params.text || 'mail', text: req.params.text || 'mail',
html: req.params.html || '', html: req.params.html || '',
attachment: file, attachments: process.env.SMTP_ENABLE ? [file] : undefined,
attachment: process.env.SMTP_ENABLE ? undefined : file,
}; };
if (transporterSMTP) {
const res = await transporterSMTP.sendMail(messageParams);
console.log('Res ', res);
if (!res.err) {
return {
status: 'success',
};
}
} else {
const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
console.log('Res ', res);
if (res.status === 200) {
return {
status: 'success',
};
}
}
}
} else {
const from = req.params.from || '';
const mailsender = process.env.SMTP_ENABLE
? process.env.SMTP_USER_EMAIL
: process.env.MAILGUN_SENDER;
const messageParams = {
from: from + ' <' + mailsender + '>',
to: req.params.recipient,
subject: req.params.subject,
text: req.params.text || 'mail',
html: req.params.html || '',
};
if (transporterSMTP) {
const res = await transporterSMTP.sendMail(messageParams);
console.log('Res ', res);
if (!res.err) {
return {
status: 'success',
};
}
} else {
const res = await mailgunClient.messages.create(mailgunDomain, messageParams); const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
console.log('Res ', res); console.log('Res ', res);
if (res.status === 200) { if (res.status === 200) {
@@ -62,23 +123,6 @@ async function sendmail(req) {
}; };
} }
} }
} else {
const from = req.params.from || '';
const messageParams = {
from: from + ' <' + process.env.MAILGUN_SENDER + '>',
to: req.params.recipient,
subject: req.params.subject,
text: req.params.text || 'mail',
html: req.params.html || '',
};
const res = await mailgunClient.messages.create(mailgunDomain, messageParams);
console.log('Res ', res);
if (res.status === 200) {
return {
status: 'success',
};
}
} }
} catch (err) { } catch (err) {
console.log('err ', err); console.log('err ', err);
@@ -123,6 +123,9 @@ export default async function (request) {
if (userDetails && userDetails.company) { if (userDetails && userDetails.company) {
newObj.set("Company", userDetails.company); newObj.set("Company", userDetails.company);
} }
if (userDetails && userDetails.jobTitle) {
newObj.set("JobTitle", userDetails.jobTitle);
}
if (planDetails && planDetails.customer_id) { if (planDetails && planDetails.customer_id) {
newObj.set("Next_billing_date", new Date(planDetails.nextBillingDate)); newObj.set("Next_billing_date", new Date(planDetails.nextBillingDate));
newObj.set("Plan", planDetails.plan); newObj.set("Plan", planDetails.plan);
@@ -0,0 +1,47 @@
/**
*
* @param {Parse} Parse
*/
exports.up = async Parse => {
// TODO: set className here
const className = 'contracts_Users';
const schema = new Parse.Schema(className);
// schema.addString('Name');
// schema.addString('Phone');
// schema.addString('JobTitle');
// schema.addString('Email');
// schema.addString('Company');
// schema.addString('UserRole');
// schema.addObject('Plan');
// schema.addString('Customer_id');
// schema.addString('Subscription_id');
// schema.addString('Next_billing_date');
// schema.addBoolean('IsContactEntry');
// schema.addBoolean('ShareWithTeam');
// schema.addPointer('TenantId', 'partners_Tenant');
// schema.addPointer('UserId', '_User');
// schema.addPointer('CreatedBy', '_User');
schema.setCLP({
get: {},
find: {},
count: {},
create: { '*': true },
update: { '*': true },
delete: {},
addField: {},
});
return schema.update();
};
/**
*
* @param {Parse} Parse
*/
exports.down = async Parse => {
// TODO: set className here
const className = 'contracts_Users';
const schema = new Parse.Schema(className);
return schema.purge().then(() => schema.delete());
};
@@ -0,0 +1,556 @@
/**
*
* @param {Parse} Parse
*/
exports.up = async Parse => {
const className = 'w_menu';
const userMenu = new Parse.Query(className);
const updateUserMenu = await userMenu.get('H9vRfEYKhT');
updateUserMenu.set('menuItems', [
{
icon: 'fas fa-tachometer-alt',
title: 'Dashboard',
target: '',
pageType: 'dashboard',
description: '',
objectId: '35KBoSgoAK',
},
{
icon: 'far fa-newspaper',
title: 'New Document',
target: '_self',
pageType: null,
description: null,
objectId: null,
children: [
{
icon: 'fas fa-pen-nib',
title: 'Sign yourself',
target: '_self',
pageType: 'form',
description: '',
objectId: 'sHAnZphf69',
},
{
icon: 'fas fa-file-signature',
title: 'Request signatures',
target: '_self',
pageType: 'form',
description: '',
objectId: '8mZzFxbG1z',
},
],
},
{
icon: 'fas fa-folder',
title: 'OpenSignDrive™',
target: '_self',
pageType: 'mf',
description: '',
objectId:
'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive',
},
{
icon: 'fas fa-address-card',
title: 'Reports',
target: '_self',
pageType: null,
description: '',
objectId: null,
children: [
{
icon: 'fas fa-signature',
title: 'Need your sign',
target: '_self',
pageType: 'report',
description: '',
objectId: '4Hhwbp482K',
},
{
icon: 'fas fa-tasks',
title: 'In Progress',
target: '_self',
pageType: 'report',
description: '',
objectId: '1MwEuxLEkF',
},
{
icon: 'fas fa-check-circle',
title: 'Completed',
target: '_self',
pageType: 'report',
description: '',
objectId: 'kQUoW4hUXz',
},
{
icon: 'fas fa-edit',
title: 'Drafts',
target: '_self',
pageType: 'report',
description: '',
objectId: 'ByHuevtCFY',
},
{
icon: 'fas fa-times-circle',
title: 'Declined',
target: '_self',
pageType: 'report',
description: '',
objectId: 'UPr2Fm5WY3',
},
{
icon: 'fas fa-hourglass-end',
title: 'Expired',
target: '_self',
pageType: 'report',
description: '',
objectId: 'zNqBHXHsYH',
},
{
icon: 'fa-solid fa-address-book',
title: 'Contactbook',
target: '_self',
pageType: 'report',
description: '',
objectId: '5KhaPr482K',
},
],
},
{
icon: 'fas fa-cog',
title: 'Settings',
target: '_self',
pageType: null,
description: '',
objectId: null,
children: [
{
icon: 'fas fa-pen-fancy',
title: 'My Signature',
target: '_self',
pageType: 'mf',
description: '',
objectId:
'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign',
},
],
},
]);
const AdminMenu = new Parse.Query(className);
const updateAdminMenu = await AdminMenu.get('VPh91h0ZHk');
updateAdminMenu.set('menuItems', [
{
icon: 'fas fa-tachometer-alt',
title: 'Dashboard',
target: '',
pageType: 'dashboard',
description: '',
objectId: '35KBoSgoAK',
},
{
icon: 'far fa-newspaper',
title: 'New Document',
target: '_self',
pageType: null,
description: null,
objectId: null,
children: [
{
icon: 'fas fa-pen-nib',
title: 'Sign yourself',
target: '_self',
pageType: 'form',
description: '',
objectId: 'sHAnZphf69',
},
{
icon: 'fas fa-file-signature',
title: 'Request signatures',
target: '_self',
pageType: 'form',
description: '',
objectId: '8mZzFxbG1z',
},
],
},
{
icon: 'fas fa-folder',
title: 'OpenSignDrive™',
target: '_self',
pageType: 'mf',
description: '',
objectId:
'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive',
},
{
icon: 'fas fa-address-card',
title: 'Reports',
target: '_self',
pageType: null,
description: '',
objectId: null,
children: [
{
icon: 'fas fa-signature',
title: 'Need your sign',
target: '_self',
pageType: 'report',
description: '',
objectId: '4Hhwbp482K',
},
{
icon: 'fas fa-tasks',
title: 'In Progress',
target: '_self',
pageType: 'report',
description: '',
objectId: '1MwEuxLEkF',
},
{
icon: 'fas fa-check-circle',
title: 'Completed',
target: '_self',
pageType: 'report',
description: '',
objectId: 'kQUoW4hUXz',
},
{
icon: 'fas fa-edit',
title: 'Drafts',
target: '_self',
pageType: 'report',
description: '',
objectId: 'ByHuevtCFY',
},
{
icon: 'fas fa-times-circle',
title: 'Declined',
target: '_self',
pageType: 'report',
description: '',
objectId: 'UPr2Fm5WY3',
},
{
icon: 'fas fa-hourglass-end',
title: 'Expired',
target: '_self',
pageType: 'report',
description: '',
objectId: 'zNqBHXHsYH',
},
{
icon: 'fa-solid fa-address-book',
title: 'Contactbook',
target: '_self',
pageType: 'report',
description: '',
objectId: '5KhaPr482K',
},
],
},
{
icon: 'fas fa-cog',
title: 'Settings',
target: '_self',
pageType: null,
description: '',
objectId: null,
children: [
{
icon: 'fas fa-pen-fancy',
title: 'My Signature',
target: '_self',
pageType: 'mf',
description: '',
objectId:
'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign',
},
{
icon: 'far fa-user',
title: 'Add User',
target: '_self',
pageType: 'form',
description: '',
objectId: 'lM0xRnM3iE',
},
],
},
]);
// TODO: Set the schema here
// Example:
// schema.addString('name').addNumber('cash');
const batch = [updateUserMenu, updateAdminMenu];
return Parse.Object.saveAll(batch, { useMasterKey: true });
};
/**
*
* @param {Parse} Parse
*/
exports.down = async Parse => {
// TODO: set className here
const className = 'w_menu';
const userMenu = new Parse.Query(className);
const revertUserMenu = await userMenu.get('H9vRfEYKhT');
revertUserMenu.set('menuItems', [
{
icon: 'fas fa-tachometer-alt',
title: 'Dashboard',
target: '',
pageType: 'dashboard',
description: '',
objectId: '35KBoSgoAK',
},
{
icon: 'far fa-newspaper',
title: 'New Document',
target: '_self',
pageType: null,
description: null,
objectId: null,
children: [
{
icon: 'fas fa-pen-nib',
title: 'Sign yourself',
target: '_self',
pageType: 'form',
description: '',
objectId: 'sHAnZphf69',
},
{
icon: 'fas fa-file-signature',
title: 'Request signatures',
target: '_self',
pageType: 'form',
description: '',
objectId: '8mZzFxbG1z',
},
],
},
{
icon: 'fas fa-folder',
title: 'OpenSignDrive™',
target: '_self',
pageType: 'mf',
description: '',
objectId:
'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive',
},
{
icon: 'fas fa-address-card',
title: 'Reports',
target: '_self',
pageType: null,
description: '',
objectId: null,
children: [
{
icon: 'fas fa-signature',
title: 'Need your sign',
target: '_self',
pageType: 'report',
description: '',
objectId: '4Hhwbp482K',
},
{
icon: 'fas fa-tasks',
title: 'In Progress',
target: '_self',
pageType: 'report',
description: '',
objectId: '1MwEuxLEkF',
},
{
icon: 'fas fa-check-circle',
title: 'Completed',
target: '_self',
pageType: 'report',
description: '',
objectId: 'kQUoW4hUXz',
},
{
icon: 'fas fa-edit',
title: 'Drafts',
target: '_self',
pageType: 'report',
description: '',
objectId: 'ByHuevtCFY',
},
{
icon: 'fas fa-times-circle',
title: 'Declined',
target: '_self',
pageType: 'report',
description: '',
objectId: 'UPr2Fm5WY3',
},
{
icon: 'fas fa-hourglass-end',
title: 'Expired',
target: '_self',
pageType: 'report',
description: '',
objectId: 'zNqBHXHsYH',
},
],
},
{
icon: 'fas fa-cog',
title: 'Settings',
target: '_self',
pageType: null,
description: '',
objectId: null,
children: [
{
icon: 'fas fa-pen-fancy',
title: 'My Signature',
target: '_self',
pageType: 'mf',
description: '',
objectId:
'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign',
},
],
},
]);
const adminMenu = new Parse.Query(className);
const revertAdminMenu = await adminMenu.get('VPh91h0ZHk');
revertAdminMenu.set('menuItems', [
{
icon: 'fas fa-tachometer-alt',
title: 'Dashboard',
target: '',
pageType: 'dashboard',
description: '',
objectId: '35KBoSgoAK',
},
{
icon: 'far fa-newspaper',
title: 'New Document',
target: '_self',
pageType: null,
description: null,
objectId: null,
children: [
{
icon: 'fas fa-pen-nib',
title: 'Sign yourself',
target: '_self',
pageType: 'form',
description: '',
objectId: 'sHAnZphf69',
},
{
icon: 'fas fa-file-signature',
title: 'Request signatures',
target: '_self',
pageType: 'form',
description: '',
objectId: '8mZzFxbG1z',
},
],
},
{
icon: 'fas fa-folder',
title: 'OpenSignDrive™',
target: '_self',
pageType: 'mf',
description: '',
objectId:
'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive',
},
{
icon: 'fas fa-address-card',
title: 'Reports',
target: '_self',
pageType: null,
description: '',
objectId: null,
children: [
{
icon: 'fas fa-signature',
title: 'Need your sign',
target: '_self',
pageType: 'report',
description: '',
objectId: '4Hhwbp482K',
},
{
icon: 'fas fa-tasks',
title: 'In Progress',
target: '_self',
pageType: 'report',
description: '',
objectId: '1MwEuxLEkF',
},
{
icon: 'fas fa-check-circle',
title: 'Completed',
target: '_self',
pageType: 'report',
description: '',
objectId: 'kQUoW4hUXz',
},
{
icon: 'fas fa-edit',
title: 'Drafts',
target: '_self',
pageType: 'report',
description: '',
objectId: 'ByHuevtCFY',
},
{
icon: 'fas fa-times-circle',
title: 'Declined',
target: '_self',
pageType: 'report',
description: '',
objectId: 'UPr2Fm5WY3',
},
{
icon: 'fas fa-hourglass-end',
title: 'Expired',
target: '_self',
pageType: 'report',
description: '',
objectId: 'zNqBHXHsYH',
},
],
},
{
icon: 'fas fa-cog',
title: 'Settings',
target: '_self',
pageType: null,
description: '',
objectId: null,
children: [
{
icon: 'fas fa-pen-fancy',
title: 'My Signature',
target: '_self',
pageType: 'mf',
description: '',
objectId:
'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign',
},
{
icon: 'far fa-user',
title: 'Add User',
target: '_self',
pageType: 'form',
description: '',
objectId: 'lM0xRnM3iE',
},
],
},
]);
// TODO: Set the schema here
// Example:
// schema.addString('name').addNumber('cash');
const batch = [revertUserMenu, revertAdminMenu];
return Parse.Object.saveAll(batch, { useMasterKey: true });
};
@@ -10,7 +10,7 @@
<br /> <br />
<p><a href="{{{link}}}" style="background-color: lightskyblue; cursor: pointer; border-radius: 5px; padding: 10px; border-style: solid; border-width: 2px; text-decoration: none; font-weight: bolder; color:blue">Verify email</a></p> <p><a href="{{{link}}}" style="background-color: lightskyblue; cursor: pointer; border-radius: 5px; padding: 10px; border-style: solid; border-width: 2px; text-decoration: none; font-weight: bolder; color:blue">Verify email</a></p>
<br /> <br />
<p>ExampleApp</p> <p><a href="https://www.opensignlabs.com">OpenSign™</a></p>
</body> </body>
</html> </html>
+65 -31
View File
@@ -17,10 +17,12 @@ import S3Adapter from 'parse-server-s3-adapter';
import FSFilesAdapter from 'parse-server-fs-adapter'; import FSFilesAdapter from 'parse-server-fs-adapter';
import AWS from 'aws-sdk'; import AWS from 'aws-sdk';
import { app as customRoute } from './cloud/customRoute/customApp.js'; import { app as customRoute } from './cloud/customRoute/customApp.js';
import { exec } from 'child_process';
import { createTransport } from 'nodemailer';
const spacesEndpoint = new AWS.Endpoint(process.env.DO_ENDPOINT); const spacesEndpoint = new AWS.Endpoint(process.env.DO_ENDPOINT);
// console.log("configuration ", configuration); // console.log("configuration ", configuration);
if (process.env.USE_LOCAL !== "TRUE") { if (process.env.USE_LOCAL !== 'TRUE') {
const s3Options = { const s3Options = {
bucket: process.env.DO_SPACE, // globalConfig.S3FilesAdapter.bucket, bucket: process.env.DO_SPACE, // globalConfig.S3FilesAdapter.bucket,
baseUrl: process.env.DO_BASEURL, baseUrl: process.env.DO_BASEURL,
@@ -36,18 +38,31 @@ if (process.env.USE_LOCAL !== "TRUE") {
var fsAdapter = new S3Adapter(s3Options); var fsAdapter = new S3Adapter(s3Options);
} else { } else {
var fsAdapter = new FSFilesAdapter({ var fsAdapter = new FSFilesAdapter({
"filesSubDirectory": "files" // optional, defaults to ./files filesSubDirectory: 'files', // optional, defaults to ./files
}); });
} }
let transporterMail;
let mailgunClient; let mailgunClient;
let mailgunDomain; let mailgunDomain;
if (process.env.MAILGUN_API_KEY) {
if (process.env.SMTP_ENABLE) {
transporterMail = createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT || 465,
secure: process.env.SMTP_SECURE || true,
auth: {
user: process.env.SMTP_USER_EMAIL,
pass: process.env.SMTP_PASS,
},
});
} else if (process.env.MAILGUN_API_KEY) {
const mailgun = new Mailgun(formData); const mailgun = new Mailgun(formData);
mailgunClient = mailgun.client({ mailgunClient = mailgun.client({
username: 'api', username: 'api',
key: process.env.MAILGUN_API_KEY, key: process.env.MAILGUN_API_KEY,
}); });
mailgunDomain = process.env.MAILGUN_DOMAIN; mailgunDomain = process.env.MAILGUN_DOMAIN;
} }
@@ -59,41 +74,46 @@ export const config = {
masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret! masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret!
masterKeyIps: ['0.0.0.0/0', '::1'], // '::1' masterKeyIps: ['0.0.0.0/0', '::1'], // '::1'
serverURL: process.env.SERVER_URL || 'http://localhost:8080/app', // Don't forget to change to https if needed serverURL: process.env.SERVER_URL || 'http://localhost:8080/app', // Don't forget to change to https if needed
// verifyUserEmails: true, verifyUserEmails: true,
publicServerURL: process.env.SERVER_URL || 'http://localhost:8080/app', publicServerURL: process.env.SERVER_URL || 'http://localhost:8080/app',
// Your apps name. This will appear in the subject and body of the emails that are sent. // Your apps name. This will appear in the subject and body of the emails that are sent.
appName: 'Open Sign', appName: 'Open Sign',
allowClientClassCreation: false, allowClientClassCreation: false,
emailAdapter: process.env.MAILGUN_API_KEY emailAdapter:
? { process.env.SMTP_ENABLE || process.env.MAILGUN_API_KEY
module: 'parse-server-api-mail-adapter', ? {
options: { module: 'parse-server-api-mail-adapter',
// The email address from which emails are sent. options: {
sender: process.env.MAILGUN_SENDER, // The email address from which emails are sent.
// The email templates. sender: process.env.SMTP_ENABLE
templates: { ? process.env.SMTP_USER_EMAIL
// The template used by Parse Server to send an email for password : process.env.MAILGUN_SENDER,
// reset; this is a reserved template name. // The email templates.
passwordResetEmail: { templates: {
subjectPath: './files/password_reset_email_subject.txt', // The template used by Parse Server to send an email for password
textPath: './files/password_reset_email.txt', // reset; this is a reserved template name.
htmlPath: './files/password_reset_email.html', passwordResetEmail: {
subjectPath: './files/password_reset_email_subject.txt',
textPath: './files/password_reset_email.txt',
htmlPath: './files/password_reset_email.html',
},
// The template used by Parse Server to send an email for email
// address verification; this is a reserved template name.
verificationEmail: {
subjectPath: './files/verification_email_subject.txt',
textPath: './files/verification_email.txt',
htmlPath: './files/verification_email.html',
},
}, },
// The template used by Parse Server to send an email for email apiCallback: async ({ payload, locale }) => {
// address verification; this is a reserved template name. if (mailgunClient) {
verificationEmail: { const mailgunPayload = ApiPayloadConverter.mailgun(payload);
subjectPath: './files/verification_email_subject.txt', await mailgunClient.messages.create(mailgunDomain, mailgunPayload);
textPath: './files/verification_email.txt', } else if (transporterMail) await transporterMail.sendMail(payload);
htmlPath: './files/verification_email.html',
}, },
}, },
apiCallback: async ({ payload, locale }) => { }
const mailgunPayload = ApiPayloadConverter.mailgun(payload); : null,
await mailgunClient.messages.create(mailgunDomain, mailgunPayload);
},
},
}
: null,
filesAdapter: fsAdapter, filesAdapter: fsAdapter,
auth: { auth: {
google: { google: {
@@ -164,6 +184,20 @@ if (!process.env.TESTING) {
httpServer.headersTimeout = 100000; // in milliseconds httpServer.headersTimeout = 100000; // in milliseconds
httpServer.listen(port, function () { httpServer.listen(port, function () {
console.log('parse-server-example running on port ' + port + '.'); console.log('parse-server-example running on port ' + port + '.');
const migrate = `APPLICATION_ID=${process.env.APP_ID} SERVER_URL=http://localhost:8080/app MASTER_KEY=${process.env.MASTER_KEY} npx parse-dbtool migrate`;
exec(migrate, (error, stdout, stderr) => {
if (error) {
console.error(`Error: ${error.message}`);
return;
}
if (stderr) {
console.error(`Error: ${stderr}`);
return;
}
console.log(`Command output: ${stdout}`);
});
}); });
// This will enable the Live Query real-time server // This will enable the Live Query real-time server
await ParseServer.createLiveQueryServer(httpServer); await ParseServer.createLiveQueryServer(httpServer);
+334 -11
View File
@@ -18,16 +18,19 @@
"express-sse": "^0.5.3", "express-sse": "^0.5.3",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"jsonschema": "^1.4.1", "jsonschema": "^1.4.1",
"mailgun.js": "^9.0.1", "mailgun.js": "^9.3.0",
"mongoose": "^7.2.1", "mongoose": "^7.2.1",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"multer-s3": "^2.10.0", "multer-s3": "^2.10.0",
"node-forge": "^1.3.1", "node-forge": "^1.3.1",
"node-signpdf": "^1.5.1", "node-signpdf": "^1.5.1",
"nodemailer": "^6.9.7",
"openai": "^4.8.0", "openai": "^4.8.0",
"parse": "4.1.0", "parse": "4.1.0",
"parse-dbtool": "^1.2.0",
"parse-server": "6.3.1", "parse-server": "6.3.1",
"parse-server-api-mail-adapter": "^3.0.0", "parse-server-api-mail-adapter": "^3.0.0",
"parse-server-fs-adapter": "1.0.1",
"parse-server-s3-adapter": "^1.2.0", "parse-server-s3-adapter": "^1.2.0",
"pdf-lib": "^1.16.0", "pdf-lib": "^1.16.0",
"pdfkit": "^0.13.0", "pdfkit": "^0.13.0",
@@ -2145,7 +2148,6 @@
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"dependencies": { "dependencies": {
"fill-range": "^7.0.1" "fill-range": "^7.0.1"
}, },
@@ -2794,6 +2796,37 @@
"node": ">=0.10" "node": ">=0.10"
} }
}, },
"node_modules/date-fns": {
"version": "2.30.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
"dependencies": {
"@babel/runtime": "^7.21.0"
},
"engines": {
"node": ">=0.11"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/date-fns"
}
},
"node_modules/date-fns/node_modules/@babel/runtime": {
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz",
"integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/date-fns/node_modules/regenerator-runtime": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
"integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -3900,6 +3933,32 @@
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
}, },
"node_modules/fast-glob": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
"glob-parent": "^5.1.2",
"merge2": "^1.3.0",
"micromatch": "^4.0.4"
},
"engines": {
"node": ">=8.6.0"
}
},
"node_modules/fast-glob/node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fast-json-stable-stringify": { "node_modules/fast-json-stable-stringify": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -3999,7 +4058,6 @@
"version": "7.0.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"dependencies": { "dependencies": {
"to-regex-range": "^5.0.1" "to-regex-range": "^5.0.1"
}, },
@@ -4335,7 +4393,6 @@
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
"engines": { "engines": {
"node": "6.* || 8.* || >= 10.*" "node": "6.* || 8.* || >= 10.*"
} }
@@ -5091,7 +5148,6 @@
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"engines": { "engines": {
"node": ">=0.12.0" "node": ">=0.12.0"
} }
@@ -6016,9 +6072,9 @@
} }
}, },
"node_modules/mailgun.js": { "node_modules/mailgun.js": {
"version": "9.0.1", "version": "9.3.0",
"resolved": "https://registry.npmjs.org/mailgun.js/-/mailgun.js-9.0.1.tgz", "resolved": "https://registry.npmjs.org/mailgun.js/-/mailgun.js-9.3.0.tgz",
"integrity": "sha512-bVZ1zGh5UfQcChqIwIAil99hzoTeB3aHqAUbqmIBLMLcKfx+FF2qvhbc00WtwrFhe5dBQqQw6zPj0QBlqV4nXg==", "integrity": "sha512-iRqCglCdi+Q5anFpeRKHiytT/i34E14p/WtTE57VSeq5bATK+zQ8UnpFgPRaqGGTJqyGjqcO9m5YDRRB4/qirw==",
"dependencies": { "dependencies": {
"axios": "^1.3.3", "axios": "^1.3.3",
"base-64": "^1.0.0", "base-64": "^1.0.0",
@@ -6087,6 +6143,14 @@
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
}, },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"engines": {
"node": ">= 8"
}
},
"node_modules/methods": { "node_modules/methods": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
@@ -6095,6 +6159,18 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/micromatch": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"dependencies": {
"braces": "^3.0.2",
"picomatch": "^2.3.1"
},
"engines": {
"node": ">=8.6"
}
},
"node_modules/mime": { "node_modules/mime": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
@@ -6799,6 +6875,14 @@
"node-forge": "^1.2.1" "node-forge": "^1.2.1"
} }
}, },
"node_modules/nodemailer": {
"version": "6.9.7",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.7.tgz",
"integrity": "sha512-rUtR77ksqex/eZRLmQ21LKVH5nAAsVicAtAYudK7JgwenEDZ0UIQ1adUGqErz7sMkWYxWTTU1aeP2Jga6WQyJw==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/nodemon": { "node_modules/nodemon": {
"version": "2.0.22", "version": "2.0.22",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz",
@@ -7328,6 +7412,234 @@
"crypto-js": "4.1.1" "crypto-js": "4.1.1"
} }
}, },
"node_modules/parse-dbtool": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/parse-dbtool/-/parse-dbtool-1.2.0.tgz",
"integrity": "sha512-APRMPdQ2jyJ7SBouPYZsCD4BjB0zIrSEgALgeYZsVSDrrtoqXhUHJHi42tF/0ocTA/nolteUMzlHT+msrqPvjQ==",
"dependencies": {
"chalk": "^4.1.1",
"date-fns": "^2.21.3",
"dotenv": "^10.0.0",
"fast-glob": "^3.2.5",
"parse": "^3.2.0",
"ts-dedent": "^2.1.1",
"yargs": "^17.0.1"
},
"bin": {
"parse-dbtool": "src/parse-dbtool.js"
}
},
"node_modules/parse-dbtool/node_modules/@babel/runtime": {
"version": "7.18.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.0.tgz",
"integrity": "sha512-YMQvx/6nKEaucl0MY56mwIG483xk8SDNdlUwb2Ts6FUpr7fm85DxEmsY18LXBNhcTz6tO6JwZV8w1W06v8UKeg==",
"dependencies": {
"regenerator-runtime": "^0.13.4"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/parse-dbtool/node_modules/@babel/runtime-corejs3": {
"version": "7.17.8",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.8.tgz",
"integrity": "sha512-ZbYSUvoSF6dXZmMl/CYTMOvzIFnbGfv4W3SEHYgMvNsFTeLaF2gkGAF4K2ddmtSK4Emej+0aYcnSC6N5dPCXUQ==",
"dependencies": {
"core-js-pure": "^3.20.2",
"regenerator-runtime": "^0.13.4"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/parse-dbtool/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/parse-dbtool/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/parse-dbtool/node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
"wrap-ansi": "^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/parse-dbtool/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/parse-dbtool/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/parse-dbtool/node_modules/dotenv": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
"engines": {
"node": ">=10"
}
},
"node_modules/parse-dbtool/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/parse-dbtool/node_modules/idb-keyval": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.0.3.tgz",
"integrity": "sha512-yh8V7CnE6EQMu9YDwQXhRxwZh4nv+8xm/HV4ZqK4IiYFJBWYGjJuykADJbSP+F/GDXUBwCSSNn/14IpGL81TuA==",
"dependencies": {
"safari-14-idb-fix": "^3.0.0"
}
},
"node_modules/parse-dbtool/node_modules/parse": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/parse/-/parse-3.5.1.tgz",
"integrity": "sha512-uxkLVNfbqgZ/pStg/jIQGh09tOUkPZorzDIqz9vSFjZ3iIZzgvNk6VBbjXjcMWsR8LyFPOR1ROR6/y9Dedn3/w==",
"dependencies": {
"@babel/runtime": "7.18.0",
"@babel/runtime-corejs3": "7.17.8",
"idb-keyval": "6.0.3",
"react-native-crypto-js": "1.0.0",
"uuid": "3.4.0",
"ws": "8.6.0",
"xmlhttprequest": "1.8.0"
},
"optionalDependencies": {
"crypto-js": "4.1.1"
}
},
"node_modules/parse-dbtool/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/parse-dbtool/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/parse-dbtool/node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/parse-dbtool/node_modules/ws": {
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.6.0.tgz",
"integrity": "sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/parse-dbtool/node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"engines": {
"node": ">=10"
}
},
"node_modules/parse-dbtool/node_modules/yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
"yargs-parser": "^21.1.1"
},
"engines": {
"node": ">=12"
}
},
"node_modules/parse-dbtool/node_modules/yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"engines": {
"node": ">=12"
}
},
"node_modules/parse-server": { "node_modules/parse-server": {
"version": "6.3.1", "version": "6.3.1",
"resolved": "https://registry.npmjs.org/parse-server/-/parse-server-6.3.1.tgz", "resolved": "https://registry.npmjs.org/parse-server/-/parse-server-6.3.1.tgz",
@@ -7403,6 +7715,12 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/parse-server-fs-adapter": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parse-server-fs-adapter/-/parse-server-fs-adapter-1.0.1.tgz",
"integrity": "sha512-5IRKAT2QkzHrYrBESY4E8jsV1sl+XVBTKGyUvBPgBR2QzsTTqiyU/lFZD8PAJavA+TH1BLyLTUMZbhZhswNVbQ==",
"deprecated": "use @parse/fs-files-adapter"
},
"node_modules/parse-server-s3-adapter": { "node_modules/parse-server-s3-adapter": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/parse-server-s3-adapter/-/parse-server-s3-adapter-1.2.0.tgz", "resolved": "https://registry.npmjs.org/parse-server-s3-adapter/-/parse-server-s3-adapter-1.2.0.tgz",
@@ -7881,7 +8199,6 @@
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"engines": { "engines": {
"node": ">=8.6" "node": ">=8.6"
}, },
@@ -8455,7 +8772,6 @@
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -9221,7 +9537,6 @@
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"dependencies": { "dependencies": {
"is-number": "^7.0.0" "is-number": "^7.0.0"
}, },
@@ -9283,6 +9598,14 @@
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
}, },
"node_modules/ts-dedent": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz",
"integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==",
"engines": {
"node": ">=6.10"
}
},
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.5.2", "version": "2.5.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz",
+4 -2
View File
@@ -27,18 +27,20 @@
"express-sse": "^0.5.3", "express-sse": "^0.5.3",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"jsonschema": "^1.4.1", "jsonschema": "^1.4.1",
"mailgun.js": "^9.0.1", "mailgun.js": "^9.3.0",
"mongoose": "^7.2.1", "mongoose": "^7.2.1",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"multer-s3": "^2.10.0", "multer-s3": "^2.10.0",
"node-forge": "^1.3.1", "node-forge": "^1.3.1",
"node-signpdf": "^1.5.1", "node-signpdf": "^1.5.1",
"nodemailer": "^6.9.7",
"openai": "^4.8.0", "openai": "^4.8.0",
"parse": "4.1.0", "parse": "4.1.0",
"parse-dbtool": "^1.2.0",
"parse-server": "6.3.1", "parse-server": "6.3.1",
"parse-server-api-mail-adapter": "^3.0.0", "parse-server-api-mail-adapter": "^3.0.0",
"parse-server-s3-adapter": "^1.2.0",
"parse-server-fs-adapter": "1.0.1", "parse-server-fs-adapter": "1.0.1",
"parse-server-s3-adapter": "^1.2.0",
"pdf-lib": "^1.16.0", "pdf-lib": "^1.16.0",
"pdfkit": "^0.13.0", "pdfkit": "^0.13.0",
"razorpay": "^2.8.6", "razorpay": "^2.8.6",
+37
View File
@@ -0,0 +1,37 @@
// const { exec } = require('child_process');
import { exec } from 'child_process';
const migrate =
'APPLICATION_ID=legadranaxn SERVER_URL=http://localhost:8080/app MASTER_KEY=XnAwPDRQQyMr npx parse-dbtool migrate';
// `APPLICATION_ID=${process.env.APP_ID} SERVER_URL=${process.env.SERVER_URL} MASTER_KEY=${process.env.MASTER_KEY} npx parse-dbtool migrate`;
exec(migrate, (error, stdout, stderr) => {
if (error) {
console.error(`Error: ${error.message}`);
return;
}
if (stderr) {
console.error(`Error: ${stderr}`);
return;
}
console.log(`Command output: ${stdout}`);
});
// const seeder =
// 'APPLICATION_ID=legadranaxn SERVER_URL=http://localhost:8080/app MASTER_KEY=XnAwPDRQQyMr npx parse-dbtool seed';
// exec(seeder, (error, stdout, stderr) => {
// if (error) {
// console.error(`Error: ${error.message}`);
// return;
// }
// if (stderr) {
// console.error(`Error: ${stderr}`);
// return;
// }
// console.log(`Command output: ${stdout}`);
// });
@@ -40,7 +40,7 @@
"id": "c1935cc0-28d4-3d73-b72a-8c1e3d18a17f", "id": "c1935cc0-28d4-3d73-b72a-8c1e3d18a17f",
"queryType": "", "queryType": "",
"class": "contracts_Document", "class": "contracts_Document",
"query": "where={\"CreatedBy\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"#UserId.objectId#\"},\"IsCompleted\":{\"$ne\":true},\"IsDeclined\":{\"$ne\":true},\"Type\":{\"$ne\":\"Folder\"},\"Placeholders\":{\"$ne\":null},\"ExpiryDate\":{\"#*gt\":{\"__type\":\"#Date#\",\"iso\":\"#today#\"}}}&count=1", "query": "where={\"IsDeclined\":{\"$ne\":true},\"IsCompleted\":{\"$ne\":true},\"Type\":{\"$ne\":\"Folder\"},\"Placeholders\":{\"$ne\":null},\"ExpiryDate\":{\"#*gt\":{\"__type\":\"#Date#\",\"iso\":\"#today#\"}}}&include=Signers,AuditTrail.UserPtr",
"key": "count", "key": "count",
"Redirect_type": "Report", "Redirect_type": "Report",
"Redirect_id": "1MwEuxLEkF", "Redirect_id": "1MwEuxLEkF",
@@ -1,4 +1,5 @@
[{ [
{
"_id": "H9vRfEYKhT", "_id": "H9vRfEYKhT",
"_created_at": { "_created_at": {
"$date": "2023-09-04T14:04:00.669Z" "$date": "2023-09-04T14:04:00.669Z"
@@ -105,6 +106,14 @@
"pageType": "report", "pageType": "report",
"description": "", "description": "",
"objectId": "zNqBHXHsYH" "objectId": "zNqBHXHsYH"
},
{
"icon": "fa-solid fa-address-book",
"title": "Contactbook",
"target": "_self",
"pageType": "report",
"description": "",
"objectId": "5KhaPr482K"
} }
] ]
}, },
@@ -237,6 +246,14 @@
"pageType": "report", "pageType": "report",
"description": "", "description": "",
"objectId": "zNqBHXHsYH" "objectId": "zNqBHXHsYH"
},
{
"icon": "fa-solid fa-address-book",
"title": "Contactbook",
"target": "_self",
"pageType": "report",
"description": "",
"objectId": "5KhaPr482K"
} }
] ]
}, },
@@ -269,4 +286,5 @@
], ],
"menuTitle": "Admin Menu", "menuTitle": "Admin Menu",
"menuType": "Side Menu" "menuType": "Side Menu"
}] }
]
+54
View File
@@ -0,0 +1,54 @@
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=
+23
View File
@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIUAZQ9QST2eBZz5k9pCa//mHQVm1QwDQYJKoZIhvcNAQEL
BQAwcjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQKDA1P
cGVuU2lnbiBMYWJzMREwDwYDVQQDDAhPcGVuU2lnbjElMCMGCSqGSIb3DQEJARYW
aGVsbG9Ab3BlbnNpZ25sYWJzLmNvbTAeFw0yMzExMTcxOTQ0MzZaFw0yNDExMTYx
OTQ0MzZaMHIxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEWMBQGA1UE
CgwNT3BlblNpZ24gTGFiczERMA8GA1UEAwwIT3BlblNpZ24xJTAjBgkqhkiG9w0B
CQEWFmhlbGxvQG9wZW5zaWdubGFicy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQDLRKLjCSrvV1zAY2leWxCvdKTUaThpQO8nWPE/4v5ilMU2aRON
krAnli0LUfQ/tIRWNurxwVjJ7HrW3ICLn05GBLjm2AUCfuMbJCvOEEdmFJqRY04n
12fBZWz2KtzbZEIBVxLhc4E4g+Rz68hQA2fqwNuFdyGkkIbhVXpZIePEppqRmw+2
uuDvIzJ77rdDaLqwwPoHWenZ2uZTedKXx7PGYs98psg35GvcpssqAJGAIAi9Rzg/
ZV4oSpGXCjn/TJy61zTDbmPFCS/rC1XBWzBQfwDeBPDI18W6gPVX6N4dp0Ao+n8Q
txeI6g4FzMH91KPbdbZXxm8rZqXj87VQs9trAgMBAAGjUzBRMB0GA1UdDgQWBBRN
NtRPagnqovdmbrdhSUON9Rwd3TAfBgNVHSMEGDAWgBRNNtRPagnqovdmbrdhSUON
9Rwd3TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBrcPyA7GHq
+ol9qjy9HijpoU5MaEiV9v9H8/0v7KoXUND3rMl37yFyjxGN8uda8WxpEhE2eFnk
Xjtm2NgPrv8qeYHor/A3y5RfQhnlCY4kE1bREZGhcuKihR4rOtmComwFjx4Ibwwj
4nKsflj6rXcWKSfSNHLkXFXHPYwyqRsKdtClrD/8YJn6LeeMlMjIYGGP4qyi2WwS
Z8hExWGEMaMWiA9rxTMX6iu/parGH/pWU/55Os3WlcHPhlvqchBkQFJ+f8b+NYz0
vIHQgwn4K5WMsZVLxoiUcU7cSqE/qhnP+pzBf8lRaYwd+zUznDvzpKKz6nFgeHok
s8BK7JAKkIsl
-----END CERTIFICATE-----
+30
View File
@@ -0,0 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,5932FA9F02938D1B
6gkkZP80WrVnR3dVwkimtfirSeYNXZlrXXBv+Ddjyq7FScqca7svJFd8ObC0xXjg
nbxChDKS8SXcSjsNCTzixG0QReO5vaqovrpQoYbkSQ9GRMIVV8WuWNzlyMnypNJ4
Z6hdpd5nkc1hIP8A6WcY3lA8msyHceU9IidEEb75CE743qsvUMko+XvqntZx/LNe
0uK8Bs+cXeDzolpNX8ORKBTAOMii+WPlN2l+9ldsWTECEk4GmWa51QfpKouLxz5E
u7fuGuku/nPKGb4Yj7sCgaD91UabRksDLS9UGDBqeNL+mogG3gY/Iu0/q2cUs6XR
x1W6KW1eJHnOf1pAp7+G/zNqzdsxI3pnoR+nsV6/G0glBLar+Xqc99B568lnUWWv
5NGN3Buz1axx1jPKIknDcT4Skmvt6TcmgrjoCQ9XvmNKVClpExQ+dKPmJI/EVNoU
jjDZyfghcJ6BEMcTgoOBDiUrPM0273sb89u/AzyUA1tTciW2KARz6cOUTPWVRSRn
4yXpkA4BJDpxRmK68BXorZLNxtvHk+on80c9tu5e+IVa3Gu1K7gc269TPmlIolAM
v//i+jpwJ4Pe2IGVYdojMr15useUv7JC6/Kconnkx4q9rkMriguuXoQt8qW3kvEs
Ur8KuibtDqhz2zGbsKboQFMOd6cdd+63dJCGAUqk4hFrSikTw3LhkXNcg9GZHq1z
WFAfaA3x2jd+kJJ5xg8xMVEHax5IAOXDL2ektyPFpI1UZOuTc2i7FK6Y0NnXPkSN
G/+DsKdLWT943mPfZj01mTRi3MgseDXsHMHGmmPxW9J4jv+WW4OdpHvd474QzJ8b
vQmyiKq4XPHsuQUkzHVPbTrGe1B9z4p97YQKdEfXP2ChGFsUHCYQdpHyXwie2+pq
E2rc7Bai0OuL0anYMSIvDrJ0DE8mVVaFur1b2Uz6ieCDlrOXnzD1BrcleiZem7og
on/3oCUK+qxibCCcd5Hg2HtPusa43U0/UbCrqb2sww9iN36DLdtef/jlozKNiBx9
e8ZztF6GtAKhIdgGW/M9TXMUZOYr7aaXO71MsqhwpVWZ5dNqagOBzhmd7Etokf1H
O0WxJZ5XPDsnlKwYq86ssK+2RCNYAuvZoM3dRCysPvXoBFmsmHDzKdbKcckd8Vxr
6P1yaCkB/iX55dUqwKfIuqxY3m4MA2Us9DD0BRxZOSUqHhzHHSogsLhqLQEQENA4
U9N/v/za81UaU8nfkAswsGlTdTKjWH6Fzc0NeagbEFtpUaG/WIHPesUzU7ZNvMzR
SQACVWl62Dley2g2eAgcrsIn78MbwNJI2YN5eXIw0K2MiMlGXWOEvkjIIVfjc0/d
QxLFJwqShZBVO+jnAJ8jti7mP6PgskjtfHNAIphRJ4fm9h/Ns1YMpipBRVBDhbwY
AOVT4bRw9Q3O5I0pe10ZdViAhexegQ8yGt3pUlKaUf9GRwIFEknjZ5Pc98V/R/wC
INSIOZzDHj2uyZ3p7ToF1Z6kVVbbyfqDOnxUiV2ykR8ZqQMXNWcEJKH8qRqI+VHf
oszD2BQvXgkWdrJtHuHjJCdDl03Y+daS5yP8IKTDucHvRv4ZSMghZ34SJTw5MaBP
-----END RSA PRIVATE KEY-----
Binary file not shown.
+20
View File
@@ -36,6 +36,7 @@
"react-scrollbars-custom": "^4.1.1", "react-scrollbars-custom": "^4.1.1",
"react-signature-canvas": "^1.0.6", "react-signature-canvas": "^1.0.6",
"reactour": "^1.19.1", "reactour": "^1.19.1",
"select-dom": "^9.0.0",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
} }
}, },
@@ -18702,6 +18703,20 @@
"resolved": "https://registry.npmjs.org/scrollparent/-/scrollparent-2.0.1.tgz", "resolved": "https://registry.npmjs.org/scrollparent/-/scrollparent-2.0.1.tgz",
"integrity": "sha512-HSdN78VMvFCSGCkh0oYX/tY4R3P1DW61f8+TeZZ4j2VLgfwvw0bpRSOv4PCVKisktIwbzHCfZsx+rLbbDBqIBA==" "integrity": "sha512-HSdN78VMvFCSGCkh0oYX/tY4R3P1DW61f8+TeZZ4j2VLgfwvw0bpRSOv4PCVKisktIwbzHCfZsx+rLbbDBqIBA=="
}, },
"node_modules/select-dom": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/select-dom/-/select-dom-9.0.0.tgz",
"integrity": "sha512-AD1NfASSwJQc1Sy713R1vT9CMmUSUo2tg0j1FtkRGIxllTphDrkuH2pYYvhRlGaoq3pS6tcKkKS/diEZLy+7BQ==",
"dependencies": {
"typed-query-selector": "^2.11.0"
},
"engines": {
"node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/fregante"
}
},
"node_modules/select-hose": { "node_modules/select-hose": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -20203,6 +20218,11 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/typed-query-selector": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.11.0.tgz",
"integrity": "sha512-qBs4sfmnLlPOyo2oSdvHbIFHe2CPgU54/1UGfSNceb7LARpIEVxUaeRX0Doje6oKpuySS2stqy90R3YrynR8Kg=="
},
"node_modules/typedarray-to-buffer": { "node_modules/typedarray-to-buffer": {
"version": "3.1.5", "version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
@@ -32,6 +32,7 @@
"react-scrollbars-custom": "^4.1.1", "react-scrollbars-custom": "^4.1.1",
"react-signature-canvas": "^1.0.6", "react-signature-canvas": "^1.0.6",
"reactour": "^1.19.1", "reactour": "^1.19.1",
"select-dom": "^9.0.0",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"scripts": { "scripts": {
@@ -1,7 +1,15 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import "./certificate.css"; import "./certificate.css";
import opensignLogo from "../../assests/open-sign-logo.png";
import { Page, Text, View, Document, StyleSheet } from "@react-pdf/renderer"; import {
Page,
Text,
View,
Document,
StyleSheet,
Image
} from "@react-pdf/renderer";
function Certificate({ pdfData }) { function Certificate({ pdfData }) {
const [isMultiSigners, setIsMultiSigners] = useState(); const [isMultiSigners, setIsMultiSigners] = useState();
@@ -49,70 +57,34 @@ function Certificate({ pdfData }) {
fontSize: "11px", fontSize: "11px",
marginBottom: "10px", marginBottom: "10px",
color: "gray" color: "gray"
},
image: {
width: "71px",
height: "17px"
} }
}); });
const generatedDate = () => { const generatedDate = () => {
const newDate = new Date(); const newDate = new Date();
const localExpireDate = newDate.toLocaleDateString("en-US", { const utcTime = newDate.toUTCString();
day: "numeric",
month: "long",
year: "numeric"
});
var currentOffset = newDate.getTimezoneOffset();
var ISTOffset = 330; // IST offset UTC +5:30
var ISTTime = new Date(
newDate.getTime() + (ISTOffset + currentOffset) * 60000
);
// ISTTime now represents the time in IST coordinates
var hoursIST = ISTTime.getHours();
var minutesIST = ISTTime.getMinutes();
return ( return (
<Text <Text
style={{ style={{
textAlign: "right",
color: "gray", color: "gray",
fontSize: "10px", fontSize: "10px"
marginBottom: "30px"
}} }}
> >
Generated On {localExpireDate} {hoursIST}:{minutesIST} IST Generated On {utcTime}
</Text> </Text>
); );
}; };
const changeCompletedDate = () => { const changeCompletedDate = () => {
const completedOn = pdfData[0].updatedAt; const completedOn = pdfData[0].updatedAt;
const newDate = new Date(completedOn); const newDate = new Date(completedOn);
const localExpireDate = newDate.toLocaleDateString("en-US", { const utcTime = newDate.toUTCString();
day: "numeric",
month: "long",
year: "numeric"
});
var currentOffset = newDate.getTimezoneOffset(); return <Text style={styles.textStyle2}>{utcTime}</Text>;
var ISTOffset = 330; // IST offset UTC +5:30
var ISTTime = new Date(
newDate.getTime() + (ISTOffset + currentOffset) * 60000
);
// ISTTime now represents the time in IST coordinates
var hoursIST = ISTTime.getHours();
var minutesIST = ISTTime.getMinutes();
return (
<Text style={styles.textStyle2}>
{localExpireDate} {hoursIST}:{minutesIST} IST
</Text>
);
}; };
const signerName = (data) => { const signerName = (data) => {
@@ -143,7 +115,19 @@ function Certificate({ pdfData }) {
{/** Page defines a single page of content. */} {/** Page defines a single page of content. */}
<Page size="A4" style={styles.page}> <Page size="A4" style={styles.page}>
<View style={styles.section1}> <View style={styles.section1}>
{generatedDate()} <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" }}> <View style={{ justifyContent: "center" }}>
<Text <Text
style={{ style={{
@@ -182,7 +166,9 @@ function Certificate({ pdfData }) {
</Text> </Text>
<Text style={styles.textStyle}> <Text style={styles.textStyle}>
Organization : &nbsp; Organization : &nbsp;
<Text style={styles.textStyle2}>__</Text> <Text style={styles.textStyle2}>
{pdfData[0].ExtUserPtr.Company}
</Text>
</Text> </Text>
<Text style={styles.textStyle}> <Text style={styles.textStyle}>
Completed on : &nbsp;{changeCompletedDate()} Completed on : &nbsp;{changeCompletedDate()}
@@ -260,6 +246,12 @@ function Certificate({ pdfData }) {
{pdfData[0].ExtUserPtr.Name} {pdfData[0].ExtUserPtr.Name}
</Text> </Text>
</Text> </Text>
<Text style={styles.textStyle}>
Email : &nbsp;
<Text style={styles.textStyle2}>
{pdfData[0].ExtUserPtr.Email}
</Text>
</Text>
<Text style={styles.textStyle}> <Text style={styles.textStyle}>
Accessed from : &nbsp; Accessed from : &nbsp;
<Text style={styles.textStyle2}> <Text style={styles.textStyle2}>
@@ -1,61 +1,47 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import Loader from "./component/loader"; import Loader from "./component/loader";
import { getHostUrl } from "../utils/Utils"; import { contractDocument, getHostUrl } from "../utils/Utils";
function DraftDocument() { function DraftDocument() {
const navigate = useNavigate(); const navigate = useNavigate();
const [pdfDetails, setPdfDetails] = useState([]); const [pdfDetails, setPdfDetails] = useState([]);
const [isLoading, setIsLoading] = useState({ const [isLoading, setIsLoading] = useState({
isLoad: true, isLoad: true,
message: "This might take some time", message: "This might take some time"
}); });
const rowLevel = const rowLevel =
localStorage.getItem("rowlevel") && localStorage.getItem("rowlevel") &&
JSON.parse(localStorage.getItem("rowlevel")); JSON.parse(localStorage.getItem("rowlevel"));
const signObjId = const docId =
rowLevel && rowLevel?.id rowLevel && rowLevel?.id
? rowLevel.id ? rowLevel.id
: rowLevel?.objectId && rowLevel.objectId; : rowLevel?.objectId && rowLevel.objectId;
useEffect(() => { useEffect(() => {
if (signObjId) { if (docId) {
getDocumentDetails(); getDocumentDetails();
} }
}, []); }, []);
//get document details //get document details
const getDocumentDetails = async () => { const getDocumentDetails = async () => {
await axios //getting document details
.get( const documentData = await contractDocument(docId);
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem( if (documentData && documentData.length > 0) {
"_appName" setPdfDetails(documentData);
)}_Document?where={"objectId":"${signObjId}"}&include=ExtUserPtr,Signers`, const loadObj = {
{ isLoad: false
headers: { };
"Content-Type": "application/json", setIsLoading(loadObj);
"X-Parse-Application-Id": localStorage.getItem("parseAppId"), } else if (
"X-Parse-Session-Token": localStorage.getItem("accesstoken"), documentData === "Error: Something went wrong!" ||
}, (documentData.result && documentData.result.error)
} ) {
) alert("Error: Something went wrong!");
.then((Listdata) => { } else {
const json = Listdata.data; alert("No data found!");
const res = json.results; }
if (res[0] && res.length > 0) {
setPdfDetails(res);
const loadObj = {
isLoad: false,
};
setIsLoading(loadObj);
} else {
alert("No data found!");
}
})
.catch((err) => {
console.log("axois err ", err);
});
}; };
//check document type and render on signyour self and placeholder route //check document type and render on signyour self and placeholder route
@@ -63,24 +49,25 @@ function DraftDocument() {
const data = pdfDetails[0]; const data = pdfDetails[0];
const checkSignerExist = const checkSignerExist =
pdfDetails[0] && pdfDetails[0].Signers && pdfDetails[0].Signers; pdfDetails[0] && pdfDetails[0].Signers && pdfDetails[0].Signers;
const isPlaceholder = const isPlaceholder =
pdfDetails[0].Placeholders && pdfDetails[0].Placeholders; pdfDetails[0].Placeholders && pdfDetails[0].Placeholders;
const isDecline = data.IsDeclined && data.IsDeclined; const isDecline = data.IsDeclined && data.IsDeclined;
const signUrl = data.SignedUrl && data.SignedUrl; const signUrl = data.SignedUrl && data.SignedUrl;
const expireDate = pdfDetails[0] && pdfDetails[0].ExpiryDate.iso && pdfDetails[0].ExpiryDate.iso; const expireDate =
pdfDetails[0] &&
pdfDetails[0].ExpiryDate.iso &&
pdfDetails[0].ExpiryDate.iso;
const expireUpdateDate = new Date(expireDate).getTime(); const expireUpdateDate = new Date(expireDate).getTime();
const currDate = new Date().getTime(); const currDate = new Date().getTime();
const hostUrl = getHostUrl(); const hostUrl = getHostUrl();
//checking document is completed and signer exist then navigate to pdfRequestFiles file //checking document is completed and signer exist then navigate to pdfRequestFiles file
if (data.IsCompleted && checkSignerExist) { if (data.IsCompleted && checkSignerExist) {
navigate(`${hostUrl}pdfRequestFiles`); navigate(`${hostUrl}pdfRequestFiles`);
} }
//checking document is completed and signer does not exist then navigate to recipientSignPdf file //checking document is completed and signer does not exist then navigate to recipientSignPdf file
else if (data.IsCompleted && !checkSignerExist) { else if (data.IsCompleted && !checkSignerExist) {
navigate( navigate(`${hostUrl}signaturePdf`);
`${hostUrl}signaturePdf`
);
} }
//checking document is declined by someone then navigate to pdfRequestFiles file //checking document is declined by someone then navigate to pdfRequestFiles file
else if (isDecline) { else if (isDecline) {
@@ -99,7 +99,7 @@ function PdfFileComponent({
//function for navigate user to microapp-signature component //function for navigate user to microapp-signature component
const checkPdfStatus = async (data) => { const checkPdfStatus = async (data) => {
const hostUrl = getHostUrl(); const hostUrl = getHostUrl();
const expireDate = data.ExpiryDate.iso; const expireDate = data.ExpiryDate.iso;
const expireUpdateDate = new Date(expireDate).getTime(); const expireUpdateDate = new Date(expireDate).getTime();
@@ -221,13 +221,19 @@ function PdfFileComponent({
// console.log("download") // console.log("download")
const pdfName = data && data.Name; const pdfName = data && data.Name;
const pdfUrl = data && data.SignedUrl ? data.SignedUrl : data.URL; const pdfUrl = data && data.SignedUrl ? data.SignedUrl : data.URL;
saveAs(pdfUrl, `${pdfName}_signed_by_OpenSign™.pdf`); saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
} else if (selectType === "Rename") { } else if (selectType === "Rename") {
// console.log("rename") // console.log("rename")
setRenameValue(data.Name); setRenameValue(data.Name);
setRename(data.objectId); setRename(data.objectId);
} }
}; };
const sanitizeFileName = (pdfName) => {
// Replace spaces with underscore
return pdfName.replace(/ /g, '_');
}
const handleEnterPress = (e, data) => { const handleEnterPress = (e, data) => {
if (e.key === "Enter") { if (e.key === "Enter") {
handledRenameDoc(data); handledRenameDoc(data);
@@ -6,6 +6,7 @@ import PdfFileComponent from "./FolderDrive/legaDriveComponent";
import Modal from "react-bootstrap/Modal"; import Modal from "react-bootstrap/Modal";
import ModalHeader from "react-bootstrap/esm/ModalHeader"; import ModalHeader from "react-bootstrap/esm/ModalHeader";
import { themeColor, iconColor } from "../../utils/ThemeColor/backColor"; import { themeColor, iconColor } from "../../utils/ThemeColor/backColor";
import { getDrive } from "../../utils/Utils";
function PdfFile() { function PdfFile() {
const scrollRef = useRef(null); const scrollRef = useRef(null);
@@ -15,28 +16,24 @@ function PdfFile() {
const [pdfData, setPdfData] = useState([]); const [pdfData, setPdfData] = useState([]);
const [isFolder, setIsFolder] = useState(false); const [isFolder, setIsFolder] = useState(false);
const [newFolderName, setNewFolderName] = useState(); const [newFolderName, setNewFolderName] = useState();
// const [parentFolderName, setParentFolderName] = useState();
// const [parentFolder, setParentFolder] = useState([]);
const [error, setError] = useState(); const [error, setError] = useState();
const [folderLoader, setIsFolderLoader] = useState(false); const [folderLoader, setIsFolderLoader] = useState(false);
const [isShowSort, setIsShowSort] = useState(false); const [isShowSort, setIsShowSort] = useState(false);
const [isLoading, setIsLoading] = useState({ const [isLoading, setIsLoading] = useState({
isLoad: true, isLoad: true,
message: "This might take some time", message: "This might take some time"
}); });
const [docId, setDocId] = useState(); const [docId, setDocId] = useState();
const [handleError, setHandleError] = useState(); const [handleError, setHandleError] = useState();
const [folderName, setFolderName] = useState([]); const [folderName, setFolderName] = useState([]);
const currentUser =
const senderUser =
localStorage.getItem( localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser` `Parse/${localStorage.getItem("parseAppId")}/currentUser`
) && ) &&
localStorage.getItem( localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser` `Parse/${localStorage.getItem("parseAppId")}/currentUser`
); );
const jsonSender = JSON.parse(senderUser); const jsonCurrentUser = JSON.parse(currentUser);
useEffect(() => { useEffect(() => {
if (docId) { if (docId) {
@@ -50,104 +47,59 @@ function PdfFile() {
const getPdfDocumentList = async () => { const getPdfDocumentList = async () => {
const load = { const load = {
isLoad: true, isLoad: true,
message: "This might take some time", message: "This might take some time"
}; };
setIsLoading(load); setIsLoading(load);
//?where={"Type":"Folder" }&include=ExtUserPtr,Signers const driveDetails = await getDrive();
//?where={"$or":[{"Type":{"$exists":true}},{"Folder":{"$exists":false}}]}&include=ExtUserPtr,Signers
// "CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${jsonSender.objectId}"}
// where={"Folder":{"$exists":false} }&include=ExtUserPtr,Signers`,
await axios
.get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document?where={"Folder":{"$exists":false},"$or":[{"CreatedBy":{"$exists":false}},{"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${
jsonSender.objectId
}"}}]}&include=ExtUserPtr,Signers`,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken"),
},
}
)
.then((Listdata) => {
const json = Listdata.data;
const res = json.results;
// console.log("result", res);
if (res[0] && res.length > 0) {
setPdfData(res);
}
const data = [ if (driveDetails) {
{ if (driveDetails.length > 0) {
name: "OpenSignDrive™", setPdfData(driveDetails);
objectId: "", }
}, const data = [
]; {
setFolderName(data); name: "OpenSignDrive™",
const loadObj = { objectId: ""
isLoad: false, }
}; ];
setIsLoading(loadObj); setFolderName(data);
}) const loadObj = {
.catch((err) => { isLoad: false
const loadObj = { };
isLoad: false, setIsLoading(loadObj);
}; } else if (driveDetails === "Error: Something went wrong!") {
setHandleError("Error: Something went wrong!"); const loadObj = {
setIsLoading(loadObj); isLoad: false
}); };
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
}
}; };
//function for get parent folder document list //function for get parent folder document list
const getPdfFolderDocumentList = async () => { const getPdfFolderDocumentList = async () => {
const load = { const load = {
isLoad: true, isLoad: true,
message: "This might take some time", message: "This might take some time"
}; };
setIsLoading(load); setIsLoading(load);
//{"$inQuery":{"where":{"objectId":"${docId}"},"className":"${appName}_Document"}} const driveDetails = await getDrive(docId);
//"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${jsonSender.objectId}"} if (driveDetails) {
await axios if (driveDetails.length > 0) {
.get( setPdfData(driveDetails);
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem( } else {
"_appName" setPdfData([]);
)}_Document?where={"Folder":{"__type":"Pointer","className":"${localStorage.getItem( }
"_appName" const loadObj = {
)}_Document","objectId":"${docId}"},"$or":[{"CreatedBy":{"$exists":false}},{"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${ isLoad: false
jsonSender.objectId };
}"}}]}&include=ExtUserPtr,Signers,Folder`, setIsLoading(loadObj);
{ } else if (driveDetails === "Error: Something went wrong!") {
headers: { const loadObj = {
"Content-Type": "application/json", isLoad: false
"X-Parse-Application-Id": localStorage.getItem("parseAppId"), };
"X-Parse-Session-Token": localStorage.getItem("accesstoken"), setHandleError("Error: Something went wrong!");
}, setIsLoading(loadObj);
} }
)
.then((Listdata) => {
const json = Listdata.data;
const res = json.results;
if (res[0] && res.length > 0) {
setPdfData(res);
} else {
setPdfData([]);
}
const loadObj = {
isLoad: false,
};
setIsLoading(loadObj);
})
.catch((err) => {
const loadObj = {
isLoad: false,
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
});
}; };
//function for get all pdf document list //function for get all pdf document list
@@ -158,7 +110,7 @@ function PdfFile() {
const handleRoute = (data) => { const handleRoute = (data) => {
let loadObj = { let loadObj = {
isLoad: true, isLoad: true,
message: "This might take some time", message: "This might take some time"
}; };
if (data.name === "LegaDrive™") { if (data.name === "LegaDrive™") {
setIsLoading(loadObj); setIsLoading(loadObj);
@@ -167,7 +119,7 @@ function PdfFile() {
} else { } else {
setTimeout(() => { setTimeout(() => {
const loadObj = { const loadObj = {
isLoad: false, isLoad: false
}; };
setIsLoading(loadObj); setIsLoading(loadObj);
}, 1000); }, 1000);
@@ -176,12 +128,11 @@ function PdfFile() {
setIsLoading(loadObj); setIsLoading(loadObj);
setTimeout(() => { setTimeout(() => {
const loadObj = { const loadObj = {
isLoad: false, isLoad: false
}; };
setIsLoading(loadObj); setIsLoading(loadObj);
}, 1000); }, 1000);
} else { } else {
// console.log("go here1",data.objectId)
const findIndex = folderName.findIndex( const findIndex = folderName.findIndex(
(fold) => fold.objectId === data.objectId (fold) => fold.objectId === data.objectId
); );
@@ -207,22 +158,32 @@ function PdfFile() {
setIsFolderLoader(true); setIsFolderLoader(true);
const getParentObjId = folderName[folderName.length - 1]; const getParentObjId = folderName[folderName.length - 1];
const isParentId = getParentObjId && getParentObjId.objectId; const parentId = getParentObjId && getParentObjId.objectId;
let data; let data;
if (isParentId) { if (parentId) {
data = { data = {
Name: newFolderName, Name: newFolderName,
Type: "Folder", Type: "Folder",
Folder: { Folder: {
__type: "Pointer", __type: "Pointer",
className: `${localStorage.getItem("_appName")}_Document`, className: `${localStorage.getItem("_appName")}_Document`,
objectId: isParentId, objectId: parentId
}, },
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: jsonCurrentUser.objectId
}
}; };
} else { } else {
data = { data = {
Name: newFolderName, Name: newFolderName,
Type: "Folder", Type: "Folder",
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: jsonCurrentUser.objectId
}
}; };
} }
@@ -237,8 +198,8 @@ function PdfFile() {
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"), "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken"), "X-Parse-Session-Token": localStorage.getItem("accesstoken")
}, }
} }
) )
@@ -388,7 +349,7 @@ function PdfFile() {
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center"
}} }}
> >
<img <img
@@ -406,7 +367,7 @@ function PdfFile() {
style={{ style={{
margin: "10px 0px 10px 0px", margin: "10px 0px 10px 0px",
fontSize: "15px", fontSize: "15px",
fontWeight: "400", fontWeight: "400"
}} }}
> >
Name* Name*
@@ -428,7 +389,7 @@ function PdfFile() {
display: "flex", display: "flex",
alignItems: "flex-end", alignItems: "flex-end",
justifyContent: "flex-end", justifyContent: "flex-end",
alignContent: "flex-end", alignContent: "flex-end"
}} }}
> >
<button <button
@@ -437,7 +398,7 @@ function PdfFile() {
borderRadius: "0px", borderRadius: "0px",
border: "1.5px solid #e3e2e1", border: "1.5px solid #e3e2e1",
fontWeight: "600", fontWeight: "600",
color: "black", color: "black"
}} }}
className="finishBtn" className="finishBtn"
onClick={() => setIsFolder(false)} onClick={() => setIsFolder(false)}
@@ -448,7 +409,7 @@ function PdfFile() {
<button <button
onClick={() => handleAddFolder()} onClick={() => handleAddFolder()}
style={{ style={{
background: themeColor(), background: themeColor()
}} }}
type="button" type="button"
className="finishBtn" className="finishBtn"
@@ -469,7 +430,7 @@ function PdfFile() {
alignItems: "center", alignItems: "center",
height: "100vh", height: "100vh",
width: "100%", width: "100%",
flexDirection: "column", flexDirection: "column"
}} }}
> >
<img <img
@@ -488,7 +449,7 @@ function PdfFile() {
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center",
height: "100vh", height: "100vh",
width: "100%", width: "100%"
}} }}
> >
<span style={{ fontSize: "20px", color: "gray" }}> <span style={{ fontSize: "20px", color: "gray" }}>
@@ -502,7 +463,7 @@ function PdfFile() {
onMouseEnter={(e) => handleMouseEnter(e)} onMouseEnter={(e) => handleMouseEnter(e)}
ref={scrollRef} ref={scrollRef}
style={{ style={{
width: "100%", width: "100%"
}} }}
className="folderPath" className="folderPath"
> >
@@ -514,7 +475,7 @@ function PdfFile() {
style={{ style={{
color: "#a64b4e", color: "#a64b4e",
fontWeight: "400", fontWeight: "400",
cursor: "pointer", cursor: "pointer"
}} }}
> >
{data.name} {data.name}
@@ -523,7 +484,7 @@ function PdfFile() {
color: "#a64b4e", color: "#a64b4e",
fontWeight: "200", fontWeight: "200",
cursor: "pointer", cursor: "pointer",
margin: "0 4px", margin: "0 4px"
}} }}
> >
&gt; &gt;
@@ -545,13 +506,13 @@ function PdfFile() {
style={{ style={{
marginRight: "5px", marginRight: "5px",
fontSize: "14px", fontSize: "14px",
color: `${iconColor()}`, color: `${iconColor()}`
}} }}
></i> ></i>
<span <span
style={{ style={{
fontSize: "15px", fontSize: "15px",
color: `${iconColor()}`, color: `${iconColor()}`
}} }}
> >
{selectedSort} {selectedSort}
@@ -694,7 +655,7 @@ function PdfFile() {
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center",
height: "50vh", height: "50vh",
width: "100%", width: "100%"
}} }}
> >
<span style={{ fontWeight: "bold" }}>No Data Found!</span> <span style={{ fontWeight: "bold" }}>No Data Found!</span>
@@ -0,0 +1,16 @@
import React from "react";
const PageNotFound = () => {
return (
<div className="flex items-center justify-center h-screen w-full bg-white rounded">
<div className="text-center">
<h1 className="text-[60px] lg:text-[120px] font-semibold text-black">
404
</h1>
<p className="text-[30px] lg:text-[50px] text-black">Page Not Found</p>
</div>
</div>
);
};
export default PageNotFound;
@@ -1,6 +1,6 @@
import React, { useState, useRef, useEffect } from "react"; import React, { useState, useRef, useEffect } from "react";
import { themeColor } from "../utils/ThemeColor/backColor"; import { themeColor } from "../utils/ThemeColor/backColor";
import { PDFDocument, rgb } from "pdf-lib"; import { PDFDocument } from "pdf-lib";
import "../css/signature.css"; import "../css/signature.css";
import axios from "axios"; import axios from "axios";
import ModalHeader from "react-bootstrap/esm/ModalHeader"; import ModalHeader from "react-bootstrap/esm/ModalHeader";
@@ -12,14 +12,21 @@ import { useParams } from "react-router-dom";
import SignPad from "./component/signPad"; import SignPad from "./component/signPad";
import RenderAllPdfPage from "./component/renderAllPdfPage"; import RenderAllPdfPage from "./component/renderAllPdfPage";
import { import {
convertPNGtoJPEG,
contractDocument,
getBase64FromIMG, getBase64FromIMG,
getBase64FromUrl getBase64FromUrl,
urlValidator,
multiSignEmbed,
embedDocId,
pdfNewWidthFun
} from "../utils/Utils"; } from "../utils/Utils";
import Loader from "./component/loader"; import Loader from "./component/loader";
import HandleError from "./component/HandleError"; import HandleError from "./component/HandleError";
import Nodata from "./component/Nodata"; import Nodata from "./component/Nodata";
import Header from "./component/header"; import Header from "./component/header";
import RenderPdf from "./component/renderPdf"; import RenderPdf from "./component/renderPdf";
import CustomModal from "./component/CustomModal";
function PdfRequestFiles() { function PdfRequestFiles() {
const { docId } = useParams(); const { docId } = useParams();
@@ -64,7 +71,8 @@ function PdfRequestFiles() {
const [isSigned, setIsSigned] = useState(false); const [isSigned, setIsSigned] = useState(false);
const [isExpired, setIsExpired] = useState(false); const [isExpired, setIsExpired] = useState(false);
const [alreadySign, setAlreadySign] = useState(false); const [alreadySign, setAlreadySign] = useState(false);
const [containerWH, setContainerWH] = useState({});
const divRef = useRef(null);
const rowLevel = const rowLevel =
localStorage.getItem("rowlevel") && localStorage.getItem("rowlevel") &&
JSON.parse(localStorage.getItem("rowlevel")); JSON.parse(localStorage.getItem("rowlevel"));
@@ -85,167 +93,152 @@ function PdfRequestFiles() {
const jsonSender = JSON.parse(senderUser); const jsonSender = JSON.parse(senderUser);
useEffect(() => { useEffect(() => {
const clientWidth = window.innerWidth;
const value = docId ? 80 : 30;
const pdfWidth = clientWidth - 160 - 200 - value;
//160 is width of left side, 200 is width of right side component and 50 is space of middle compoent
//pdf from left and right component
setPdfNewWidth(pdfWidth);
if (documentId) { if (documentId) {
getDocumentDetails(); getDocumentDetails();
} }
}, []); }, []);
useEffect(() => {
if (divRef.current) {
const pdfWidth = pdfNewWidthFun(divRef);
setPdfNewWidth(pdfWidth);
setContainerWH({
width: divRef.current.offsetWidth,
height: divRef.current.offsetHeight
});
}
}, [divRef.current]);
//function for get document details for perticular signer with signer'object id //function for get document details for perticular signer with signer'object id
const getDocumentDetails = async () => { const getDocumentDetails = async () => {
await axios //getting document details
.get( const documentData = await contractDocument(documentId);
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem( if (documentData && documentData.length > 0) {
"_appName" const isCompleted =
)}_Document?where={"objectId":"${documentId}"}&include=ExtUserPtr,Signers,UserPtr`, documentData[0].IsCompleted && documentData[0].IsCompleted;
{ const expireDate = documentData[0].ExpiryDate.iso;
headers: { const declined = documentData[0].IsDeclined && documentData[0].IsDeclined;
"Content-Type": "application/json", const expireUpdateDate = new Date(expireDate).getTime();
"X-Parse-Application-Id": localStorage.getItem("parseAppId"), const currDate = new Date().getTime();
"X-Parse-Session-Token": localStorage.getItem("accesstoken") const getSigners = documentData[0].Signers;
} const getCurrentSigner =
} getSigners &&
) getSigners.filter(
.then((Listdata) => { (data) => data.UserId.objectId === jsonSender.objectId
const json = Listdata.data; );
const res = json.results;
if (res[0] && res.length > 0) { const currUserId = getCurrentSigner[0]
const isCompleted = res[0].IsCompleted && res[0].IsCompleted; ? getCurrentSigner[0].objectId
const expireDate = res[0].ExpiryDate.iso; : "";
const declined = res[0].IsDeclined && res[0].IsDeclined; setSignerObjectId(currUserId);
const expireUpdateDate = new Date(expireDate).getTime(); if (documentData[0].SignedUrl) {
const currDate = new Date().getTime(); setPdfUrl(documentData[0].SignedUrl);
const getSigners = res[0].Signers; } else {
const getCurrentSigner = setPdfUrl(documentData[0].URL);
getSigners && }
getSigners.filter( if (isCompleted) {
(data) => data.UserId.objectId === jsonSender.objectId setIsSigned(true);
); const data = {
isCertificate: true,
const currUserId = getCurrentSigner[0] isModal: true
? getCurrentSigner[0].objectId
: "";
setSignerObjectId(currUserId);
if (res[0].SignedUrl) {
setPdfUrl(res[0].SignedUrl);
} else {
setPdfUrl(res[0].URL);
}
if (isCompleted) {
setIsSigned(true);
const data = {
isCertificate: true,
isModal: true
};
setAlreadySign(true);
setIsCompleted(data);
} else if (declined) {
const currentDecline = {
currnt: "another",
isDeclined: true
};
setIsDecline(currentDecline);
} else if (currDate > expireUpdateDate) {
setIsExpired(true);
}
if (res.length > 0) {
const checkDocIdExist =
json.results[0].AuditTrail &&
json.results[0].AuditTrail.length > 0 &&
json.results[0].AuditTrail.filter(
(data) => data.Activity === "Signed"
);
const checkAlreadySign =
json.results[0].AuditTrail &&
json.results[0].AuditTrail.length > 0 &&
json.results[0].AuditTrail.filter(
(data) =>
data.UserPtr.objectId === currUserId &&
data.Activity === "Signed"
);
if (
checkAlreadySign &&
checkAlreadySign[0] &&
checkAlreadySign.length > 0
) {
setAlreadySign(true);
}
let signers = [];
let unSignedSigner = [];
//check document is signed or not
if (checkDocIdExist && checkDocIdExist.length > 0) {
setAlreadySign(true);
setIsDocId(true);
const signerRes = res[0].Signers;
//comparison auditTrail user details with signers user details
for (let i = 0; i < signerRes.length; i++) {
const signerId = signerRes[i].objectId;
let isSigned = false;
for (let j = 0; j < checkDocIdExist.length; j++) {
const signedExist =
checkDocIdExist[j] && checkDocIdExist[j].UserPtr.objectId;
//checking signerObjId and auditTrail User objId
// if match then add signed data in signer array and break loop
if (signerId === signedExist) {
signers.push({ ...signerRes[i], ...signerRes[i] });
isSigned = true;
break;
}
// if does not match then add unsigned data in unSignedSigner array
}
if (!isSigned) {
unSignedSigner.push({ ...signerRes[i], ...signerRes[i] });
}
}
setSignedSigners(signers);
setUnSignedSigners(unSignedSigner);
setSignerPos(res[0].Placeholders);
} else {
let unsigned = [];
for (let i = 0; i < res.length; i++) {
unsigned.push(res[i].Signers);
}
setUnSignedSigners(unsigned[0]);
setSignerPos(res[0].Placeholders);
}
setPdfDetails(res);
setIsUiLoading(false);
} else {
alert("No data found!");
}
} else {
setNoData(true);
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
setIsUiLoading(false);
}
})
.catch((err) => {
console.log("err", err);
const loadObj = {
isLoad: false
}; };
setHandleError("Error: Something went wrong!"); setAlreadySign(true);
setIsLoading(loadObj); setIsCompleted(data);
}); } else if (declined) {
const currentDecline = {
currnt: "another",
isDeclined: true
};
setIsDecline(currentDecline);
} else if (currDate > expireUpdateDate) {
setIsExpired(true);
}
if (documentData.length > 0) {
const checkDocIdExist =
documentData[0].AuditTrail &&
documentData[0].AuditTrail.length > 0 &&
documentData[0].AuditTrail.filter(
(data) => data.Activity === "Signed"
);
const checkAlreadySign =
documentData[0].AuditTrail &&
documentData[0].AuditTrail.length > 0 &&
documentData[0].AuditTrail.filter(
(data) =>
data.UserPtr.objectId === currUserId && data.Activity === "Signed"
);
if (
checkAlreadySign &&
checkAlreadySign[0] &&
checkAlreadySign.length > 0
) {
setAlreadySign(true);
}
let signers = [];
let unSignedSigner = [];
//check document is signed or not
if (checkDocIdExist && checkDocIdExist.length > 0) {
setIsDocId(true);
const signerRes = documentData[0].Signers;
//comparison auditTrail user details with signers user details
for (let i = 0; i < signerRes.length; i++) {
const signerId = signerRes[i].objectId;
let isSigned = false;
for (let j = 0; j < checkDocIdExist.length; j++) {
const signedExist =
checkDocIdExist[j] && checkDocIdExist[j].UserPtr.objectId;
//checking signerObjId and auditTrail User objId
// if match then add signed data in signer array and break loop
if (signerId === signedExist) {
signers.push({ ...signerRes[i], ...signerRes[i] });
isSigned = true;
break;
}
// if does not match then add unsigned data in unSignedSigner array
}
if (!isSigned) {
unSignedSigner.push({ ...signerRes[i], ...signerRes[i] });
}
}
setSignedSigners(signers);
setUnSignedSigners(unSignedSigner);
setSignerPos(documentData[0].Placeholders);
} else {
let unsigned = [];
for (let i = 0; i < documentData.length; i++) {
unsigned.push(documentData[i].Signers);
}
setUnSignedSigners(unsigned[0]);
setSignerPos(documentData[0].Placeholders);
}
setPdfDetails(documentData);
setIsUiLoading(false);
} else {
alert("No data found!");
}
} else if (
documentData === "Error: Something went wrong!" ||
(documentData.result && documentData.result.error)
) {
const loadObj = {
isLoad: false
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
} else {
setNoData(true);
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
setIsUiLoading(false);
}
await axios await axios
.get( .get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem( `${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
@@ -287,7 +280,6 @@ function PdfRequestFiles() {
const checkUser = signerPos.filter( const checkUser = signerPos.filter(
(data) => data.signerObjId === signerObjectId (data) => data.signerObjId === signerObjectId
); );
if (checkUser && checkUser.length > 0) { if (checkUser && checkUser.length > 0) {
let checkSignUrl = []; let checkSignUrl = [];
const checkSign = checkUser[0].placeHolder.filter( const checkSign = checkUser[0].placeHolder.filter(
@@ -325,67 +317,25 @@ function PdfRequestFiles() {
if (isDocId) { if (isDocId) {
pdfBase64 = await getBase64FromUrl(url); pdfBase64 = await getBase64FromUrl(url);
} else { } else {
for (let i = 0; i < allPages; i++) { //embed document's object id to all pages in pdf document
const font = await pdfDoc.embedFont("Helvetica"); await embedDocId(pdfDoc, documentId, allPages);
const fontSize = 10;
const textContent =
documentId && `OpenSign™ DocumentId: ${documentId}`;
const pages = pdfDoc.getPages();
const page = pages[i];
page.drawText(textContent, {
x: 10,
y: page.getHeight() - 10,
size: fontSize,
font,
color: rgb(0.5, 0.5, 0.5)
});
}
pdfBase64 = await pdfDoc.saveAsBase64({ pdfBase64 = await pdfDoc.saveAsBase64({
useObjectStreams: false useObjectStreams: false
}); });
} }
for (let i = 0; i < pngUrl.length; i++) { for (let i = 0; i < pngUrl.length; i++) {
const imgUrlList = pngUrl[i].pos; const imgUrlList = pngUrl[i].pos;
const pageNo = pngUrl[i].pageNumber; const pageNo = pngUrl[i].pageNumber;
imgUrlList.map(async (data) => { imgUrlList.map(async (data) => {
//cheking signUrl is defau;t signature url of custom url //cheking signUrl is defau;t signature url of custom url
let ImgUrl = data.SignUrl; let ImgUrl = data.SignUrl;
const checkUrl = ImgUrl.includes("https:"); const checkUrl = urlValidator(ImgUrl);
//if default signature url then convert it in base 64 //if default signature url then convert it in base 64
if (checkUrl) { if (checkUrl) {
ImgUrl = await getBase64FromIMG(ImgUrl + "?get"); ImgUrl = await getBase64FromIMG(ImgUrl + "?get");
} }
//function for called convert png signatre to jpeg in base 64 //function for called convert png signatre to jpeg in base 64
const convertPNGtoJPEG = (base64Data) => {
return new Promise((resolve, reject) => {
const canvas = document.createElement("canvas");
const img = new Image();
img.src = base64Data;
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
// Convert to JPEG by using the canvas.toDataURL() method
const jpegBase64Data = canvas.toDataURL("image/jpeg");
resolve(jpegBase64Data);
};
img.onerror = (error) => {
reject(error);
};
});
};
convertPNGtoJPEG(ImgUrl) convertPNGtoJPEG(ImgUrl)
.then((jpegBase64Data) => { .then((jpegBase64Data) => {
const removeBase64Fromjpeg = "data:image/jpeg;base64,"; const removeBase64Fromjpeg = "data:image/jpeg;base64,";
@@ -412,123 +362,15 @@ function PdfRequestFiles() {
} }
//else if signature is more than one then embed all sign with the use of pdf-lib //else if signature is more than one then embed all sign with the use of pdf-lib
else if (pngUrl.length > 0 && pngUrl[0].pos.length > 0) { else if (pngUrl.length > 0 && pngUrl[0].pos.length > 0) {
for (let i = 0; i < allPages; i++) { //embed document's object id to all pages in pdf document
const font = await pdfDoc.embedFont("Helvetica"); await embedDocId(pdfDoc, documentId, allPages);
//embed multi signature in pdf
const fontSize = 10; const pdfBytes = await multiSignEmbed(
const textContent = pngUrl,
documentId && `OpenSign™ DocumentId: ${documentId} `; pdfDoc,
pdfOriginalWidth,
const pages = pdfDoc.getPages(); false
const page = pages[i]; );
page.drawText(textContent, {
x: 10,
y: page.getHeight() - 10,
size: fontSize,
font,
color: rgb(0.5, 0.5, 0.5)
});
}
for (let i = 0; i < pngUrl.length; i++) {
const pageNo = pngUrl[i].pageNumber;
const imgUrlList = pngUrl[i].pos;
const pages = pdfDoc.getPages();
const page = pages[pageNo - 1];
const images = await Promise.all(
imgUrlList.map(async (url) => {
let signUrl = url.SignUrl;
const checkUrl = url.SignUrl.includes("https:");
if (checkUrl) {
signUrl = signUrl + "?get";
}
const res = await fetch(signUrl);
return res.arrayBuffer();
})
);
images.forEach(async (imgData, id) => {
let img;
if (
imgUrlList[id].ImageType &&
imgUrlList[id].ImageType === "image/jpeg"
) {
img = await pdfDoc.embedJpg(imgData);
} else if (
imgUrlList[id].ImageType &&
imgUrlList[id].ImageType === "image/png"
) {
img = await pdfDoc.embedPng(imgData);
} else {
img = await pdfDoc.embedPng(imgData);
}
const imgHeight = imgUrlList[id].Height
? imgUrlList[id].Height
: 60;
const imgWidth = imgUrlList[id].Width
? imgUrlList[id].Width
: 150;
const isMobile = window.innerWidth < 767;
const newWidth = window.innerWidth;
const scale = isMobile ? pdfOriginalWidth / newWidth : 1;
const xPos = (pos) => {
//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) {
const x = pos.xPosition * (pos.scale / scale);
return x * scale + 50;
} else {
const x = pos.xPosition / scale;
return x * 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) {
const x = pos.xPosition * pos.scale + 50;
return x;
} else {
return pos.xPosition;
}
}
};
const yPos = (pos) => {
//checking both condition mobile and desktop view
const y = pos.yPosition / scale;
if (isMobile) {
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
if (pos.isMobile) {
const y = pos.yPosition * (pos.scale / scale);
return page.getHeight() - y * scale - imgHeight;
} else {
return page.getHeight() - y * scale - imgHeight;
}
} 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) {
const y = pos.yPosition * pos.scale;
return page.getHeight() - y - imgHeight;
} else {
return page.getHeight() - pos.yPosition - imgHeight;
}
}
};
page.drawImage(img, {
x: xPos(imgUrlList[id]),
y: yPos(imgUrlList[id]),
width: imgWidth,
height: imgHeight
});
});
}
const pdfBytes = await pdfDoc.saveAsBase64({
useObjectStreams: false
});
signPdfFun(pdfBytes, documentId, pngUrl); signPdfFun(pdfBytes, documentId, pngUrl);
} }
@@ -590,12 +432,12 @@ function PdfRequestFiles() {
if (isMobile) { if (isMobile) {
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale //if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
if (pos.isMobile) { if (pos.isMobile) {
const y = pos.yPosition * (pos.scale / scale); const y = pos.yBottom * (pos.scale / scale);
yPosition = pos.isDrag yPosition = pos.isDrag
? y * scale - height ? y * scale - height
: pos.firstYPos : pos.firstYPos
? y * scale - height + pos.firstYPos ? y * scale - height + pos.firstYPos
: y * scale - height; : y * scale - height;
return yPosition; return yPosition;
} else { } else {
const y = pos.yBottom / scale; const y = pos.yBottom / scale;
@@ -603,8 +445,8 @@ function PdfRequestFiles() {
yPosition = pos.isDrag yPosition = pos.isDrag
? y * scale - height ? y * scale - height
: pos.firstYPos : pos.firstYPos
? y * scale - height + pos.firstYPos ? y * scale - height + pos.firstYPos
: y * scale - height; : y * scale - height;
return yPosition; return yPosition;
} }
} else { } else {
@@ -615,15 +457,15 @@ function PdfRequestFiles() {
yPosition = pos.isDrag yPosition = pos.isDrag
? y - height ? y - height
: pos.firstYPos : pos.firstYPos
? y - height + pos.firstYPos ? y - height + pos.firstYPos
: y - height; : y - height;
return yPosition; return yPosition;
} else { } else {
yPosition = pos.isDrag yPosition = pos.isDrag
? pos.yBottom - height ? pos.yBottom - height
: pos.firstYPos : pos.firstYPos
? pos.yBottom - height + pos.firstYPos ? pos.yBottom - height + pos.firstYPos
: pos.yBottom - height; : pos.yBottom - height;
return yPosition; return yPosition;
} }
} }
@@ -912,6 +754,7 @@ function PdfRequestFiles() {
//function for set decline true on press decline button //function for set decline true on press decline button
const declineDoc = async () => { const declineDoc = async () => {
setIsDecline({ isDeclined: false });
const data = { const data = {
IsDeclined: true IsDeclined: true
}; };
@@ -983,7 +826,39 @@ function PdfRequestFiles() {
</div> </div>
)} )}
<div className="signatureContainer"> <div className="signatureContainer" ref={divRef}>
{/* this modal is used to show decline alert */}
<CustomModal
containerWH={containerWH}
show={isDecline.isDeclined}
headMsg="Document Declined Alert!"
bodyMssg={
isDecline.currnt === "Sure" ? (
<p className="pTagBody">
Are you sure want to decline this document ?
</p>
) : isDecline.currnt === "YouDeclined" ? (
<p className="pTagBody">You have declined this document!</p>
) : (
isDecline.currnt === "another" && (
<p className="pTagBody">
You cannot sign this document as it has been declined by
one or more person(s).
</p>
)
)
}
footerMessage={isDecline.currnt === "Sure"}
declineDoc={declineDoc}
setIsDecline={setIsDecline}
/>
{/* this modal is used for show expired alert */}
<CustomModal
containerWH={containerWH}
show={isExpired}
headMsg="Document Expired!"
bodyMssg="This Document is no longer available."
/>
{/* this component used to render all pdf pages in left side */} {/* this component used to render all pdf pages in left side */}
<RenderAllPdfPage <RenderAllPdfPage
signPdfUrl={pdfDetails[0].URL} signPdfUrl={pdfDetails[0].URL}
@@ -999,66 +874,6 @@ function PdfRequestFiles() {
marginRight: pdfOriginalWidth > 500 && "20px" marginRight: pdfOriginalWidth > 500 && "20px"
}} }}
> >
<Modal show={isExpired}>
<ModalHeader className="bg-danger">
<span className="spanTagHead">Document Expired!</span>
</ModalHeader>
<Modal.Body>
<p className="pTagBody">
This Document is no longer available.
</p>
</Modal.Body>
</Modal>
{/* this modal is used for show decline alert */}
<Modal show={isDecline.isDeclined}>
<ModalHeader className="bg-danger">
<span className="spanTagHead">Document Declined Alert!</span>
</ModalHeader>
<Modal.Body>
{isDecline.currnt === "Sure" ? (
<p className="pTagBody">
Are you sure want to decline this document ?
</p>
) : isDecline.currnt === "YouDeclined" ? (
<p className="pTagBody">You have declined this document!</p>
) : (
isDecline.currnt === "another" && (
<p className="pTagBody">
You cannot sign this document as it has been declined by
one or more person(s).
</p>
)
)}
</Modal.Body>
<Modal.Footer>
{isDecline.currnt === "Sure" && (
<>
<button
style={{
color: "black"
}}
type="button"
className="finishBtn"
onClick={() => setIsDecline({ isDeclined: false })}
>
Close
</button>
<button
style={{
background: "#de4337"
}}
type="button"
className="finishBtn"
onClick={() => declineDoc()}
>
Yes
</button>
</>
)}
</Modal.Footer>
</Modal>
{/* this modal is used show this document is already sign */} {/* this modal is used show this document is already sign */}
<Modal show={isCompleted.isModal}> <Modal show={isCompleted.isModal}>
@@ -1068,7 +883,7 @@ function PdfRequestFiles() {
<Modal.Body> <Modal.Body>
<p className="pTagBody"> <p className="pTagBody">
This document has been signed by all Sigers. This document has been signed by all Signers.
</p> </p>
</Modal.Body> </Modal.Body>
@@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect } from "react"; import React, { useState, useRef, useEffect } from "react";
import { PDFDocument, rgb } from "pdf-lib"; import { PDFDocument } from "pdf-lib";
import "../css/./signature.css"; import "../css/./signature.css";
import sign from "../assests/sign3.png"; import sign from "../assests/sign3.png";
import stamp from "../assests/stamp2.png"; import stamp from "../assests/stamp2.png";
@@ -15,7 +15,14 @@ import EmailComponent from "./component/emailComponent";
import FieldsComponent from "./component/fieldsComponent"; import FieldsComponent from "./component/fieldsComponent";
import Modal from "react-bootstrap/Modal"; import Modal from "react-bootstrap/Modal";
import ModalHeader from "react-bootstrap/esm/ModalHeader"; import ModalHeader from "react-bootstrap/esm/ModalHeader";
import { getBase64FromIMG } from "../utils/Utils"; import {
convertPNGtoJPEG,
contractDocument,
getBase64FromIMG,
embedDocId,
multiSignEmbed,
pdfNewWidthFun
} from "../utils/Utils";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import Tour from "reactour"; import Tour from "reactour";
import { onSaveImage, onSaveSign } from "../utils/Utils"; import { onSaveImage, onSaveSign } from "../utils/Utils";
@@ -24,7 +31,9 @@ import HandleError from "./component/HandleError";
import Nodata from "./component/Nodata"; import Nodata from "./component/Nodata";
import Header from "./component/header"; import Header from "./component/header";
import RenderPdf from "./component/renderPdf"; import RenderPdf from "./component/renderPdf";
import { contractUsers, contactBook } from "../utils/Utils"; import { contractUsers, contactBook, urlValidator } from "../utils/Utils";
import { modalAlign } from "../utils/Utils";
//For signYourself inProgress section signer can add sign and complete doc sign. //For signYourself inProgress section signer can add sign and complete doc sign.
function SignYourSelf() { function SignYourSelf() {
const [pdfDetails, setPdfDetails] = useState([]); const [pdfDetails, setPdfDetails] = useState([]);
@@ -73,7 +82,7 @@ function SignYourSelf() {
status: false, status: false,
type: "load" type: "load"
}); });
const divRef = useRef(null);
const nodeRef = useRef(null); const nodeRef = useRef(null);
const [{ isOver }, drop] = useDrop({ const [{ isOver }, drop] = useDrop({
accept: "BOX", accept: "BOX",
@@ -160,68 +169,57 @@ function SignYourSelf() {
const jsonSender = JSON.parse(senderUser); const jsonSender = JSON.parse(senderUser);
useEffect(() => { useEffect(() => {
const clientWidth = window.innerWidth;
const value = docId ? 80 : 80;
const pdfWidth = clientWidth - 160 - 200 - value;
//160 is width of left side, 200 is width of right side component and 50 is space of middle compoent
//pdf from left and right component
setPdfNewWidth(pdfWidth);
if (documentId) { if (documentId) {
getDocumentDetails(); getDocumentDetails(true);
} }
}, []); }, []);
useEffect(() => {
if (divRef.current) {
const pdfWidth = pdfNewWidthFun(divRef);
setPdfNewWidth(pdfWidth);
}
}, [divRef.current]);
//function for get document details for perticular signer with signer'object id //function for get document details for perticular signer with signer'object id
const getDocumentDetails = async () => { const getDocumentDetails = async (showComplete) => {
await axios //getting document details
.get( const documentData = await contractDocument(documentId);
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document?where={"objectId":"${documentId}"}&include=ExtUserPtr,Signers`,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
)
.then((Listdata) => {
const json = Listdata.data;
const res = json.results;
if (res[0] && res.length > 0) { if (documentData && documentData.length > 0) {
setPdfDetails(res); setPdfDetails(documentData);
const isCompleted = res[0].IsCompleted && res[0].IsCompleted; const isCompleted =
if (isCompleted) { documentData[0].IsCompleted && documentData[0].IsCompleted;
const docStatus = { if (isCompleted) {
isCompleted: isCompleted const docStatus = {
}; isCompleted: isCompleted
setDocumentStatus(docStatus);
const alreadySign = {
status: true,
mssg: "You have successfully signed the document!"
};
setShowAlreadySignDoc(alreadySign);
setPdfUrl(res[0].SignedUrl);
}
} else {
setNoData(true);
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
}
})
.catch((err) => {
const loadObj = {
isLoad: false
}; };
setHandleError("Error: Something went wrong!"); setDocumentStatus(docStatus);
setIsLoading(loadObj); setPdfUrl(documentData[0].SignedUrl);
}); const alreadySign = {
status: true,
mssg: "You have successfully signed the document!"
};
if (showComplete) {
setShowAlreadySignDoc(alreadySign);
}
}
} else if (
documentData === "Error: Something went wrong!" ||
(documentData.result && documentData.result.error)
) {
const loadObj = {
isLoad: false
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
} else {
setNoData(true);
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
}
await axios await axios
.get( .get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem( `${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
@@ -252,13 +250,10 @@ function SignYourSelf() {
setHandleError("Error: Something went wrong!"); setHandleError("Error: Something went wrong!");
setIsLoading(loadObj); setIsLoading(loadObj);
}); });
const contractUsersRes = await contractUsers(jsonSender.objectId);
if ( const contractUsersRes = await contractUsers(jsonSender.email);
contractUsersRes !== "Error: Something went wrong!" &&
contractUsersRes && if (contractUsersRes[0] && contractUsersRes.length > 0) {
contractUsersRes[0]
) {
setContractName("_Users"); setContractName("_Users");
setSignerUserId(contractUsersRes[0].objectId); setSignerUserId(contractUsersRes[0].objectId);
const tourstatuss = const tourstatuss =
@@ -285,14 +280,12 @@ function SignYourSelf() {
setIsLoading(loadObj); setIsLoading(loadObj);
} else if (contractUsersRes.length === 0) { } else if (contractUsersRes.length === 0) {
const contractContactBook = await contactBook(jsonSender.objectId); const contractContactBook = await contactBook(jsonSender.objectId);
if (contractContactBook && contractContactBook[0]) { if (contractContactBook && contractContactBook.length > 0) {
setContractName("_Contactbook"); setContractName("_Contactbook");
setSignerUserId(contractContactBook[0].objectId); setSignerUserId(contractContactBook[0].objectId);
const tourstatuss = const tourstatuss =
contractContactBook[0].TourStatus && contractContactBook[0].TourStatus &&
contractContactBook[0].TourStatus; contractContactBook[0].TourStatus;
if (tourstatuss && tourstatuss.length > 0) { if (tourstatuss && tourstatuss.length > 0) {
setTourStatus(tourstatuss); setTourStatus(tourstatuss);
const checkTourRecipients = tourstatuss.filter( const checkTourRecipients = tourstatuss.filter(
@@ -302,6 +295,8 @@ function SignYourSelf() {
setCheckTourStatus(checkTourRecipients[0].signyourself); setCheckTourStatus(checkTourRecipients[0].signyourself);
} }
} }
} else {
setNoData(true);
} }
const loadObj = { const loadObj = {
isLoad: false isLoad: false
@@ -432,24 +427,7 @@ function SignYourSelf() {
//checking if signature is only one then send image url in jpeg formate to server //checking if signature is only one then send image url in jpeg formate to server
if (xyPostion.length === 1 && xyPostion[0].pos.length === 1) { if (xyPostion.length === 1 && xyPostion[0].pos.length === 1) {
//embed document's object id to all pages in pdf document //embed document's object id to all pages in pdf document
for (let i = 0; i < allPages; i++) { await embedDocId(pdfDoc, documentId, allPages);
const font = await pdfDoc.embedFont("Helvetica");
const fontSize = 10;
const textContent =
documentId && `OpenSign™ DocumentId: ${documentId}`;
const pages = pdfDoc.getPages();
const page = pages[i];
page.drawText(textContent, {
x: 10,
y: page.getHeight() - 10,
size: fontSize,
font,
color: rgb(0.5, 0.5, 0.5)
});
}
const pdfBase64 = await pdfDoc.saveAsBase64({ const pdfBase64 = await pdfDoc.saveAsBase64({
useObjectStreams: false useObjectStreams: false
}); });
@@ -460,39 +438,13 @@ function SignYourSelf() {
imgUrlList.map(async (data) => { imgUrlList.map(async (data) => {
let ImgUrl = data.SignUrl; let ImgUrl = data.SignUrl;
//cheking signUrl is defau;t signature url of custom url //cheking signUrl is defau;t signature url of custom url
const checkUrl = ImgUrl.includes("https:"); const checkUrl = urlValidator(ImgUrl);
//if default signature url then convert it in base 64 //if default signature url then convert it in base 64
if (checkUrl) { if (checkUrl) {
ImgUrl = await getBase64FromIMG(ImgUrl + "?get"); ImgUrl = await getBase64FromIMG(ImgUrl + "?get");
} }
//function for convert signature png base64 url to jpeg base64 //function for convert signature png base64 url to jpeg base64
const convertPNGtoJPEG = (base64Data) => {
return new Promise((resolve, reject) => {
const canvas = document.createElement("canvas");
const img = new Image();
img.src = base64Data;
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
// Convert to JPEG by using the canvas.toDataURL() method
const jpegBase64Data = canvas.toDataURL("image/jpeg");
resolve(jpegBase64Data);
};
img.onerror = (error) => {
reject(error);
};
});
};
convertPNGtoJPEG(ImgUrl) convertPNGtoJPEG(ImgUrl)
.then((jpegBase64Data) => { .then((jpegBase64Data) => {
const removeBase64Fromjpeg = "data:image/jpeg;base64,"; const removeBase64Fromjpeg = "data:image/jpeg;base64,";
@@ -500,7 +452,6 @@ function SignYourSelf() {
removeBase64Fromjpeg, removeBase64Fromjpeg,
"" ""
); );
//function for call to embed signature in pdf and get digital signature pdf //function for call to embed signature in pdf and get digital signature pdf
signPdfFun(newImgUrl, documentId, data, pdfBase64, pageNo); signPdfFun(newImgUrl, documentId, data, pdfBase64, pageNo);
}) })
@@ -512,91 +463,15 @@ function SignYourSelf() {
} }
//else if signature is more than one then embed all sign with the use of pdf-lib //else if signature is more than one then embed all sign with the use of pdf-lib
else if (xyPostion.length > 0 && xyPostion[0].pos.length > 0) { else if (xyPostion.length > 0 && xyPostion[0].pos.length > 0) {
for (let i = 0; i < allPages; i++) { //embed document's object id to all pages in pdf document
const font = await pdfDoc.embedFont("Helvetica"); await embedDocId(pdfDoc, documentId, allPages);
//embed multi signature in pdf
const fontSize = 10; const pdfBytes = await multiSignEmbed(
const textContent = pngUrl,
documentId && `OpenSign™ DocumentId: ${documentId} `; pdfDoc,
pdfOriginalWidth,
const pages = pdfDoc.getPages(); true
const page = pages[i]; );
page.drawText(textContent, {
x: 10,
y: page.getHeight() - 10,
size: fontSize,
font,
color: rgb(0.5, 0.5, 0.5)
});
}
for (let i = 0; i < pngUrl.length; i++) {
const pageNo = pngUrl[i].pageNumber;
const imgUrlList = pngUrl[i].pos;
const pages = pdfDoc.getPages();
const page = pages[pageNo - 1];
const images = await Promise.all(
imgUrlList.map(async (url) => {
let signUrl = url.SignUrl;
const checkUrl = url.SignUrl.includes("https:");
if (checkUrl) {
signUrl = signUrl + "?get";
}
const res = await fetch(signUrl);
return res.arrayBuffer();
})
);
images.forEach(async (imgData, id) => {
let img;
if (
imgUrlList[id].ImageType &&
imgUrlList[id].ImageType === "image/jpeg"
) {
img = await pdfDoc.embedJpg(imgData);
} else if (
imgUrlList[id].ImageType &&
imgUrlList[id].ImageType === "image/png"
) {
img = await pdfDoc.embedPng(imgData);
} else {
img = await pdfDoc.embedPng(imgData);
}
const imgHeight = imgUrlList[id].Height
? imgUrlList[id].Height
: 60;
const imgWidth = imgUrlList[id].Width ? imgUrlList[id].Width : 150;
const isMobile = window.innerWidth < 767;
const newWidth = window.innerWidth;
const scale = isMobile ? pdfOriginalWidth / newWidth : 1;
const posY = () => {
if (id === 0) {
return (
page.getHeight() -
imgUrlList[id].yPosition * scale -
imgHeight
);
} else if (id > 0) {
return page.getHeight() - imgUrlList[id].yPosition * scale;
}
};
page.drawImage(img, {
x: isMobile
? imgUrlList[id].xPosition * scale + imgWidth / 2
: imgUrlList[id].xPosition,
y: posY(),
width: imgWidth,
height: imgHeight
});
});
}
const pdfBytes = await pdfDoc.saveAsBase64({ useObjectStreams: false });
signPdfFun(pdfBytes, documentId); signPdfFun(pdfBytes, documentId);
} }
setIsSignPad(false); setIsSignPad(false);
@@ -615,17 +490,18 @@ function SignYourSelf() {
pageNo pageNo
) => { ) => {
let singleSign; let singleSign;
const isMobile = window.innerWidth < 767; const isMobile = window.innerWidth < 767;
const newWidth = window.innerWidth; const newWidth = window.innerWidth - 32;
const scale = isMobile ? pdfOriginalWidth / newWidth : 1; const scale = isMobile ? pdfOriginalWidth / newWidth : 1;
const imgWidth = xyPosData.Width.Width ? xyPosData.Width.Width : 150; const imgWidth = xyPosData ? xyPosData.Width : 150;
if (xyPostion.length === 1 && xyPostion[0].pos.length === 1) { if (xyPostion.length === 1 && xyPostion[0].pos.length === 1) {
const height = xyPosData.Height ? xyPosData.Height : 60; const height = xyPosData.Height ? xyPosData.Height : 60;
const bottomY = xyPosData.isDrag const bottomY = xyPosData.isDrag
? xyPosData.yBottom * scale - height ? xyPosData.yBottom * scale - height * scale
: xyPosData.firstYPos : xyPosData.firstYPos
? xyPosData.yBottom * scale - height + xyPosData.firstYPos ? xyPosData.yBottom * scale - height * scale + xyPosData.firstYPos
: xyPosData.yBottom * scale - height; : xyPosData.yBottom * scale - height * scale;
singleSign = { singleSign = {
pdfFile: pdfBase64Url, pdfFile: pdfBase64Url,
@@ -633,11 +509,11 @@ function SignYourSelf() {
sign: { sign: {
Base64: base64Url, Base64: base64Url,
Left: isMobile Left: isMobile
? xyPosData.xPosition * scale + imgWidth / 2 ? xyPosData.xPosition * scale + 43
: xyPosData.xPosition, : xyPosData.xPosition,
Bottom: bottomY, Bottom: bottomY,
Width: xyPosData.Width ? xyPosData.Width : 150, Width: xyPosData.Width ? xyPosData.Width * scale : 150 * scale,
Height: height, Height: height * scale,
Page: pageNo Page: pageNo
} }
}; };
@@ -661,15 +537,7 @@ function SignYourSelf() {
// console.log("json ", json); // console.log("json ", json);
setPdfUrl(json.result.data); setPdfUrl(json.result.data);
if (json.result.data) { if (json.result.data) {
const docStatus = { getDocumentDetails(false);
isCompleted: true
};
setDocumentStatus(docStatus);
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
} }
}) })
.catch((err) => { .catch((err) => {
@@ -1009,7 +877,7 @@ function SignYourSelf() {
) : noData ? ( ) : noData ? (
<Nodata /> <Nodata />
) : ( ) : (
<div className="signatureContainer"> <div className="signatureContainer" ref={divRef}>
{/* this component used for UI interaction and show their functionality */} {/* this component used for UI interaction and show their functionality */}
{pdfLoadFail && !checkTourStatus && ( {pdfLoadFail && !checkTourStatus && (
<Tour <Tour
@@ -1041,7 +909,11 @@ function SignYourSelf() {
> >
{/* this modal is used show this document is already sign */} {/* this modal is used show this document is already sign */}
<Modal show={showAlreadySignDoc.status}> <Modal
show={showAlreadySignDoc.status}
onShow={() => modalAlign()}
backdropClassName="signature-backdrop"
>
<ModalHeader style={{ background: themeColor() }}> <ModalHeader style={{ background: themeColor() }}>
<span style={{ color: "white" }}> Sign Documents</span> <span style={{ color: "white" }}> Sign Documents</span>
</ModalHeader> </ModalHeader>
@@ -1115,6 +987,8 @@ function SignYourSelf() {
pdfDetails={pdfDetails} pdfDetails={pdfDetails}
isShowHeader={true} isShowHeader={true}
currentSigner={true} currentSigner={true}
alreadySign={pdfUrl ? true : false}
isSignYourself={true}
/> />
{/* className="hidePdf" */} {/* className="hidePdf" */}
@@ -0,0 +1,59 @@
import React from "react";
import "../../css/customModal.css";
import "../../css/signature.css";
function CustomModal({
show,
headMsg,
bodyMssg,
footerMessage,
declineDoc,
setIsDecline,
containerWH
}) {
const isMobile = window.innerWidth < 767;
return (
show && (
<div
className="parentDiv"
style={{
width: containerWH && containerWH.width,
height: isMobile ? "100%" : containerWH && containerWH.height
}}
>
<div className="childDiv">
<div className="modalHeadDiv bg-danger">{headMsg && headMsg}</div>
<div className="modalBodyDIv">
<p className="pTagBody">{bodyMssg && bodyMssg}</p>
</div>
{footerMessage && (
<div className="modalFooterDiv">
<button
style={{
color: "black"
}}
type="button"
className="finishBtn"
onClick={() => setIsDecline({ isDeclined: false })}
>
Close
</button>
<button
style={{
background: "#de4337"
}}
type="button"
className="finishBtn"
onClick={() => declineDoc()}
>
Yes
</button>
</div>
)}
</div>
</div>
)
);
}
export default CustomModal;
@@ -1,5 +1,5 @@
import React, { useEffect } from "react"; import React from "react";
import axios from "axios";
function DefaultSignature({ function DefaultSignature({
themeColor, themeColor,
@@ -26,11 +26,9 @@ function EmailComponent({
//function for send email //function for send email
const sendEmail = async () => { const sendEmail = async () => {
setIsLoading(true); setIsLoading(true);
let sendMail, recipent; let sendMail;
for (let i = 0; i < emailCount.length; i++) { for (let i = 0; i < emailCount.length; i++) {
try { try {
const imgPng = const imgPng =
"https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"; "https://qikinnovation.ams3.digitaloceanspaces.com/logo.png";
// "https://qikinnovation.ams3.digitaloceanspaces.com/mailLogo_2023-08-18T12%3A51%3A31.573Z.png"; // "https://qikinnovation.ams3.digitaloceanspaces.com/mailLogo_2023-08-18T12%3A51%3A31.573Z.png";
@@ -41,7 +39,7 @@ function EmailComponent({
"X-Parse-Application-Id": localStorage.getItem("parseAppId"), "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessionToken: localStorage.getItem("accesstoken") sessionToken: localStorage.getItem("accesstoken")
}; };
const themeBGcolor = themeColor(); const themeBGcolor = themeColor();
let params = { let params = {
pdfName: pdfName, pdfName: pdfName,
@@ -109,19 +107,38 @@ function EmailComponent({
const handleToPrint = async (event) => { const handleToPrint = async (event) => {
event.preventDefault(); event.preventDefault();
const base64 = await getBase64FromUrl(pdfUrl); const pdf = await getBase64FromUrl(pdfUrl);
printModule({ printable: base64, type: "pdf", base64: true }); 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 //handle download signed pdf
const handleDownloadPdf = () => { const handleDownloadPdf = () => {
saveAs(pdfUrl, `${pdfName}_signed_by_OpenSign™.pdf`); 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); const isAndroid = /Android/i.test(navigator.userAgent);
return ( return (
<div> <div>
{/* isEmail */} {/* isEmail */}
@@ -153,7 +170,7 @@ function EmailComponent({
)} )}
<ModalHeader style={{ background: themeColor() }}> <ModalHeader style={{ background: themeColor() }}>
<span style={{ color: "white" }}>Email Documents</span> <span style={{ color: "white" }}>Successfully signed!</span>
<div style={{ display: "flex", flexDirection: "row" }}> <div style={{ display: "flex", flexDirection: "row" }}>
<div></div> <div></div>
@@ -239,20 +256,25 @@ function EmailComponent({
style={{ style={{
display: "flex", display: "flex",
flexDirection: "row", flexDirection: "row",
flexWrap: "wrap" flexWrap: "wrap"
}} }}
> >
{emailCount.map((data, ind) => { {emailCount.map((data, ind) => {
return ( return (
<div className="emailChip" <div
style={{display:"flex", flexDirection:"row", alignItems:"center"}} className="emailChip"
key={ind}> style={{
display: "flex",
flexDirection: "row",
alignItems: "center"
}}
key={ind}
>
<span <span
style={{ style={{
color: "white", color: "white",
fontSize: "13px", fontSize: "13px"
marginRight: "20px"
}} }}
> >
{data} {data}
@@ -264,7 +286,8 @@ function EmailComponent({
src={close} src={close}
width={10} width={10}
height={10} height={10}
style={{ fontWeight: "600" }} style={{ fontWeight: "600", marginLeft: "7px" }}
className="emailChipClose"
/> />
</div> </div>
); );
@@ -27,17 +27,17 @@ function Header({
signersdata, signersdata,
isMailSend, isMailSend,
alertSendEmail, alertSendEmail,
isSigned,
isCompleted, isCompleted,
isShowHeader, isShowHeader,
decline, decline,
currentSigner, currentSigner,
dataTut4, dataTut4,
alreadySign alreadySign,
isSignYourself
}) { }) {
const isMobile = window.innerWidth < 767; const isMobile = window.innerWidth < 767;
const navigate = useNavigate(); const navigate = useNavigate();
const isGuestSigner = localStorage.getItem("isGuestSigner");
//for go to previous page //for go to previous page
function previousPage() { function previousPage() {
changePage(-1); changePage(-1);
@@ -60,27 +60,181 @@ function Header({
event.preventDefault(); event.preventDefault();
const pdf = await getBase64FromUrl(pdfUrl); const pdf = await getBase64FromUrl(pdfUrl);
const isAndroidDevice = navigator.userAgent.match(/Android/i);
printModule({ printable: pdf, type: "pdf", base64: true }); 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 //handle download signed pdf
const handleDownloadPdf = () => { const handleDownloadPdf = () => {
const pdfName = pdfDetails[0] && pdfDetails[0].Name; const pdfName = pdfDetails[0] && pdfDetails[0].Name;
saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
saveAs(pdfUrl, `${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, url, loading, error }) => (
<>
{loading ? (
<div
style={{
border: "none",
backgroundColor: "#fff"
}}
>
<i
className="fa fa-certificate"
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 fa-certificate"
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`}
>
{({ blob, url, loading, error }) =>
loading ? (
<button
type="button"
className="defaultBtn certificateBtn"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center"
}}
>
<i
className="fa fa-certificate"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px"
}}
aria-hidden="true"
></i>
Certificate
</button>
) : (
<button
type="button"
className="defaultBtn certificateBtn"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center"
}}
>
<i
className="fa fa-certificate"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px"
}}
aria-hidden="true"
></i>
Certificate
</button>
)
}
</PDFDownloadLink>
);
};
return ( return (
<div <div
style={{ paddingBottom: "5px", paddingTop: "5px" }} style={{ padding: !isGuestSigner && "5px 0px 5px 0px" }}
className="mobileHead" className="mobileHead"
> >
{isMobile && isShowHeader ? ( {isMobile && isShowHeader ? (
<div <div
id="navbar" id="navbar"
className="stickyHead" className={isGuestSigner ? "stickySignerHead" : "stickyHead"}
style={{ width: window.innerWidth - 30 + "px" }} style={{
width: isGuestSigner
? window.innerWidth
: window.innerWidth - 30 + "px"
}}
> >
<div className="preBtn2"> <div className="preBtn2">
<div <div
@@ -124,16 +278,16 @@ function Header({
style={{ color: "gray", cursor: "pointer" }} style={{ color: "gray", cursor: "pointer" }}
></i> ></i>
</div> </div>
{pdfUrl ? ( {pdfUrl && alreadySign ? (
<DropdownMenu.Root> <DropdownMenu.Root>
<DropdownMenu.Trigger asChild> <DropdownMenu.Trigger asChild>
<div <div
// onClick={() => handleDownloadPdf()}
style={{ style={{
color: themeColor(), color: themeColor(),
border: "none", border: "none",
fontWeight: "650", fontWeight: "650",
fontSize: "16px" fontSize: "16px",
padding: "0px 3px 0px 5px"
}} }}
> >
<i className="fa fa-ellipsis-v" aria-hidden="true"></i> <i className="fa fa-ellipsis-v" aria-hidden="true"></i>
@@ -163,44 +317,41 @@ function Header({
Download Download
</div> </div>
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Item className="DropdownMenuItem"> {recipient && pdfDetails[0] && pdfDetails.length > 0 ? (
<PDFDownloadLink <DropdownMenu.Item className="DropdownMenuItem">
style={{ textDecoration: "none" }} <CertificateDropDown />
document={<Certificate pdfData={pdfDetails} />} </DropdownMenu.Item>
fileName={`completion certificate-${ ) : isPdfRequestFiles &&
pdfDetails[0] && pdfDetails[0].Name alreadySign &&
}.pdf`} isCompleted.isCertificate ? (
<DropdownMenu.Item className="DropdownMenuItem">
<CertificateDropDown />
</DropdownMenu.Item>
) : (
isSignYourself && (
<DropdownMenu.Item className="DropdownMenuItem">
<CertificateDropDown />
</DropdownMenu.Item>
)
)}
<DropdownMenu.Item
className="DropdownMenuItem"
onClick={handleToPrint}
>
<div
style={{
display: "flex",
flexDirection: "row"
}}
> >
{({ blob, url, loading, error }) => ( {" "}
<> <i
{console.log("error", error)} className="fa fa-print"
{loading ? ( aria-hidden="true"
"Loading document..." style={{ marginRight: "2px" }}
) : ( ></i>
<button Print
type="button" </div>
className="defaultBtn certificateBtn"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center"
}}
>
<i
className="fa fa-certificate"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px"
}}
aria-hidden="true"
></i>
Certificate
</button>
)}
</>
)}
</PDFDownloadLink>
</DropdownMenu.Item> </DropdownMenu.Item>
</DropdownMenu.Content> </DropdownMenu.Content>
</DropdownMenu.Portal> </DropdownMenu.Portal>
@@ -251,6 +402,8 @@ function Header({
onClick={() => { onClick={() => {
if (!pdfUrl) { if (!pdfUrl) {
embedImages(); embedImages();
} else if (isPdfRequestFiles) {
embedImages();
} }
}} }}
style={{ style={{
@@ -281,40 +434,7 @@ function Header({
pdfUrl || isAlreadySign.mssg ? ( pdfUrl || isAlreadySign.mssg ? (
<div style={{ display: "flex", flexDirection: "row" }}> <div style={{ display: "flex", flexDirection: "row" }}>
{pdfDetails[0] && pdfDetails.length > 0 && ( {pdfDetails[0] && pdfDetails.length > 0 && (
<PDFDownloadLink <CertificateComponent />
style={{ textDecoration: "none" }}
document={<Certificate pdfData={pdfDetails} />}
fileName={`completion certificate-${
pdfDetails[0] && pdfDetails[0].Name
}.pdf`}
>
{({ blob, url, loading, error }) =>
loading ? (
"Loading document..."
) : (
<button
type="button"
className="defaultBtn certificateBtn"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center"
}}
>
<i
className="fa fa-certificate"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px"
}}
aria-hidden="true"
></i>
Certificate
</button>
)
}
</PDFDownloadLink>
)} )}
<button <button
onClick={handleToPrint} onClick={handleToPrint}
@@ -439,42 +559,7 @@ function Header({
) : isPdfRequestFiles ? ( ) : isPdfRequestFiles ? (
alreadySign ? ( alreadySign ? (
<div style={{ display: "flex", flexDirection: "row" }}> <div style={{ display: "flex", flexDirection: "row" }}>
{isCompleted.isCertificate && ( {isCompleted.isCertificate && <CertificateComponent />}
<PDFDownloadLink
style={{ textDecoration: "none" }}
document={<Certificate pdfData={pdfDetails} />}
fileName={`completion certificate-${
pdfDetails[0] && pdfDetails[0].Name
}.pdf`}
>
{({ blob, url, loading, error }) =>
loading ? (
"Loading document..."
) : (
<button
type="button"
className="defaultBtn certificateBtn"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center"
}}
>
<i
className="fa fa-certificate"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px"
}}
aria-hidden="true"
></i>
Certificate
</button>
)
}
</PDFDownloadLink>
)}
<button <button
onClick={handleToPrint} onClick={handleToPrint}
type="button" type="button"
@@ -561,40 +646,7 @@ function Header({
) )
) : pdfUrl || (documentStatus && documentStatus.isCompleted) ? ( ) : pdfUrl || (documentStatus && documentStatus.isCompleted) ? (
<div style={{ display: "flex", flexDirection: "row" }}> <div style={{ display: "flex", flexDirection: "row" }}>
<PDFDownloadLink <CertificateComponent />
style={{ textDecoration: "none" }}
document={<Certificate pdfData={pdfDetails} />}
fileName={`completion certificate-${
pdfDetails[0] && pdfDetails[0].Name
}.pdf`}
>
{({ blob, url, loading, error }) =>
loading ? (
"Loading document..."
) : (
<button
type="button"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center"
}}
className="defaultBtn certificateBtn"
>
<i
className="fa fa-certificate"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px"
}}
aria-hidden="true"
></i>
Certificate
</button>
)
}
</PDFDownloadLink>
<button <button
onClick={handleToPrint} onClick={handleToPrint}
type="button" type="button"
File diff suppressed because it is too large Load Diff
@@ -38,19 +38,15 @@ function Login() {
const handleChange = (event) => { const handleChange = (event) => {
const { value } = event.target; const { value } = event.target;
setOTP(value); setOTP(value);
}; };
//send email OTP function //send email OTP function
const SendOtp = async (e) => { const SendOtp = async (e) => {
const serverUrl = const serverUrl =
localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl"); localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl");
const parseId = const parseId =
localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId"); localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId");
if (serverUrl && localStorage) { if (serverUrl && localStorage) {
setLoading(true); setLoading(true);
e.preventDefault(); e.preventDefault();
@@ -84,13 +80,10 @@ function Login() {
e.preventDefault(); e.preventDefault();
const serverUrl = const serverUrl =
localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl"); localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl");
const parseId = const parseId =
localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId"); localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId");
if (OTP) { if (OTP) {
setLoading(true); setLoading(true);
try { try {
let url = `${serverUrl}functions/AuthLoginAsMail/`; let url = `${serverUrl}functions/AuthLoginAsMail/`;
const headers = { const headers = {
@@ -102,7 +95,6 @@ function Login() {
otp: OTP otp: OTP
}; };
let user = await axios.post(url, body, { headers: headers }); let user = await axios.post(url, body, { headers: headers });
if (user.data.result === "Invalid Otp") { if (user.data.result === "Invalid Otp") {
alert("Invalid Otp"); alert("Invalid Otp");
setLoading(false); setLoading(false);
@@ -114,9 +106,12 @@ function Login() {
localStorage.setItem("UserInformation", JSON.stringify(_user)); localStorage.setItem("UserInformation", JSON.stringify(_user));
localStorage.setItem("username", _user.name); localStorage.setItem("username", _user.name);
localStorage.setItem("accesstoken", _user.sessionToken); localStorage.setItem("accesstoken", _user.sessionToken);
//save isGuestSigner true in local to handle login flow header in mobile view
localStorage.setItem("isGuestSigner", true);
setLoading(false); setLoading(false);
//navigate user to on signature page navigate(
navigate(`/recipientSignPdf/${id}/${contactBookId}`); `/loadmf/signmicroapp/recipientSignPdf/${id}/${contactBookId}`
);
} }
} catch (error) {} } catch (error) {}
} else { } else {
@@ -172,9 +167,7 @@ function Login() {
<span className="KNLO"> <span className="KNLO">
Verification code is sent to your email Verification code is sent to your email
</span> </span>
<div className="card card-box" <div className="card card-box" style={{ borderRadius: "0px" }}>
style={{borderRadius:"0px"}}
>
<div className="card-body"> <div className="card-body">
<input <input
type="email" type="email"
@@ -189,7 +182,6 @@ function Login() {
<div className="btnContainer"> <div className="btnContainer">
{loading ? ( {loading ? (
<button <button
// className="btn btn-info loadinBtn "
type="button" type="button"
style={{ style={{
background: themeColor(), background: themeColor(),
@@ -213,15 +205,7 @@ function Login() {
color: "white", color: "white",
marginLeft: "0px !important" marginLeft: "0px !important"
}} }}
// className="btn btn-sm otpButton"
onClick={(e) => SendOtp(e)} onClick={(e) => SendOtp(e)}
// style={{
// marginBottom: "4px",
// width: "210px",
// background: themeColor(),
// color: "white",
// fontWeight: "600"
// }}
> >
Send OTP Send OTP
</button> </button>
@@ -17,7 +17,12 @@ import HandleError from "./component/HandleError";
import Nodata from "./component/Nodata"; import Nodata from "./component/Nodata";
import SignerListPlace from "./component/signerListPlace"; import SignerListPlace from "./component/signerListPlace";
import Header from "./component/header"; import Header from "./component/header";
import { contactBook, contractUsers, getHostUrl } from "../utils/Utils"; import {
pdfNewWidthFun,
contractDocument,
contractUsers,
getHostUrl
} from "../utils/Utils";
import RenderPdf from "./component/renderPdf"; import RenderPdf from "./component/renderPdf";
import ModalComponent from "./component/modalComponent"; import ModalComponent from "./component/modalComponent";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@@ -31,13 +36,10 @@ function PlaceHolderSign() {
const [pageNumber, setPageNumber] = useState(1); const [pageNumber, setPageNumber] = useState(1);
const [signBtnPosition, setSignBtnPosition] = useState([]); const [signBtnPosition, setSignBtnPosition] = useState([]);
const [xySignature, setXYSignature] = useState({}); const [xySignature, setXYSignature] = useState({});
const signRef = useRef(null);
const dragRef = useRef(null);
const [dragKey, setDragKey] = useState(); const [dragKey, setDragKey] = useState();
const [signersdata, setSignersData] = useState(); const [signersdata, setSignersData] = useState();
const [signerObjId, setSignerObjId] = useState(); const [signerObjId, setSignerObjId] = useState();
const [signerPos, setSignerPos] = useState([]); const [signerPos, setSignerPos] = useState([]);
const [isSelectListId, setIsSelectId] = useState(); const [isSelectListId, setIsSelectId] = useState();
const [isSendAlert, setIsSendAlert] = useState({}); const [isSendAlert, setIsSendAlert] = useState({});
const [isSend, setIsSend] = useState(false); const [isSend, setIsSend] = useState(false);
@@ -56,6 +58,9 @@ function PlaceHolderSign() {
const [pdfOriginalWidth, setPdfOriginalWidth] = useState(); const [pdfOriginalWidth, setPdfOriginalWidth] = useState();
const [contractName, setContractName] = useState(""); const [contractName, setContractName] = useState("");
const { docId } = useParams(); const { docId } = useParams();
const signRef = useRef(null);
const dragRef = useRef(null);
const divRef = useRef(null);
const [isShowEmail, setIsShowEmail] = useState(false); const [isShowEmail, setIsShowEmail] = useState(false);
const [selectedEmail, setSelectedEmail] = useState(false); const [selectedEmail, setSelectedEmail] = useState(false);
const [pdfLoadFail, setPdfLoadFail] = useState({ const [pdfLoadFail, setPdfLoadFail] = useState({
@@ -156,69 +161,53 @@ function PlaceHolderSign() {
const jsonSender = JSON.parse(senderUser); const jsonSender = JSON.parse(senderUser);
useEffect(() => { useEffect(() => {
const clientWidth = window.innerWidth;
const value = docId ? 80 : 30;
const pdfWidth = clientWidth - 160 - 200 - value;
//160 is width of left side, 200 is width of right side component and 50 is space of middle compoent
//pdf from left and right component
setPdfNewWidth(pdfWidth);
if (documentId) { if (documentId) {
getDocumentDetails(); getDocumentDetails();
} }
}, []); }, []);
useEffect(() => {
if (divRef.current) {
const pdfWidth = pdfNewWidthFun(divRef);
setPdfNewWidth(pdfWidth);
}
}, [divRef.current]);
//function for get document details //function for get document details
const getDocumentDetails = async () => { const getDocumentDetails = async () => {
await axios //getting document details
.get( const documentData = await contractDocument(documentId);
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem( if (documentData && documentData.length > 0) {
"_appName" setPdfDetails(documentData);
)}_Document?where={"objectId":"${documentId}"}&include=ExtUserPtr,Signers`,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
)
.then((Listdata) => {
const json = Listdata.data;
const res = json.results;
if (res[0] && res.length > 0) { const currEmail = documentData[0].ExtUserPtr.Email;
setPdfDetails(res); const filterCurrEmail = documentData[0].Signers.filter(
(data) => data.Email === currEmail
);
const currEmail = res[0].ExtUserPtr.Email; setCurrentEmail(filterCurrEmail);
const filterCurrEmail = res[0].Signers.filter( setSignersData(documentData[0]);
(data) => data.Email === currEmail
);
setCurrentEmail(filterCurrEmail); setSignerObjId(documentData[0].Signers[0].objectId);
setSignersData(res[0]); setContractName(documentData[0].Signers[0].className);
setIsSelectId(0);
setSignerObjId(res[0].Signers[0].objectId); } else if (
setContractName(res[0].Signers[0].className); documentData === "Error: Something went wrong!" ||
setIsSelectId(0); (documentData.result && documentData.result.error)
} else { ) {
setNoData(true); const loadObj = {
const loadObj = { isLoad: false
isLoad: false };
}; setHandleError("Error: Something went wrong!");
setIsLoading(loadObj); setIsLoading(loadObj);
} } else {
}) setNoData(true);
.catch((err) => {
console.log("axois err ", err);
const loadObj = {
isLoad: false
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
});
const res = await contractUsers(jsonSender.objectId);
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
}
const res = await contractUsers(jsonSender.email);
if (res[0] && res.length) { if (res[0] && res.length) {
setSignerUserId(res[0].objectId); setSignerUserId(res[0].objectId);
const tourstatus = res[0].TourStatus && res[0].TourStatus; const tourstatus = res[0].TourStatus && res[0].TourStatus;
@@ -242,24 +231,12 @@ function PlaceHolderSign() {
setHandleError("Error: Something went wrong!"); setHandleError("Error: Something went wrong!");
setIsLoading(loadObj); setIsLoading(loadObj);
} else if (res.length === 0) { } else if (res.length === 0) {
const res = await contactBook(jsonSender.objectId); setNoData(true);
if (res[0] && res.length) {
setSignerUserId(res[0].objectId); const loadObj = {
const tourstatus = res[0].TourStatus && res[0].TourStatus; isLoad: false
if (tourstatus && tourstatus.length > 0) { };
setTourStatus(tourstatus); setIsLoading(loadObj);
const checkTourRecipients = tourstatus.filter(
(data) => data.placeholder
);
if (checkTourRecipients && checkTourRecipients.length > 0) {
setCheckTourStatus(checkTourRecipients[0].placeholder);
}
}
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
}
} }
}; };
@@ -275,7 +252,7 @@ function PlaceHolderSign() {
getSignerPos(item, monitor); getSignerPos(item, monitor);
} }
}; };
const getSignerPos = (item, monitor) => { const getSignerPos = (item, monitor) => {
const key = Math.floor(1000 + Math.random() * 9000); const key = Math.floor(1000 + Math.random() * 9000);
let filterSignerPos = signerPos.filter( let filterSignerPos = signerPos.filter(
@@ -396,7 +373,7 @@ function PlaceHolderSign() {
blockColor: color[isSelectListId], blockColor: color[isSelectListId],
placeHolder: xyPosArr placeHolder: xyPosArr
}; };
setSignerPos((prev) => [...prev, placeHolderPos]); setSignerPos((prev) => [...prev, placeHolderPos]);
} }
}; };
@@ -626,7 +603,7 @@ function PlaceHolderSign() {
setSignBtnPosition([]); setSignBtnPosition([]);
setPageNumber((prevPageNumber) => prevPageNumber + offset); setPageNumber((prevPageNumber) => prevPageNumber + offset);
} }
//function for capture position on hover signature button //function for capture position on hover signature button
const handleDivClick = (e) => { const handleDivClick = (e) => {
const divRect = e.currentTarget.getBoundingClientRect(); const divRect = e.currentTarget.getBoundingClientRect();
@@ -679,7 +656,7 @@ function PlaceHolderSign() {
year: "numeric" year: "numeric"
}); });
let sender = signersdata.ExtUserPtr.Email; let sender = signersdata.ExtUserPtr.Email;
const signerMail = signersdata.Signers; const signerMail = signersdata.Signers;
for (let i = 0; i < signerMail.length; i++) { for (let i = 0; i < signerMail.length; i++) {
try { try {
@@ -698,7 +675,8 @@ function PlaceHolderSign() {
"parseAppId" "parseAppId"
)}&${localStorage.getItem("_appName")}`; )}&${localStorage.getItem("_appName")}`;
let signPdf = `https://qik-ai-org.github.io/Sign-MicroappV2/#/login/${signersdata.objectId}/${signerMail[i].Email}/${objectId}/${serverParams}`; const hostUrl = window.location.origin + "/loadmf/signmicroapp";
let signPdf = `${hostUrl}/login/${signersdata.objectId}/${signerMail[i].Email}/${objectId}/${serverParams}`;
const themeBGcolor = themeColor(); const themeBGcolor = themeColor();
let params = { let params = {
@@ -855,7 +833,7 @@ function PlaceHolderSign() {
) : noData ? ( ) : noData ? (
<Nodata /> <Nodata />
) : ( ) : (
<div className="signatureContainer"> <div className="signatureContainer" ref={divRef}>
{/* this component used for UI interaction and show their functionality */} {/* this component used for UI interaction and show their functionality */}
{!checkTourStatus && ( {!checkTourStatus && (
//this tour component used in your html component where you want to put //this tour component used in your html component where you want to put
@@ -951,7 +929,7 @@ function PlaceHolderSign() {
background: themeColor() background: themeColor()
}} }}
> >
<span style={{ color: "white" }}>Send Mail </span> <span style={{ color: "white" }}>Mails Sent</span>
</Modal.Header> </Modal.Header>
{/* signature modal */} {/* signature modal */}
@@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect } from "react"; import React, { useState, useRef, useEffect } from "react";
import { PDFDocument, rgb } from "pdf-lib"; import { PDFDocument } from "pdf-lib";
import "../css/./signature.css"; import "../css/./signature.css";
import axios from "axios"; import axios from "axios";
import Modal from "react-bootstrap/Modal"; import Modal from "react-bootstrap/Modal";
@@ -14,7 +14,14 @@ import DefaultSignature from "./component/defaultSignature";
import { import {
getBase64FromUrl, getBase64FromUrl,
getBase64FromIMG, getBase64FromIMG,
contactBookName pdfNewWidthFun,
convertPNGtoJPEG,
contractUsers,
contactBook,
contractDocument,
urlValidator,
multiSignEmbed,
embedDocId
} from "../utils/Utils"; } from "../utils/Utils";
import Tour from "reactour"; import Tour from "reactour";
import Signedby from "./component/signedby"; import Signedby from "./component/signedby";
@@ -23,8 +30,9 @@ import Loader from "./component/loader";
import HandleError from "./component/HandleError"; import HandleError from "./component/HandleError";
import Nodata from "./component/Nodata"; import Nodata from "./component/Nodata";
import Header from "./component/header"; import Header from "./component/header";
import ModalComponent from "./component/modalComponent";
import RenderPdf from "./component/renderPdf"; import RenderPdf from "./component/renderPdf";
import CustomModal from "./component/CustomModal";
import { modalAlign } from "../utils/Utils";
function EmbedPdfImage() { function EmbedPdfImage() {
const { id, contactBookId } = useParams(); const { id, contactBookId } = useParams();
const [isSignPad, setIsSignPad] = useState(false); const [isSignPad, setIsSignPad] = useState(false);
@@ -67,52 +75,61 @@ function EmbedPdfImage() {
status: false, status: false,
type: "load" type: "load"
}); });
const [containerWH, setContainerWH] = useState({});
const docId = id && id; const docId = id && id;
const isMobile = window.innerWidth < 767; const isMobile = window.innerWidth < 767;
const index = xyPostion.findIndex((object) => { const index = xyPostion.findIndex((object) => {
return object.pageNumber === pageNumber; return object.pageNumber === pageNumber;
}); });
const divRef = useRef(null);
const senderUser = localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
)
? localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
)
: `${localStorage.getItem("UserInformation")}` &&
`${localStorage.getItem("UserInformation")}`;
const jsonSender = JSON.parse(senderUser);
//check isGuestSigner is present in local if yes than handle login flow header in mobile view
const isGuestSigner = localStorage.getItem("isGuestSigner");
useEffect(() => { useEffect(() => {
const clientWidth = window.innerWidth;
const pdfWidth = clientWidth - 160 - 220 - 30;
//160 is width of left side, 200 is width of right side component and 50 is space of middle compoent
//pdf from left and right component
setPdfNewWidth(pdfWidth);
getDocumentDetails(); getDocumentDetails();
}, []); }, []);
useEffect(() => {
if (divRef.current) {
const pdfWidth = pdfNewWidthFun(divRef);
setPdfNewWidth(pdfWidth);
setContainerWH({
width: divRef.current.offsetWidth,
height: divRef.current.offsetHeight
});
}
}, [divRef.current]);
//function for get document details for perticular signer with signer'object id //function for get document details for perticular signer with signer'object id
const getDocumentDetails = async () => { const getDocumentDetails = async () => {
let currUserId, userObjectId; let currUserId, userObjectId;
const json = await contactBookName(contactBookId, "_Contactbook"); //getting contracts_contactBook details
if (json !== "Error: Something went wrong!" && json && json.results[0]) { const json = await contactBook(contactBookId);
if (json && json.length > 0) {
setContractName("_Contactbook"); setContractName("_Contactbook");
if (json.results[0]) {
userObjectId = json.results[0].UserId.objectId;
setUserObjectID(userObjectId);
currUserId = json.results[0].objectId;
setSignerUserId(currUserId); userObjectId = json[0].UserId.objectId;
const tourstatus = setUserObjectID(userObjectId);
json.results[0].TourStatus && json.results[0].TourStatus; currUserId = json[0].objectId;
if (tourstatus && tourstatus.length > 0) { setSignerUserId(currUserId);
setTourStatus(tourstatus); const tourstatus = json[0].TourStatus && json[0].TourStatus;
const checkTourRecipients = tourstatus.filter(
(data) => data.recipientssign if (tourstatus && tourstatus.length > 0) {
); setTourStatus(tourstatus);
if (checkTourRecipients && checkTourRecipients.length > 0) { const checkTourRecipients = tourstatus.filter(
setCheckTourStatus(checkTourRecipients[0].recipientssign); (data) => data.recipientssign
} );
if (checkTourRecipients && checkTourRecipients.length > 0) {
setCheckTourStatus(checkTourRecipients[0].recipientssign);
} }
} else {
setNoData(true);
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
} }
} else if (json === "Error: Something went wrong!") { } else if (json === "Error: Something went wrong!") {
const loadObj = { const loadObj = {
@@ -121,18 +138,16 @@ function EmbedPdfImage() {
setHandleError("Error: Something went wrong!"); setHandleError("Error: Something went wrong!");
setIsLoading(loadObj); setIsLoading(loadObj);
} else { } else {
const json = await contactBookName(contactBookId, "_Users"); const json = await contractUsers(jsonSender.email);
if (json && json.length > 0) {
if (json !== "Error: Something went wrong!" && json && json.results[0]) {
setContractName("_Users"); setContractName("_Users");
if (json.results[0]) { if (json[0]) {
userObjectId = json.results[0].UserId.objectId; userObjectId = json[0].UserId.objectId;
setUserObjectID(userObjectId); setUserObjectID(userObjectId);
currUserId = json.results[0].objectId; currUserId = json[0].objectId;
setSignerUserId(currUserId); setSignerUserId(currUserId);
const tourstatus = const tourstatus = json[0].TourStatus && json[0].TourStatus;
json.results[0].TourStatus && json.results[0].TourStatus;
if (tourstatus && tourstatus.length > 0) { if (tourstatus && tourstatus.length > 0) {
setTourStatus(tourstatus); setTourStatus(tourstatus);
@@ -156,171 +171,170 @@ function EmbedPdfImage() {
}; };
setHandleError("Error: Something went wrong!"); setHandleError("Error: Something went wrong!");
setIsLoading(loadObj); setIsLoading(loadObj);
} } else {
} setNoData(true);
await axios
.get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document?where={"objectId":"${docId}"}&include=ExtUserPtr,Signers,AuditTrail
,`,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
)
.then((Listdata) => {
const json = Listdata.data;
const res = json.results;
if (res[0] && res.length > 0) {
const declined = res[0].IsDeclined && res[0].IsDeclined;
const isCompleted = res[0].IsCompleted && res[0].IsCompleted;
const expireDate = res[0].ExpiryDate.iso;
const expireUpdateDate = new Date(expireDate).getTime();
const currDate = new Date().getTime();
if (isCompleted) {
//checking document is completed (signed by all requested signers) than isCompleted true
//then show alert with completed message
const alreadySign = {
status: true,
mssg: "This document has been successfully signed!"
};
setIsAlreadySign(alreadySign);
setPdfUrl(res[0].SignedUrl);
setSignedPdfData(json.results);
setCompletePdfData(res);
} else if (declined) {
const currentDecline = {
currnt: "another",
isDeclined: true
};
setIsDecline(currentDecline);
setSignedPdfData(json.results);
} else if (currDate > expireUpdateDate) {
setIsExpired(true);
const checkDocIdExist =
json.results[0].AuditTrail &&
json.results[0].AuditTrail.length > 0 &&
json.results[0].AuditTrail.filter(
(data) => data.Activity === "Signed"
);
//if signed by someone than go to in if condition
// and second signer could not be add documentId
//for that setIsDocId true
if (checkDocIdExist && checkDocIdExist.length > 0) {
setIsDocId(true);
const currUser =
json.results[0].Placeholders &&
json.results[0].Placeholders.filter(
(data) => data.signerObjId === currUserId
);
setSignedPdfData(json.results);
setXyPostion(currUser[0].placeHolder);
const key = currUser[0].placeHolder[0].pos[0].key;
setSignKey(key);
}
//for show current requested signer's placeholder
else {
const currUser =
json.results[0].Placeholders &&
json.results[0].Placeholders.filter(
(data) => data.signerObjId === currUserId
);
setSignedPdfData(json.results);
setXyPostion(currUser[0].placeHolder);
const key = currUser[0].placeHolder[0].pos[0].key;
setSignKey(key);
}
} else {
//checking document has signed by someone or not
const checkDocIdExist =
json.results[0].AuditTrail &&
json.results[0].AuditTrail.length > 0 &&
json.results[0].AuditTrail.filter(
(data) => data.Activity === "Signed"
);
//if signed by someone than go to in if condition
// and second signer could not be add documentId
//for that setIsDocId true
if (checkDocIdExist && checkDocIdExist.length > 0) {
setIsDocId(true);
//condition for checking document signed by current requested user or not
const checkAlreadyBySigner = json.results[0].AuditTrail.filter(
(data) =>
data.UserPtr.objectId === currUserId &&
data.Activity === "Signed"
);
// if checkAlreadyBySigner has some data that current user already sign this document
// then show alert with message
if (checkAlreadyBySigner && checkAlreadyBySigner.length > 0) {
const alreadySign = {
status: true,
mssg: "You have successfully signed the document!"
};
setIsAlreadySign(alreadySign);
setPdfUrl(res[0].SignedUrl);
setSignedPdfData(json.results);
}
//else show placeholder of current requested signer
else {
const currUser =
json.results[0].Placeholders &&
json.results[0].Placeholders.filter(
(data) => data.signerObjId === currUserId
);
setSignedPdfData(json.results);
setXyPostion(currUser[0].placeHolder);
const key = currUser[0].placeHolder[0].pos[0].key;
setSignKey(key);
}
}
//for show current requested signer's placeholder
else {
const currUser =
json.results[0].Placeholders &&
json.results[0].Placeholders.filter(
(data) => data.signerObjId === currUserId
);
setSignedPdfData(json.results);
setXyPostion(currUser[0].placeHolder);
const key = currUser[0].placeHolder[0].pos[0].key;
setSignKey(key);
}
}
}
})
.catch((err) => {
const loadObj = { const loadObj = {
isLoad: false isLoad: false
}; };
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj); setIsLoading(loadObj);
console.log("err", err); }
}); }
//getting document details
const documentData = await contractDocument(docId);
if (documentData && documentData.length > 0) {
const declined = documentData[0].IsDeclined && documentData[0].IsDeclined;
const isCompleted =
documentData[0].IsCompleted && documentData[0].IsCompleted;
const expireDate = documentData[0].ExpiryDate.iso;
const expireUpdateDate = new Date(expireDate).getTime();
const currDate = new Date().getTime();
if (isCompleted) {
//checking document is completed (signed by all requested signers) than isCompleted true
//then show alert with completed message
const alreadySign = {
status: true,
mssg: "This document has been successfully signed!"
};
setIsAlreadySign(alreadySign);
setPdfUrl(documentData[0].SignedUrl);
setSignedPdfData(documentData);
setCompletePdfData(documentData);
} else if (declined) {
const currentDecline = {
currnt: "another",
isDeclined: true
};
setIsDecline(currentDecline);
setSignedPdfData(documentData);
} else if (currDate > expireUpdateDate) {
setIsExpired(true);
const checkDocIdExist =
documentData[0].AuditTrail &&
documentData[0].AuditTrail.length > 0 &&
documentData[0].AuditTrail.filter(
(data) => data.Activity === "Signed"
);
//if signed by someone than go to in if condition
// and second signer could not be add documentId
//for that setIsDocId true
if (checkDocIdExist && checkDocIdExist.length > 0) {
setIsDocId(true);
const currUser =
documentData.Placeholders &&
documentData.Placeholders.filter(
(data) => data.signerObjId === currUserId
);
setSignedPdfData(documentData);
setXyPostion(currUser[0].placeHolder);
const key = currUser[0].placeHolder[0].pos[0].key;
setSignKey(key);
}
//for show current requested signer's placeholder
else {
const currUser =
documentData[0].Placeholders &&
documentData[0].Placeholders.filter(
(data) => data.signerObjId === currUserId
);
setSignedPdfData(documentData);
setXyPostion(currUser[0].placeHolder);
const key = currUser[0].placeHolder[0].pos[0].key;
setSignKey(key);
}
} else {
//checking document has signed by someone or not
const checkDocIdExist =
documentData[0].AuditTrail &&
documentData[0].AuditTrail.length > 0 &&
documentData[0].AuditTrail.filter(
(data) => data.Activity === "Signed"
);
//if signed by someone than go to in if condition
// and second signer could not be add documentId
//for that setIsDocId true
if (checkDocIdExist && checkDocIdExist.length > 0) {
setIsDocId(true);
//condition for checking document signed by current requested user or not
const checkAlreadyBySigner = documentData[0].AuditTrail.filter(
(data) =>
data.UserPtr.objectId === currUserId && data.Activity === "Signed"
);
// if checkAlreadyBySigner has some data that current user already sign this document
// then show alert with message
if (checkAlreadyBySigner && checkAlreadyBySigner.length > 0) {
const alreadySign = {
status: true,
mssg: "You have successfully signed the document!"
};
setIsAlreadySign(alreadySign);
setPdfUrl(documentData[0].SignedUrl);
setSignedPdfData(documentData);
}
//else show placeholder of current requested signer
else {
const currUser =
documentData[0].Placeholders &&
documentData[0].Placeholders.filter(
(data) => data.signerObjId === currUserId
);
setSignedPdfData(documentData);
setXyPostion(currUser[0].placeHolder);
const key = currUser[0].placeHolder[0].pos[0].key;
setSignKey(key);
}
}
//for show current requested signer's placeholder
else {
const currUser =
documentData[0].Placeholders &&
documentData[0].Placeholders.filter(
(data) => data.signerObjId === currUserId
);
setSignedPdfData(documentData);
setXyPostion(currUser[0].placeHolder);
const key = currUser[0].placeHolder[0].pos[0].key;
setSignKey(key);
}
}
} else if (
documentData === "Error: Something went wrong!" ||
(documentData.result && documentData.result.error)
) {
const loadObj = {
isLoad: false
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
} else {
setNoData(true);
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
}
await axios await axios
.get( .get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem( `${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
@@ -409,23 +423,8 @@ function EmbedPdfImage() {
if (isDocId) { if (isDocId) {
pdfBase64 = await getBase64FromUrl(url); pdfBase64 = await getBase64FromUrl(url);
} else { } else {
for (let i = 0; i < allPages; i++) { //embed document's object id to all pages in pdf document
const font = await pdfDoc.embedFont("Helvetica"); await embedDocId(pdfDoc, docId, allPages);
const fontSize = 10;
const textContent = docId && `OpenSign™ DocumentId: ${docId} `;
const pages = pdfDoc.getPages();
const page = pages[i];
page.drawText(textContent, {
x: 10,
y: page.getHeight() - 10,
size: fontSize,
font,
color: rgb(0.5, 0.5, 0.5)
});
}
pdfBase64 = await pdfDoc.saveAsBase64({ useObjectStreams: false }); pdfBase64 = await pdfDoc.saveAsBase64({ useObjectStreams: false });
} }
for (let i = 0; i < xyPostion.length; i++) { for (let i = 0; i < xyPostion.length; i++) {
@@ -434,38 +433,13 @@ function EmbedPdfImage() {
imgUrlList.map(async (data) => { imgUrlList.map(async (data) => {
//cheking signUrl is defau;t signature url of custom url //cheking signUrl is defau;t signature url of custom url
let ImgUrl = data.SignUrl; let ImgUrl = data.SignUrl;
const checkUrl = ImgUrl.includes("https:"); const checkUrl = urlValidator(ImgUrl);
//if default signature url then convert it in base 64 //if default signature url then convert it in base 64
if (checkUrl) { if (checkUrl) {
ImgUrl = await getBase64FromIMG(ImgUrl + "?get"); ImgUrl = await getBase64FromIMG(ImgUrl + "?get");
} }
//function for called convert png signatre to jpeg in base 64 //function for convert signature png base64 url to jpeg base64
const convertPNGtoJPEG = (base64Data) => {
return new Promise((resolve, reject) => {
const canvas = document.createElement("canvas");
const img = new Image();
img.src = base64Data;
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
// Convert to JPEG by using the canvas.toDataURL() method
const jpegBase64Data = canvas.toDataURL("image/jpeg");
resolve(jpegBase64Data);
};
img.onerror = (error) => {
reject(error);
};
});
};
convertPNGtoJPEG(ImgUrl) convertPNGtoJPEG(ImgUrl)
.then((jpegBase64Data) => { .then((jpegBase64Data) => {
const removeBase64Fromjpeg = "data:image/jpeg;base64,"; const removeBase64Fromjpeg = "data:image/jpeg;base64,";
@@ -485,123 +459,18 @@ function EmbedPdfImage() {
} }
//else if signature is more than one then embed all sign with the use of pdf-lib //else if signature is more than one then embed all sign with the use of pdf-lib
else if (xyPostion.length > 0 && xyPostion[0].pos.length > 0) { else if (xyPostion.length > 0 && xyPostion[0].pos.length > 0) {
for (let i = 0; i < allPages; i++) { //embed document's object id to all pages in pdf document
const font = await pdfDoc.embedFont("Helvetica"); await embedDocId(pdfDoc, docId, allPages);
//embed multi signature in pdf
const fontSize = 10; const pdfBytes = await multiSignEmbed(
const textContent = docId && `OpenSign™ DocumentId: ${docId} `; pngUrl,
pdfDoc,
const pages = pdfDoc.getPages(); pdfOriginalWidth,
const page = pages[i]; false
);
page.drawText(textContent, {
x: 10,
y: page.getHeight() - 10,
size: fontSize,
font,
color: rgb(0.5, 0.5, 0.5)
});
}
for (let i = 0; i < pngUrl.length; i++) {
const pageNo = pngUrl[i].pageNumber;
const imgUrlList = pngUrl[i].pos;
const pages = pdfDoc.getPages();
const page = pages[pageNo - 1];
const images = await Promise.all(
imgUrlList.map(async (url) => {
let signUrl = url.SignUrl;
const checkUrl = url.SignUrl.includes("https:");
if (checkUrl) {
signUrl = signUrl + "?get";
}
const res = await fetch(signUrl);
return res.arrayBuffer();
})
);
images.forEach(async (imgData, id) => {
let img;
if (
imgUrlList[id].ImageType &&
imgUrlList[id].ImageType === "image/jpeg"
) {
img = await pdfDoc.embedJpg(imgData);
} else if (
imgUrlList[id].ImageType &&
imgUrlList[id].ImageType === "image/png"
) {
img = await pdfDoc.embedPng(imgData);
} else {
img = await pdfDoc.embedPng(imgData);
}
const imgHeight = imgUrlList[id].Height
? imgUrlList[id].Height
: 60;
const imgWidth = imgUrlList[id].Width ? imgUrlList[id].Width : 150;
const isMobile = window.innerWidth < 767;
const newWidth = window.innerWidth;
const scale = isMobile ? pdfOriginalWidth / newWidth : 1;
const xPos = (pos) => {
//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) {
const x = pos.xPosition * (pos.scale / scale);
return x * scale + 50;
} else {
const x = pos.xPosition / scale;
return x * 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) {
const x = pos.xPosition * pos.scale + 50;
return x;
} else {
return pos.xPosition;
}
}
};
const yPos = (pos) => {
//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) {
const y = pos.yPosition * (pos.scale / scale);
return page.getHeight() - y * scale - imgHeight;
} else {
const y = pos.yPosition / scale;
return page.getHeight() - y * scale - imgHeight;
}
} 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) {
const y = pos.yPosition * pos.scale;
return page.getHeight() - y - imgHeight;
} else {
return page.getHeight() - pos.yPosition - imgHeight;
}
}
};
page.drawImage(img, {
x: xPos(imgUrlList[id]),
y: yPos(imgUrlList[id]),
width: imgWidth,
height: imgHeight
});
});
}
const pdfBytes = await pdfDoc.saveAsBase64({ useObjectStreams: false });
signPdfFun(pdfBytes, docId); signPdfFun(pdfBytes, docId);
} }
setIsSignPad(false); setIsSignPad(false);
setXyPostion([]); setXyPostion([]);
} }
} }
@@ -652,8 +521,8 @@ function EmbedPdfImage() {
yPosition = pos.isDrag yPosition = pos.isDrag
? y * scale - height ? y * scale - height
: pos.firstYPos : pos.firstYPos
? y * scale - height + pos.firstYPos ? y * scale - height + pos.firstYPos
: y * scale - height; : y * scale - height;
return yPosition; return yPosition;
} else { } else {
const y = pos.yBottom / scale; const y = pos.yBottom / scale;
@@ -661,8 +530,8 @@ function EmbedPdfImage() {
yPosition = pos.isDrag yPosition = pos.isDrag
? y * scale - height ? y * scale - height
: pos.firstYPos : pos.firstYPos
? y * scale - height + pos.firstYPos ? y * scale - height + pos.firstYPos
: y * scale - height; : y * scale - height;
return yPosition; return yPosition;
} }
} else { } else {
@@ -673,15 +542,15 @@ function EmbedPdfImage() {
yPosition = pos.isDrag yPosition = pos.isDrag
? y - height ? y - height
: pos.firstYPos : pos.firstYPos
? y - height + pos.firstYPos ? y - height + pos.firstYPos
: y - height; : y - height;
return yPosition; return yPosition;
} else { } else {
yPosition = pos.isDrag yPosition = pos.isDrag
? pos.yBottom - height ? pos.yBottom - height
: pos.firstYPos : pos.firstYPos
? pos.yBottom - height + pos.firstYPos ? pos.yBottom - height + pos.firstYPos
: pos.yBottom - height; : pos.yBottom - height;
return yPosition; return yPosition;
} }
} }
@@ -952,7 +821,37 @@ function EmbedPdfImage() {
) : noData ? ( ) : noData ? (
<Nodata /> <Nodata />
) : ( ) : (
<div className="signatureContainer"> <div className="signatureContainer" ref={divRef}>
{/* this modal is used to show decline alert */}
<CustomModal
containerWH={containerWH}
show={isDecline.isDeclined}
headMsg="Document Declined Alert!"
bodyMssg={
isDecline.currnt === "Sure" ? (
<p>Are you sure want to decline this document ?</p>
) : isDecline.currnt === "YouDeclined" ? (
<p>You have declined this document!</p>
) : (
isDecline.currnt === "another" && (
<p>
You cannot sign this document as it has been declined by one
or more person(s).
</p>
)
)
}
footerMessage={isDecline.currnt === "Sure"}
declineDoc={declineDoc}
setIsDecline={setIsDecline}
/>
{/* this modal is used for show expired alert */}
<CustomModal
containerWH={containerWH}
show={isExpired}
headMsg="Document Expired!"
bodyMssg="This Document is no longer available."
/>
{/* this component used for UI interaction and show their functionality */} {/* this component used for UI interaction and show their functionality */}
{pdfLoadFail.status && {pdfLoadFail.status &&
!isExpired && !isExpired &&
@@ -971,63 +870,16 @@ function EmbedPdfImage() {
{/* pdf render view */} {/* pdf render view */}
<div <div
style={{ style={{
marginLeft: pdfOriginalWidth > 500 && "20px", marginLeft: !isGuestSigner && pdfOriginalWidth > 500 && "20px",
marginRight: pdfOriginalWidth > 500 && "20px" marginRight: !isGuestSigner && pdfOriginalWidth > 500 && "20px"
}} }}
> >
{/* this modal is used for show decline alert */}
<Modal show={isDecline.isDeclined}>
<ModalHeader className="bg-danger" style={{ color: "white" }}>
Document Declined Alert!
</ModalHeader>
<Modal.Body>
{isDecline.currnt === "Sure" ? (
<p>Are you sure want to decline this document ?</p>
) : isDecline.currnt === "YouDeclined" ? (
<p>You have declined this document!</p>
) : (
isDecline.currnt === "another" && (
<p>
You cannot sign this document as it has been declined by
one or more person(s).
</p>
)
)}
</Modal.Body>
<Modal.Footer>
{isDecline.currnt === "Sure" && (
<>
<button
style={{
color: "black"
}}
type="button"
className="finishBtn"
onClick={() => setIsDecline({ isDeclined: false })}
>
Close
</button>
<button
style={{
background: "#de4337"
}}
type="button"
className="finishBtn"
onClick={() => declineDoc()}
>
Yes
</button>
</>
)}
</Modal.Footer>
</Modal>
{/* this modal component is used for show expired document */}
<ModalComponent isShow={isExpired} type={"expire"} />
{/* this modal is used show this document is already sign */} {/* this modal is used show this document is already sign */}
<Modal show={isAlreadySign.status}> <Modal
show={isAlreadySign.status}
onShow={() => modalAlign()}
backdropClassName="signature-backdrop"
>
<ModalHeader style={{ background: themeColor() }}> <ModalHeader style={{ background: themeColor() }}>
<span style={{ color: "white" }}> Sign Documents</span> <span style={{ color: "white" }}> Sign Documents</span>
</ModalHeader> </ModalHeader>
@@ -1083,7 +935,7 @@ function EmbedPdfImage() {
{/* pdf header which contain finish back button */} {/* pdf header which contain finish back button */}
<Header <Header
recipient={true} recipient={true}
pdfDetails={completePdfData} pdfDetails={signedPdfData}
isAlreadySign={isAlreadySign} isAlreadySign={isAlreadySign}
pageNumber={pageNumber} pageNumber={pageNumber}
allPages={allPages} allPages={allPages}
@@ -1094,6 +946,7 @@ function EmbedPdfImage() {
isShowHeader={true} isShowHeader={true}
currentSigner={true} currentSigner={true}
decline={true} decline={true}
alreadySign={pdfUrl ? true : false}
/> />
<RenderPdf <RenderPdf
@@ -1138,7 +991,6 @@ function EmbedPdfImage() {
)} )}
</div> </div>
)} )}
{/* ndD5gdaxqw */}
</DndProvider> </DndProvider>
); );
} }
+7 -1
View File
@@ -8,6 +8,7 @@ import Login from "./Component/login";
import DraftDocument from "./Component/DraftDocument"; import DraftDocument from "./Component/DraftDocument";
import PdfRequestFiles from "./Component/PdfRequestFiles"; import PdfRequestFiles from "./Component/PdfRequestFiles";
import LegaDrive from "./Component/LegaDrive/LegaDrive"; import LegaDrive from "./Component/LegaDrive/LegaDrive";
import PageNotFound from "./Component/PageNotFound";
// `AppRoutes` is used to define route path of app and // `AppRoutes` is used to define route path of app and
// it expose to host app, check moduleFederation.config.js for more // it expose to host app, check moduleFederation.config.js for more
@@ -33,7 +34,10 @@ function AppRoutes() {
{/*Add default signature of user route */} {/*Add default signature of user route */}
<Route path="/managesign" element={<ManageSign />} /> <Route path="/managesign" element={<ManageSign />} />
{/* login page route */} {/* login page route */}
<Route path="/login/:id/:userMail/:contactBookId/:serverUrl" element={<Login />} /> <Route
path="/login/:id/:userMail/:contactBookId/:serverUrl"
element={<Login />}
/>
{/* draft document route to handle and navigate route page accordiing to document status */} {/* draft document route to handle and navigate route page accordiing to document status */}
<Route path="/draftDocument" element={<DraftDocument />} /> <Route path="/draftDocument" element={<DraftDocument />} />
{/* for user signature (need your sign route) with row level data */} {/* for user signature (need your sign route) with row level data */}
@@ -42,6 +46,8 @@ function AppRoutes() {
<Route path="/pdfRequestFiles/:docId" element={<PdfRequestFiles />} /> <Route path="/pdfRequestFiles/:docId" element={<PdfRequestFiles />} />
{/* lega drive route */} {/* lega drive route */}
<Route path="/legadrive" element={<LegaDrive />} /> <Route path="/legadrive" element={<LegaDrive />} />
{/* Page Not Found */}
<Route path="*" element={<PageNotFound />} />
</Routes> </Routes>
</div> </div>
); );
Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Some files were not shown because too many files have changed in this diff Show More