Compare commits

...
199 Commits
Author SHA1 Message Date
AndrewandGitHub 350854ab6b Merge pull request #321 from OpenSignLabs/fix_submitbtn_template 2024-01-12 19:53:25 +05:30
prafull-opensignlabsandGitHub cc980758fd Update TemplateForm.js 2024-01-12 19:49:51 +05:30
prafull-opensignlabsandGitHub 0f1ce43cc5 Merge pull request #320 from OpenSignLabs/modal-ui
fix: replace title Role to Roles in template creation flow
2024-01-12 19:24:53 +05:30
RaktimaNXG 5e1a9cdc20 "fix: replace title Role to Roles in template creation flow" 2024-01-12 17:25:11 +05:30
prafull-opensignlabsandGitHub 550ce10c92 Merge pull request #318 from OpenSignLabs/modal-ui
fix: modal-ui,replace loading pdf to loading document, onclick placeholder open user details popup
2024-01-12 15:38:11 +05:30
RaktimaandGitHub 6080c59bd7 fix: clear image after upload image on sign pad 2024-01-12 15:23:30 +05:30
RaktimaNXG 273a35d42f fix:resolved on-drag placeholder user-details popup open in edit template flow 2024-01-12 15:03:09 +05:30
RaktimaNXG 2f195fe02e fix: clear image issue after upload image using sign pad 2024-01-12 14:27:33 +05:30
RaktimaNXG 0715ca9d85 fix: on-drag placeholder user-details popup open issue,close button design, remove unnecessary code & npm package 2024-01-12 14:07:53 +05:30
RaktimaNXG 1ec10fbcfc fix: modal-ui,replace loading pdf to loading document, onclick placeholder open user details popup 2024-01-11 14:53:14 +05:30
AmolandGitHub 274620d17b Merge pull request #314 from OpenSignLabs/fix_draft_report
update draft report query
2024-01-10 21:04:52 +05:30
prafull-opensignlabsandGitHub 06db7d2360 update draft report query 2024-01-10 21:04:20 +05:30
AndrewandGitHub 2b3549e4df Merge pull request #313 from OpenSignLabs/opensign-drive 2024-01-10 20:48:52 +05:30
RaktimaNXG d16478792c fix:document name bold,openSign to OpenSign™ in email login flow 2024-01-10 19:49:17 +05:30
prafull-opensignlabsandGitHub 7ba2ef6420 Merge pull request #311 from OpenSignLabs/opensign-drive
feat: implement of document delete and move to folder in opensigndrive
2024-01-10 18:29:32 +05:30
prafull-opensignlabsandGitHub b5d98796b7 update template details on save 2024-01-10 18:28:38 +05:30
RaktimaNXG 97c17cfe84 fix: table view design opensign-drive 2024-01-10 18:19:11 +05:30
RaktimaNXG 4b4e200090 extend expire date from current date 2024-01-10 16:57:22 +05:30
RaktimaNXG 232d38440d add extend days value from timeToCompleteDays filed for expired document 2024-01-10 16:12:39 +05:30
RaktimaNXG 341bd9bef0 fix: draft document redirect issue 2024-01-10 15:27:35 +05:30
RaktimaNXG 2f4d04c722 fix: draft document redirect issue 2024-01-10 15:23:35 +05:30
RaktimaNXG 148ae40e1a extend expire date of expired draft document 2024-01-10 15:11:26 +05:30
prafull-opensignlabs 9cb0ced4f6 add migration script for update menu & add IsArchive field in document cls 2024-01-10 12:21:00 +05:30
RaktimaNXG 9a3b70de43 fix: expired document redirect wrong route in opensign-drive 2024-01-10 11:19:16 +05:30
RaktimaNXG 742b8f7eae fix: move folder on same folder issue 2024-01-10 10:57:22 +05:30
RaktimaNXG abc58941e3 fix: onclick to open folder issuein opensign-drive 2024-01-10 10:44:33 +05:30
RaktimaNXG aac200bfd3 fix: right click move functionality issue opensign-drive 2024-01-09 20:20:56 +05:30
RaktimaNXG 27d3297d61 fix: decline alert header message, add icon for right click menu on opensign-drive,on enter create folder 2024-01-09 20:02:40 +05:30
RaktimaNXG 72431b2c82 fix: redirect wrong route of draft docment issue in openSign-drive 2024-01-09 17:24:27 +05:30
RaktimaNXG 3ca48e5848 fix: folder list display issue in move folder modal,add alert for delete document, change modal css 2024-01-09 14:35:45 +05:30
prafull-opensignlabsandGitHub 14784ec80f added validation to get non archive document in getdrive cloud function 2024-01-09 11:36:22 +05:30
prafull-opensignlabsandGitHub 127741eb27 remove override box css 2024-01-09 11:08:03 +05:30
RaktimaNXG 2ed987fe10 feat: implement document delete and move funationality in openSign-drive 2024-01-08 22:12:23 +05:30
AndrewandGitHub 7aaa1876c8 Merge pull request #308 from OpenSignLabs/need-your-sign 2024-01-06 19:31:30 +05:30
RaktimaNXG 390ffb83a2 fix: user redirect wrong route after send placeholder to signers 2024-01-06 18:41:53 +05:30
prafull-opensignlabsandGitHub d63e51b8cb Merge pull request #307 from OpenSignLabs/need-your-sign
fix: placeholder display issue of all signers after save placeholder and login flow
2024-01-05 18:38:15 +05:30
RaktimaNXG 7bd8d64649 fix: instance signature flow issue after send placeholder 2024-01-05 17:37:57 +05:30
RaktimaNXG f9e6f49ede fix: placeholder display issue of all signers after save placeholder and login flow 2024-01-05 17:00:41 +05:30
AndrewandGitHub b701d2863f Merge pull request #295 from OpenSignLabs/text-input 2024-01-05 15:58:04 +05:30
RaktimaandGitHub cf47093227 Merge branch 'staging' into text-input 2024-01-05 12:07:14 +05:30
RaktimaNXG 81d0aea66c fix: text-input signatureissue 2024-01-04 16:14:23 +05:30
AndrewandGitHub 506ca35be8 Merge pull request #305 from OpenSignLabs/pdflib-sign 2024-01-03 20:46:41 +05:30
RaktimaNXG 1cd6718489 fix: single signature issue, change react tour message, add icon for create new tamplate 2024-01-03 19:47:22 +05:30
RaktimaNXG 153c5db4b5 fix: input signature image height issue and limit 30 character of input text signature 2024-01-03 16:17:32 +05:30
RaktimaNXG ac9367a715 fix: fontstyle after save text signature issue 2024-01-03 13:46:44 +05:30
RaktimaNXG 081dae0b90 fix: font style for first time on save text signature 2024-01-03 13:07:59 +05:30
RaktimaandGitHub e286390aec Merge branch 'staging' into text-input 2024-01-03 12:44:55 +05:30
RaktimaNXG cf88eb2124 fix: font-style issue after save text signature 2024-01-03 12:43:01 +05:30
prafull-opensignlabsandGitHub 3226e4fd85 Merge pull request #304 from OpenSignLabs/feat_template
add hyperlink in completed mail for any query
2024-01-03 11:55:39 +05:30
prafull-opensignlabs cab94eb63d add hyperlink in completed mail for any query 2024-01-03 11:52:11 +05:30
prafull-opensignlabsandGitHub bbd5d6805e Merge pull request #303 from OpenSignLabs/feat_template
bug fix in template flow as well as placeholder is not working in mobile view
2024-01-03 10:14:09 +05:30
prafull-opensignlabs 2904ba3085 bug fix in template flow as well as placeholder is not working in mobile view 2024-01-03 10:03:12 +05:30
RaktimaNXG ee609061ed fix: text input signature font-family for mobile view 2024-01-02 10:03:06 +05:30
prafull-opensignlabsandGitHub 6c98a4e899 Merge pull request #301 from OpenSignLabs/feat_template
add don't show button for tour and minor bug fix
2024-01-01 11:46:01 +05:30
prafull-opensignlabs eef9ee7f3c remove unncessary navigation 2024-01-01 11:00:04 +05:30
prafull-opensignlabs 2cb4575db1 add dont show button for reactour and minor bug fix in template flow 2024-01-01 10:49:37 +05:30
prafull-opensignlabsandGitHub e7bcad80cc Merge pull request #298 from OpenSignLabs/staging
sync fork
2023-12-31 16:05:11 +05:30
AndrewandGitHub 353839a1dc Merge pull request #297 from OpenSignLabs/fix 2023-12-31 16:02:18 +05:30
prafull-opensignlabsandGitHub e6d30744ba Update Pgsignup.js 2023-12-31 16:01:37 +05:30
prafull-opensignlabsandGitHub b67932f448 Merge pull request #296 from OpenSignLabs/staging
sync fork
2023-12-30 20:02:38 +05:30
prafull-opensignlabs c185c42b80 vertically center button in reports, add title for template route and placeholder route 2023-12-30 19:52:36 +05:30
prafull-opensignlabs 4648ace84e fix : minor bug fix in template 2023-12-29 23:00:37 +05:30
prafull-opensignlabs ccdf50dbe0 add validation for delete contact 2023-12-29 16:50:10 +05:30
RaktimaNXG 852a3dc8bb feat: Enable text input signature feature 2023-12-29 16:36:49 +05:30
prafull-opensignlabs d49b7bd201 change query of progress and recent sent for signtuare reports 2023-12-29 12:59:57 +05:30
prafull-opensignlabs 07f2ceed6e add session validation, updated migration script and minor ui changes 2023-12-29 12:31:36 +05:30
prafull-opensignlabsandGitHub 751c7b5787 Merge pull request #294 from OpenSignLabs/feat_template
fix: minor template issues, resize issue in mobile, change recipient list Ui in mobile
2023-12-28 19:38:11 +05:30
prafull-opensignlabs e82384dff8 fix: signyourself flow, add validtion in template flow, change UI recipientlist in mobile view 2023-12-28 19:36:06 +05:30
RaktimaNXG 92d3a85147 fix: placeholder resize issue in mobile view 2023-12-28 17:30:08 +05:30
prafull-opensignlabsandGitHub c5762a0baf Merge pull request #293 from OpenSignLabs/feat_template
fix: minor bug fix in template component
2023-12-28 14:41:12 +05:30
prafull-opensignlabs dc40b04a18 fix: minor bug fix in template compoent 2023-12-28 14:39:52 +05:30
prafull-opensignlabsandGitHub 1cca5a3085 Merge pull request #292 from OpenSignLabs/feat_template
fix: add recipient required validation and dropbox is not visible
2023-12-28 12:33:02 +05:30
prafull-opensignlabs 4fe4ca638c add receipent required validation 2023-12-28 12:29:05 +05:30
prafull-opensignlabs b8c7110c63 resolve issue of receipent in not selected by default and dropbox upload 2023-12-28 12:15:02 +05:30
prafull-opensignlabsandGitHub 711ab6a556 Merge pull request #290 from OpenSignLabs/feat_template
feat: Introducing Template Creation Functionality: Streamline Document Generation and Sharing
2023-12-27 17:44:07 +05:30
prafull-opensignlabs 7a12f54587 add contactbook form in contactbook report 2023-12-27 17:41:51 +05:30
prafull-opensignlabs 056f4b3e80 remove random words from file upload input to show correct pdf name 2023-12-27 16:31:19 +05:30
prafull-opensignlabs 730a7a4e15 add reactour for template 2023-12-27 16:26:56 +05:30
prafull-opensignlabs a4b4dc885c removed unnecessary assets 2023-12-27 14:17:19 +05:30
prafull-opensignlabs 8562a4bb46 change fetch function 2023-12-27 08:21:49 +05:30
prafull-opensignlabs d3b56432e0 resolve color issue on drag placeholder 2023-12-27 08:11:17 +05:30
prafull-opensignlabs 527c5be42c add attach user icon in mobile view 2023-12-26 23:03:27 +05:30
prafull-opensignlabs 6c1d0c712a resolve delete user not working properly with placholder 2023-12-26 20:04:16 +05:30
prafull-opensignlabs fd0ec5fd31 resolve resize issue for template placeholder 2023-12-26 18:52:53 +05:30
prafull-opensignlabs f5f19c9b52 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into feat_template 2023-12-26 16:50:21 +05:30
prafull-opensignlabsandGitHub 642ef4f5b7 Merge pull request #286 from OpenSignLabs/placeholder
feat: add copy placeholder feature and change in UI of placeholder
2023-12-26 15:33:22 +05:30
prafull-opensignlabs 66b65e600b add validtion for fetch template 2023-12-26 13:53:54 +05:30
prafull-opensignlabs 01a130ef8c add username in placeholder and validtion for fetch template 2023-12-26 13:52:52 +05:30
prafull-opensignlabs c3bccb5412 show role name in placeholder 2023-12-26 09:27:50 +05:30
prafull-opensignlabsandGitHub b32e6e71f8 Merge pull request #288 from OpenSignLabs/staging
sync fork
2023-12-25 19:05:40 +05:30
RaktimaNXG 3b5875e283 fix: size of the placeholder changed after the signature was uploaded in need-your-sign report 2023-12-22 12:44:38 +05:30
prafull-opensignlabs da42fe97ae add/Choose form to link user and ui changes 2023-12-21 21:40:42 +05:30
AmolandGitHub 56bb7d36eb chore: remove mailgun api key value 2023-12-21 16:32:59 +05:30
AmolandGitHub d86b7345d7 chore: set smtp dummy values 2023-12-21 16:25:15 +05:30
AmolandGitHub c1c17160ff chore: set SMTP_ENABLE to true 2023-12-21 16:21:05 +05:30
RaktimaNXG d400c843e4 fix: modified variable name as required and added comment 2023-12-21 15:14:29 +05:30
prafull-opensignlabs 4e67ab50fe resolve minor ui issues 2023-12-20 23:57:50 +05:30
prafull-opensignlabs 74c9e21d55 resolve minor ui issues 2023-12-20 23:57:02 +05:30
RaktimaNXG fefcdf6ffc feat: placeholder copy all pages feature at same location and change placeholder design 2023-12-20 19:31:59 +05:30
prafull-opensignlabs 5170e4eee2 migration script for template class 2023-12-20 17:32:51 +05:30
prafull-opensignlabs 8ebfd781c3 add template report and form , as well as migration code for it 2023-12-20 14:33:41 +05:30
prafull-opensignlabs 4e8988bf57 add template feature 2023-12-19 18:58:28 +05:30
prafull-opensignlabsandGitHub c26734751f Merge pull request #282 from OpenSignLabs/staging
sync fork
2023-12-18 10:57:46 +05:30
AndrewandGitHub 8c209f5a9e Merge pull request #280 from OpenSignLabs/all-contributors/add-VikramNagwal 2023-12-17 10:22:59 +05:30
allcontributors[bot]andGitHub 995a2a5cef docs: update .all-contributorsrc 2023-12-17 04:52:20 +00:00
allcontributors[bot]andGitHub 71fd7b20a6 docs: update README.md 2023-12-17 04:52:19 +00:00
AndrewandGitHub d8e73eef72 Merge pull request #279 from VikramNagwal/staging 2023-12-17 10:21:54 +05:30
prafull-opensignlabs ca6b4e7d82 add createDocument from template functionality 2023-12-16 22:19:12 +05:30
prafull-opensignlabs cb4a94d036 add createDocument from template functionality 2023-12-16 22:19:01 +05:30
prafull-opensignlabsandGitHub 300ddb810f Update LoginFacebook.js 2023-12-16 17:03:35 +05:30
prafull-opensignlabsandGitHub 0b687310fd Update LoginGoogle.js 2023-12-16 17:03:04 +05:30
jeremyito07 61209f4c6c fix: Removed "/test" Route with comments 2023-12-16 10:23:48 +05:30
prafull-opensignlabs 3e741ac2f9 add functionality of add placholder in template 2023-12-15 19:01:05 +05:30
jeremyito07 c4507dd06b fix: removed "/test" route from application 2023-12-15 18:35:18 +05:30
prafull-opensignlabsandGitHub f65b23ca26 Merge pull request #278 from OpenSignLabs/staging
Sync fork
2023-12-15 16:37:32 +05:30
prafull-opensignlabsandGitHub 773e8b8dbb Merge pull request #260 from OpenSignLabs/placeholder-block
fix: placeholder block issue for select multisigners
2023-12-15 16:32:49 +05:30
AmolandGitHub 91976d2355 chore: add dependabot dependency update check 2023-12-15 13:47:21 +05:30
RaktimaNXG 77042224a1 fix: opensign-drive drop-down issue 2023-12-15 13:19:26 +05:30
RaktimaNXG 0b64908eab increase zIndex of header and footer 2023-12-15 10:59:41 +05:30
RaktimaNXG fc3f134bd5 fix: zIndex of placeholder-block and added signyourself & request signature form in openSign drive 2023-12-15 10:22:00 +05:30
RaktimaNXG d6c2c66fdd fix: image-upload issue in mobile view 2023-12-13 18:12:47 +05:30
prafull-opensignlabsandGitHub db9b8d2ba1 Merge pull request #261 from OpenSignLabs/staging
sync fork
2023-12-12 19:57:56 +05:30
RaktimaNXG d5853e6fc3 fix: placeholder block issue for select multisigners 2023-12-12 19:23:21 +05:30
AmolandGitHub 765c3c19fa Merge pull request #259 from OpenSignLabs/placeholder-resize 2023-12-12 18:27:54 +05:30
prafull-opensignlabs 2b345ff840 add new template form 2023-12-12 17:57:11 +05:30
RaktimaNXG f13991b88b fix: upload large size image overflow in placeholder 2023-12-12 15:15:19 +05:30
RaktimaNXG 47ddac3529 fix: multisign signature issue in mobile view 2023-12-11 17:50:36 +05:30
RaktimaNXG e51feaa1fe Refactor code 2023-12-08 17:11:01 +05:30
RaktimaNXG d224a44e54 fix: mobile to desktop and desktop to mobile view placeholder location issue 2023-12-07 20:01:15 +05:30
AmolandGitHub f5c0694e32 Merge pull request #249 from OpenSignLabs/placeholder-resize 2023-12-06 18:52:47 +05:30
RaktimaNXG dec13e8b5f fix: image resize placeholder location issue in mobile to mobile and desktop to desktop view 2023-12-06 16:37:59 +05:30
RaktimaandGitHub dd536dc7d0 Merge branch 'staging' into placeholder-resize 2023-12-06 10:13:03 +05:30
AmolandGitHub b6ce00519f Merge pull request #257 from OpenSignLabs/send-mail 2023-12-06 09:33:24 +05:30
RaktimaNXG 7495955420 fix: design of email sent toast message 2023-12-05 14:12:12 +05:30
AndrewandGitHub d17951af30 Merge pull request #258 from OpenSignLabs/profile_ui 2023-12-05 14:11:00 +05:30
prafull-opensignlabs 42c6f03f28 remove outline of buttons in profile ui 2023-12-05 13:47:46 +05:30
prafull-opensignlabs a9d6bc2246 update user profile ui 2023-12-05 13:32:14 +05:30
RaktimaNXG 428bb3b7c3 fix: design of sent mail message,change variable name emailCount to emailList 2023-12-05 13:08:42 +05:30
RaktimaNXG ac0cdd28cf feat: mail button on header after sign document in signyourself flow 2023-12-05 12:07:25 +05:30
RaktimaNXG 37250f8a11 fix multiple signature location issue after complete signature in signyourself flow 2023-12-05 10:51:58 +05:30
AmolandGitHub 0102480954 Merge pull request #255 from OpenSignLabs/main
Merge pull request #229 from OpenSignLabs/staging
2023-12-04 18:23:02 +05:30
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 9a4bd79d75 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into placeholder-resize 2023-12-04 16:08:31 +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
RaktimaNXG 0c4b8143b2 fix: placeholder and signyourself location issue in mobille view 2023-12-04 11:34:51 +05:30
RaktimaNXG 1cc4cf93cb fix: resize placeholder design and adding resize option for recipients, added signers's name on placeholder 2023-12-01 20:09:22 +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 4327b2e348 Merge pull request #229 from OpenSignLabs/staging
patch: typo fix
2023-11-24 19:25:47 +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
119 changed files with 12891 additions and 6201 deletions
+27
View File
@@ -178,6 +178,33 @@
"contributions": [
"a11y"
]
},
{
"login": "Govinda04",
"name": "Govinda Kocharekar",
"avatar_url": "https://avatars.githubusercontent.com/u/50038172?v=4",
"profile": "https://github.com/Govinda04",
"contributions": [
"code"
]
},
{
"login": "crediblebilal",
"name": "Bilal Ahmad Bhat",
"avatar_url": "https://avatars.githubusercontent.com/u/55330484?v=4",
"profile": "https://bilal.cc",
"contributions": [
"code"
]
},
{
"login": "VikramNagwal",
"name": "Vikram",
"avatar_url": "https://avatars.githubusercontent.com/u/123088024?v=4",
"profile": "https://github.com/VikramNagwal",
"contributions": [
"code"
]
}
]
}
+9 -2
View File
@@ -39,11 +39,18 @@ DO_ACCESS_KEY_ID=
DO_SECRET_ACCESS_KEY=
# Digital ocean spaces region or AWS s3 region
DO_REGION=us-west
# Set this to true id you are using local storage instead of s3 compatible storage
# USE_LOCAL=TRUE
# Email mailgun config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
MAILGUN_API_KEY=
# Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
MAILGUN_API_KEY=XXXXX
MAILGUN_DOMAIN=mail.yourdomain.com
MAILGUN_SENDER=postmaster@mail.yourdomain.com
SMTP_ENABLE=
SMTP_HOST=
SMTP_PORT=
SMTP_USER_EMAIL=
SMTP_PASS=
# Base64 encoded PFX or p12 document signing certificate file *********************************************************************************************************************
PFX_BASE64=
+8 -2
View File
@@ -44,10 +44,16 @@ DO_REGION=us-west
# local storage
USE_LOCAL=TRUE
# Email mailgun config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
MAILGUN_API_KEY=XXXXX
# Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
MAILGUN_API_KEY=
MAILGUN_DOMAIN=mail.yourdomain.com
MAILGUN_SENDER=postmaster@mail.yourdomain.com
SMTP_ENABLE=
SMTP_HOST=smtp.yourhost.com
SMTP_PORT=443
SMTP_USER_EMAIL=mailer@yourdomain.com
SMTP_PASS=password
# Base64 encoded PFX or p12 document signing certificate file *********************************************************************************************************************
PFX_BASE64='MIIKCQIBAzCCCc8GCSqGSIb3DQEHAaCCCcAEggm8MIIJuDCCBG8GCSqGSIb3DQEH
+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
+22
View File
@@ -0,0 +1,22 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
# maintain dependencies for frontend
- package-ecosystem: "npm" # See documentation for possible values
directory: "/apps/OpenSign" # Location of package manifests
schedule:
interval: "weekly"
# maintain dependencies for server
- package-ecosystem: "npm" # See documentation for possible values
directory: "/apps/OpenSignServer" # Location of package manifests
schedule:
interval: "weekly"
# maintain dependencies for microfrontends
- package-ecosystem: "npm" # See documentation for possible values
directory: "microfrontends/SignDocuments" # Location of package manifests
schedule:
interval: "weekly"
+1 -2
View File
@@ -98,8 +98,7 @@ Environment Varaibles:
| 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 | http://localhost:3000 | Set it to the URL form where the app home page will be accessed |
| PUBLIC_URL | 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. |
| 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. |
+5
View File
@@ -128,6 +128,11 @@ 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/rishabjasrotia"><img src="https://avatars.githubusercontent.com/u/33950743?v=4?s=100" width="100px;" alt="Rishab"/><br /><sub><b>Rishab</b></sub></a><br /><a href="#code-rishabjasrotia" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://session.it"><img src="https://avatars.githubusercontent.com/u/327285?v=4?s=100" width="100px;" alt="Maurizio Pillitu"/><br /><sub><b>Maurizio Pillitu</b></sub></a><br /><a href="#bug-maoo" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://luisparra.dev"><img src="https://avatars.githubusercontent.com/u/16653744?v=4?s=100" width="100px;" alt="Luis Parra"/><br /><sub><b>Luis Parra</b></sub></a><br /><a href="#a11y-lsprr" title="Accessibility">️♿️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Govinda04"><img src="https://avatars.githubusercontent.com/u/50038172?v=4?s=100" width="100px;" alt="Govinda Kocharekar"/><br /><sub><b>Govinda Kocharekar</b></sub></a><br /><a href="#code-Govinda04" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://bilal.cc"><img src="https://avatars.githubusercontent.com/u/55330484?v=4?s=100" width="100px;" alt="Bilal Ahmad Bhat"/><br /><sub><b>Bilal Ahmad Bhat</b></sub></a><br /><a href="#code-crediblebilal" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/VikramNagwal"><img src="https://avatars.githubusercontent.com/u/123088024?v=4?s=100" width="100px;" alt="Vikram"/><br /><sub><b>Vikram</b></sub></a><br /><a href="#code-VikramNagwal" title="Code">💻</a></td>
</tr>
</tbody>
</table>
+3 -2
View File
@@ -42,7 +42,8 @@
"scripts": {
"start": "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",
"test": "react-scripts test",
"eject": "react-scripts eject",
@@ -85,4 +86,4 @@
"pretty-quick": "^3.1.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"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" />
<title>Open sign</title>
<title>OpenSign</title>
</head>
<body>
@@ -50,4 +50,4 @@
-->
</body>
</html>
</html>
View File
+19 -2
View File
@@ -15,6 +15,7 @@ import ForgetPassword from "./routes/ForgetPassword";
import ChangePassword from "./routes/ChangePassword";
import ReportMicroapp from "./components/ReportMicroapp";
import LoadMf from "./routes/LoadMf";
import ValidateRoute from "./primitives/ValidateRoute";
function App() {
const [isloading, setIsLoading] = useState(true);
@@ -58,8 +59,24 @@ function App() {
) : (
<BrowserRouter>
<Routes>
<Route exact path="/" element={<Login />} />
<Route exact path="/signup" element={<Signup />} />
<Route
exact
path="/"
element={
<ValidateRoute>
<Login />
</ValidateRoute>
}
/>
<Route
exact
path="/signup"
element={
<ValidateRoute>
<Signup />
</ValidateRoute>
}
/>
<Route exact path="/loadmf/:remoteApp/*" element={<LoadMf />} />
<Route exact path="/forgetpassword" element={<ForgetPassword />} />
{process.env.REACT_APP_ENABLE_SUBSCRIPTION && (
@@ -32,6 +32,7 @@ const AppendFormInForm = (props) => {
try {
const query = new Parse.Query("contracts_Contactbook");
query.equalTo("CreatedBy", user);
query.notEqualTo("IsDeleted", true);
query.equalTo("Email", user.getEmail());
const res = await query.first();
// console.log(res);
@@ -45,6 +46,7 @@ const AppendFormInForm = (props) => {
// Define a function to handle form submission
const handleSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
setIsLoader(true);
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
@@ -104,13 +106,18 @@ const AppendFormInForm = (props) => {
const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res));
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
if (props.details) {
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
}
if (props.closePopup) {
props.closePopup();
}
if (props.handleUserData) {
props.handleUserData(parseData);
}
setIsLoader(false);
// Reset the form fields
@@ -157,13 +164,18 @@ const AppendFormInForm = (props) => {
const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res));
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
if (props.details) {
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
}
if (props.closePopup) {
props.closePopup();
}
if (props.handleUserData) {
props.handleUserData(parseData);
}
setIsLoader(false);
// Reset the form fields
setAddYourself(false);
+15 -7
View File
@@ -1,8 +1,20 @@
import React, { useEffect, useState } from "react";
import Package from "../../package.json";
import axios from "axios";
const Footer = () => {
const [showButton, setShowButton] = useState(false);
const [version, setVersion] = useState("");
useEffect(() => {
axios
.get("/version.txt")
.then((response) => {
setVersion(response.data); // Set the retrieved data to the state variable
})
.catch((error) => {
console.error("Error reading the file:", error);
});
}, []);
const handleScroll = () => {
if (window.pageYOffset >= 50) {
setShowButton(true);
@@ -25,16 +37,12 @@ const Footer = () => {
}, []);
const appName = "OpenSign™";
return (
<>
<div className="bg-[#222c3c] text-[#98a6ba] text-center text-[13px] py-3">
All Rights Reserved &copy; {new Date().getFullYear()} &nbsp;
{appName}{" "}
(version:{" "}
{localStorage.getItem("appVersion") &&
`${Package.version}.${localStorage.getItem("appVersion")}`}
)
{appName} ( version: {version ? version : `${Package.version} `})
</div>
<button
className={`${
@@ -86,7 +86,7 @@ const LoginFacebook = ({
email: userDetails.Email,
// "passsword":userDetails.Phone,
phone: userDetails.Phone,
role: "contracts_Admin",
role: "contracts_User",
company: userDetails.Company
}
};
+4 -4
View File
@@ -43,8 +43,9 @@ const GoogleSignInBtn = ({
});
});
const clearStorage = async () => {
await Parse.User.logOut();
if (Parse.User.current()) {
await Parse.User.logOut();
}
let baseUrl = localStorage.getItem("BaseUrl12");
let appid = localStorage.getItem("AppID12");
let applogo = localStorage.getItem("appLogo");
@@ -74,7 +75,6 @@ const GoogleSignInBtn = ({
localStorage.setItem("userSettings", userSettings);
localStorage.setItem("baseUrl", baseUrl);
localStorage.setItem("parseAppId", appid);
};
const responseGoogle = async (response) => {
clearStorage();
@@ -148,7 +148,7 @@ const GoogleSignInBtn = ({
email: userDetails.Email,
// "passsword":userDetails.Phone,
phone: userDetails.Phone,
role: "contracts_Admin",
role: "contracts_User",
company: userDetails.Company,
jobTitle: userDetails.Destination
}
+8 -6
View File
@@ -5,7 +5,7 @@ import Parse from "parse";
import axios from "axios";
import "../styles/spinner.css";
import TreeFormComponent from "./TreeFormComponent";
import TreeEditForm from "./TreeEditForm";
// import TreeEditForm from "./TreeEditForm";
import "../styles/modal.css";
import Modal from "react-modal";
@@ -22,7 +22,7 @@ const TreeWidget = (props) => {
const [schemaState, setSchemaState] = useState({});
const [TabURL, setTabURL] = useState("");
const [editable, setEditable] = useState(false);
const [editId, setEditId] = useState("");
// const [editId, setEditId] = useState("");
const [defaultState, setDefaultState] = useState(false);
const [isShowModal, setIsShowModal] = useState(false);
const selectFolderHandle = async () => {
@@ -472,6 +472,8 @@ const TreeWidget = (props) => {
props.schema.data.FolderTypeField,
props.schema.data.FolderTypeValue
);
const currentUser = Parse.User.current();
folder.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
if (tabList.length > 0) {
let len = tabList.length - 1;
folder.set(props.schema.data.ParentFolderField, {
@@ -698,7 +700,7 @@ const TreeWidget = (props) => {
))}
<hr />
</div>
{editable && (
{/* {editable && (
<TreeEditForm
FormId={props.schema.data.FormId}
objectId={editId}
@@ -707,7 +709,7 @@ const TreeWidget = (props) => {
selectFolderHandle();
}}
/>
)}
)} */}
{isAddField && !loader && !editable && (
<TreeFormComponent
Id={props.schema.data.FormId}
@@ -795,7 +797,7 @@ const TreeWidget = (props) => {
</a>
</div>
{fldr[props.schema.data.FolderTypeField] ===
{/* {fldr[props.schema.data.FolderTypeField] ===
props.schema.data.FolderTypeValue && (
<a
className="float-right"
@@ -815,7 +817,7 @@ const TreeWidget = (props) => {
aria-hidden="true"
></i>
</a>
)}
)} */}
</li>
)
)}
@@ -9,6 +9,7 @@ function DashboardReport(props) {
const [isLoader, setIsLoader] = useState(true);
const [reportName, setReportName] = useState("");
const [actions, setActions] = useState([]);
const [heading, setHeading] = useState([]);
const [isNextRecord, setIsNextRecord] = useState(false);
const [isMoreDocs, setIsMoreDocs] = useState(true);
const abortController = new AbortController();
@@ -43,6 +44,7 @@ function DashboardReport(props) {
if (json) {
setActions(json.actions);
setReportName(json.reportName);
setHeading(json.heading);
Parse.serverURL = localStorage.getItem("BaseUrl12");
Parse.initialize(localStorage.getItem("AppID12"));
const currentUser = Parse.User.current().id;
@@ -140,7 +142,9 @@ function DashboardReport(props) {
<ReportTable
ReportName={reportName}
List={List}
setList={setList}
actions={actions}
heading={heading}
setIsNextRecord={setIsNextRecord}
isMoreDocs={isMoreDocs}
docPerPage={docPerPage}
@@ -0,0 +1,147 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import Alert from "../../primitives/Alert";
const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
const folderPtr = {
__type: "Pointer",
className: folderCls,
objectId: parentFolderId
};
const [name, setName] = useState("");
const [folderList, setFolderList] = useState([]);
const [isAlert, setIsAlert] = useState(false);
const [selectedParent, setSelectedParent] = useState();
const [alert, setAlert] = useState({ type: "info", message: "" });
useEffect(() => {
fetchFolder();
// eslint-disable-next-line
}, []);
const fetchFolder = async () => {
try {
const FolderQuery = new Parse.Query(folderCls);
if (parentFolderId) {
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
} else {
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
}
const res = await FolderQuery.find();
if (res) {
const result = JSON.parse(JSON.stringify(res));
if (result) {
setFolderList(result);
}
}
} catch (error) {
console.log("Err ", error);
}
};
const handleCreateFolder = async (event) => {
event.preventDefault();
if (name) {
const currentUser = Parse.User.current();
const exsitQuery = new Parse.Query(folderCls);
exsitQuery.equalTo("Name", name);
exsitQuery.equalTo("Type", "Folder");
if (parentFolderId) {
exsitQuery.equalTo("Folder", folderPtr);
}
const templExist = await exsitQuery.first();
if (templExist) {
setAlert({ type: "dange", message: "Folder already exist!" });
setIsAlert(true);
setTimeout(() => {
setIsAlert(false);
}, 1000);
} else {
const template = new Parse.Object(folderCls);
template.set("Name", name);
template.set("Type", "Folder");
if (selectedParent) {
template.set("Folder", {
__type: "Pointer",
className: folderCls,
objectId: selectedParent
});
} else if (parentFolderId) {
template.set("Folder", folderPtr);
}
template.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
const res = await template.save();
if (res) {
setAlert({
type: "success",
message: "Folder created successfully!"
});
setIsAlert(true);
setTimeout(() => {
setIsAlert(false);
}, 1000);
if (onSuccess) {
onSuccess(res);
}
}
}
} else {
setAlert({ type: "info", message: "Please fill folder name" });
setIsAlert(true);
setTimeout(() => {
setIsAlert(false);
}, 1000);
}
};
const handleOptions = (e) => {
setSelectedParent(e.target.value);
};
return (
<div>
{isAlert && <Alert type={alert.type}>{alert.message}</Alert>}
<div id="createFolder">
<h1 className="text-base font-semibold">Create Folder</h1>
<div className="text-xs mt-2">
<label className="block">
Name<span className="text-red-500 text-[13px]">*</span>
</label>
<input
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
</div>
<div className="text-xs mt-2">
<label className="block">Parent Folder</label>
<select
value={selectedParent}
onChange={handleOptions}
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
>
<option>select</option>
{folderList.length > 0 &&
folderList.map((x) => (
<option key={x.objectId} value={x.objectId}>
{x.Name}
</option>
))}
</select>
</div>
<div>
<button
onClick={handleCreateFolder}
className="flex items-center rounded p-2 bg-[#32a3ac] text-white mt-3"
>
<i className="fa-solid fa-plus mr-1"></i>
<span>Create</span>
</button>
</div>
</div>
</div>
);
};
export default CreateFolder;
@@ -0,0 +1,60 @@
import React, { useCallback, useMemo } from "react";
import { useDropScript } from "../../hook/useScript";
const DROPBOX_APP_KEY = process.env.REACT_APP_DROPBOX_API_KEY; // App key
const DROPBOX_SDK_URL = "https://www.dropbox.com/static/api/2/dropins.js";
const DROPBOX_SCRIPT_ID = "dropboxjs";
export default function DropboxChooser({ children, onSuccess, onCancel }) {
useDropScript(DROPBOX_SDK_URL, {
attrs: {
id: DROPBOX_SCRIPT_ID,
"data-app-key": DROPBOX_APP_KEY
}
});
const options = useMemo(
() => ({
// Required. Called when a user selects an item in the Chooser.
success: (files) => {
// console.log("success", files);
onSuccess && onSuccess(files);
},
// Optional. Called when the user closes the dialog without selecting a file
// and does not include any parameters.
cancel: () => {
console.log("cancel");
onCancel && onCancel();
},
// Optional. "preview" (default) is a preview link to the document for sharing,
// "direct" is an expiring link to download the contents of the file. For more
linkType: "direct", // or "preview"
multiselect: false, // 是否支持多选
extensions: [".pdf"],
// Optional. A value of false (default) limits selection to files,
// while true allows the user to select both folders and files.
// You cannot specify `linkType: "direct"` when using `folderselect: true`.
folderselect: false // or true
}),
[onSuccess, onCancel]
);
const handleChoose = useCallback((e) => {
e.preventDefault()
if (window.Dropbox) {
window.Dropbox.choose(options);
}
}, [options]);
return (
<div onClick={handleChoose}>
{children || (
<button className="px-2 py-[2px] text-2xl rounded border-[1px] text-blue-400 border-gray-300 w-full">
<i className="fa-brands fa-dropbox"></i>
</button>
)}
</div>
);
}
@@ -2,14 +2,12 @@ import React, { useState, useEffect } from "react";
import { SaveFileSize } from "../../constant/saveFileSize";
import Parse from "parse";
import sanitizeFileName from "../../primitives/sanitizeFileName";
import DropboxChooser from "./DropboxChoose";
const FileUpload = (props) => {
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [_fileupload, setFileUpload] = useState("");
const [fileload, setfileload] = useState(false);
const [localValue, setLocalValue] = useState("");
const [Message] = useState(false);
const [percentage, setpercentage] = useState(0);
@@ -25,7 +23,6 @@ const FileUpload = (props) => {
const onChange = (e) => {
try {
let files = e.target.files;
setLocalValue(e.target.files);
if (typeof files[0] !== "undefined") {
if (props.schema.filetypes && props.schema.filetypes.length > 0) {
var fileName = files[0].name;
@@ -106,6 +103,56 @@ const FileUpload = (props) => {
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 =
props.formData &&
props.schema.uploadtype === "s3viajw" ? null : props.formData &&
@@ -207,55 +254,55 @@ const FileUpload = (props) => {
</div>
<>
{localValue ? (
<input
type="file"
id="hashfile"
style={{
border: "1px solid #ccc",
color: "gray",
backgroundColor: "white",
padding: "5px 10px",
borderRadius: "4px",
fontSize: "13px",
width: "100%",
fontWeight: "bold"
}}
accept="application/pdf,application/vnd.ms-excel"
onChange={onChange}
/>
) : props.formData ? (
<div
style={{
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]}
{props.formData ? (
<div className="flex gap-2 justify-center items-center">
<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]">
<div className="break-all">
file selected : {props.formData?.split("/")[3]?.split("_")[1]}
</div>
<div
onClick={() => {
console.log("clicked");
setFileUpload([]);
props.onChange(undefined);
}}
className="cursor-pointer px-[10px] text-[20px] font-bold bg-white text-red-500"
>
<i className="fa-solid fa-xmark"></i>
</div>
</div>
{process.env.REACT_APP_DROPBOX_API_KEY && (
<DropboxChooser
onSuccess={dropboxSuccess}
onCancel={dropboxCancel}
/>
)}
</div>
) : (
<input
type="file"
id="hashfile"
style={{
border: "1px solid #ccc",
color: "gray",
backgroundColor: "white",
padding: "5px 10px",
borderRadius: "4px",
fontSize: "13px",
width: "100%",
fontWeight: "bold"
}}
accept="application/pdf,application/vnd.ms-excel"
onChange={onChange}
/>
<div className="flex gap-2 justify-center items-center">
<input
type="file"
id="hashfile"
style={{
border: "1px solid #ccc",
color: "gray",
backgroundColor: "white",
padding: "5px 10px",
borderRadius: "4px",
fontSize: "13px",
width: "100%",
fontWeight: "bold"
}}
accept="application/pdf,application/vnd.ms-excel"
onChange={onChange}
/>
{process.env.REACT_APP_DROPBOX_API_KEY && (
<DropboxChooser
onSuccess={dropboxSuccess}
onCancel={dropboxCancel}
/>
)}
</div>
)}
</>
</React.Fragment>
@@ -0,0 +1,261 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import CreateFolder from "./CreateFolder";
import ModalUi from "../../primitives/ModalUi";
const SelectFolder = ({ required, onSuccess, folderCls }) => {
const [isOpen, SetIsOpen] = useState(false);
const [clickFolder, setClickFolder] = useState("");
const [selectFolder, setSelectedFolder] = useState({});
const [folderList, setFolderList] = useState([]);
const [tabList, setTabList] = useState([]);
const [isLoader, setIsLoader] = useState(false);
const [folderPath, setFolderPath] = useState("");
const [isAdd, setIsAdd] = useState(false);
useEffect(() => {
if (isOpen) {
setIsAdd(false);
setClickFolder({});
setFolderList([]);
setTabList([]);
fetchFolder();
}
// eslint-disable-next-line
}, [isOpen]);
const fetchFolder = async (folderPtr) => {
setIsLoader(true);
try {
const FolderQuery = new Parse.Query(folderCls);
if (folderPtr) {
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
} else {
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
}
const res = await FolderQuery.find();
if (res) {
const result = JSON.parse(JSON.stringify(res));
if (result) {
setFolderList(result);
setIsLoader(false);
}
setIsLoader(false);
}
} catch (error) {
setIsLoader(false);
}
};
const handleSelect = (item) => {
setFolderList([]);
setClickFolder({ ObjectId: item.objectId, Name: item.Name });
if (tabList.length > 0) {
const tab = tabList.some((x) => x.objectId === item.objectId);
if (!tab) {
setTabList((tabs) => [...tabs, item]);
const folderPtr = {
__type: "Pointer",
className: folderCls,
objectId: item.objectId
};
fetchFolder(folderPtr);
}
} else {
setTabList((tabs) => [...tabs, item]);
const folderPtr = {
__type: "Pointer",
className: folderCls,
objectId: item.objectId
};
fetchFolder(folderPtr);
}
};
const handleSubmit = () => {
let url = "Root";
tabList.forEach((t) => {
url = url + " / " + t.Name;
});
setFolderPath(url);
setSelectedFolder(clickFolder);
if (onSuccess) {
onSuccess(clickFolder);
}
SetIsOpen(false);
};
const handleCancel = () => {
SetIsOpen(false);
setClickFolder({});
setFolderList([]);
setTabList([]);
};
const removeTabListItem = async (e, i) => {
e.preventDefault();
// setEditable(false);
if (!isAdd) {
setIsLoader(true);
let folderPtr;
if (i) {
setFolderList([]);
let list = tabList.filter((itm, j) => {
if (j <= i) {
return itm;
}
});
let _len = list.length - 1;
folderPtr = {
__type: "Pointer",
className: folderCls,
objectId: list[_len].objectId
};
setTabList(list);
} else {
setClickFolder({});
setSelectedFolder({});
setFolderList([]);
setTabList([]);
}
fetchFolder(folderPtr);
}
};
const handleCreate = () => {
setIsAdd(!isAdd);
};
const handleAddFolder = () => {
setFolderList([]);
if (clickFolder && clickFolder.ObjectId) {
fetchFolder({
__type: "Pointer",
className: folderCls,
objectId: clickFolder.ObjectId
});
} else {
fetchFolder();
}
handleCreate();
};
return (
<div className="text-xs mt-2 ">
<div>
<label className="block">
Select Folder
{required && <span className="text-red-500 text-[13px]">*</span>}
</label>
</div>
<div className="rounded px-[20px] py-[20px] bg-white border border-gray-200 shadow flex max-w-sm gap-8 items-center">
<div>
<i
className="far fa-folder-open text-[40px] text-[#33bbff]"
style={{ fontSize: "40px" }}
aria-hidden="true"
></i>
</div>
<div className="font-semibold ">
<div className="flex items-center gap-2">
<p>
{selectFolder && selectFolder.Name ? selectFolder.Name : "Root"}
</p>
<div className="text-black text-sm" onClick={() => SetIsOpen(true)}>
<i
className="fa fa-pencil"
title="Select Folder"
aria-hidden="true"
></i>
</div>
</div>
<p className="text-[10px] text-gray-400">
{selectFolder && selectFolder.Name ? `(${folderPath})` : ""}
</p>
</div>
</div>
<ModalUi
title={"Select Folder"}
isOpen={isOpen}
handleClose={handleCancel}
>
<div className="w-full min-w-[300px] md:min-w-[500px] px-3">
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
<span
className="cursor-pointer"
title="Root"
onClick={(e) => removeTabListItem(e)}
>
Root /{" "}
</span>
{tabList &&
tabList.map((tab, i) => (
<React.Fragment key={`${tab.objectId}-${i}`}>
<span
className="cursor-pointer"
title={tab.Name}
onClick={(e) => removeTabListItem(e, i)}
>
{tab.Name}
</span>
{" / "}
</React.Fragment>
))}
<hr />
</div>
<div className="mt-2 mb-3">
{!isAdd &&
folderList.length > 0 &&
folderList.map((folder) => (
<div
key={folder.Name}
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer"
onClick={() => handleSelect(folder)}
>
<div className="flex items-center gap-2">
<i
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
aria-hidden="true"
></i>
<span className="font-semibold">{folder.Name}</span>
</div>
</div>
))}
{isAdd && (
<CreateFolder
parentFolderId={clickFolder && clickFolder.ObjectId}
folderCls={folderCls}
onSuccess={handleAddFolder}
/>
)}
{isLoader && (
<div className="flex justify-center">
<i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i>
</div>
)}
</div>
</div>
<hr />
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
<div
className="text-[30px] cursor-pointer text-[#32a3ac]"
title="Save Here"
onClick={handleCreate}
>
{isAdd ? (
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
) : (
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
)}
</div>
<div
className="text-[30px] cursor-pointer"
title="Save Here"
onClick={handleSubmit}
>
<i className="fas fa-save" aria-hidden="true"></i>
</div>
</div>
</ModalUi>
</div>
);
};
export default SelectFolder;
@@ -0,0 +1,190 @@
import React, { useState, useEffect } from "react";
import Select from "react-select";
import AppendFormInForm from "../AppendFormInForm";
import Modal from "react-modal";
import Parse from "parse";
function arrayMove(array, from, to) {
array = array.slice();
array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]);
return array;
}
/**
* react-sortable-hoc is depcreated not usable from react 18.x.x
* need to replace it with @dnd-kit
* code changes required
*/
const SignersInput = (props) => {
Modal.setAppElement("body");
const [state, setState] = useState(undefined);
// const [editFormData, setEditFormData] = useState([]);
const [selected, setSelected] = React.useState([]);
const [isModal, setIsModel] = useState(false);
const onChange = (selectedOptions) => setSelected(selectedOptions);
const [modalIsOpen, setModalIsOpen] = useState(false);
const onSortEnd = ({ oldIndex, newIndex }) => {
const newValue = arrayMove(selected, oldIndex, newIndex);
setSelected(newValue);
};
const GetSelectListData = async () => {
try {
const currentUser = Parse.User.current();
const contactbook = new Parse.Query("contracts_Contactbook");
contactbook.equalTo(
"CreatedBy",
Parse.User.createWithoutData(currentUser.id)
);
contactbook.notEqualTo("IsDeleted", true);
const contactRes = await contactbook.find();
if (contactRes) {
const res = JSON.parse(JSON.stringify(contactRes));
let list = [];
// let _selected = [];
res.forEach((x) => {
let obj = {
label: x.Name,
value: x.objectId,
isChecked: true
};
list.push(obj);
});
setState(list);
}
} catch (error) {
console.log("err", error);
}
};
useEffect(() => {
GetSelectListData();
}, []);
useEffect(() => {
if (selected && selected.length) {
let newData = [];
selected.forEach((x) => {
newData.push(x.value);
});
if (props.onChange) {
props.onChange(newData);
}
}
// eslint-disable-next-line
}, [selected]);
const handleModalCloseClick = () => {
setIsModel(false);
setModalIsOpen(false);
};
const openModal = () => {
setModalIsOpen(true);
};
// `handleNewDetails` is used to set just save from quick form to selected option in dropdown
const handleNewDetails = (data) => {
setState([...state, data]);
if (selected.length > 0) {
setSelected([...selected, data]);
} else {
setSelected([data]);
}
};
return (
<div className="text-xs mt-2 ">
<label className="block">
Signers
{props.required && <span className="text-red-500 text-[13px]">*</span>}
</label>
<div style={{ display: "flex", gap: 5 }}>
<div style={{ flexWrap: "wrap", width: "100%" }}>
<Select
onSortEnd={onSortEnd}
distance={4}
isMulti
options={state || []}
value={selected}
onChange={onChange}
closeMenuOnSelect={false}
/>
</div>
<div
onClick={() => {
setIsModel(true);
openModal();
}}
style={{
cursor: "pointer",
borderRadius: 4,
border: "1px solid #ccc",
minHeight: 38,
minWidth: 48,
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
<i className="fas fa-plus"></i>
</div>
<Modal
isOpen={modalIsOpen}
onRequestClose={handleModalCloseClick}
shouldCloseOnOverlayClick={false}
id="modal1"
contentLabel="Modal"
style={{
content: {
top: "50%",
left: "50%",
right: "auto",
bottom: "auto",
transform: "translate(-50%, -50%)",
padding: 0
},
overlay: {
width: "100%",
backgroundColor: "rgba(0, 0, 0, 0.75)",
zIndex: 50
}
}}
>
<div className="min-w-full md:min-w-[500px]">
<div
type="button"
className="flex justify-between items-center p-3 border-b-[1px] border-gray-300"
>
<div className=" text-black text-xl font-semibold pl-3">
Add Signer
</div>
<button onClick={handleModalCloseClick}>
<i
style={{ fontSize: 25 }}
className="fa fa-times-circle"
aria-hidden="true"
></i>
</button>
</div>
{isModal && (
<AppendFormInForm
valueKey={"objectId"}
displayKey={"Name"}
details={handleNewDetails}
closePopup={handleModalCloseClick}
/>
)}
</div>
</Modal>
</div>
</div>
);
};
export default SignersInput;
@@ -42,9 +42,8 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
return (
<aside
className={`${isOpen ? "block" : "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"
}`}
className={`bg-white text-[#444] h-screen w-full md:w-[300px] overflow-y-auto transform transition-transform z-40 md:translate-x-0
${isOpen ? "translate-x-0 block" : "-translate-x-full hidden"}`}
>
<div className="flex px-2 py-3 gap-2 items-center shadow-md">
<div className="w-[75px] h-[75px] rounded-full ring-[2px] ring-offset-2 ring-gray-400 overflow-hidden">
+2
View File
@@ -0,0 +1,2 @@
export const contactCls = "contracts_Contactbook";
export const templateCls = "contracts_Template";
+17
View File
@@ -15,3 +15,20 @@ export const useScript = (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]);
};
+12 -1
View File
@@ -4,4 +4,15 @@
body{
background-color: white;
}
}
/* Custom CSS to hide scrollbar */
.hide-scrollbar::-webkit-scrollbar {
display: none;
}
.hide-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
+3 -4
View File
@@ -14,7 +14,7 @@ export const formJson = (id) => {
type: "string",
title: "Select Document",
filetypes: [],
maxfilesizeKB: "5000",
maxfilesizeKB: "10000",
uploadtype: "regular",
helpbody: "",
helplink: ""
@@ -113,7 +113,7 @@ export const formJson = (id) => {
});
formData = {
jsonSchema: {
title: "New Document",
title: "Request signatures",
description: "",
type: "object",
required: ["URL", "Name", "Note", "TimeToCompleteDays", "Signers"],
@@ -147,7 +147,7 @@ export const formJson = (id) => {
class: "contracts_Contactbook",
displayKey: "Name",
valueKey: "objectId",
query: `where={"CreatedBy":${userPtr}}&keys=Name`,
query: `where={"CreatedBy":${userPtr},"IsDeleted":{"$ne":true}}&keys=Name`,
isPointer: true,
helpbody: "",
helplink: "",
@@ -582,4 +582,3 @@ export const formJson = (id) => {
return formData;
}
};
+51
View File
@@ -1,11 +1,15 @@
export default function reportJson(id) {
// console.log("json ", json);
const head = ["Sr.No", "Title", "Note", "Folder", "File", "Owner", "Signers"];
const contactbook = ["Sr.No", "Title", "Email", "Phone"];
const dashboardReportHead = ["Title", "File", "Owner", "Signers"];
switch (id) {
// draft documents report
case "ByHuevtCFY":
return {
reportName: "Draft Documents",
heading: head,
actions: [
{
btnLabel: "sign",
@@ -21,6 +25,7 @@ export default function reportJson(id) {
case "4Hhwbp482K":
return {
reportName: "Need your sign",
heading: head,
actions: [
{
btnLabel: "sign",
@@ -36,6 +41,7 @@ export default function reportJson(id) {
case "1MwEuxLEkF":
return {
reportName: "In-progress documents",
heading: head,
actions: [
{
btnLabel: "View",
@@ -51,6 +57,7 @@ export default function reportJson(id) {
case "kQUoW4hUXz":
return {
reportName: "Completed Documents",
heading: head,
actions: [
{
btnLabel: "View",
@@ -66,6 +73,7 @@ export default function reportJson(id) {
case "UPr2Fm5WY3":
return {
reportName: "Declined Documents",
heading: head,
actions: [
{
btnLabel: "View",
@@ -81,6 +89,7 @@ export default function reportJson(id) {
case "zNqBHXHsYH":
return {
reportName: "Expired Documents",
heading: head,
actions: [
{
btnLabel: "View",
@@ -96,6 +105,7 @@ export default function reportJson(id) {
case "d9k3UfYHBc":
return {
reportName: "Recently sent for signatures",
heading: dashboardReportHead,
actions: [
{
btnLabel: "View",
@@ -111,6 +121,7 @@ export default function reportJson(id) {
case "5Go51Q7T8r":
return {
reportName: "Recent signature requests",
heading: dashboardReportHead,
actions: [
{
btnLabel: "Sign",
@@ -126,6 +137,7 @@ export default function reportJson(id) {
case "kC5mfynCi4":
return {
reportName: "Drafts",
heading: ["Title", "Note", "Folder", "File", "Owner", "Signers"],
actions: [
{
btnLabel: "sign",
@@ -137,6 +149,45 @@ 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"
}
],
form: "ContactBook"
};
// template report
case "6TeaPr321t":
return {
reportName: "Templates",
heading: head,
actions: [
{
btnLabel: "Use",
btnColor: "#4bd396",
textColor: "white",
btnIcon: "fa fa-plus",
redirectUrl:
"remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/placeHolderSign"
},
{
btnLabel: "Edit",
btnColor: "#00c9d5",
textColor: "white",
btnIcon: "fa fa-plus",
redirectUrl:
"remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/template"
}
]
};
default:
return null;
}
+1 -1
View File
@@ -52,7 +52,7 @@
"subtitle": "Customization available Priority support.",
"btnText": "Contact us",
"url": "https://www.opensignlabs.com/contact-us",
"target": "_self",
"target": "_blank",
"benefits": [
"All features",
"Custom domain",
+74 -26
View File
@@ -7,10 +7,35 @@ import Tour from "reactour";
import axios from "axios";
import { useSelector } from "react-redux";
import Parse from "parse";
import ModalUi from "../primitives/ModalUi";
import { useNavigate } from "react-router-dom";
const HomeLayout = ({ children }) => {
const navigate = useNavigate();
const { width } = useWindowSize();
const [isOpen, setIsOpen] = useState(false);
const [isOpen, setIsOpen] = useState(true);
const arr = useSelector((state) => state.TourSteps);
const [isUserValid, setIsUserValid] = useState(true);
useEffect(() => {
(async () => {
try {
// Use the session token to validate the user
const userQuery = new Parse.Query(Parse.User);
const user = await userQuery.get(Parse.User.current().id, {
sessionToken: localStorage.getItem("accesstoken")
});
if (user) {
setIsUserValid(true);
} else {
setIsUserValid(false);
}
} catch (error) {
// Session token is invalid or there was an error
setIsUserValid(false);
}
})();
}, []);
// reactour state
const [isCloseBtn, setIsCloseBtn] = useState(true);
@@ -19,20 +44,16 @@ const HomeLayout = ({ children }) => {
const [tourConfigs, setTourConfigs] = useState([]);
const showSidebar = () => {
setIsOpen(!isOpen);
setIsOpen((value) => !value);
};
useEffect(() => {
if (width && width <= 768) {
setIsOpen(false);
} else {
setIsOpen(true);
}
}, [width]);
useEffect(() => {
if (localStorage.getItem("domain") === "sign" && arr && arr.length > 0) {
handleDynamicSteps();
} else if (
if (
localStorage.getItem("domain") === "contracts" &&
arr &&
arr.length > 0
@@ -155,32 +176,59 @@ const HomeLayout = ({ children }) => {
setIsOpen(false);
}
};
const handleLoginBtn = () => {
try {
Parse.User.logOut();
} catch (err) {
console.log("err ", err);
} finally {
localStorage.removeItem("accesstoken");
navigate("/", { replace: true });
}
};
return (
<div>
<div className="sticky top-0 z-50">
<Header showSidebar={showSidebar} />
</div>
<div className="flex md:flex-row flex-col z-50">
<Sidebar isOpen={isOpen} closeSidebar={closeSidebar} />
{isUserValid ? (
<>
<div className="flex md:flex-row flex-col z-50">
<Sidebar isOpen={isOpen} closeSidebar={closeSidebar} />
<div className="relative h-screen flex flex-col justify-between w-full overflow-y-auto">
<div className="bg-[#eef1f5] p-3">{children}</div>
<div className="z-30">
<Footer />
<div className="relative h-screen flex flex-col justify-between w-full overflow-y-auto">
<div className="bg-[#eef1f5] p-3">{children}</div>
<div className="z-30">
<Footer />
</div>
</div>
</div>
</div>
</div>
<Tour
onRequestClose={closeTour}
steps={tourConfigs}
isOpen={isTour}
closeWithMask={false}
disableKeyboardNavigation={["esc"]}
// disableInteraction={true}
scrollOffset={-100}
rounded={5}
showCloseButton={isCloseBtn}
/>
<Tour
onRequestClose={closeTour}
steps={tourConfigs}
isOpen={isTour}
closeWithMask={false}
disableKeyboardNavigation={["esc"]}
// disableInteraction={true}
scrollOffset={-100}
rounded={5}
showCloseButton={isCloseBtn}
/>
</>
) : (
<ModalUi title={"Session Expired"} isOpen={true} showClose={false}>
<div className="flex flex-col justify-center items-center py-4 md:py-5 gap-5">
<p className="text-xl font-normal">Your session has expired.</p>
<button
onClick={handleLoginBtn}
className="text-base px-3 py-1.5 rounded shadow-md text-white bg-[#1ab6ce]"
>
Login
</button>
</div>
</ModalUi>
)}
</div>
);
};
+30
View File
@@ -0,0 +1,30 @@
import React from "react";
const Alert = ({ children, type }) => {
const textcolor = type ? theme(type) : theme();
function theme(color) {
switch (color) {
case "success":
return "border-[#c3e6cb] bg-[#d4edda] text-[#155724]";
case "info":
return "border-[#adcdeb] bg-[#c1daf0] text-[#153756]";
case "danger":
return "border-[#f0a8a8] bg-[#f4bebe] text-[#c42121]";
default:
return "border-[#d6d6d6] bg-[#d9d9d9] text-[#575757]";
}
}
return (
<>
{children && (
<div
className={`z-40 fixed top-20 left-1/2 transform -translate-x-1/2 border-[1px] text-sm ${textcolor} rounded py-[.75rem] px-[1.25rem] `}
>
{children}
</div>
)}
</>
);
};
export default Alert;
+379 -71
View File
@@ -1,18 +1,30 @@
import React, { useState, useEffect, useMemo } from "react";
import pad from "../assets/images/pad.svg";
import { useNavigate } from "react-router-dom";
import axios from "axios";
import "../styles/report.css";
import ModalUi from "./ModalUi";
import AppendFormInForm from "../components/AppendFormInForm";
const ReportTable = ({
ReportName,
List,
setList,
actions,
heading,
setIsNextRecord,
isMoreDocs,
docPerPage
docPerPage,
form
}) => {
const navigate = useNavigate();
const [currentPage, setCurrentPage] = useState(1);
// const pageNumbers = [];
const [actLoader, setActLoader] = useState({});
const [isAlert, setIsAlert] = useState(false);
const [isErr, setIsErr] = useState(false);
const [isDocErr, setIsDocErr] = useState(false);
const [isContactform, setIsContactform] = useState(false);
const [isDeleteModal, setIsDeleteModal] = useState({});
const startIndex = (currentPage - 1) * docPerPage;
// For loop is used to calculate page numbers visible below table
// Initialize pageNumbers using useMemo to avoid unnecessary re-creation
@@ -51,14 +63,129 @@ const ReportTable = ({
}, [isMoreDocs, pageNumbers, currentPage, setIsNextRecord]);
// `handlemicroapp` is used to open microapp
const handlemicroapp = (item, url) => {
localStorage.removeItem("rowlevel");
navigate("/rpmf/" + url);
localStorage.setItem("rowlevel", JSON.stringify(item));
const handlemicroapp = async (item, url, btnLabel) => {
if (ReportName === "Templates") {
if (btnLabel === "Edit") {
navigate(`/asmf/${url}/${item.objectId}`);
} else {
setActLoader({ [`${item.objectId}_${btnLabel}`]: true });
try {
const params = {
templateId: item.objectId
};
const templateDeatils = await axios.post(
`${localStorage.getItem("baseUrl")}functions/getTemplate`,
params,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessionToken: localStorage.getItem("accesstoken")
}
}
);
// console.log("templateDeatils.data ", templateDeatils.data);
const templateData =
templateDeatils.data && templateDeatils.data.result;
if (!templateData.error) {
const Doc = templateData;
let signers = [];
if (Doc.Signers?.length > 0) {
Doc.Signers?.forEach((x) => {
if (x.objectId) {
const obj = {
__type: "Pointer",
className: "contracts_Contactbook",
objectId: x.objectId
};
signers.push(obj);
}
});
}
let placeholdersArr = [];
if (Doc.Placeholders?.length > 0) {
placeholdersArr = Doc.Placeholders;
const data = {
Name: Doc.Name,
URL: Doc.URL,
SignedUrl: Doc.SignedUrl,
Description: Doc.Description,
Note: Doc.Note,
Placeholders: placeholdersArr,
ExtUserPtr: {
__type: "Pointer",
className: "contracts_Users",
objectId: Doc.ExtUserPtr.objectId
},
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: Doc.CreatedBy.objectId
},
Signers: signers
};
try {
const res = await axios.post(
`${localStorage.getItem(
"baseUrl"
)}classes/${localStorage.getItem("_appName")}_Document`,
data,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id":
localStorage.getItem("parseAppId"),
"X-Parse-Session-Token":
localStorage.getItem("accesstoken")
}
}
);
// console.log("Res ", res.data);
if (res.data && res.data.objectId) {
setActLoader({});
setIsAlert(true);
navigate(`/asmf/${url}/${res.data.objectId}`, {
state: { title: "Use Template" }
});
}
} catch (err) {
console.log("Err", err);
setIsAlert(true);
setIsErr(true);
setActLoader({});
}
} else {
setIsDocErr(true);
setActLoader({});
}
} else {
setIsAlert(true);
setIsErr(true);
setActLoader({});
}
} catch (err) {
console.log("err", err);
setIsAlert(true);
setIsErr(true);
setActLoader({});
}
}
} else {
localStorage.removeItem("rowlevel");
navigate("/rpmf/" + url);
localStorage.setItem("rowlevel", JSON.stringify(item));
}
// localStorage.setItem("rowlevelMicro");
};
const handlebtn = () => {
console.log("clicked");
const handlebtn = async (item) => {
if (ReportName === "Contactbook") {
setIsDeleteModal({ [item.objectId]: true });
}
};
// Get current list
@@ -71,19 +198,83 @@ const ReportTable = ({
const paginateFront = () => setCurrentPage(currentPage + 1);
const paginateBack = () => setCurrentPage(currentPage - 1);
const handleContactFormModal = () => {
setIsContactform(!isContactform);
};
const handleUserData = (data) => {
setList((prevData) => [data, ...prevData]);
};
const handleDelete = async (item) => {
setIsDeleteModal({});
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({});
}
};
const handleCloseDeleteModal = () => setIsDeleteModal({});
return (
<div className="p-2 overflow-x-scroll w-full bg-white rounded-md">
<h2 className="text-[23px] font-light my-2">{ReportName}</h2>
{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>
)}
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
<div className="font-light">{ReportName}</div>
{ReportName === "Templates" && (
<i
onClick={() => navigate("/form/template")}
className="fa-solid fa-square-plus text-sky-400 text-[25px]"
></i>
)}
{form && (
<div
className="cursor-pointer"
onClick={() => handleContactFormModal()}
>
<i className="fa-solid fa-square-plus text-sky-400 text-[25px]"></i>
</div>
)}
</div>
<table className="table-auto w-full border-collapse">
<thead className="text-[14px]">
<tr className="border-y-[1px]">
<th className="px-4 py-2 font-thin">Sr.No</th>
<th className="px-4 py-2 font-thin">Name</th>
<th className="px-4 py-2 font-thin">Note</th>
<th className="px-4 py-2 font-thin">Folder</th>
<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>
{heading?.map((item, index) => (
<React.Fragment key={index}>
<th className="px-4 py-2 font-thin">{item}</th>
</React.Fragment>
))}
{actions?.length > 0 && (
<th className="px-4 py-2 font-thin">Action</th>
)}
@@ -92,61 +283,158 @@ const ReportTable = ({
<tbody className="text-[12px]">
{List?.length > 0 ? (
<>
{currentLists.map((item, index) => (
<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">
{item?.Signers ? formatRow(item?.Signers) : "-"}
</td>
<td className="px-4 py-2 flex flex-col justify-center items-center gap-2 text-white">
{actions?.length > 0 &&
actions.map((act, index) => (
<button
key={index}
onClick={() =>
act?.redirectUrl
? handlemicroapp(item, act.redirectUrl)
: handlebtn(item)
}
className={`flex justify-center items-center w-full gap-1 px-2 py-1 rounded shadow`}
style={{
backgroundColor: act.btnColor
? act.btnColor
: "#3ac9d6",
color: act?.textColor ? act?.textColor : "white"
}}
{currentLists.map((item, index) =>
ReportName === "Contactbook" ? (
<tr className="border-y-[1px]" key={index}>
{heading.includes("Sr.No") && (
<td className="px-4 py-2">{startIndex + index + 1}</td>
)}
<td className="px-4 py-2 font-semibold">{item?.Name} </td>
<td className="px-4 py-2">{item?.Email || "-"}</td>
<td className="px-4 py-2">{item?.Phone || "-"}</td>
<td className="px-3 py-2 text-white">
{actions?.length > 0 &&
actions.map((act, index) => (
<button
key={index}
onClick={() =>
act?.redirectUrl
? handlemicroapp(item, act.redirectUrl)
: handlebtn(item)
}
className={`mb-1 flex justify-center items-center gap-1 px-2 py-1 rounded shadow`}
style={{
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>
))}
{isDeleteModal[item.objectId] && (
<ModalUi
isOpen
title={"Delete Contact"}
handleClose={handleCloseDeleteModal}
>
<span>
{act?.btnIcon && <i className={act.btnIcon}></i>}
</span>
<span className="uppercase">
{act?.btnLabel ? act.btnLabel : "view"}
</span>
</button>
// )
))}
</td>
</tr>
))}
<div className="m-[20px]">
<div className="text-lg font-normal text-black">
Are you sure you want to delete this contact?
</div>
<hr className="bg-[#ccc] mt-4 " />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={() => handleDelete(item)}
className="bg-[#1ab6ce] rounded-sm shadow-md text-[12px] font-semibold uppercase text-white py-1.5 px-3 focus:outline-none"
>
Yes
</button>
<button
onClick={handleCloseDeleteModal}
className="bg-[#188ae2] rounded-sm shadow-md text-[12px] font-semibold uppercase text-white py-1.5 px-3 text-center ml-[2px] focus:outline-none"
>
No
</button>
</div>
</div>
</ModalUi>
)}
</td>
</tr>
) : (
<tr className="border-y-[1px]" key={index}>
{heading.includes("Sr.No") && (
<td className="px-4 py-2">{startIndex + index + 1}</td>
)}
<td className="px-4 py-2 font-semibold w-56">
{item?.Name}{" "}
</td>
{heading.includes("Note") && (
<td className="px-4 py-2">{item?.Note || "-"}</td>
)}
{heading.includes("Folder") && (
<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">
{item?.Signers ? formatRow(item?.Signers) : "-"}
</td>
<td className="px-3 py-2 text-white">
{actions?.length > 0 &&
actions.map((act, index) => (
<button
key={index}
onClick={() =>
act?.redirectUrl
? handlemicroapp(
item,
act.redirectUrl,
act.btnLabel
)
: handlebtn(item)
}
className={`mb-1 flex justify-center items-center gap-1 px-2 py-1 rounded shadow`}
style={{
backgroundColor: act.btnColor
? act.btnColor
: "#3ac9d6",
color: act?.textColor ? act?.textColor : "white"
}}
>
<span>
{act?.btnIcon && (
<i
className={
actLoader[
`${item.objectId}_${act.btnLabel}`
]
? "fa-solid fa-spinner fa-spin-pulse"
: act.btnIcon
}
></i>
)}
</span>
<span className="uppercase">
{act?.btnLabel ? act.btnLabel : "view"}
</span>
</button>
))}
</td>
</tr>
)
)}
</>
) : (
<></>
@@ -199,6 +487,26 @@ const ReportTable = ({
<div className="text-sm font-semibold">No Data Available</div>
</div>
)}
<ModalUi
title={"Add Contact"}
isOpen={isContactform}
handleClose={handleContactFormModal}
>
<AppendFormInForm
handleUserData={handleUserData}
closePopup={handleContactFormModal}
/>
</ModalUi>
<ModalUi
headColor={"#dc3545"}
isOpen={isDocErr}
title={"Receipent required"}
handleClose={() => setIsDocErr(false)}
>
<div style={{ height: "100%", padding: 20 }}>
<p>Please add receipent in template!</p>
</div>
</ModalUi>
</div>
);
};
+28
View File
@@ -0,0 +1,28 @@
import React, { useState } from "react";
const Modal = ({ children, Title }) => {
const [isOpen, SetIsOpen] = useState(false);
return (
<>
{children && (
<div
className={`fixed top-20 left-1/2 transform -translate-x-1/2 border-[1px] text-sm bg-white rounded `}
>
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem] ">
<div className="font-semibold text-xl text-black">{Title}</div>
<div
onClick={() => SetIsOpen()}
className="px-2 py-1 bg-gray-400 rounded cursor-pointer"
>
<i className="fa-solid fa-xmark"></i>
</div>
</div>
<hr />
{isOpen && <div>{children}</div>}
</div>
)}
</>
);
};
export default Modal;
+40
View File
@@ -0,0 +1,40 @@
import React from "react";
const ModalUi = ({
children,
title,
isOpen,
headColor,
handleClose,
showHeader = true,
showClose = true
}) => {
return (
<>
{isOpen && (
<div className="fixed z-[999] top-0 left-0 w-[100%] h-[100%] bg-black bg-opacity-[75%]">
<div className="fixed z-[1000] top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-sm bg-white rounded shadow-md max-h-90 min-w-[90%] md:min-w-[500px] overflow-y-auto hide-scrollbar">
{showHeader && (
<div
className="flex justify-between rounded-t items-center py-[15px] px-[20px] text-white"
style={{ background: headColor ? headColor : "#32a3ac" }}
>
<div className="text-[1.2rem] font-normal">{title}</div>
{showClose && (
<div
className="text-[1.5rem] cursor-pointer"
onClick={() => handleClose && handleClose()}
>
&times;
</div>
)}
</div>
)}
<div>{children}</div>
</div>
</div>
)}
</>
);
};
export default ModalUi;
@@ -0,0 +1,336 @@
import React, { useState } from "react";
import sanitizeFileName from "./sanitizeFileName";
import Parse from "parse";
import DropboxChooser from "../components/fields/DropboxChoose";
import Alert from "./Alert";
import SelectFolder from "../components/fields/SelectFolder";
// import SignersInput from "../components/fields/SignersInput";
import Title from "../components/Title";
import { useNavigate } from "react-router-dom";
import { templateCls } from "../constant/const";
const TemplateForm = () => {
const navigate = useNavigate();
const [signers, setSigners] = useState([]);
const [folder, setFolder] = useState({ ObjectId: "", Name: "" });
const [formData, setFormData] = useState({
Name: "",
Description: "",
Note: "Please review and sign this document"
});
const [fileupload, setFileUpload] = useState([]);
const [fileload, setfileload] = useState(false);
const [percentage, setpercentage] = useState(0);
const [isAlert, setIsAlert] = useState(false);
const [isSubmit, setIsSubmit] = useState(false);
const [isErr, setIsErr] = useState("");
const handleStrInput = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const handleFileInput = (e) => {
setpercentage(0);
try {
let files = e.target.files;
if (typeof files[0] !== "undefined") {
const mb = Math.round(files[0].bytes / Math.pow(1024, 2));
if (mb > 10) {
alert(
`The selected file size is too large. Please select a file less than ${Math.round(
10
)} MB`
);
return;
}
handleFileUpload(files[0]);
} else {
alert("Please select file.");
return false;
}
} catch (error) {
alert(error.message);
return false;
}
};
const handleFileUpload = async (file) => {
Parse.serverURL = process.env.REACT_APP_SERVERURL;
Parse.initialize(process.env.REACT_APP_APPID);
setfileload(true);
const fileName = file.name;
const name = sanitizeFileName(fileName);
const pdfFile = file;
const parseFile = new Parse.File(name, pdfFile);
try {
const response = await parseFile.save({
progress: (progressValue, loaded, total, { type }) => {
if (type === "upload" && progressValue !== null) {
const percentCompleted = Math.round((loaded * 100) / total);
setpercentage(percentCompleted);
}
}
});
// The response object will contain information about the uploaded file
// You can access the URL of the uploaded file using response.url()
setFileUpload(response.url());
setfileload(false);
if (response.url()) {
return response.url();
}
} catch (error) {
setfileload(false);
setpercentage(0);
console.error("Error uploading file:", error);
}
};
const dropboxSuccess = async (files) => {
setfileload(true);
const file = files[0];
const url = file.link;
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);
setpercentage(percentCompleted);
}
}
});
setFileUpload(response.url());
setfileload(false);
if (response.url()) {
return response.url();
}
} catch (error) {
setfileload(false);
setpercentage(0);
console.error("Error uploading file:", error);
}
}
};
const dropboxCancel = async () => {};
const handleSubmit = async (e) => {
e.preventDefault();
setIsSubmit(true);
try {
const currentUser = Parse.User.current();
const template = new Parse.Object(templateCls);
Object.entries(formData).forEach((item) =>
template.set(item[0], item[1])
);
template.set("URL", fileupload);
template.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
if (folder && folder.ObjectId) {
template.set("Folder", {
__type: "Pointer",
className: templateCls,
objectId: folder.ObjectId
});
}
if (signers && signers.length > 0) {
template.set("Signers", signers);
}
const ExtCls = JSON.parse(localStorage.getItem("Extand_Class"));
template.set("ExtUserPtr", {
__type: "Pointer",
className: "contracts_Users",
objectId: ExtCls[0].objectId
});
const res = await template.save();
if (res) {
setSigners([]);
setFolder({ ObjectId: "", Name: "" });
setFormData({
Name: "",
Description: "",
Note: ""
});
setFileUpload([]);
setpercentage(0);
navigate(
"/asmf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/template/" +
res.id
);
}
} catch (err) {
console.log("err ", err);
setIsErr(true);
} finally {
setIsAlert(true);
setTimeout(() => {
setIsAlert(false);
}, 1000);
setIsSubmit(false);
}
};
const handleFolder = (data) => {
setFolder(data);
};
// const handleSigners = (data) => {
// if (data && data.length > 0) {
// const updateSigners = data.map((x) => ({
// __type: "Pointer",
// className: "contracts_Contactbook",
// objectId: x
// }));
// setSigners(updateSigners);
// }
// };
const handleReset = () => {
setSigners([]);
setFolder({ ObjectId: "", Name: "" });
setFormData({
Name: "",
Description: "",
Note: ""
});
setFileUpload([]);
setpercentage(0);
};
return (
<div className="shadow-md rounded my-2 p-3 bg-[#ffffff] md:border-[1px] md:border-gray-600/50">
<Title title="New Template" />
{isAlert && (
<Alert type={isErr ? "danger" : "success"}>
{isErr
? "Something went wrong please try again!"
: "Template created successfully!"}
</Alert>
)}
<form onSubmit={handleSubmit}>
<h1 className="text-[20px] font-semibold mb-4">New Template</h1>
{fileload && (
<div className="flex items-center gap-x-2">
<div className="h-2 rounded-full w-[200px] md:w-[400px] bg-gray-200">
<div
className="h-2 rounded-full bg-blue-500"
style={{ width: `${percentage}%` }}
></div>
</div>
<span className="text-black text-sm">{percentage}%</span>
</div>
)}
<div className="text-xs">
<label className="block">
File<span className="text-red-500 text-[13px]">*</span>
</label>
{fileupload.length > 0 ? (
<div className="flex gap-2 justify-center items-center">
<div className="flex justify-between items-center px-2 py-2 w-full font-bold rounded border-[1px] border-[#ccc] text-gray-500 bg-white text-[13px]">
<div className="break-all">
file selected : {fileupload?.split("/")[3]?.split("_")[1]}
</div>
<div
onClick={() => {
setFileUpload([]);
}}
className="cursor-pointer px-[10px] text-[20px] font-bold bg-white text-red-500"
>
<i className="fa-solid fa-xmark"></i>
</div>
</div>
{process.env.REACT_APP_DROPBOX_API_KEY && (
<DropboxChooser
onSuccess={dropboxSuccess}
onCancel={dropboxCancel}
/>
)}
</div>
) : (
<div className="flex gap-2 justify-center items-center">
<input
type="file"
className="bg-white px-2 py-1.5 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
onChange={(e) => handleFileInput(e)}
accept="application/pdf,application/vnd.ms-excel"
required
/>
{process.env.REACT_APP_DROPBOX_API_KEY && (
<DropboxChooser
onSuccess={dropboxSuccess}
onCancel={dropboxCancel}
/>
)}
</div>
)}
</div>
<div className="text-xs mt-2">
<label className="block">
Title<span className="text-red-500 text-[13px]">*</span>
</label>
<input
name="Name"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
value={formData.Name}
onChange={(e) => handleStrInput(e)}
required
/>
</div>
<div className="text-xs mt-2">
<label className="block">
Note<span className="text-red-500 text-[13px]">*</span>
</label>
<input
name="Note"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
value={formData.Note}
onChange={(e) => handleStrInput(e)}
required
/>
</div>
<div className="text-xs mt-2">
<label className="block">Description</label>
<input
name="Description"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
value={formData.Description}
onChange={(e) => handleStrInput(e)}
/>
</div>
{/* <SignersInput onChange={handleSigners} /> */}
<SelectFolder onSuccess={handleFolder} folderCls={templateCls} />
<div className="flex items-center mt-3 gap-2 text-white">
<button
className={`${
isSubmit && "cursor-progress"
} bg-[#1ab6ce] rounded-sm shadow-md text-[14px] font-semibold uppercase text-white py-1.5 px-2.5 focus:outline-none`}
type="submit"
disabled={isSubmit}
>
Submit
</button>
<div
className="bg-[#188ae2] rounded-sm shadow-md text-[14px] font-semibold uppercase text-white py-1.5 px-2.5 text-center ml-[2px] focus:outline-none"
onClick={() => handleReset()}
>
Reset
</div>
</div>
</form>
</div>
);
};
export default TemplateForm;
@@ -0,0 +1,34 @@
import React, { useEffect } from "react";
import Parse from "parse";
const ValidateRoute = ({ children }) => {
useEffect(() => {
(async () => {
try {
// Use the session token to validate the user
const userQuery = new Parse.Query(Parse.User);
const user = await userQuery.get(Parse.User.current().id, {
sessionToken: localStorage.getItem("accesstoken")
});
if (!user) {
handlelogout();
}
} catch (error) {
handlelogout();
}
})();
}, []);
const handlelogout = async () => {
try {
Parse.User.logOut();
localStorage.removeItem("accesstoken");
} catch (err) {
console.log("err ", err);
} finally {
localStorage.removeItem("accesstoken");
}
};
return <div>{children}</div>;
};
export default ValidateRoute;
+15 -15
View File
@@ -2,11 +2,12 @@ import React, { useState, useEffect } from "react";
import Parse from "parse";
import "../styles/loader.css";
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 { save_tourSteps } from "../redux/actions";
import { connect } from "react-redux";
const Dashboard = (props) => {
const navigate = useNavigate();
const { id } = useParams();
const [dashboard, setdashboard] = useState([]);
const [classnameArray, setclassnameArray] = useState([]);
@@ -15,6 +16,19 @@ const Dashboard = (props) => {
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
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) => {
setloading(true);
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 = (
<GetDashboard
dashboard={dashboard}
+14 -9
View File
@@ -25,6 +25,7 @@ import TreeWidget from "../components/TreeWidget";
import parse from "html-react-parser";
import Title from "../components/Title";
import { formJson } from "../json/FormJson";
import TemplateForm from "../primitives/TemplateForm";
const widget = {
TimeWidget: TimeWidget
};
@@ -41,15 +42,19 @@ const fields = () => {
function FormBuilderFn(props) {
const { id } = useParams();
const navigate = useNavigate();
return (
<FormBuilder
removeState={props.removeState}
removeLevel2State={props.removeLevel2State}
removeLevel3State={props.removeLevel3State}
id={id}
navigate={navigate}
/>
);
if (id === "template") {
return <TemplateForm />;
} else {
return (
<FormBuilder
removeState={props.removeState}
removeLevel2State={props.removeLevel2State}
removeLevel3State={props.removeLevel3State}
id={id}
navigate={navigate}
/>
);
}
}
class FormBuilder extends Component {
state = {
+3 -3
View File
@@ -1183,17 +1183,17 @@ function Login(props) {
</div>
<div className="form-group">
<label
htmlFor="Destination"
htmlFor="JobTitle"
style={{ display: "flex" }}
className="col-form-label"
>
Destination{" "}
Job Title
<span style={{ fontSize: 13, color: "red" }}>*</span>
</label>
<input
type="text"
className="form-control"
id="Destination"
id="JobTitle"
value={userDetails.Destination}
onChange={(e) =>
setUserDetails({
+56 -15
View File
@@ -21,6 +21,9 @@ const PgSignUp = (props) => {
});
const [validationMessage, setValidationMessage] = useState("");
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
useEffect(() => {
@@ -71,8 +74,8 @@ const PgSignUp = (props) => {
const res = await Parse.Cloud.run("getUserDetails", params);
// console.log("res", res);
if (res) {
const checkUser = new Parse.Query(extClass);
const updateQuery = await checkUser.get(res.id);
const updateQuery = new Parse.Object(extClass);
updateQuery.id = res.id;
updateQuery.set(
"Next_billing_date",
new Date(zohoRes.data.result.nextBillingDate)
@@ -104,21 +107,23 @@ const PgSignUp = (props) => {
// "handleSubmit" is used to save user details signup him/her who come from plan-pricing page
const handleSubmit = (e) => {
e.preventDefault();
setIsLoader(true);
if (formData.password === formData.confirmPassword) {
const url = window.location.href;
let paramString = url.split("?")[1];
let queryString = new URLSearchParams(paramString);
// console.log("url ", queryString);
if (lengthValid && caseDigitValid && specialCharValid) {
setIsLoader(true);
if (formData.password === formData.confirmPassword) {
const url = window.location.href;
let paramString = url.split("?")[1];
let queryString = new URLSearchParams(paramString);
// console.log("url ", queryString);
let obj = { ...formData };
for (let pair of queryString.entries()) {
// console.log("Key is: " + pair[0]);
// console.log("Value is: " + pair[1]);
obj = { ...obj, [pair[0]]: pair[1] };
let obj = { ...formData };
for (let pair of queryString.entries()) {
// console.log("Key is: " + pair[0]);
// console.log("Value is: " + pair[1]);
obj = { ...obj, [pair[0]]: pair[1] };
}
saveUser(obj);
// console.log("obj ", obj);}
}
saveUser(obj);
// console.log("obj ", obj);}
}
};
const saveUser = async (obj) => {
@@ -194,6 +199,15 @@ const PgSignUp = (props) => {
const newPassword = e.target.value;
setFormData({ ...formData, [e.target.name]: e.target.value });
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 newConfirmPassword = e.target.value;
@@ -485,6 +499,33 @@ const PgSignUp = (props) => {
>
{validationMessage}
</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">
<button type="submit" className="signupbtn">
Submit
@@ -136,8 +136,13 @@ const PlanSubscriptions = () => {
<p>{item.subtitle}</p>
</div>
</div>
<NavLink
to={item.url + details}
to={
item.btnText === "Subscribe"
? item.url + details
: item.url
}
className="bg-[#002862] w-full text-white py-2 rounded uppercase hover:no-underline hover:text-white"
target={item.target}
>
+7
View File
@@ -12,8 +12,10 @@ const Report = () => {
const [isLoader, setIsLoader] = useState(true);
const [reportName, setReportName] = useState("");
const [actions, setActions] = useState([]);
const [heading, setHeading] = useState([]);
const [isNextRecord, setIsNextRecord] = useState(false);
const [isMoreDocs, setIsMoreDocs] = useState(true);
const [form, setForm]= useState("")
const abortController = new AbortController();
const docPerPage = 10;
@@ -47,7 +49,9 @@ const Report = () => {
const json = reportJson(id);
if (json) {
setActions(json.actions);
setHeading(json.heading);
setReportName(json.reportName);
setForm(json.form)
Parse.serverURL = localStorage.getItem("BaseUrl12");
Parse.initialize(localStorage.getItem("AppID12"));
const currentUser = Parse.User.current().id;
@@ -146,10 +150,13 @@ const Report = () => {
<ReportTable
ReportName={reportName}
List={List}
setList={setList}
actions={actions}
heading={heading}
setIsNextRecord={setIsNextRecord}
isMoreDocs={isMoreDocs}
docPerPage={docPerPage}
form={form}
/>
) : (
<div className="flex items-center justify-center h-screen w-full bg-white rounded">
+167 -76
View File
@@ -25,92 +25,138 @@ const Signup = (props) => {
toastDescription: ""
});
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 image = props.appInfo.applogo;
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 handleSubmit = (event) => {
setState({ loading: true });
const userDetails = {
name: name,
email: email,
phone: phone,
company: company,
jobTitle: jobTitle
};
localStorage.setItem("userDetails", JSON.stringify(userDetails));
try {
event.preventDefault();
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
event.preventDefault();
if (lengthValid && caseDigitValid && specialCharValid) {
clearStorage();
setState({ loading: true });
const userDetails = {
name: name,
email: email,
phone: phone,
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 });
}
};
try {
const usersignup = await Parse.Cloud.run("usersignup", params);
if (usersignup) {
handleNavigation(r.getSessionToken());
}
}
})
.catch(async (err) => {
if (err.code === 202) {
const params = { email: email };
const res = await Parse.Cloud.run("getUserDetails", params);
// console.log("Res ", res);
if (res) {
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);
}
} catch (err) {
alert(err.message);
setState({ loading: false });
}
}
}
})
.catch(async (err) => {
if (err.code === 202) {
const params = { email: email };
const res = await Parse.Cloud.run("getUserDetails", params);
// console.log("Res ", res);
if (res) {
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);
}
alert(err.message);
setState({ loading: false });
}
} else {
alert(err.message);
setState({ loading: false });
}
});
} catch (error) {
console.log("err ", error);
});
} catch (error) {
console.log("err ", error);
}
}
};
@@ -396,6 +442,19 @@ const Signup = (props) => {
// eslint-disable-next-line
}, []);
const handlePasswordChange = (e) => {
const newPassword = e.target.value;
setPassword(newPassword);
// Check conditions separately
setLengthValid(newPassword.length >= 8);
setCaseDigitValid(
/[a-z]/.test(newPassword) &&
/[A-Z]/.test(newPassword) &&
/\d/.test(newPassword)
);
setSpecialCharValid(/[!@#$%^&*()\-_=+{};:,<.>]/.test(newPassword));
};
return (
<div className="bg-white">
{state.loading && (
@@ -508,7 +567,7 @@ const Signup = (props) => {
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
name="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
onChange={(e) => handlePasswordChange(e)}
required
/>
<span
@@ -524,6 +583,38 @@ const Signup = (props) => {
)}
</span>
</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 className="flex flex-col md:flex-row justify-between items-stretch gap-8 text-center text-xs font-bold mt-2">
+111 -109
View File
@@ -158,124 +158,126 @@ function UserProfile() {
></div>
</div>
) : (
<div className="bg-white flex flex-col justify-center shadow rounded">
<div className="flex flex-col justify-center items-center my-4">
<div className="w-[200px] h-[200px] overflow-hidden rounded-full">
<img
className="object-contain w-full h-full"
src={Image === "" ? dp : Image}
alt="dp"
/>
</div>
{editmode && (
<input
type="file"
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) => {
let files = e.target.files;
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 className="flex justify-center items-center w-full">
<div className="bg-white flex flex-col justify-center shadow rounded w-[450px]">
<div className="flex flex-col justify-center items-center my-4">
<div className="w-[200px] h-[200px] overflow-hidden rounded-full">
<img
className="object-contain w-full h-full"
src={Image === "" ? dp : Image}
alt="dp"
/>
</div>
{editmode && (
<input
type="file"
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) => {
let files = e.target.files;
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">
{localStorage.getItem("_user_role")}
</div>
)}
<div className="text-base font-semibold pt-4">
{localStorage.getItem("_user_role")}
</div>
</div>
<ul className="w-full flex flex-col p-2 text-sm">
<li
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
editmode ? "py-1" : "py-2"
}`}
>
<span>Name:</span>{" "}
{editmode ? (
<input
type="text"
value={name}
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
onChange={(e) => SetName(e.target.value)}
/>
) : (
<span>{localStorage.getItem("username")}</span>
)}
</li>
<li
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
editmode ? "py-1" : "py-2"
}`}
>
<span>Phone:</span>{" "}
{editmode ? (
<input
type="text"
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
onChange={(e) => SetPhone(e.target.value)}
value={Phone}
/>
) : (
<span>{UserProfile && UserProfile.phone}</span>
)}
</li>
<li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all">
<span>Email:</span>{" "}
<span>{UserProfile && UserProfile.email}</span>
</li>
<li className="flex justify-between items-center border-y-[1px] border-gray-300 py-2 break-all">
<span>Is Email verified:</span>{" "}
<span>
{UserProfile && UserProfile.emailVerified
? "Verified"
: "Not verified"}
</span>
</li>
</ul>
<div className="flex justify-center pb-4">
{editmode ? (
<button
type="button"
onClick={handleSubmit}
className="rounded bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] px-4 py-2 mr-4"
<ul className="w-full flex flex-col p-2 text-sm">
<li
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
editmode ? "py-1" : "py-2"
}`}
>
Save
</button>
) : (
<span className="font-semibold">Name:</span>{" "}
{editmode ? (
<input
type="text"
value={name}
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
onChange={(e) => SetName(e.target.value)}
/>
) : (
<span>{localStorage.getItem("username")}</span>
)}
</li>
<li
className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all ${
editmode ? "py-1" : "py-2"
}`}
>
<span className="font-semibold">Phone:</span>{" "}
{editmode ? (
<input
type="text"
className="py-1 px-2 text-sm border-[1px] border-[#15b4e9] text-black rounded"
onChange={(e) => SetPhone(e.target.value)}
value={Phone}
/>
) : (
<span>{UserProfile && UserProfile.phone}</span>
)}
</li>
<li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all">
<span className="font-semibold">Email:</span>{" "}
<span>{UserProfile && UserProfile.email}</span>
</li>
<li className="flex justify-between items-center border-y-[1px] border-gray-300 py-2 break-all">
<span className="font-semibold">Is Email verified:</span>{" "}
<span>
{UserProfile && UserProfile.emailVerified
? "Verified"
: "Not verified"}
</span>
</li>
</ul>
<div className="flex justify-center pt-2 pb-3 md:pt-3 md:pb-4">
{editmode ? (
<button
type="button"
onClick={handleSubmit}
className="rounded shadow focus:outline-none border-[2px] border-[#15b4e9] bg-white text-[#15b4e9] px-4 py-2 mr-4"
>
Save
</button>
) : (
<button
type="button"
onClick={() => {
setEditMode(true);
}}
className="rounded shadow focus:outline-none text-white bg-[#e7505a] px-4 py-2 mr-4"
>
Edit
</button>
)}
<button
type="button"
onClick={() => {
setEditMode(true);
if (editmode) {
setEditMode(false);
} else {
navigate("/changepassword");
}
}}
className="rounded shadow text-white bg-[#e7505a] px-4 py-2 mr-4"
className={`rounded shadow focus:outline-none text-white bg-[#3598dc] ${
editmode ? "px-4 py-2 " : "p-2"
}`}
>
Edit
{editmode ? "Cancel" : "Change Password"}
</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>
)}
+2 -4
View File
@@ -2211,7 +2211,5 @@
background-position: -2em 0;
}
}
.box:nth-of-type(n + 43) {
display: none;
}
+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;
}
}
+8 -4
View File
@@ -17,6 +17,8 @@ import getUserDetails from './parsefunction/getUserDetails.js';
import getDocument from './parsefunction/getDocument.js';
import getDrive from './parsefunction/getDrive.js';
import getReport from './parsefunction/getReport.js';
import TemplateAfterSave from './parsefunction/TemplateAfterSave.js';
import GetTemplate from './parsefunction/GetTemplate.js';
Parse.Cloud.define('AddUserToRole', addUserToGroups);
Parse.Cloud.define('UserGroups', getUserGroups);
@@ -26,9 +28,6 @@ Parse.Cloud.define('googlesign', GoogleSign);
Parse.Cloud.define('zohodetails', ZohoDetails);
Parse.Cloud.define('usersignup', usersignup);
Parse.Cloud.define('facebooksign', FacebookSign);
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
Parse.Cloud.define('SendOTPMailV1', sendMailOTPv1);
Parse.Cloud.define('sendmail', SendMailv1);
Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail);
@@ -36,4 +35,9 @@ 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)
Parse.Cloud.define('getReport', getReport)
Parse.Cloud.define("getTemplate", GetTemplate)
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
Parse.Cloud.afterSave("contracts_Template", TemplateAfterSave)
@@ -16,6 +16,7 @@ async function ContactbookAftersave(request) {
acl.setWriteAccess(object.get('UserId'), true);
object.setACL(acl);
object.set('IsDeleted', false)
// Continue saving the object
return object.save(null, { useMasterKey: true });
}
@@ -0,0 +1,53 @@
import axios from 'axios';
export default async function GetTemplate(request) {
const serverUrl = process.env.SERVER_URL;
const templateId = request.params.templateId;
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;
// console.log("templateId ", templateId)
// console.log("userId ",userId)
if (templateId && userId) {
try {
const template = new Parse.Query('contracts_Template');
template.equalTo('objectId', templateId);
template.include('ExtUserPtr');
template.include('Signers');
template.include('CreateBy');
const res = await template.first({ useMasterKey: true });
// console.log("res ", res)
if (res) {
// console.log("res ",res)
const acl = res.getACL();
console.log("acl", acl.getReadAccess(userId))
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', err);
if (err.code == 209) {
return { error: 'Invalid session token' };
} else {
return { error: "You don't have access of this document!" };
}
}
}
@@ -0,0 +1,83 @@
export default async function TemplateAfterSave(request) {
try {
if (!request.original) {
console.log('new entry is insert in contracts_Template');
// update acl of New Document If There are signers present in array
const signers = request.object.get('Signers');
if (signers && signers.length > 0) {
await updateAclDoc(request.object.id);
} else {
await updateSelfDoc(request.object.id);
}
} else {
if (request.user) {
const signers = request.object.get('Signers');
if (signers && signers.length > 0) {
await updateAclDoc(request.object.id);
} else {
await updateSelfDoc(request.object.id);
}
}
}
} catch (err) {
console.log('err in aftersave of contracts_Template');
console.log(err);
}
async function updateAclDoc(objId) {
// console.log("In side updateAclDoc func")
// console.log(objId)
const Query = new Parse.Query('contracts_Template');
Query.include('Signers');
const updateACL = await Query.get(objId, { useMasterKey: true });
const res = JSON.parse(JSON.stringify(updateACL));
// console.log("res");
// console.log(JSON.stringify(res));
const UsersPtr = res.Signers.map(item => item.UserId);
if (res.Signers[0].ExtUserPtr) {
const ExtUserSigners = res.Signers.map(item => {
return {
__type: 'Pointer',
className: 'contracts_Users',
objectId: item.ExtUserPtr.objectId,
};
});
updateACL.set('Signers', ExtUserSigners);
}
// console.log("UsersPtr")
// console.log(JSON.stringify(UsersPtr))
const newACL = new Parse.ACL();
newACL.setPublicReadAccess(false);
newACL.setPublicWriteAccess(false);
newACL.setReadAccess(request.user, true);
newACL.setWriteAccess(request.user, true);
UsersPtr.forEach(x => {
newACL.setReadAccess(x.objectId, true);
newACL.setWriteAccess(x.objectId, true);
});
updateACL.setACL(newACL);
updateACL.save(null, { useMasterKey: true });
}
async function updateSelfDoc(objId) {
// console.log("Inside updateSelfDoc func")
const Query = new Parse.Query('contracts_Template');
const updateACL = await Query.get(objId, { useMasterKey: true });
// const res = JSON.parse(JSON.stringify(updateACL));
// console.log("res");
// console.log(JSON.stringify(res));
const newACL = new Parse.ACL();
newACL.setPublicReadAccess(false);
newACL.setPublicWriteAccess(false);
newACL.setReadAccess(request.user, true);
newACL.setWriteAccess(request.user, true);
updateACL.setACL(newACL);
updateACL.save(null, { useMasterKey: true });
}
}
@@ -21,6 +21,7 @@ export default async function getDocument(request) {
query.include('Signers');
query.include('AuditTrail.UserPtr');
query.include('Placeholders');
query.notEqualTo('IsArchive', true)
const res = await query.first({ useMasterKey: true });
if (res) {
const acl = res.getACL();
@@ -40,7 +41,7 @@ export default async function getDocument(request) {
return { error: 'Please pass required parameters!' };
}
} catch (err) {
console.log('err');
console.log('err', err);
if (err.code == 209) {
return { error: 'Invalid session token' };
} else {
@@ -16,9 +16,9 @@ export default async function getDrive(request) {
if (userId) {
let url;
if (docId) {
url = `${classUrl}?where={"Folder":{"__type":"Pointer","className":"contracts_Document","objectId":"${docId}"},"$or":[{"CreatedBy":{"$exists":false}},{"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"}}]}&include=ExtUserPtr,Signers,Folder`;
url = `${classUrl}?where={"Folder":{"__type":"Pointer","className":"contracts_Document","objectId":"${docId}"},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,Signers,Folder`;
} else {
url = `${classUrl}?where={"Folder":{"$exists":false},"$or":[{"CreatedBy":{"$exists":false}},{"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"}}]}&include=ExtUserPtr,Signers`;
url = `${classUrl}?where={"Folder":{"$exists":false},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,Signers`;
}
try {
const res = await axios.get(url, {
@@ -1,5 +1,5 @@
import reportJson from './reportsJson.js';
import axios from 'axios'
import axios from 'axios';
export default async function getReport(request) {
const reportId = request.params.reportId;
@@ -19,6 +19,7 @@ export default async function getReport(request) {
const userId = userRes.data && userRes.data.objectId;
if (userId) {
const json = reportId && reportJson(reportId, userId);
const clsName = json?.reportClass ? json.reportClass : 'contracts_Document';
if (json) {
const { params, keys } = json;
const orderBy = '-updatedAt';
@@ -29,7 +30,7 @@ export default async function getReport(request) {
'X-Parse-Application-Id': appId,
'X-Parse-Master-Key': process.env.MASTER_KEY,
};
const url = `${serverUrl}/classes/contracts_Document?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`;
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;
+110 -90
View File
@@ -2,7 +2,7 @@ import SignPDF from './SignPDF.min.cjs';
import fs from 'node:fs';
import axios from 'axios';
import FormData from 'form-data';
import plainplaceholder from './customSignPdf/plainplaceholder.min.js';
// import plainplaceholder from './customSignPdf/plainplaceholder.min.js';
import { plainAddPlaceholder } from 'node-signpdf/dist/helpers/index.js';
const serverUrl = process.env.SERVER_URL,
APPID = process.env.APP_ID,
@@ -19,20 +19,20 @@ async function uploadFile(a) {
console.log('err ', e), fs.unlinkSync(a);
}
}
async function updateDoc(t, s, r, i, o, n) {
async function updateDoc(t, s, r, i, n, o) {
try {
var d = {
UserPtr: { __type: 'Pointer', className: n, objectId: r },
UserPtr: { __type: 'Pointer', className: o, objectId: r },
SignedUrl: s,
Activity: 'Signed',
ipAddress: i,
};
let e;
var l = (e = o.AuditTrail && 0 < o.AuditTrail.length ? [...o.AuditTrail, d] : [d]).filter(
var l = (e = n.AuditTrail && 0 < n.AuditTrail.length ? [...n.AuditTrail, d] : [d]).filter(
e => 'Signed' === e.Activity
);
let a = !1;
!((o.Signers && 0 < o.Signers.length && l.length !== o.Signers.length) || !(a = !0));
!((n.Signers && 0 < n.Signers.length && l.length !== n.Signers.length) || !(a = !0));
var p = { SignedUrl: s, AuditTrail: e, IsCompleted: a };
await axios.put(serverUrl + '/classes/contracts_Document/' + t, p, {
headers: {
@@ -61,7 +61,7 @@ async function sendMail(e) {
s +
' Standard is attached to this email. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from Open Sign. For any queries regarding this email, please contact the sender ' +
t.Mail +
' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.</p></div></div></body></html>',
' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>'
};
await axios.post(serverUrl + '/functions/sendmailv3', a, {
headers: {
@@ -86,7 +86,7 @@ async function sendCompletedMail(e) {
s +
'. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from Open Sign. For any queries regarding this email, please contact the sender ' +
t.Mail +
' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.</p></div></div></body></html>',
' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>',
};
await axios.post(serverUrl + '/functions/sendmailv3', a, {
headers: {
@@ -96,115 +96,135 @@ async function sendCompletedMail(e) {
},
});
}
async function PDF(s, r) {
async function PDF(i, n) {
try {
var i = s.params.sign,
e = s.params.docId,
o = s.params.userId,
n = await axios.get(serverUrl + '/classes/contracts_Document/' + e + '?include=ExtUserPtr', {
headers: {
'Content-Type': 'application/json',
'X-Parse-Application-Id': APPID,
'X-Parse-Master-Key': masterKEY,
},
}),
d = await axios.get(serverUrl + '/users/me', {
i.params.sign;
var e = i.params.docId,
a = i.params.userId,
o = await axios.get(
serverUrl + '/classes/contracts_Document/' + e + '?include=ExtUserPtr,Signers',
{
headers: {
'Content-Type': 'application/json',
'X-Parse-Application-Id': APPID,
'X-Parse-Master-Key': masterKEY,
},
}
),
t = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': APPID,
'X-Parse-Session-Token': s.headers.sessiontoken,
'X-Parse-Session-Token': i.headers.sessiontoken,
},
});
if (!d.data || !d.data.objectId) return { status: 'error', message: 'this user not allowed!' };
if (!t.data || !t.data.objectId) return { status: 'error', message: 'this user not allowed!' };
{
var l,
var d,
l,
p,
c,
m = JSON.stringify({ objectId: o });
let a, t;
t = o
? (l = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + m, {
c = JSON.stringify({ objectId: a });
let s, r;
r = a
? (d = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + c, {
headers: {
'X-Parse-Application-Id': APPID,
'X-Parse-Session-Token': s.headers.sessiontoken,
'X-Parse-Session-Token': i.headers.sessiontoken,
},
})).data && 0 < l.data.results.length
? ((a = l), 'contracts_Contactbook')
: ((a = await axios.get(serverUrl + '/classes/contracts_Users?where=' + m, {
headers: {
'X-Parse-Application-Id': APPID,
'X-Parse-Master-Key': masterKEY,
},
})).data && 0 < d.data.results.length
? ((s = d), 'contracts_Contactbook')
: ((s = await axios.get(serverUrl + '/classes/contracts_Users?where=' + c, {
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
})),
'contracts_Users')
: ((p = JSON.stringify({
UserId: { __type: 'Pointer', className: '_User', objectId: d.data.objectId },
: ((l = JSON.stringify({
UserId: { __type: 'Pointer', className: '_User', objectId: t.data.objectId },
})),
(c = await axios.get(serverUrl + '/classes/contracts_Users?where=' + p, {
headers: {
'X-Parse-Application-Id': APPID,
'X-Parse-Master-Key': masterKEY,
},
})).data && 0 < c.data.results.length
? ((a = c), 'contracts_Users')
: ((a = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + p, {
(p = await axios.get(serverUrl + '/classes/contracts_Users?where=' + l, {
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
})).data && 0 < p.data.results.length
? ((s = p), 'contracts_Users')
: ((s = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + l, {
headers: {
'X-Parse-Application-Id': APPID,
'X-Parse-Session-Token': s.headers.sessiontoken,
'X-Parse-Session-Token': i.headers.sessiontoken,
},
})),
'contracts_Contactbook'));
var g = a.data.results[0].Name,
h = a.data.results[0].Email;
if (!s.params.pdfFile) return { status: 'error', message: 'pdf file not present!' };
var m = s.data.results[0].Name,
g = s.data.results[0].Email;
if (!i.params.pdfFile) return { status: 'error', message: 'pdf file not present!' };
{
let e = Buffer.from(s.params.pdfFile, 'base64');
let e = Buffer.from(i.params.pdfFile, 'base64');
var u = process.env.PFX_BASE64,
f = Buffer.from(u, 'base64');
e = i
? plainplaceholder({
pdfBuffer: e,
reason: 'Digitally signed by Open sign for ' + g + ' <' + h + '>',
location: 'test location',
signatureLength: 1e4,
sign: i,
})
: plainAddPlaceholder({
pdfBuffer: e,
reason: 'Digitally signed by Open sign for ' + g + ' <' + h + '>',
location: 'test location',
signatureLength: 1e4,
});
var y = await new SignPDF(e, f).signPDF(),
v = `./exports/exported_file_${Math.floor(5e3 * Math.random())}.pdf`,
P = (fs.writeFileSync(v, y), await uploadFile(v));
if (P && P.imageUrl) {
const r = await updateDoc(
s.params.docId,
P.imageUrl,
a.data.results[0].objectId,
s.headers['x-real-ip'],
n.data,
t
h = Buffer.from(u, 'base64'),
f = {
UserPtr: { __type: 'Pointer', className: r, objectId: s.data.results[0].objectId },
SignedUrl: '',
Activity: 'Signed',
ipAddress: i.headers['x-real-ip'],
};
let a;
var y = (a =
o.data.AuditTrail && 0 < o.data.AuditTrail.length
? [...o.data.AuditTrail, f]
: [f]).filter(e => 'Signed' === e.Activity);
let t = !1;
!(
(o.data.Signers && 0 < o.data.Signers.length && y.length !== o.data.Signers.length) ||
!(t = !0)
);
var v,
P,
x = `./exports/exported_file_${Math.floor(5e3 * Math.random())}.pdf`,
A =
(t
? ((v = o.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')),
(e =
v && 0 < v.length
? plainAddPlaceholder({
pdfBuffer: e,
reason: 'Digitally signed by Open sign for ' + v?.join(', '),
location: 'location',
signatureLength: 1e4,
})
: plainAddPlaceholder({
pdfBuffer: e,
reason: 'Digitally signed by Open sign for ' + m + ' <' + g + '>',
location: 'location',
signatureLength: 1e4,
})),
(P = await new SignPDF(e, h).signPDF()),
fs.writeFileSync(x, P))
: fs.writeFileSync(x, e),
await uploadFile(x));
if (A && A.imageUrl) {
const n = await updateDoc(
i.params.docId,
A.imageUrl,
s.data.results[0].objectId,
i.headers['x-real-ip'],
o.data,
r
);
return (
sendMail({
url: P.imageUrl,
sender: { Mail: n.data.ExtUserPtr.Email, Name: n.data.ExtUserPtr.Name },
pdfName: n.data.Name,
receiver: h,
url: A.imageUrl,
sender: { Mail: o.data.ExtUserPtr.Email, Name: o.data.ExtUserPtr.Name },
pdfName: o.data.Name,
receiver: g,
}),
r &&
r.isCompleted &&
n &&
n.isCompleted &&
sendCompletedMail({
url: P.imageUrl,
sender: { Mail: n.data.ExtUserPtr.Email, Name: 'Open sign' },
pdfName: n.data.Name,
receiver: n.data.ExtUserPtr.Email,
url: A.imageUrl,
sender: { Mail: o.data.ExtUserPtr.Email, Name: 'Open sign' },
pdfName: o.data.Name,
receiver: o.data.ExtUserPtr.Email,
}),
fs.unlinkSync(v),
console.log('New Signed PDF created called: ' + v),
'success' === r.message
? { status: 'success', data: P.imageUrl }
fs.unlinkSync(x),
console.log('New Signed PDF created called: ' + x),
'success' === n.message
? { status: 'success', data: A.imageUrl }
: { status: 'error', message: 'please provide required parameters!' }
);
}
@@ -7,11 +7,11 @@ export default function reportJson(id, userId) {
return {
reportName: 'Draft Documents',
params: {
Type: null,
$or: [
{ Signers: null, SignedUrl: null },
{ Signers: { $exists: true }, Placeholders: null },
],
Type: { $ne: 'Folder' },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
IsArchive: { $ne: true },
$or: [{Signers:{$eq:[]}}, { Signers: null }, { Signers: { $exists: true }, Placeholders: null }],
CreatedBy: {
__type: 'Pointer',
className: '_User',
@@ -28,10 +28,23 @@ export default function reportJson(id, userId) {
Type: { $ne: 'Folder' },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
IsArchive: { $ne: true },
ExpiryDate: {
$gt: { __type: 'Date', iso: new Date().toISOString() },
},
Placeholders: { $ne: null },
Signers: {
$inQuery: {
where: {
UserId: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
},
className: 'contracts_Contactbook',
},
},
},
keys: [
'Name',
@@ -50,10 +63,11 @@ export default function reportJson(id, userId) {
reportName: 'In-progress documents',
params: {
Type: { $ne: 'Folder' },
Signers: { $ne: null },
Signers: { $exists: true, $ne: [] },
Placeholders: { $ne: null },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
IsArchive: { $ne: true },
CreatedBy: {
__type: 'Pointer',
className: '_User',
@@ -70,7 +84,7 @@ export default function reportJson(id, userId) {
return {
reportName: 'Completed Documents',
params: {
Type: null,
Type: { $ne: 'Folder' },
IsCompleted: true,
CreatedBy: {
__type: 'Pointer',
@@ -78,6 +92,7 @@ export default function reportJson(id, userId) {
objectId: currentUserId,
},
IsDeclined: { $ne: true },
IsArchive: { $ne: true },
},
keys: [
'Name',
@@ -96,6 +111,7 @@ export default function reportJson(id, userId) {
reportName: 'Declined Documents',
params: {
Type: null,
IsArchive: { $ne: true },
IsDeclined: true,
CreatedBy: {
__type: 'Pointer',
@@ -113,6 +129,7 @@ export default function reportJson(id, userId) {
params: {
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
IsArchive: { $ne: true },
Type: { $ne: 'Folder' },
$and: [
{
@@ -141,10 +158,11 @@ export default function reportJson(id, userId) {
reportName: 'Recently sent for signatures',
params: {
Type: { $ne: 'Folder' },
Signers: { $ne: null },
Signers: { $exists: true, $ne: [] },
Placeholders: { $ne: null },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
IsArchive: { $ne: true },
CreatedBy: {
__type: 'Pointer',
className: '_User',
@@ -154,7 +172,7 @@ export default function reportJson(id, userId) {
$gt: { __type: 'Date', iso: new Date().toISOString() },
},
},
keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'],
keys: ['Name', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'],
};
// Recent signature requests report show on dashboard
case '5Go51Q7T8r':
@@ -164,32 +182,67 @@ export default function reportJson(id, userId) {
Type: { $ne: 'Folder' },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
IsArchive: { $ne: true },
ExpiryDate: {
$gt: { __type: 'Date', iso: new Date().toISOString() },
},
Placeholders: { $ne: null },
Signers: {
$inQuery: {
where: {
UserId: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
},
className: 'contracts_Contactbook',
},
},
},
keys: [
'Name',
'Note',
'Folder.Name',
'URL',
'ExtUserPtr.Name',
'Signers.Name',
'Signers.UserId',
'AuditTrail',
],
keys: ['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 },
],
Type: { $ne: 'Folder' },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
IsArchive: { $ne: true },
$or: [{Signers:{$eq:[]}}, { Signers: 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',
reportClass: 'contracts_Contactbook',
params: {
CreatedBy: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
IsDeleted: { $ne: true },
},
keys: ['Name', 'Email', 'Phone'],
};
// Templates report
case '6TeaPr321t':
return {
reportName: 'Templates',
reportClass: 'contracts_Template',
params: {
Type: { $ne: 'Folder' },
IsArchive: { $ne: true },
CreatedBy: {
__type: 'Pointer',
className: '_User',
@@ -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 });
};
@@ -0,0 +1,588 @@
/**
*
* @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: 'fa-solid fa-paper-plane',
title: 'Request signatures',
target: '_self',
pageType: 'form',
description: '',
objectId: '8mZzFxbG1z',
},
{
icon: 'fas fa-file-signature',
title: 'New template',
target: '_self',
pageType: 'form',
description: '',
objectId: 'template',
},
],
},
{
icon: 'fa-solid fa-file-contract',
title: 'Templates',
target: '_self',
pageType: 'report',
description: '',
objectId: '6TeaPr321t',
},
{
icon: 'fas fa-folder',
title: 'OpenSign™ Drive',
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: 'fa-solid fa-paper-plane',
title: 'Request signatures',
target: '_self',
pageType: 'form',
description: '',
objectId: '8mZzFxbG1z',
},
{
icon: 'fas fa-file-signature',
title: 'New template',
target: '_self',
pageType: 'form',
description: '',
objectId: 'template',
},
],
},
{
icon: 'fa-solid fa-file-contract',
title: 'Templates',
target: '_self',
pageType: 'report',
description: '',
objectId: '6TeaPr321t',
},
{
icon: 'fas fa-folder',
title: 'OpenSign™ Drive',
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 });
};
@@ -0,0 +1,40 @@
/**
*
* @param {Parse} Parse
*/
exports.up = async Parse => {
const className = 'contracts_Template';
const schema = new Parse.Schema(className);
schema.addString('Name');
schema.addString('URL');
schema.addString('Note');
schema.addString('Description');
schema.addArray('Signers');
schema.addBoolean('IsArchive');
schema.addArray('Placeholders');
schema.addPointer('Folder', 'contracts_Template');
schema.addString('Type');
schema.addPointer('CreatedBy', '_User');
schema.addPointer('ExtUserPtr', 'contracts_Users');
schema.addBoolean('EnablePhoneOTP')
schema.addBoolean('EnableEmailOTP')
schema.addBoolean('SendinOrder')
schema.addBoolean('SentToOthers')
schema.addBoolean('AutomaticReminders')
return schema.save();
};
/**
*
* @param {Parse} Parse
*/
exports.down = async Parse => {
const className = 'contracts_Template';
const schema = new Parse.Schema(className);
return schema.purge().then(() => schema.delete());
};
@@ -0,0 +1,23 @@
/**
*
* @param {Parse} Parse
*/
exports.up = async Parse => {
// TODO: set className here
const className = 'contracts_Document';
const schema = new Parse.Schema(className);
schema.addBoolean('IsArchive');
return schema.update();
};
/**
*
* @param {Parse} Parse
*/
exports.down = async Parse => {
// TODO: set className here
const className = 'contracts_Document';
const schema = new Parse.Schema(className);
schema.deleteField('IsArchive');
return schema.update();
};
Binary file not shown.
+4 -7
View File
@@ -18,6 +18,7 @@ import FSFilesAdapter from 'parse-server-fs-adapter';
import AWS from 'aws-sdk';
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);
// console.log("configuration ", configuration);
@@ -68,7 +69,9 @@ if (process.env.SMTP_ENABLE) {
export const config = {
databaseURI:
process.env.DATABASE_URI || process.env.MONGODB_URI || 'mongodb://localhost:27017/dev',
cloud: process.env.CLOUD || __dirname + '/cloud/main.js',
cloud: function () {
import('./cloud/main.js');
},
appId: process.env.APP_ID || 'myAppId',
masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret!
masterKeyIps: ['0.0.0.0/0', '::1'], // '::1'
@@ -169,12 +172,6 @@ app.get('/', function (req, res) {
res.status(200).send('open-sign-server is running !!!');
});
// There will be a test page available on the /test path of your server url
// Remove this before launching your app
app.get('/test', function (req, res) {
res.sendFile(path.join(__dirname, '/public/test.html'));
});
if (!process.env.TESTING) {
const port = process.env.PORT || 8080;
const httpServer = http.createServer(app);
@@ -1,4 +1,5 @@
[{
[
{
"_id": "H9vRfEYKhT",
"_created_at": {
"$date": "2023-09-04T14:04:00.669Z"
@@ -105,6 +106,14 @@
"pageType": "report",
"description": "",
"objectId": "zNqBHXHsYH"
},
{
"icon": "fa-solid fa-address-book",
"title": "Contactbook",
"target": "_self",
"pageType": "report",
"description": "",
"objectId": "5KhaPr482K"
}
]
},
@@ -237,6 +246,14 @@
"pageType": "report",
"description": "",
"objectId": "zNqBHXHsYH"
},
{
"icon": "fa-solid fa-address-book",
"title": "Contactbook",
"target": "_self",
"pageType": "report",
"description": "",
"objectId": "5KhaPr482K"
}
]
},
@@ -269,4 +286,5 @@
],
"menuTitle": "Admin Menu",
"menuType": "Side Menu"
}]
}
]
+200 -22
View File
@@ -29,14 +29,15 @@
"react-dnd-touch-backend": "^16.0.1",
"react-dom": "^18.2.0",
"react-draggable": "^4.4.6",
"react-helmet": "^6.1.0",
"react-pdf": "^7.4.0",
"react-rnd": "^10.4.1",
"react-router-dom": "^6.16.0",
"react-scripts": "5.0.1",
"react-scrollbars-custom": "^4.1.1",
"react-select": "^5.8.0",
"react-signature-canvas": "^1.0.6",
"reactour": "^1.19.1",
"select-dom": "^9.0.0",
"web-vitals": "^2.1.4"
}
},
@@ -2310,6 +2311,65 @@
"postcss-selector-parser": "^6.0.10"
}
},
"node_modules/@emotion/babel-plugin": {
"version": "11.11.0",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz",
"integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==",
"dependencies": {
"@babel/helper-module-imports": "^7.16.7",
"@babel/runtime": "^7.18.3",
"@emotion/hash": "^0.9.1",
"@emotion/memoize": "^0.8.1",
"@emotion/serialize": "^1.1.2",
"babel-plugin-macros": "^3.1.0",
"convert-source-map": "^1.5.0",
"escape-string-regexp": "^4.0.0",
"find-root": "^1.1.0",
"source-map": "^0.5.7",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/babel-plugin/node_modules/convert-source-map": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
},
"node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@emotion/babel-plugin/node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@emotion/cache": {
"version": "11.11.0",
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz",
"integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==",
"dependencies": {
"@emotion/memoize": "^0.8.1",
"@emotion/sheet": "^1.2.2",
"@emotion/utils": "^1.2.1",
"@emotion/weak-memoize": "^0.3.1",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/hash": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz",
"integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ=="
},
"node_modules/@emotion/is-prop-valid": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz",
@@ -2322,8 +2382,52 @@
"node_modules/@emotion/memoize": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==",
"peer": true
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
},
"node_modules/@emotion/react": {
"version": "11.11.1",
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.1.tgz",
"integrity": "sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==",
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.11.0",
"@emotion/cache": "^11.11.0",
"@emotion/serialize": "^1.1.2",
"@emotion/use-insertion-effect-with-fallbacks": "^1.0.1",
"@emotion/utils": "^1.2.1",
"@emotion/weak-memoize": "^0.3.1",
"hoist-non-react-statics": "^3.3.1"
},
"peerDependencies": {
"react": ">=16.8.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@emotion/serialize": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.2.tgz",
"integrity": "sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==",
"dependencies": {
"@emotion/hash": "^0.9.1",
"@emotion/memoize": "^0.8.1",
"@emotion/unitless": "^0.8.1",
"@emotion/utils": "^1.2.1",
"csstype": "^3.0.2"
}
},
"node_modules/@emotion/serialize/node_modules/@emotion/unitless": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz",
"integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ=="
},
"node_modules/@emotion/sheet": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz",
"integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA=="
},
"node_modules/@emotion/stylis": {
"version": "0.8.5",
@@ -2337,6 +2441,24 @@
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==",
"peer": true
},
"node_modules/@emotion/use-insertion-effect-with-fallbacks": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz",
"integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==",
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@emotion/utils": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz",
"integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg=="
},
"node_modules/@emotion/weak-memoize": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz",
"integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww=="
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@@ -10608,6 +10730,11 @@
"url": "https://github.com/avajs/find-cache-dir?sponsor=1"
}
},
"node_modules/find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
},
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -14810,6 +14937,11 @@
"node": ">= 4.0.0"
}
},
"node_modules/memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
},
"node_modules/merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@@ -17748,6 +17880,25 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg=="
},
"node_modules/react-fast-compare": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
},
"node_modules/react-helmet": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz",
"integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==",
"dependencies": {
"object-assign": "^4.1.1",
"prop-types": "^15.7.2",
"react-fast-compare": "^3.1.1",
"react-side-effect": "^2.1.0"
},
"peerDependencies": {
"react": ">=16.3.0"
}
},
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -18003,6 +18154,34 @@
"react": ">=16.0.0"
}
},
"node_modules/react-select": {
"version": "5.8.0",
"resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz",
"integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==",
"dependencies": {
"@babel/runtime": "^7.12.0",
"@emotion/cache": "^11.4.0",
"@emotion/react": "^11.8.1",
"@floating-ui/dom": "^1.0.1",
"@types/react-transition-group": "^4.4.0",
"memoize-one": "^6.0.0",
"prop-types": "^15.6.0",
"react-transition-group": "^4.3.0",
"use-isomorphic-layout-effect": "^1.1.2"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-side-effect": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz",
"integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==",
"peerDependencies": {
"react": "^16.3.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-signature-canvas": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/react-signature-canvas/-/react-signature-canvas-1.0.6.tgz",
@@ -18703,20 +18882,6 @@
"resolved": "https://registry.npmjs.org/scrollparent/-/scrollparent-2.0.1.tgz",
"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": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -19527,6 +19692,11 @@
"postcss": "^8.2.15"
}
},
"node_modules/stylis": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
},
"node_modules/sucrase": {
"version": "3.34.0",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz",
@@ -20218,11 +20388,6 @@
"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": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
@@ -20443,6 +20608,19 @@
}
}
},
"node_modules/use-isomorphic-layout-effect": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
"integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/use-sidecar": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
+2 -1
View File
@@ -25,14 +25,15 @@
"react-dnd-touch-backend": "^16.0.1",
"react-dom": "^18.2.0",
"react-draggable": "^4.4.6",
"react-helmet": "^6.1.0",
"react-pdf": "^7.4.0",
"react-rnd": "^10.4.1",
"react-router-dom": "^6.16.0",
"react-scripts": "5.0.1",
"react-scrollbars-custom": "^4.1.1",
"react-select": "^5.8.0",
"react-signature-canvas": "^1.0.6",
"reactour": "^1.19.1",
"select-dom": "^9.0.0",
"web-vitals": "^2.1.4"
},
"scripts": {
@@ -47,7 +47,7 @@
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
/>
<title>OpenSign App</title>
<title>OpenSign</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
@@ -47,65 +47,34 @@ function DraftDocument() {
//check document type and render on signyour self and placeholder route
const handleDraftDoc = () => {
const data = pdfDetails[0];
const checkSignerExist =
pdfDetails[0] && pdfDetails[0].Signers && pdfDetails[0].Signers;
const isPlaceholder =
pdfDetails[0].Placeholders && pdfDetails[0].Placeholders;
const isDecline = data.IsDeclined && data.IsDeclined;
const signUrl = data.SignedUrl && data.SignedUrl;
const expireDate =
pdfDetails[0] &&
pdfDetails[0].ExpiryDate.iso &&
pdfDetails[0].ExpiryDate.iso;
const expireUpdateDate = new Date(expireDate).getTime();
const currDate = new Date().getTime();
const hostUrl = getHostUrl();
const signerExist = data.Signers && data.Signers;
const isDecline = data.IsDeclined && data.IsDeclined;
const isPlaceholder = data.Placeholders && data.Placeholders;
//checking document is completed and signer exist then navigate to pdfRequestFiles file
if (data.IsCompleted && checkSignerExist) {
navigate(`${hostUrl}pdfRequestFiles`);
//checking if document has completed and request signature flow
if (data?.IsCompleted && signerExist?.length > 0) {
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
}
//checking document is completed and signer does not exist then navigate to recipientSignPdf file
else if (data.IsCompleted && !checkSignerExist) {
navigate(`${hostUrl}signaturePdf`);
//checking if document has completed and signyour-self flow
else if (!signerExist && !isPlaceholder) {
navigate(`${hostUrl}signaturePdf/${data.objectId}`);
}
//checking document is declined by someone then navigate to pdfRequestFiles file
//checking if document has declined by someone
else if (isDecline) {
navigate(`${hostUrl}pdfRequestFiles`);
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
//checking draft type document
}
//checking document has expired and signers exist and placeholder does not set yet then navigate to pdfRequestFiles file
//draft type request sign document
//Inprogress document
else if (isPlaceholder?.length > 0 && signerExist?.length > 0) {
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
} //placeholder draft document
else if (
currDate > expireUpdateDate &&
checkSignerExist &&
!isPlaceholder
(signerExist?.length > 0 &&
(!isPlaceholder || isPlaceholder?.length === 0)) ||
((!signerExist || signerExist?.length === 0) && isPlaceholder?.length > 0)
) {
navigate(`${hostUrl}placeHolderSign`);
}
//checking document has expired and signers does not exist and document not signed yet then navigate to pdfRequestFiles file
//draft type signyouselfdocument
else if (
currDate > expireUpdateDate &&
!checkSignerExist &&
!isPlaceholder &&
!signUrl
) {
// window.location.hash = `/signaturePdf`;
navigate(`${hostUrl}signaturePdf`);
}
//checking document has expired and signers exist and document then navigate to pdfRequestFiles file
else if (currDate > expireUpdateDate) {
// window.location.hash = `/pdfRequestFiles`;
navigate(`${hostUrl}pdfRequestFiles`);
}
//checking document has expired not been expired yet and signers exist and placeholder does not set yet then navigate to pdfRequestFiles file
//draft type request sign document
else if (!signUrl && checkSignerExist) {
navigate(`${hostUrl}placeHolderSign`);
// window.location.hash = `/placeHolderSign`;
} else {
// window.location.hash = `/signaturePdf/`;
navigate(`${hostUrl}signaturePdf`);
navigate(`${hostUrl}placeHolderSign/${data.objectId}`);
}
};
@@ -10,6 +10,9 @@ import { getHostUrl } from "../../../utils/Utils";
import { useNavigate } from "react-router-dom";
import Table from "react-bootstrap/Table";
import * as HoverCard from "@radix-ui/react-hover-card";
import SelectFolder from "../../../premitives/SelectFolder";
import ModalUi from "../../../premitives/ModalUi";
import { themeColor } from "../../../utils/ThemeColor/backColor";
function PdfFileComponent({
pdfData,
@@ -18,11 +21,20 @@ function PdfFileComponent({
setIsLoading,
setPdfData,
isList,
setIsAlert
}) {
const [rename, setRename] = useState("");
const [renameValue, setRenameValue] = useState("");
const inputRef = useRef(null);
const [isOpenMoveModal, setIsOpenMoveModal] = useState(false);
const [selectDoc, setSelectDoc] = useState();
const [isDeleteDoc, setIsDeleteDoc] = useState(false);
const contextMenu = [
{ type: "Download", icon: "fa-solid fa-arrow-down" },
{ type: "Rename", icon: "fa-solid fa-font" },
{ type: "Move", icon: "fa-solid fa-file-export" },
{ type: "Delete", icon: "fa-solid fa-trash" }
];
const navigate = useNavigate();
//to focus input box on press rename to change doc name
@@ -39,12 +51,12 @@ function PdfFileComponent({
const handleOnclikFolder = (data) => {
const folderData = {
name: data.Name,
objectId: data.objectId,
objectId: data.objectId
};
setFolderName((prev) => [...prev, folderData]);
const loadObj = {
isLoad: true,
message: "This might take some time",
message: "This might take some time"
};
setIsLoading(loadObj);
@@ -57,7 +69,7 @@ function PdfFileComponent({
if (trimmedValue.length > 0) {
const updateName = {
Name: renameValue,
Name: renameValue
};
const docId = data.objectId;
@@ -83,8 +95,8 @@ function PdfFileComponent({
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken"),
},
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
)
.then((result) => {
@@ -92,89 +104,191 @@ function PdfFileComponent({
// console.log("res", res);
})
.catch((err) => {
console.log("error updating field is decline ", err);
setIsAlert({
isShow: true,
alertMessage: "something went wrong"
});
});
}
};
//function for navigate user to microapp-signature component
const checkPdfStatus = async (data) => {
const hostUrl = getHostUrl();
const expireDate = data.ExpiryDate.iso;
const expireUpdateDate = new Date(expireDate).getTime();
const currDate = new Date().getTime();
const signerExist = data.Signers && data.Signers;
const signUrl = data.SignedUrl && data.SignedUrl;
const isDecline = data.IsDeclined && data.IsDeclined;
const isPlaceholder = data.Placeholders && data.Placeholders;
//checking and navigate to signyouself page
const checkPlaceHolder = data.Placeholders;
//checking if document has completed
if (data.IsCompleted && signerExist) {
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
// window.location.hash = `/pdfRequestFiles/${data.objectId}`;
} else if (data.IsCompleted && !signerExist) {
navigate(
`${hostUrl}signaturePdf/${data.objectId}`
);
// window.location.hash = `/recipientSignPdf/${data.objectId}/${data.ExtUserPtr.Phone}`;
//checking if document has completed and request signature flow
if (data?.IsCompleted && signerExist?.length > 0) {
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
}
//checking if document has completed and signyour-self flow
else if (!signerExist && !isPlaceholder) {
navigate(`${hostUrl}signaturePdf/${data.objectId}`);
}
//checking if document has declined by someone
else if (isDecline) {
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
// window.location.hash = `/pdfRequestFiles/${data.objectId}`;
} else if (currDate > expireUpdateDate && signerExist && !isPlaceholder) {
// window.location.hash = `/placeHolderSign/${data.objectId}`;
navigate(`${hostUrl}placeHolderSign/${data.objectId}`);
} else if (
currDate > expireUpdateDate &&
!signerExist &&
!isPlaceholder &&
!signUrl
) {
navigate(`${hostUrl}signaturePdf/${data.objectId}`);
// window.location.hash = `/signaturePdf/${data.objectId}`;
//checking draft type document
}
//checking if document has expired
else if (currDate > expireUpdateDate) {
//Inprogress document
else if (isPlaceholder?.length > 0 && signerExist?.length > 0) {
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
// window.location.hash = `/pdfRequestFiles/${data.objectId}`;
} //checking if document is draft signers type and signers placeholder does not placed yet
else if (!signUrl && signerExist) {
// window.location.hash = `/placeHolderSign/${data.objectId}`;
navigate(`${hostUrl}placeHolderSign/${data.objectId}`);
}
//checking if document is request type and signers placeholder exist and does not completed yet
//then user can check progress of document and sign also
} //placeholder draft document
else if (
checkPlaceHolder &&
checkPlaceHolder.length > 0 &&
!data.IsCompleted
(signerExist?.length > 0 &&
(!isPlaceholder || isPlaceholder?.length === 0)) ||
((!signerExist || signerExist?.length === 0) && isPlaceholder?.length > 0)
) {
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
// window.location.hash = `/pdfRequestFiles/${data.objectId}`;
navigate(`${hostUrl}placeHolderSign/${data.objectId}`);
}
//checking document is draft and signyourself type then user can sign document
else {
navigate(`${hostUrl}signaturePdf/${data.objectId}`);
// navigate(`/signaturePdf/${data.objectId}`);
// window.location.hash = `/signaturePdf/${data.objectId}`;
};
const handleMenuItemClick = (selectType, data) => {
switch (selectType) {
case "Download":
const pdfName = data && data.Name;
const pdfUrl = data && data.SignedUrl ? data.SignedUrl : data.URL;
saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
break;
case "Rename":
setRenameValue(data.Name);
setRename(data.objectId);
break;
case "Delete":
setIsDeleteDoc(true);
setSelectDoc(data);
break;
case "Move":
handleMoveDocument(data);
break;
}
};
//function for delete document
const handleDeleteDocument = async (docData) => {
setIsDeleteDoc(false);
const docId = docData.objectId;
const data = {
IsArchive: true
};
await axios
.put(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document/${docId}`,
data,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
)
.then((result) => {
const res = result.data;
if (res) {
const updatedData = pdfData.filter((x) => x.objectId !== docId);
setPdfData(updatedData);
}
})
.catch((err) => {
setIsAlert({
isShow: true,
alertMessage: "something went wrong"
});
});
};
const handleMoveDocument = async (docData) => {
setIsOpenMoveModal(true);
setSelectDoc(docData);
};
//function for move document from one folder to another folder
const handleMoveFolder = async (selectFolderData) => {
const selecFolderId = selectDoc?.Folder?.objectId;
const moveFolderId = selectFolderData?.ObjectId;
let updateDocId = selectDoc?.objectId;
let updateData;
const checkExist = moveFolderId
? selecFolderId === moveFolderId
? true
: false
: selecFolderId
? false
: true;
if (!checkExist) {
if (moveFolderId) {
updateData = {
Folder: {
__type: "Pointer",
className: `${localStorage.getItem("_appName")}_Document`,
objectId: moveFolderId
}
};
} else {
updateData = {
Folder: { __op: "Delete" }
};
}
await axios
.put(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document/${updateDocId}`,
updateData,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
)
.then((Listdata) => {
// console.log("Listdata ", Listdata);
const res = Listdata.data;
if (res) {
const updatedData = pdfData.filter(
(x) => x.objectId !== updateDocId
);
setPdfData(updatedData);
}
})
.catch((err) => {
console.log("err", err);
});
setIsOpenMoveModal(false);
} else {
alert("folder already exist!");
setIsOpenMoveModal(false);
}
};
const sanitizeFileName = (pdfName) => {
// Replace spaces with underscore
return pdfName.replace(/ /g, "_");
};
const handleEnterPress = (e, data) => {
if (e.key === "Enter") {
handledRenameDoc(data);
}
};
const handleDraftDoc = (data) => {
window.location.hash = `/mf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9MZWdhR2VuaWUtTWljcm9hcHBWMi9yZW1vdGVFbnRyeS5qcw==&moduleToLoad=AppRoutes&remoteName=legageniemicroapp/legagenie?${data.objectId}`;
};
//component to handle type of document and render according to type
const handleFolderData = (data, ind, listType) => {
// console.log("data", data);
let createddate,
status,
isDecline,
signerExist,
isExpire,
isComplete,
signUrl,
isPlaceholder;
let createddate, status, isDecline, signerExist, isComplete, isPlaceholder;
if (data.Type !== "Folder") {
const expireDate = data.ExpiryDate && data.ExpiryDate.iso;
const createdDate = data.createdAt && data.createdAt;
@@ -183,67 +297,51 @@ function PdfFileComponent({
isDecline = data.IsDeclined && data.IsDeclined;
isPlaceholder = data.Placeholders && data.Placeholders;
signerExist = data.Signers && data.Signers;
signUrl = data.SignedUrl && data.SignedUrl;
const expireUpdateDate = new Date(expireDate).getTime();
const currDate = new Date().getTime();
let isExpire = false;
if (currDate > expireUpdateDate) {
isExpire = true;
} else {
isExpire = false;
}
if (isComplete) {
status = "Completed";
} else if (isDecline) {
status = "Declined";
} else if (isExpire && !isPlaceholder && signerExist) {
// status = "Expired";
} else if (!signerExist || signerExist?.length === 0) {
status = "Draft";
} else if (isExpire && !isPlaceholder && !signerExist && !signUrl) {
// status = "Expired";
} else if (
signerExist?.length > 0 &&
(!isPlaceholder || isPlaceholder?.length === 0)
) {
status = "Draft";
} else if (isExpire) {
status = "Expired";
} else if (!signUrl) {
status = "Draft";
} else {
status = "InComplete";
status = "In Progress";
}
}
const handleDraftDoc = (data) => {
window.location.hash = `/mf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9MZWdhR2VuaWUtTWljcm9hcHBWMi9yZW1vdGVFbnRyeS5qcw==&moduleToLoad=AppRoutes&remoteName=legageniemicroapp/legagenie?${data.objectId}`;
const signersName = () => {
const getSignersName = signerExist.map((data) => data.Name);
const signerName = getSignersName.join(",");
return (
<span
className="statusSpan"
style={{ width: "90%", wordWrap: "break-word" }}
>
{signerName}{" "}
</span>
);
};
const handleMenuItemClick = (selectType, data) => {
// console.log("data",data)
if (selectType === "Download") {
// console.log("download")
const pdfName = data && data.Name;
const pdfUrl = data && data.SignedUrl ? data.SignedUrl : data.URL;
saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
} else if (selectType === "Rename") {
// console.log("rename")
setRenameValue(data.Name);
setRename(data.objectId);
}
};
const sanitizeFileName = (pdfName) => {
// Replace spaces with underscore
return pdfName.replace(/ /g, '_');
}
const handleEnterPress = (e, data) => {
if (e.key === "Enter") {
handledRenameDoc(data);
}
};
return listType === "table" ? (
data.Type === "Folder" ? (
<tr onClick={() => handleOnclikFolder(data)}>
<td>
<td
style={{ cursor: "pointer", display: "flex", alignItems: "center" }}
>
<i
className="fa fa-folder"
aria-hidden="true"
@@ -261,7 +359,9 @@ function PdfFileComponent({
</tr>
) : data.Type === "AIDoc" ? (
<tr onClick={() => handleDraftDoc(data)}>
<td>
<td
style={{ cursor: "pointer", display: "flex", alignItems: "center" }}
>
<i
className="fa fa-file-text"
style={{ color: "#0ea3ed", marginRight: "8px", fontSize: "26px" }}
@@ -278,7 +378,9 @@ function PdfFileComponent({
</tr>
) : (
<tr onClick={() => checkPdfStatus(data)}>
<td>
<td
style={{ cursor: "pointer", display: "flex", alignItems: "center" }}
>
<i
className="fa fa-file-pdf"
style={{ color: "#ed4d0e", marginRight: "8px", fontSize: "26px" }}
@@ -312,7 +414,7 @@ function PdfFileComponent({
style={{
display: "flex",
flexDirection: "column",
cursor: "pointer",
cursor: "pointer"
}}
>
<img
@@ -333,7 +435,6 @@ function PdfFileComponent({
}}
autoFocus={true}
type="text"
// onFocus={()=>console.log("focus")}
onBlur={() => handledRenameDoc(data)}
onKeyDown={(e) => handleEnterPress(e, data)}
ref={inputRef}
@@ -344,7 +445,7 @@ function PdfFileComponent({
width: "100px",
border: "1.5px solid black",
borderRadius: "2px",
fontSize: "10px",
fontSize: "10px"
}}
/>
) : (
@@ -359,19 +460,12 @@ function PdfFileComponent({
sideOffset={5}
align="end"
>
{/* <ContextMenu.Item
onClick={() => handleMenuItemClick("Download", data)}
onSelect={(e) => console.log("event", e)}
className="ContextMenuItem"
>
Download
</ContextMenu.Item> */}
<ContextMenu.Item
onClick={() => handleMenuItemClick("Rename", data)}
className="ContextMenuItem"
>
Rename
<i class="fa-solid fa-font"></i>
<span style={{ marginLeft: "8px" }}>Rename</span>
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
@@ -385,7 +479,7 @@ function PdfFileComponent({
style={{
display: "flex",
flexDirection: "column",
cursor: "pointer",
cursor: "pointer"
}}
>
<img
@@ -406,7 +500,6 @@ function PdfFileComponent({
}}
autoFocus={true}
type="text"
// onFocus={()=>console.log("focus")}
onBlur={() => handledRenameDoc(data)}
onKeyDown={(e) => handleEnterPress(e, data)}
ref={inputRef}
@@ -417,7 +510,7 @@ function PdfFileComponent({
width: "100px",
border: "1.5px solid black",
borderRadius: "2px",
fontSize: "10px",
fontSize: "10px"
}}
/>
) : (
@@ -432,26 +525,19 @@ function PdfFileComponent({
sideOffset={5}
align="end"
>
{/* <ContextMenu.Item
onClick={() => handleMenuItemClick("Download", data)}
onSelect={(e) => console.log("event", e)}
className="ContextMenuItem"
>
Download
</ContextMenu.Item> */}
<ContextMenu.Item
onClick={() => handleMenuItemClick("Rename", data)}
className="ContextMenuItem"
>
Rename
<i class="fa-solid fa-font"></i>
<span style={{ marginLeft: "8px" }}>Rename</span>
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
</div>
) : (
<HoverCard.Root>
<HoverCard.Root openDelay={0} closeDelay={100}>
<HoverCard.Trigger asChild>
<div>
<ContextMenu.Root>
@@ -484,7 +570,7 @@ function PdfFileComponent({
width: "100px",
border: "1.5px solid black",
borderRadius: "2px",
fontSize: "10px",
fontSize: "10px"
}}
/>
) : (
@@ -508,7 +594,7 @@ function PdfFileComponent({
<i className="fa fa-file"></i>
</div>
) : (
status === "InComplete" && (
status === "In Progress" && (
<div className="status-badge in-progress">
<i className="fa fa-paper-plane"></i>
</div>
@@ -522,20 +608,18 @@ function PdfFileComponent({
sideOffset={5}
align="end"
>
<ContextMenu.Item
onClick={() => handleMenuItemClick("Download", data)}
onSelect={(e) => console.log("event", e)}
className="ContextMenuItem"
>
Download
</ContextMenu.Item>
<ContextMenu.Item
onClick={() => handleMenuItemClick("Rename", data)}
className="ContextMenuItem"
>
Rename
</ContextMenu.Item>
{contextMenu.map((menu, ind) => {
return (
<ContextMenu.Item
key={ind}
onClick={() => handleMenuItemClick(menu.type, data)}
className="ContextMenuItem"
>
<i class={menu.icon}></i>
<span style={{ marginLeft: "8px" }}>{menu.type}</span>
</ContextMenu.Item>
);
})}
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
@@ -558,56 +642,110 @@ function PdfFileComponent({
{signerExist && (
<>
<strong style={{ fontSize: "13px" }}>Signers: </strong>
{signerExist.map((data, key) => {
return (
<React.Fragment key={key}>
<span className="statusSpan">{data.Name}, </span>
</React.Fragment>
);
})}
{/* <span className="statusSpan">kjefjjnejkfnkbjs bbfjkdsbjbfjkbjk kscbjkbjkb</span> */}
{signersName()}
</>
)}
<HoverCard.Arrow className="HoverCardArrow" />
</HoverCard.Content>
</HoverCard.Portal>
</HoverCard.Root>
);
};
//component to handle type of document and render according to type
return isList ? (
<div className="container" style={{overflowX:"auto"}}>
<Table striped bordered hover >
<thead>
<tr>
<th>Name</th>
<th>Created Date</th>
<th>Type</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
//component to handle type of document and render according to type
return (
<>
{isList ? (
<div className="container" style={{ overflowX: "auto" }}>
<Table striped bordered hover>
<thead>
<tr>
<th>Name</th>
<th>Created Date</th>
<th>Type</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{pdfData.map((data, ind) => {
return (
<React.Fragment key={ind}>
{handleFolderData(data, ind, "table")}
</React.Fragment>
);
})}
</tbody>
</Table>
</div>
) : (
<div className="pdfContainer">
{pdfData.map((data, ind) => {
return (
<React.Fragment key={ind}>
{handleFolderData(data, ind, "table")}
</React.Fragment>
<div className="box" key={ind}>
{handleFolderData(data, ind, "list")}
</div>
);
})}
</tbody>
</Table>
</div>
) : (
<div className="pdfContainer">
{pdfData.map((data, ind) => {
return (
<div className="box" key={ind}>
{handleFolderData(data, ind, "list")}
</div>
);
})}
</div>
</div>
)}
{isOpenMoveModal && (
<SelectFolder
onSuccess={handleMoveFolder}
isOpenModal={isOpenMoveModal}
folderCls={"contracts_Document"}
setIsOpenMoveModal={setIsOpenMoveModal}
setPdfData={setPdfData}
/>
)}
<ModalUi
isOpen={isDeleteDoc}
headerColor={themeColor()}
title={"Delete Document"}
handleClose={() => {
setIsDeleteDoc(false);
}}
>
<div style={{ height: "100%", padding: 20 }}>
<p>Are you sure you want to delete this document?</p>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginTop: "15px",
marginBottom: "15px"
}}
></div>
<button
onClick={() => {
handleDeleteDocument(selectDoc);
}}
style={{
background: themeColor(),
color: "white"
}}
type="button"
className="finishBtn"
>
Yes
</button>
<button
onClick={() => {
setIsDeleteDoc(false);
}}
type="button"
className="finishBtn cancelBtn"
>
No
</button>
</div>
</ModalUi>
</>
);
}
@@ -6,12 +6,13 @@
.ContextMenuContent,
.ContextMenuSubContent {
min-width: 150px;
min-width: 135px;
background-color: white;
border-radius: 6px;
overflow: hidden;
padding: 5px;
box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35), 0px 10px 20px -15px rgba(22, 23, 24, 0.2);
z-index: 99;
}
.ContextMenuItem,
@@ -27,7 +28,7 @@
height: 25px;
padding: 0 5px;
position: relative;
padding-left: 25px;
padding-left: 15px;
user-select: none;
outline: none;
}
@@ -84,14 +85,10 @@
color: var(--mauve-8);
}
.dropdown-menu {
min-width: 10rem;
}
.dropdown-item {
display: block;
width: 100%;
@@ -103,26 +100,25 @@
white-space: nowrap;
background-color: transparent;
border: 0;
cursor: pointer;
}
.dropdown-item:hover {
background-color: #dad9db;
color: var(--violet-11);
}
.itemColor {
font-size: 13px !important;
}
.folderComponent {
margin: 30px;
height: 100%;
}
.inputStyle{
border: 1.6px solid #ccc !important;
}
.folderComponent::-webkit-scrollbar {
display: none;
/* for Chrome, Safari, and Opera */
@@ -402,6 +398,7 @@ a {
will-change: transform, opacity;
text-align: center;
align-items: center;
}
.HoverCardContent[data-side='top'] {
@@ -490,41 +487,74 @@ a {
display: none;
}
.folderPath{
.folderPath {
overflow-x: auto;
white-space: nowrap;
cursor: pointer;
user-select: none;
}
.folderPath::-webkit-scrollbar {
}
.folderPath::-webkit-scrollbar {
display: none;
/* for Chrome, Safari, and Opera */
}
.docDeleteBtn {
/* box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18); */
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
padding: 7px 17px;
color: white;
font-weight: 600 !important;
font-size: 12px !important;
border: none;
border-radius: 2px;
}
.docDeleteBtn:focus {
border: none;
outline: none;
}
.docDeleteBtn:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
color: white;
}
@media screen and (max-width:766px) {
.itemColor {
font-size: 10px !important;
}
}
@media (min-width: 310px) and (max-width:550px) {
.pdfContainer {
justify-content: space-around;
}
.sort {
padding: 2px;
padding: 2px;
}
.folderComponent{
.folderComponent {
margin: 10px;
}
}
@media screen and (max-width:309px) {
@media screen and (max-width:309px) {
.pdfContainer {
justify-content: center;
}
.sort {
padding: 2px;
}
.folderComponent{
margin: 10px;
}
}
.folderComponent {
margin: 10px;
}
}
@@ -1,14 +1,16 @@
import React, { useEffect, useState, useRef } from "react";
import axios from "axios";
import "./LegaDrive.css";
import loader from "../../assests/loader2.gif";
import PdfFileComponent from "./FolderDrive/legaDriveComponent";
import Modal from "react-bootstrap/Modal";
import ModalHeader from "react-bootstrap/esm/ModalHeader";
import { themeColor, iconColor } from "../../utils/ThemeColor/backColor";
import { getDrive } from "../../utils/Utils";
import { useNavigate } from "react-router-dom";
import Title from "../component/Title";
import Parse from "parse";
import ModalUi from "../../premitives/ModalUi";
function PdfFile() {
const navigate = useNavigate();
const scrollRef = useRef(null);
const [isList, setIsList] = useState(false);
const [selectedSort, setSelectedSort] = useState("Date");
@@ -24,9 +26,18 @@ function PdfFile() {
message: "This might take some time"
});
const [docId, setDocId] = useState();
const [handleError, setHandleError] = useState();
const [handleError, setHandleError] = useState("");
const [folderName, setFolderName] = useState([]);
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
const [isNewFol, setIsNewFol] = useState(false);
const currentUser =
localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
) &&
localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
);
const jsonCurrentUser = JSON.parse(currentUser);
useEffect(() => {
if (docId) {
@@ -42,30 +53,38 @@ function PdfFile() {
isLoad: true,
message: "This might take some time"
};
let driveDetails;
setIsLoading(load);
const driveDetails = await getDrive();
if (driveDetails) {
if (driveDetails.length > 0) {
setPdfData(driveDetails);
}
const data = [
{
name: "OpenSignDrive™",
objectId: ""
try {
driveDetails = await getDrive();
if (driveDetails) {
if (driveDetails.length > 0) {
setPdfData(driveDetails);
sortApps(null, null, driveDetails);
}
];
setFolderName(data);
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
} else if (driveDetails === "Error: Something went wrong!") {
const loadObj = {
isLoad: false
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
const data = [
{
name: "OpenSign™ Drive",
objectId: ""
}
];
setFolderName(data);
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
} else if (driveDetails === "Error: Something went wrong!") {
const loadObj = {
isLoad: false
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
}
} catch (e) {
setIsAlert({
isShow: true,
alertMessage: "something went wrong"
});
}
};
//function for get parent folder document list
@@ -75,23 +94,33 @@ function PdfFile() {
message: "This might take some time"
};
setIsLoading(load);
const driveDetails = await getDrive(docId);
if (driveDetails) {
if (driveDetails.length > 0) {
setPdfData(driveDetails);
} else {
setPdfData([]);
let driveDetails;
try {
driveDetails = await getDrive(docId);
if (driveDetails) {
if (driveDetails.length > 0) {
setPdfData(driveDetails);
sortApps(null, null, driveDetails);
} else {
setPdfData([]);
}
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
} else if (driveDetails === "Error: Something went wrong!") {
const loadObj = {
isLoad: false
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
}
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
} else if (driveDetails === "Error: Something went wrong!") {
const loadObj = {
isLoad: false
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
} catch (e) {
setIsAlert({
isShow: true,
alertMessage: "something went wrong!"
});
}
};
@@ -100,43 +129,16 @@ function PdfFile() {
setIsFolder(true);
};
//function for handle folder name path
const handleRoute = (data) => {
let loadObj = {
isLoad: true,
message: "This might take some time"
};
if (data.name === "LegaDrive™") {
setIsLoading(loadObj);
if (docId) {
setDocId();
} else {
setTimeout(() => {
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
}, 1000);
const handleRoute = (index) => {
const updateFolderName = folderName.filter((x, i) => {
if (i <= index) {
return x;
}
} else if (data.name === folderName[folderName.length - 1].name) {
setIsLoading(loadObj);
setTimeout(() => {
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
}, 1000);
} else {
const findIndex = folderName.findIndex(
(fold) => fold.objectId === data.objectId
);
const newFolder = folderName.slice(0, findIndex + 1);
});
setFolderName(newFolder);
const getLastId = newFolder[newFolder.length - 1];
setDocId(getLastId.objectId);
setIsLoading(loadObj);
}
setFolderName(updateFolderName);
const getLastId = updateFolderName[updateFolderName.length - 1];
setDocId(getLastId.objectId);
};
//function for add new folder name
@@ -145,67 +147,60 @@ function PdfFile() {
const value = e.target.value;
setNewFolderName(value);
};
//function for add folder
//function for create folder
const handleAddFolder = async () => {
if (newFolderName) {
setIsFolderLoader(true);
const getParentObjId = folderName[folderName.length - 1];
const isParentId = getParentObjId && getParentObjId.objectId;
let data;
if (isParentId) {
data = {
Name: newFolderName,
Type: "Folder",
Folder: {
__type: "Pointer",
className: `${localStorage.getItem("_appName")}_Document`,
objectId: isParentId
}
};
} else {
data = {
Name: newFolderName,
Type: "Folder"
};
}
const parentId = getParentObjId && getParentObjId.objectId;
const foldercls = `${localStorage.getItem("_appName")}_Document`;
const folderPtr = {
__type: "Pointer",
className: foldercls,
objectId: parentId
};
const CreatedBy = {
__type: "Pointer",
className: "_User",
objectId: jsonCurrentUser.objectId
};
// console.log("data", data);
await axios
.post(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document`,
data,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
)
try {
const exsitQuery = new Parse.Query(foldercls);
exsitQuery.equalTo("Name", newFolderName);
exsitQuery.equalTo("Type", "Folder");
if (parentId) {
exsitQuery.equalTo("Folder", folderPtr);
}
const templExist = await exsitQuery.first();
if (templExist) {
setError("Folder already exist!");
setIsFolderLoader(false);
} else {
const template = new Parse.Object(foldercls);
template.set("Name", newFolderName);
template.set("Type", "Folder");
.then((Listdata) => {
// console.log("Listdata ", Listdata);
const json = Listdata.data;
// console.log("json ", json);
if (json) {
if (parentId) {
template.set("Folder", folderPtr);
}
template.set("CreatedBy", CreatedBy);
const res = await template.save();
if (res) {
const result = JSON.parse(JSON.stringify(res));
setPdfData((prev) => [...prev, result]);
setNewFolderName();
setIsFolderLoader(false);
setIsFolder(false);
if (docId) {
getPdfFolderDocumentList();
} else {
getPdfDocumentList();
}
}
})
.catch((err) => {
console.log("axois err ", err);
alert("something went wrong");
}
} catch (e) {
setIsAlert({
isShow: true,
alertMessage: "something went wrong!"
});
}
} else {
setError("Please fill out this field");
}
@@ -227,11 +222,11 @@ function PdfFile() {
}
};
const sortApps = () => {
const selectedSortType = selectedSort;
const sortOrder = sortingOrder;
const sortApps = (type, order, driveDetails) => {
const selectedSortType = type ? type : selectedSort ? selectedSort : "Date";
const sortOrder = order ? order : sortingOrder ? sortingOrder : "Decending";
let sortingData = pdfData;
let sortingData = driveDetails;
if (selectedSortType === "Name") {
sortingApp(sortingData, "Name", sortOrder);
} else if (selectedSortType === "Date") {
@@ -293,7 +288,9 @@ function PdfFile() {
useEffect(() => {
const closeMenuOnOutsideClick = (e) => {
if (isShowSort && !e.target.closest("#menu-container")) {
setIsShowSort(false);
setIsShowSort(!isShowSort);
} else if (isNewFol && !e.target.closest("#folder-menu")) {
setIsNewFol(!isNewFol);
}
};
@@ -303,28 +300,88 @@ function PdfFile() {
// Cleanup the event listener when the component unmounts
document.removeEventListener("click", closeMenuOnOutsideClick);
};
}, [isShowSort]);
}, [isShowSort || isNewFol]);
const handleFolderTab = (folderData, isMove) => {
return folderData.map((data, id) => {
return (
<React.Fragment key={id}>
<span
onClick={() => handleRoute(id)}
style={{
color: "#a64b4e",
fontWeight: "400",
cursor: "pointer"
}}
>
{data.name}
<span
style={{
color: "#a64b4e",
fontWeight: "200",
cursor: "pointer",
margin: "0 4px"
}}
>
&gt;
</span>
</span>
</React.Fragment>
);
});
};
const oncloseFolder = () => {
setIsFolder(false);
setNewFolderName("");
setError("");
};
return (
<div className="folderComponent ">
<Title title={"OpenSign™ Drive"} drive={true} />
<div>
<Modal show={isFolder}>
<ModalHeader style={{ background: themeColor() }}>
<span style={{ color: "white" }}>Add New Folder</span>
{!folderLoader && (
<span
style={{ cursor: "pointer" }}
onClick={() => {
setNewFolderName("");
setIsFolder(false);
}}
>
X
</span>
)}
</ModalHeader>
<ModalUi
headerColor={"#dc3545"}
isOpen={isAlert.isShow}
title={"Alert"}
handleClose={() => {
setIsAlert({
isShow: false,
alertMessage: ""
});
}}
>
<div style={{ height: "100%", padding: 20 }}>
<p>{isAlert.alertMessage}</p>
<Modal.Body>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginTop: "15px",
marginBottom: "15px"
}}
></div>
<button
onClick={() =>
setIsAlert({
isShow: false,
alertMessage: ""
})
}
type="button"
className="finishBtn cancelBtn"
>
Close
</button>
</div>
</ModalUi>
<ModalUi
isOpen={isFolder}
title={"Add New Folder"}
handleClose={oncloseFolder}
>
<div style={{ height: "100%", padding: 20 }}>
{folderLoader ? (
<div
style={{
@@ -345,7 +402,13 @@ function PdfFile() {
</span>
</div>
) : (
<form style={{ display: "flex", flexDirection: "column" }}>
<form
onSubmit={(e) => {
e.preventDefault();
handleAddFolder();
}}
style={{ display: "flex", flexDirection: "column" }}
>
<label
style={{
margin: "10px 0px 10px 0px",
@@ -353,57 +416,54 @@ function PdfFile() {
fontWeight: "400"
}}
>
Name*
Name
<span style={{ color: "red" }}>*</span>
</label>
<input
required
className="form-control"
className="form-control inputStyle"
type="text"
value={newFolderName}
onChange={(e) => handleFolderName(e)}
// className="addFolderInput"
/>
<span style={{ color: "red", fontSize: "12px" }}>{error}</span>
<span
style={{ color: "red", fontSize: "12px", marginTop: "6px" }}
>
{error}
</span>
<div
style={{
margin: "20px 10px 10px 10px ",
display: "flex",
alignItems: "flex-end",
justifyContent: "flex-end",
alignContent: "flex-end"
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginTop: "15px",
marginBottom: "15px"
}}
>
></div>
<div style={{ display: "flex", flexDirection: "row" }}>
<button
type="submit"
style={{
borderRadius: "0px",
border: "1.5px solid #e3e2e1",
fontWeight: "600",
color: "black"
}}
className="finishBtn"
onClick={() => setIsFolder(false)}
>
Close
</button>
<button
onClick={() => handleAddFolder()}
style={{
background: themeColor()
}}
type="button"
type="submit"
className="finishBtn"
>
Add
</button>
<button
type="button"
className="finishBtn cancelBtn"
onClick={oncloseFolder}
>
Close
</button>
</div>
</form>
)}
</Modal.Body>
</Modal>
</div>
</ModalUi>
{isLoading.isLoad ? (
<div
@@ -450,33 +510,72 @@ function PdfFile() {
}}
className="folderPath"
>
{folderName.map((data, id) => {
return (
<span
key={id}
onClick={() => handleRoute(data)}
style={{
color: "#a64b4e",
fontWeight: "400",
cursor: "pointer"
}}
>
{data.name}
<span
style={{
color: "#a64b4e",
fontWeight: "200",
cursor: "pointer",
margin: "0 4px"
}}
>
&gt;
</span>
</span>
);
})}
{handleFolderTab(folderName)}
</div>
<div className="dropMenuBD">
<div
id="folder-menu"
className={
isNewFol ? "dropdown show dropDownStyle" : "dropdown"
}
onClick={() => setIsNewFol(!isNewFol)}
>
<div className="sort">
<i
className="fa fa-plus-square"
aria-hidden="true"
style={{ fontSize: "25px", color: `${iconColor()}` }}
></i>
</div>
<div
className={
isNewFol ? "dropdown-menu show" : "dropdown-menu"
}
aria-labelledby="dropdownMenuButton"
aria-expanded={isNewFol ? "true" : "false"}
>
{" "}
<div
style={{
display: "flex",
flexDirection: "column"
}}
>
<span
className="dropdown-item itemColor"
onClick={() => getParentFolder()}
>
<i
style={{ marginRight: "5px" }}
className="fa fa-plus"
aria-hidden="true"
></i>
Create folder
</span>
<span
className="dropdown-item itemColor"
onClick={() => navigate("/form/sHAnZphf69")}
>
<i
style={{ marginRight: "5px" }}
className="fas fa-pen-nib"
></i>
Sign Yourself
</span>
<span
className="dropdown-item itemColor"
onClick={() => navigate("/form/8mZzFxbG1z")}
>
{" "}
<i
style={{ marginRight: "5px" }}
className="fa fa-file-signature"
></i>
Request Signatures{" "}
</span>
</div>
</div>
</div>
<div
id="menu-container"
className={isShowSort ? "dropdown show" : "dropdown"}
@@ -511,7 +610,7 @@ function PdfFile() {
<span
onClick={() => {
setSelectedSort("Name");
sortApps();
sortApps("Name", null, pdfData);
}}
className="dropdown-item itemColor"
>
@@ -533,7 +632,7 @@ function PdfFile() {
<span
onClick={() => {
setSelectedSort("Date");
sortApps();
sortApps("Date", null, pdfData);
}}
className="dropdown-item itemColor"
>
@@ -556,7 +655,7 @@ function PdfFile() {
<span
onClick={() => {
setSortingOrder("Accending");
sortApps();
sortApps(null, "Accending", pdfData);
}}
className="dropdown-item itemColor"
>
@@ -578,7 +677,7 @@ function PdfFile() {
<span
onClick={() => {
setSortingOrder("Decending");
sortApps();
sortApps(null, "Decending", pdfData);
}}
className="dropdown-item itemColor"
>
@@ -620,14 +719,6 @@ function PdfFile() {
</div>
)}
</div>
<div className="sort" onClick={() => getParentFolder()}>
<i
className="fa fa-plus-square"
aria-hidden="true"
style={{ fontSize: "25px", color: `${iconColor()}` }}
></i>
</div>
</div>
</div>
@@ -654,6 +745,7 @@ function PdfFile() {
isDocId={docId}
setPdfData={setPdfData}
isList={isList}
setIsAlert={setIsAlert}
/>
)}
</>
@@ -157,7 +157,7 @@ const ManageSign = () => {
file = base64StringtoFile(image, `${replaceSpace}.png`);
}
}
console.log("isUrl ", isUrl);
// console.log("isUrl ", isUrl);
let imgUrl;
if (!isUrl) {
imgUrl = await uploadFile(file);
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect } from "react";
import { PDFDocument, rgb } from "pdf-lib";
import { PDFDocument } from "pdf-lib";
import "../css/./signature.css";
import sign from "../assests/sign3.png";
import stamp from "../assests/stamp2.png";
@@ -13,12 +13,13 @@ import { useDrag, useDrop } from "react-dnd";
import SignPad from "./component/signPad";
import EmailComponent from "./component/emailComponent";
import FieldsComponent from "./component/fieldsComponent";
import Modal from "react-bootstrap/Modal";
import ModalHeader from "react-bootstrap/esm/ModalHeader";
import {
convertPNGtoJPEG,
contractDocument,
getBase64FromIMG
embedDocId,
multiSignEmbed,
pdfNewWidthFun,
addDefaultSignatureImg,
onImageSelect
} from "../utils/Utils";
import { useParams } from "react-router-dom";
import Tour from "reactour";
@@ -28,9 +29,12 @@ import HandleError from "./component/HandleError";
import Nodata from "./component/Nodata";
import Header from "./component/header";
import RenderPdf from "./component/renderPdf";
import { contractUsers, contactBook, urlValidator } from "../utils/Utils";
import { modalAlign } from "../utils/Utils";
import { $ } from "select-dom";
import { contractUsers, contactBook } from "../utils/Utils";
import PlaceholderCopy from "./component/PlaceholderCopy";
import TourContentWithBtn from "../premitives/TourContentWithBtn";
import Title from "./component/Title";
import ModalUi from "../premitives/ModalUi";
//For signYourself inProgress section signer can add sign and complete doc sign.
function SignYourSelf() {
const [pdfDetails, setPdfDetails] = useState([]);
@@ -72,6 +76,8 @@ function SignYourSelf() {
const [tourStatus, setTourStatus] = useState([]);
const [noData, setNoData] = useState(false);
const [contractName, setContractName] = useState("");
const [containerWH, setContainerWH] = useState({});
const [isPageCopy, setIsPageCopy] = useState(false);
const [showAlreadySignDoc, setShowAlreadySignDoc] = useState({
status: false
});
@@ -79,7 +85,9 @@ function SignYourSelf() {
status: false,
type: "load"
});
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
const [isDontShow, setIsDontShow] = useState(false);
const divRef = useRef(null);
const nodeRef = useRef(null);
const [{ isOver }, drop] = useDrop({
accept: "BOX",
@@ -88,12 +96,12 @@ function SignYourSelf() {
isOver: !!monitor.isOver()
})
});
const isMobile = window.innerWidth < 767;
const pdfRef = useRef();
const [{ isDragSign }, dragSignature] = useDrag({
type: "BOX",
item: {
type: "BOX",
id: 1,
@@ -106,7 +114,6 @@ function SignYourSelf() {
const [{ isDragStamp }, dragStamp] = useDrag({
type: "BOX",
item: {
type: "BOX",
id: 2,
@@ -131,7 +138,6 @@ function SignYourSelf() {
const [{ isDragStampSS }, dragStampSS] = useDrag({
type: "BOX",
item: {
type: "BOX",
id: 4,
@@ -166,17 +172,22 @@ function SignYourSelf() {
const jsonSender = JSON.parse(senderUser);
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) {
getDocumentDetails(true);
}
}, []);
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
const getDocumentDetails = async (showComplete) => {
//getting document details
@@ -186,18 +197,19 @@ function SignYourSelf() {
setPdfDetails(documentData);
const isCompleted =
documentData[0].IsCompleted && documentData[0].IsCompleted;
if (isCompleted && showComplete) {
if (isCompleted) {
const docStatus = {
isCompleted: isCompleted
};
setDocumentStatus(docStatus);
setPdfUrl(documentData[0].SignedUrl);
const alreadySign = {
status: true,
mssg: "You have successfully signed the document!"
};
setShowAlreadySignDoc(alreadySign);
setPdfUrl(documentData[0].SignedUrl);
if (showComplete) {
setShowAlreadySignDoc(alreadySign);
}
}
} else if (
documentData === "Error: Something went wrong!" ||
@@ -314,7 +326,6 @@ function SignYourSelf() {
isDrag: false,
key: key,
isStamp: monitor,
yBottom: window.innerHeight / 2 - 60
};
@@ -390,14 +401,22 @@ function SignYourSelf() {
for (let i = 0; i < xyPostion.length; i++) {
const posData = xyPostion[i].pos.filter((pos) => !pos.SignUrl);
if (posData && posData.length > 0) {
checkSignUrl.push(posData);
}
}
if (checkSignUrl && checkSignUrl.length > 0) {
alert("Please complete your signature!");
if (xyPostion.length === 0) {
setIsAlert({
isShow: true,
alertMessage: "Please complete your signature!"
});
return;
} else if (xyPostion.length > 0 && checkSignUrl.length > 0) {
setIsAlert({
isShow: true,
alertMessage: "Please complete your signature!"
});
return;
} else {
setIsCeleb(true);
setTimeout(() => {
@@ -418,144 +437,22 @@ function SignYourSelf() {
const pdfDoc = await PDFDocument.load(existingPdfBytes, {
ignoreEncryption: true
});
const pngUrl = xyPostion;
//checking if signature is only one then send image url in jpeg formate to server
if (xyPostion.length === 1 && xyPostion[0].pos.length === 1) {
//embed document's object id to all pages in pdf document
for (let i = 0; i < allPages; i++) {
const font = await pdfDoc.embedFont("Helvetica");
const fontSize = 10;
const textContent =
documentId && `OpenSign™ DocumentId: ${documentId}`;
const flag = true;
//embed document's object id to all pages in pdf document
await embedDocId(pdfDoc, documentId, allPages);
const pages = pdfDoc.getPages();
const page = pages[i];
//embed multi signature in pdf
const pdfBytes = await multiSignEmbed(
xyPostion,
pdfDoc,
pdfOriginalWidth,
flag,
containerWH
);
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({
useObjectStreams: false
});
for (let i = 0; i < xyPostion.length; i++) {
const imgUrlList = xyPostion[i].pos;
const pageNo = xyPostion[i].pageNumber;
imgUrlList.map(async (data) => {
let ImgUrl = data.SignUrl;
//cheking signUrl is defau;t signature url of custom url
const checkUrl = urlValidator(ImgUrl);
//if default signature url then convert it in base 64
if (checkUrl) {
ImgUrl = await getBase64FromIMG(ImgUrl + "?get");
}
//function for convert signature png base64 url to jpeg base64
convertPNGtoJPEG(ImgUrl)
.then((jpegBase64Data) => {
const removeBase64Fromjpeg = "data:image/jpeg;base64,";
const newImgUrl = jpegBase64Data.replace(
removeBase64Fromjpeg,
""
);
//function for call to embed signature in pdf and get digital signature pdf
signPdfFun(newImgUrl, documentId, data, pdfBase64, pageNo);
})
.catch((error) => {
console.error("Error:", error);
});
});
}
}
//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) {
for (let i = 0; i < allPages; i++) {
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)
});
}
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;
if (url.ImageType === "image/png") {
//function for convert signature png base64 url to jpeg base64
const newUrl = await convertPNGtoJPEG(signUrl);
signUrl = newUrl;
}
const checkUrl = urlValidator(signUrl);
if (checkUrl) {
signUrl = signUrl + "?get";
}
const res = await fetch(signUrl);
return res.arrayBuffer();
})
);
images.forEach(async (imgData, id) => {
let img = await pdfDoc.embedJpg(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 (isMobile) {
if (id === 0) {
return (
page.getHeight() -
imgUrlList[id].yPosition * scale -
imgHeight
);
} else if (id > 0) {
return page.getHeight() - imgUrlList[id].yPosition * scale;
}
} else {
return page.getHeight() - imgUrlList[id].yPosition - imgHeight;
}
};
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);
}
//function for call to embed signature in pdf and get digital signature pdf
signPdfFun(pdfBytes, documentId);
setIsSignPad(false);
setIsEmail(true);
setXyPostion([]);
@@ -564,47 +461,11 @@ function SignYourSelf() {
}
//function for get digital signature
const signPdfFun = async (
base64Url,
documentId,
xyPosData,
pdfBase64Url,
pageNo
) => {
let singleSign;
const isMobile = window.innerWidth < 767;
const newWidth = window.innerWidth;
const scale = isMobile ? pdfOriginalWidth / newWidth : 1;
const imgWidth = xyPosData ? xyPosData.Width : 150;
if (xyPostion.length === 1 && xyPostion[0].pos.length === 1) {
const height = xyPosData.Height ? xyPosData.Height : 60;
const bottomY = xyPosData.isDrag
? xyPosData.yBottom * scale - height
: xyPosData.firstYPos
? xyPosData.yBottom * scale - height + xyPosData.firstYPos
: xyPosData.yBottom * scale - height;
singleSign = {
pdfFile: pdfBase64Url,
docId: documentId,
sign: {
Base64: base64Url,
Left: isMobile
? xyPosData.xPosition * scale + imgWidth / 2
: xyPosData.xPosition,
Bottom: bottomY,
Width: xyPosData.Width ? xyPosData.Width : 150,
Height: height,
Page: pageNo
}
};
} else if (xyPostion.length > 0 && xyPostion[0].pos.length > 0) {
singleSign = {
pdfFile: base64Url,
docId: documentId
};
}
const signPdfFun = async (base64Url, documentId) => {
const singleSign = {
pdfFile: base64Url,
docId: documentId
};
await axios
.post(`${localStorage.getItem("baseUrl")}functions/signPdf`, singleSign, {
@@ -616,14 +477,13 @@ function SignYourSelf() {
})
.then((Listdata) => {
const json = Listdata.data;
// console.log("json ", json);
setPdfUrl(json.result.data);
if (json.result.data) {
getDocumentDetails(false);
}
})
.catch((err) => {
// this.setState({ loading: false });
console.log("axois err ", err);
});
};
@@ -702,54 +562,43 @@ function SignYourSelf() {
//function for image upload or update
const onImageChange = (event) => {
if (event.target.files && event.target.files[0]) {
const imageType = event.target.files[0].type;
const reader = new FileReader();
reader.readAsDataURL(event.target.files[0]);
reader.onloadend = function (e) {
let width, height;
const image = new Image();
image.src = e.target.result;
image.onload = function () {
width = image.width;
height = image.height;
const aspectRatio = 460 / 184;
const imgR = width / height;
if (imgR > aspectRatio) {
width = 460;
height = 460 / imgR;
} else {
width = 184 * imgR;
height = 184;
}
setImgWH({ width: width, height: height });
imageRef.current.style.width = `${width}px`;
imageRef.current.style.height = `${height}px`;
};
image.src = reader.result;
setImage({ src: image.src, imgType: imageType });
};
onImageSelect(event, setImgWH, setImage);
}
};
//function for upload stamp or image
const saveImage = () => {
const getImage = onSaveImage(xyPostion, index, signKey, imgWH, image);
setXyPostion(getImage);
};
//function for save button to save signature or image url
const saveSign = (isDefaultSign) => {
const saveSign = (isDefaultSign, width, height) => {
const isTypeText = width && height ? true : false;
const signatureImg = isDefaultSign ? defaultSignImg : signature;
let imgWH = { width: width ? width : "", height: height ? height : "" };
setIsSignPad(false);
setIsImageSelect(false);
setImage();
if (isDefaultSign) {
const img = new Image();
img.src = defaultSignImg;
if (img.complete) {
imgWH = {
width: img.width,
height: img.height
};
}
}
const getUpdatePosition = onSaveSign(
xyPostion,
index,
signKey,
signatureImg
signatureImg,
imgWH,
isDefaultSign,
isTypeText
);
setXyPostion(getUpdatePosition);
@@ -774,60 +623,6 @@ function SignYourSelf() {
setSignBtnPosition([xySignature]);
};
//function for resize image and update width and height
const handleImageResize = (ref, key, direction, position) => {
const updateFilter = xyPostion[index].pos.filter(
(data, ind) => data.key === key && data.Width && data.Height
);
if (updateFilter.length > 0) {
const getXYdata = xyPostion[index].pos;
const getPosData = getXYdata;
const addSign = getPosData.map((url, ind) => {
if (url.key === key) {
return {
...url,
Width: ref.offsetWidth,
Height: ref.offsetHeight,
xPosition: position.x
};
}
return url;
});
const newUpdateUrl = xyPostion.map((obj, ind) => {
if (ind === index) {
return { ...obj, pos: addSign };
}
return obj;
});
setXyPostion(newUpdateUrl);
} else {
const getXYdata = xyPostion[index].pos;
const getPosData = getXYdata;
const addSign = getPosData.map((url, ind) => {
if (url.key === key) {
return {
...url,
Width: ref.offsetWidth,
Height: ref.offsetHeight
};
}
return url;
});
const newUpdateUrl = xyPostion.map((obj, ind) => {
if (ind === index) {
return { ...obj, pos: addSign };
}
return obj;
});
setXyPostion(newUpdateUrl);
}
};
const handleAllDelete = () => {
setXyPostion([]);
};
@@ -862,47 +657,38 @@ function SignYourSelf() {
}
};
//function for upload stamp or image
const saveImage = () => {
const getImage = onSaveImage(xyPostion, index, signKey, imgWH, image);
setXyPostion(getImage);
};
//function for add default signature url in local array
const addDefaultSignature = () => {
let xyDefaultPos = [];
for (let i = 0; i < xyPostion.length; i++) {
const getXYdata = xyPostion[i].pos;
const getPageNo = xyPostion[i].pageNumber;
const getPosData = getXYdata;
const getXyData = addDefaultSignatureImg(xyPostion, defaultSignImg);
const addSign = getPosData.map((url, ind) => {
if (url) {
return { ...url, SignUrl: defaultSignImg };
}
return url;
});
const newXypos = {
pageNumber: getPageNo,
pos: addSign
};
xyDefaultPos.push(newXypos);
}
setXyPostion(xyDefaultPos);
setXyPostion(getXyData);
setShowAlreadySignDoc({ status: false });
};
const handleDontShow = (isChecked) => {
setIsDontShow(isChecked);
};
const tourConfig = [
{
selector: '[data-tut="reactourFirst"]',
content: `Drag the signature or stamp placeholder onto the PDF to choose your desired signing location.`,
content: () => (
<TourContentWithBtn
message={`Drag the signature or stamp placeholder onto the PDF to choose your desired signing location.`}
isChecked={handleDontShow}
/>
),
position: "top",
style: { fontSize: "13px" }
},
{
selector: '[data-tut="reactourSecond"]',
content: `Drag and drop anywhere in this area. You can resize and move it later.`,
content: () => (
<TourContentWithBtn
message={`Drag and drop anywhere in this area. You can resize and move it later.`}
isChecked={handleDontShow}
/>
),
position: "top",
style: { fontSize: "13px" }
}
@@ -911,47 +697,49 @@ function SignYourSelf() {
//function for update TourStatus
const closeTour = async () => {
setSignTour(false);
let updatedTourStatus = [];
if (tourStatus.length > 0) {
updatedTourStatus = [...tourStatus];
const signyourselfIndex = tourStatus.findIndex(
(obj) => obj["signyourself"] === false || obj["signyourself"] === true
);
if (signyourselfIndex !== -1) {
updatedTourStatus[signyourselfIndex] = { signyourself: true };
} else {
updatedTourStatus.push({ signyourself: true });
}
} else {
updatedTourStatus = [{ signyourself: true }];
}
await axios
.put(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}${contractName}/${signerUserId}`,
{
TourStatus: updatedTourStatus
},
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessionToken: localStorage.getItem("accesstoken")
}
if (isDontShow) {
let updatedTourStatus = [];
if (tourStatus.length > 0) {
updatedTourStatus = [...tourStatus];
const signyourselfIndex = tourStatus.findIndex(
(obj) => obj["signyourself"] === false || obj["signyourself"] === true
);
if (signyourselfIndex !== -1) {
updatedTourStatus[signyourselfIndex] = { signyourself: true };
} else {
updatedTourStatus.push({ signyourself: true });
}
)
.then((Listdata) => {
// const json = Listdata.data;
})
.catch((err) => {
console.log("axois err ", err);
});
} else {
updatedTourStatus = [{ signyourself: true }];
}
await axios
.put(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}${contractName}/${signerUserId}`,
{
TourStatus: updatedTourStatus
},
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessionToken: localStorage.getItem("accesstoken")
}
}
)
.then((Listdata) => {
// const json = Listdata.data;
})
.catch((err) => {
console.log("axois err ", err);
});
}
};
return (
<DndProvider backend={HTML5Backend}>
<Title title={"Self Sign"} />
{isLoading.isLoad ? (
<Loader isLoading={isLoading} />
) : handleError ? (
@@ -959,7 +747,7 @@ function SignYourSelf() {
) : noData ? (
<Nodata />
) : (
<div className="signatureContainer">
<div className="signatureContainer" ref={divRef}>
{/* this component used for UI interaction and show their functionality */}
{pdfLoadFail && !checkTourStatus && (
<Tour
@@ -980,57 +768,92 @@ function SignYourSelf() {
setAllPages={setAllPages}
setPageNumber={setPageNumber}
setSignBtnPosition={setSignBtnPosition}
pageNumber={pageNumber}
/>
{/* pdf render view */}
<div
style={{
marginLeft: pdfOriginalWidth > 500 && "20px",
marginRight: pdfOriginalWidth > 500 && "20px"
marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px",
marginRight: !isMobile && pdfOriginalWidth > 500 && "20px"
}}
>
{/* this modal is used show this document is already sign */}
<Modal
show={showAlreadySignDoc.status}
onShow={() => modalAlign()}
backdropClassName="signature-backdrop"
<ModalUi
headerColor={"#dc3545"}
isOpen={isAlert.isShow}
title={"Alert"}
handleClose={() => {
setIsAlert({
isShow: false,
alertMessage: ""
});
}}
>
<ModalHeader style={{ background: themeColor() }}>
<span style={{ color: "white" }}> Sign Documents</span>
</ModalHeader>
<div style={{ height: "100%", padding: 20 }}>
<p>{isAlert.alertMessage}</p>
<Modal.Body>
<p>{showAlreadySignDoc.mssg}</p>
</Modal.Body>
<Modal.Footer>
<button
<div
style={{
borderRadius: "0px",
border: "1.5px solid #e3e2e1",
fontWeight: "600",
color: "black"
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginTop: "15px",
marginBottom: "15px"
}}
className="btn"
></div>
<button
onClick={() => {
setIsAlert({
isShow: false,
alertMessage: ""
});
}}
type="button"
className="finishBtn cancelBtn"
>
Ok
</button>
</div>
</ModalUi>
{/* this modal is used show this document is already sign */}
<ModalUi
isOpen={showAlreadySignDoc.status}
title={"Sign Documents"}
handleClose={() => {
setShowAlreadySignDoc({ status: false });
}}
>
<div style={{ height: "100%", padding: 20 }}>
<p>{showAlreadySignDoc.mssg}</p>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginTop: "15px",
marginBottom: "15px"
}}
></div>
<button
className="finishBtn cancelBtn"
onClick={() => setShowAlreadySignDoc({ status: false })}
>
Close
</button>
{showAlreadySignDoc.sure && (
<button
onClick={() => addDefaultSignature()}
style={{
background: themeColor()
}}
type="button"
className="finishBtn"
>
Yes
</button>
)}
</Modal.Footer>
</Modal>
</div>
</ModalUi>
<PlaceholderCopy
isPageCopy={isPageCopy}
setIsPageCopy={setIsPageCopy}
xyPostion={xyPostion}
setXyPostion={setXyPostion}
allPages={allPages}
pageNumber={pageNumber}
signKey={signKey}
/>
{/* this is modal of signature pad */}
<SignPad
isSignPad={isSignPad}
@@ -1054,9 +877,9 @@ function SignYourSelf() {
isCeleb={isCeleb}
setIsEmail={setIsEmail}
pdfName={pdfDetails[0] && pdfDetails[0].Name}
signObjId={documentId}
setSuccessEmail={setSuccessEmail}
sender={jsonSender}
setIsAlert={setIsAlert}
/>
{/* pdf header which contain funish back button */}
<Header
@@ -1071,35 +894,40 @@ function SignYourSelf() {
currentSigner={true}
alreadySign={pdfUrl ? true : false}
isSignYourself={true}
setIsEmail={setIsEmail}
/>
{/* className="hidePdf" */}
<div data-tut="reactourSecond">
<RenderPdf
pageNumber={pageNumber}
pdfOriginalWidth={pdfOriginalWidth}
pdfNewWidth={pdfNewWidth}
drop={drop}
successEmail={successEmail}
nodeRef={nodeRef}
handleTabDrag={handleTabDrag}
handleStop={handleStop}
handleImageResize={handleImageResize}
isDragging={isDragging}
setIsSignPad={setIsSignPad}
setIsStamp={setIsStamp}
handleDeleteSign={handleDeleteSign}
setSignKey={setSignKey}
pdfDetails={pdfDetails}
setIsDragging={setIsDragging}
xyPostion={xyPostion}
pdfRef={pdfRef}
pdfUrl={pdfUrl}
numPages={numPages}
pageDetails={pageDetails}
setPdfLoadFail={setPdfLoadFail}
pdfLoadFail={pdfLoadFail}
/>
{containerWH && (
<RenderPdf
pageNumber={pageNumber}
pdfOriginalWidth={pdfOriginalWidth}
pdfNewWidth={pdfNewWidth}
drop={drop}
successEmail={successEmail}
nodeRef={nodeRef}
handleTabDrag={handleTabDrag}
handleStop={handleStop}
isDragging={isDragging}
setIsSignPad={setIsSignPad}
setIsStamp={setIsStamp}
handleDeleteSign={handleDeleteSign}
setSignKey={setSignKey}
pdfDetails={pdfDetails}
setIsDragging={setIsDragging}
xyPostion={xyPostion}
pdfRef={pdfRef}
pdfUrl={pdfUrl}
numPages={numPages}
pageDetails={pageDetails}
setPdfLoadFail={setPdfLoadFail}
pdfLoadFail={pdfLoadFail}
setXyPostion={setXyPostion}
index={index}
containerWH={containerWH}
setIsPageCopy={setIsPageCopy}
/>
)}
</div>
</div>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,67 @@
import React from "react";
import ModalUi from "../../premitives/ModalUi";
const AddRoleModal = (props) => {
return (
<ModalUi
title={"Add Role"}
isOpen={props.isModalRole}
handleClose={props.handleCloseRoleModal}
>
<div className="addusercontainer">
<form
style={{ display: "flex", flexDirection: "column" }}
onSubmit={props.handleAddRole}
>
<input
value={props.roleName}
onChange={(e) => props.setRoleName(e.target.value)}
placeholder={
props.signersdata.length > 0
? "User " + (props.signersdata.length + 1)
: "User 1"
}
className="addUserInput"
/>
<p
style={{
color: "grey",
fontSize: 11,
margin: "10px 0 10px 5px"
}}
>
e.g: Hr, Director, Manager, New joinee, Accountant, etc...
</p>
<div>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginBottom: "15px"
}}
></div>
<button
type="submit"
style={{
background: "#00a2b7"
}}
className="finishBtn"
>
Add
</button>
<button
onClick={props.handleCloseRoleModal}
type="button"
className="finishBtn cancelBtn"
>
Close
</button>
</div>
</form>
</div>
</ModalUi>
);
};
export default AddRoleModal;
@@ -25,31 +25,40 @@ function CustomModal({
<div className="modalHeadDiv bg-danger">{headMsg && headMsg}</div>
<div className="modalBodyDIv">
<p className="pTagBody">{bodyMssg && bodyMssg}</p>
{footerMessage && (
<>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginTop: "15px",
marginBottom: "15px"
}}
></div>
<div className="modalFooterDiv">
<button
style={{
background: "#de4337"
}}
type="button"
className="finishBtn"
onClick={() => declineDoc()}
>
Yes
</button>
<button
type="button"
className="finishBtn cancelBtn"
onClick={() => setIsDecline({ isDeclined: false })}
>
Close
</button>
</div>
</>
)}
</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>
)
@@ -0,0 +1,101 @@
import React, { useState } from "react";
import "../../css/AddUser.css";
// import SelectFolder from "../../premitives/SelectFolder";
const EditTemplate = ({ template, onSuccess }) => {
// const [folder, setFolder] = useState({ ObjectId: "", Name: "" });
const [formData, setFormData] = useState({
Name: template?.Name || "",
Note: template?.Note || "",
Description: template?.Description || ""
});
const handleStrInput = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
// const handleFolder = (data) => {
// console.log("handleFolder ", data)
// setFolder(data);
// };
// Define a function to handle form submission
const handleSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
const data = {...formData }
onSuccess(data);
};
return (
<div className="addusercontainer">
<div className="form-wrapper">
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="name" style={{ fontSize: 13 }}>
File
</label>
<div
style={{
padding: "0.5rem 0.75rem",
border: "1px solid #d1d5db",
borderRadius: "0.375rem",
fontSize: "0.75rem",
fontWeight: "700"
}}
>
{template.URL?.split("/")[3]?.split("_")[1]}
</div>
</div>
<div className="form-section">
<label htmlFor="name" style={{ fontSize: 13 }}>
Name
<span style={{ color: "red", fontSize: 13 }}> *</span>
</label>
<input
type="text"
name="Name"
value={formData.Name}
onChange={(e) => handleStrInput(e)}
required
className="addUserInput"
/>
</div>
<div className="form-section">
<label htmlFor="Note" style={{ fontSize: 13 }}>
Note
</label>
<input
type="text"
name="Note"
id="Note"
value={formData.Note}
onChange={(e) => handleStrInput(e)}
className="addUserInput"
/>
</div>
<div className="form-section">
<label htmlFor="Description" style={{ fontSize: 13 }}>
Description
</label>
<input
type="text"
name="Description"
id="Description"
value={formData.Description}
onChange={(e) => handleStrInput(e)}
className="addUserInput"
/>
</div>
{/* <SelectFolder onSuccess={handleFolder} folderCls={"contracts_Template"} /> */}
<div className="buttoncontainer">
<button type="submit" className="submitbutton">
Submit
</button>
</div>
</form>
</div>
</div>
);
};
export default EditTemplate;
@@ -0,0 +1,35 @@
import React from "react";
import SelectSigners from "../../premitives/SelectSigners";
import AddUser from "../../premitives/AddUser";
import ModalUi from "../../premitives/ModalUi";
const LinkUserModal = (props) => {
return (
<ModalUi title={"Add/Choose Signer"} isOpen={props.isAddUser[props.uniqueId]} handleClose={props.closePopup}>
<SelectSigners
details={props.handleAddUser}
closePopup={props.closePopup}
/>
<div style={{ display: "flex", alignItems: "center", gap: 5, margin:"0 30%", color:"#808080" }}>
<span
style={{
height: 1,
width: "100%",
backgroundColor: "#ccc"
}}
></span>
<span>or</span>
<span
style={{
height: 1,
width: "100%",
backgroundColor: "#ccc"
}}
></span>
</div>
<AddUser details={props.handleAddUser} closePopup={props.closePopup} />
</ModalUi>
);
};
export default LinkUserModal;
@@ -0,0 +1,263 @@
import React, { useState } from "react";
import { themeColor } from "../../utils/ThemeColor/backColor";
import ModalUi from "../../premitives/ModalUi";
function PlaceholderCopy(props) {
const copyType = ["All pages", "All pages but last", "All pages but first"];
const [selectCopyType, setSelectCopyType] = useState("");
//get RandomKey Id
const randomKey = () => {
const randomId = Math.floor(1000 + Math.random() * 9000);
return randomId;
};
//function for get copy placeholder position
const getCopyPlaceholderPosition = (
type,
rest,
newPageNumber,
existPlaceholderPosition
) => {
let obj;
const filterPosition =
existPlaceholderPosition &&
existPlaceholderPosition.filter(
(data) => data.xPosition !== rest.xPosition
);
//copy all page placeholder at requested position except first page
if (newPageNumber === 1 && type === "first") {
if (filterPosition && filterPosition.length > 0) {
return (obj = {
pageNumber: newPageNumber,
pos: [...filterPosition]
});
}
}
//copy all page placeholder at requested position except last page
else if (newPageNumber === props.allPages && type === "last") {
if (existPlaceholderPosition) {
return (obj = {
pageNumber: newPageNumber,
pos: [...filterPosition]
});
}
}
//copy all page placeholder at requested position with existing placeholder position
else if (existPlaceholderPosition) {
return (obj = {
pageNumber: newPageNumber,
pos: [...filterPosition, rest]
});
}
//copy all page placeholder at requested position
else {
return (obj = {
pageNumber: newPageNumber,
pos: [rest]
});
}
};
//function for copy placeholder as per select copy type
const copyPlaceholder = (type) => {
let newPlaceholderPosition = [];
let newPageNumber = 1;
const signerPosition = props.xyPostion;
const signerId = props.signerObjId ? props.signerObjId : props.Id;
//handle placeholder array and copy for multiple signers placeholder at requested location
if (signerId) {
//get current signers data
let filterSignerPosition;
if (props?.signerObjId) {
filterSignerPosition = signerPosition.filter(
(data) => data.signerObjId === signerId
);
} else {
filterSignerPosition = signerPosition.filter(
(item) => item.Id === signerId
);
}
//get current pagenumber's all placeholder position data
const placeholderPosition = filterSignerPosition[0].placeHolder.filter(
(data) => data.pageNumber === props.pageNumber
);
//get current placeholder position data which user want to copy
const currentPlaceholder = placeholderPosition[0].pos.filter(
(position) => position.key === props.signKey
);
const { key, ...rest } = currentPlaceholder[0];
for (let i = 0; i < props.allPages; i++) {
const newId = randomKey();
rest.key = newId;
//get exist placeholder position for particular page
const existPlaceholder = filterSignerPosition[0].placeHolder.filter(
(data) => data.pageNumber === newPageNumber
);
const existPlaceholderPosition =
existPlaceholder[0] && existPlaceholder[0].pos;
//function for get copy to requested location of placeholder position
const getPlaceholderObj = getCopyPlaceholderPosition(
type,
rest,
newPageNumber,
existPlaceholderPosition
);
if (getPlaceholderObj) {
newPlaceholderPosition.push(getPlaceholderObj);
}
newPageNumber++;
}
let updatedSignerPlaceholder;
if (props?.signerObjId) {
updatedSignerPlaceholder = signerPosition.map((signersData, ind) => {
if (signersData.signerObjId === props.signerObjId) {
return {
...signersData,
placeHolder: newPlaceholderPosition
};
}
return signersData;
});
} else {
updatedSignerPlaceholder = signerPosition.map((signersData, ind) => {
if (signersData.Id === props.Id) {
return {
...signersData,
placeHolder: newPlaceholderPosition
};
}
return signersData;
});
}
// const updatedSignerPlaceholder = signerPosition.map(
// (signersData, ind) => {
// if (signersData.signerObjId === props.signerObjId) {
// return {
// ...signersData,
// placeHolder: newPlaceholderPosition
// };
// }
// return signersData;
// }
// );
const signersData = signerPosition;
signersData.splice(0, signerPosition.length, ...updatedSignerPlaceholder);
props.setXyPostion(signersData);
}
//handle signyourself array and copy for single signers placeholder at requested location
else {
const xyPostion = props.xyPostion;
const placeholderPosition = xyPostion.filter(
(data) => data.pageNumber === props.pageNumber
);
//get current placeholder position data which user want to copy
const currentPlaceholder = placeholderPosition[0].pos.filter(
(pos) => pos.key === props.signKey
);
const { key, ...rest } = currentPlaceholder[0];
for (let i = 0; i < props.allPages; i++) {
//get exist placeholder position for particular page
const existPlaceholder = xyPostion.filter(
(data) => data.pageNumber === newPageNumber
);
const existPlaceholderPosition =
existPlaceholder[0] && existPlaceholder[0].pos;
const newId = randomKey();
rest.key = newId;
//function for get copy to requested location of placeholder position
const getPlaceholderObj = getCopyPlaceholderPosition(
type,
rest,
newPageNumber,
existPlaceholderPosition
);
if (getPlaceholderObj) {
newPlaceholderPosition.push(getPlaceholderObj);
}
newPageNumber++;
}
props.setXyPostion(newPlaceholderPosition);
}
};
//function for getting selected type placeholder copy
const handleApplyCopy = () => {
if (selectCopyType === "All pages") {
copyPlaceholder("all");
} else if (selectCopyType === "All pages but last") {
copyPlaceholder("last");
} else if (selectCopyType === "All pages but first") {
copyPlaceholder("first");
}
};
return (
<ModalUi
isOpen={props.isPageCopy}
title={"Copy to all pages"}
handleClose={() => {
props.setIsPageCopy(false);
}}
>
<div style={{ height: "100%", padding: 20 }}>
{copyType.map((data, key) => {
return (
<div key={key} style={{ display: "flex", flexDirection: "column" }}>
<label key={key} style={{ fontSize: "16px", fontWeight: "500" }}>
<input
style={{ accentColor: "red", marginRight: "10px" }}
type="radio"
value={data}
onChange={() => setSelectCopyType(data)}
checked={selectCopyType === data}
/>
{data}
</label>
</div>
);
})}
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginTop: "15px",
marginBottom: "15px"
}}
></div>
<button
onClick={() => {
handleApplyCopy();
props.setIsPageCopy(false);
}}
style={{
background: themeColor()
}}
type="button"
disabled={!selectCopyType}
className="finishBtn"
>
Apply
</button>
<button
type="button"
className="finishBtn cancelBtn"
onClick={() => props.setIsPageCopy(false)}
>
Cancel
</button>
</div>
</ModalUi>
);
}
export default PlaceholderCopy;
@@ -0,0 +1,19 @@
import React from "react";
import { Helmet } from "react-helmet";
function Title({ title, drive }) {
return (
<Helmet>
<title>{drive ? title : `${title} - OpenSign™`}</title>
<meta name="description" content={`${title} - OpenSign™`} />
<link
rel="icon"
type="image/png"
href={localStorage.getItem("fev_Icon")}
sizes="40x40"
/>
</Helmet>
);
}
export default Title;
@@ -0,0 +1,79 @@
import React from "react";
import Modal from "react-bootstrap/Modal";
import ModalHeader from "react-bootstrap/esm/ModalHeader";
import { themeColor } from "../../utils/ThemeColor/backColor";
function AlertComponent({
isShow,
alertMessage,
setIsAlert,
isdefaultSign,
addDefaultSignature,
headBG
}) {
return (
<Modal show={isShow}>
<ModalHeader
style={{
color: "white",
background: headBG ? themeColor() : "#dc3545"
}}
>
<span>Alert</span>
</ModalHeader>
<Modal.Body>
<span>{alertMessage}</span>
</Modal.Body>
<Modal.Footer>
{isdefaultSign ? (
<>
<button
onClick={() => addDefaultSignature()}
style={{
background: themeColor()
}}
type="button"
className="finishBtn"
>
Yes
</button>
<button
onClick={() => {
setIsAlert({
isShow: false,
alertMessage: ""
});
}}
style={{
color: "black"
}}
type="button"
className="finishBtn"
>
Close
</button>
</>
) : (
<button
onClick={() => {
setIsAlert({
isShow: false,
alertMessage: ""
});
}}
style={{
color: "black"
}}
type="button"
className="finishBtn"
>
Ok
</button>
)}
</Modal.Footer>
</Modal>
);
}
export default AlertComponent;
@@ -0,0 +1,17 @@
import React from "react";
function BorderResize({ right, top }) {
return (
<div
className="borderResize"
style={{
right: right ? right + "px" : "-1px",
bottom: top ? top + "px" : "-1px",
borderRight: "3px solid #188ae2",
borderBottom: "3px solid #188ae2"
}}
></div>
);
}
export default BorderResize;
@@ -1,33 +1,35 @@
import React from "react";
function DefaultSignature({
themeColor,
defaultSignImg,
setShowAlreadySignDoc,
xyPostion
xyPostion,
setDefaultSignAlert
}) {
const confirmToaddDefaultSign = () => {
if (xyPostion.length > 0) {
const alreadySign = {
status: true,
mssg: "Are you sure you want to sign at requested locations?",
sure: true
};
setShowAlreadySignDoc(alreadySign);
setDefaultSignAlert({
isShow: true,
alertMessage:
"Are you sure you want to auto sign at requested all locations?"
});
} else {
alert("please select position!");
setDefaultSignAlert({
isShow: true,
alertMessage: "please select position!"
});
}
};
return (
<div className="signerComponent">
<div>
<div
style={{
background: themeColor(),
color: "white",
padding: "5px",
fontFamily: "sans-serif"
fontFamily: "sans-serif",
marginTop: "5px"
}}
>
Signature
@@ -41,41 +43,34 @@ function DefaultSignature({
fontWeight: "600"
}}
>
{defaultSignImg ? (
<>
<p>Your Signature</p>
<div className="defaultSignBox">
<img
alt="default img"
style={{
width: "100%",
height: "100%",
objectFit: "contain"
}}
src={defaultSignImg}
/>
</div>
<button
<>
<p>Your Signature</p>
<div className="defaultSignBox">
<img
alt="default img"
style={{
background: themeColor(),
color: "white",
marginTop: "20px",
cursor: "pointer"
width: "100%",
height: "100%",
objectFit: "contain"
}}
type="button"
className="finishBtn finishnHover"
onClick={() => confirmToaddDefaultSign()}
>
Auto Sign All
</button>
</>
) : (
<div style={{ margin: "10px" }}>
<span>
Click a signature placeholder to start signing the document!
</span>
src={defaultSignImg}
/>
</div>
)}
<button
style={{
background: themeColor(),
color: "white",
marginTop: "20px",
cursor: "pointer",
marginBottom: "10px"
}}
type="button"
className="finishBtn finishnHover"
onClick={() => confirmToaddDefaultSign()}
>
Auto Sign All
</button>
</>
</div>
</div>
);
@@ -1,9 +1,6 @@
import React, { useState } from "react";
import { saveAs } from "file-saver";
import celebration from "../../assests/newCeleb.gif";
import close from "../../assests/close.png";
import Modal from "react-bootstrap/Modal";
import ModalHeader from "react-bootstrap/esm/ModalHeader";
import axios from "axios";
import { getBase64FromUrl } from "../../utils/Utils";
import { themeColor } from "../../utils/ThemeColor/backColor";
@@ -16,18 +13,18 @@ function EmailComponent({
isCeleb,
setIsEmail,
setSuccessEmail,
signObjId,
pdfName,
sender
sender,
setIsAlert
}) {
const [emailCount, setEmailCount] = useState([]);
const [emailList, setEmailList] = useState([]);
const [emailValue, setEmailValue] = useState();
const [isLoading, setIsLoading] = useState(false);
//function for send email
const sendEmail = async () => {
setIsLoading(true);
let sendMail;
for (let i = 0; i < emailCount.length; i++) {
for (let i = 0; i < emailList.length; i++) {
try {
const imgPng =
"https://qikinnovation.ams3.digitaloceanspaces.com/logo.png";
@@ -39,12 +36,12 @@ function EmailComponent({
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessionToken: localStorage.getItem("accesstoken")
};
const openSignUrl = "https://www.opensignlabs.com/contact-us";
const themeBGcolor = themeColor();
let params = {
pdfName: pdfName,
url: pdfUrl,
recipient: emailCount[i],
recipient: emailList[i],
subject: `${sender.name} has signed the doc - ${pdfName}`,
from: sender.email,
html:
@@ -52,39 +49,61 @@ function EmailComponent({
imgPng +
" height='50' style='padding:20px,width:170px,height:40px'/> </div><div style='padding:2px;font-family:system-ui; background-color:" +
themeBGcolor +
";'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document Copy</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document " +
";'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document Copy</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document <strong>" +
pdfName +
" Standard is attached to this email. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from Open Sign. For any queries regarding this email, please contact the sender " +
" </strong>is attached to this email. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from OpenSign. For any queries regarding this email, please contact the sender " +
sender.email +
" directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.</p></div></div></body></html>"
" directly. If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href= " +
openSignUrl +
" target=_blank>here</a> </p></div></div></body></html>"
};
sendMail = await axios.post(url, params, { headers: headers });
} catch (error) {
console.log("error", error);
setIsLoading(false);
alert("Something went wrong!");
setIsEmail(false);
setIsAlert({
isShow: true,
alertMessage: "something went wrong"
});
}
}
if (sendMail.data.result.status === "success") {
setIsEmail(false);
if (sendMail && sendMail.data.result.status === "success") {
setSuccessEmail(true);
setTimeout(() => {
setSuccessEmail(false);
}, 3000);
setIsEmail(false);
setEmailValue("");
setEmailList([]);
}, 1500);
setIsLoading(false);
} else if (sendMail.data.result.status === "error") {
} else if (sendMail && sendMail.data.result.status === "error") {
setIsLoading(false);
alert("Something went wrong!");
setIsEmail(false);
setIsAlert({
isShow: true,
alertMessage: "something went wrong"
});
setEmailValue("");
setEmailList([]);
} else {
setIsLoading(false);
alert("Something went wrong!");
setIsEmail(false);
setIsAlert({
isShow: true,
alertMessage: "something went wrong"
});
setEmailValue("");
setEmailList([]);
}
};
//function for remove email
const removeChip = (index) => {
const updateEmailCount = emailCount.filter((data, key) => key !== index);
setEmailCount(updateEmailCount);
const updateEmailCount = emailList.filter((data, key) => key !== index);
setEmailList(updateEmailCount);
};
//function for get email value
const handleEmailValue = (e) => {
@@ -95,10 +114,10 @@ function EmailComponent({
//function for save email in array after press enter
const handleEnterPress = (e) => {
if (e.key === "Enter" && emailValue) {
setEmailCount((prev) => [...prev, emailValue]);
setEmailList((prev) => [...prev, emailValue]);
setEmailValue("");
} else if (e === "add" && emailValue) {
setEmailCount((prev) => [...prev, emailValue]);
setEmailList((prev) => [...prev, emailValue]);
setEmailValue("");
}
};
@@ -142,245 +161,268 @@ function EmailComponent({
return (
<div>
{/* isEmail */}
<Modal show={isEmail}>
{isLoading && (
<div
style={{
position: "absolute",
height: "100%",
width: "100%",
display: "flex",
justifyContent: "center",
flexDirection: "column",
alignItems: "center",
zIndex: "20",
backgroundColor: "#e6f2f2",
opacity: 0.8
}}
>
<img
alt="no img"
src={loader}
style={{ width: "70px", height: "70px" }}
/>
<span style={{ fontSize: "12px", fontWeight: "bold" }}>
This might take some time
</span>
</div>
)}
<ModalHeader style={{ background: themeColor() }}>
<span style={{ color: "white" }}>Successfully signed!</span>
<div style={{ display: "flex", flexDirection: "row" }}>
<div></div>
{!isAndroid && (
<button
onClick={handleToPrint}
{isEmail && (
<div className="modaloverlay">
<div className="modalcontainer">
{isLoading && (
<div
style={{
position: "absolute",
height: "100%",
width: "100%",
display: "flex",
flexDirection: "row",
alignItems: "center"
justifyContent: "center",
flexDirection: "column",
alignItems: "center",
zIndex: "20",
backgroundColor: "#e6f2f2",
opacity: 0.8
}}
className="btn btn-primary btn-sm"
>
<i
className="fa fa-print"
style={{
fontSize: "15px",
marginRight: "3px",
color: "white"
}}
aria-hidden="true"
></i>
Print
</button>
<img
alt="no img"
src={loader}
style={{ width: "70px", height: "70px" }}
/>
<span style={{ fontSize: "12px", fontWeight: "bold" }}>
This might take some time
</span>
</div>
)}
<div style={{ background: "#32a3ac" }} className="modalheader">
<span style={{ color: "white" }}>Successfully signed!</span>
<button
className="btn btn-danger btn-sm"
onClick={() => handleDownloadPdf()}
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
marginLeft: "10px"
}}
>
<i
className="fa fa-download"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px"
}}
aria-hidden="true"
></i>
Download
</button>
</div>
</ModalHeader>
<div style={{ display: "flex", flexDirection: "row" }}>
<div></div>
{!isAndroid && (
<button
onClick={handleToPrint}
style={{
display: "flex",
flexDirection: "row",
alignItems: "center"
}}
className="btn btn-primary btn-sm"
>
<i
className="fa fa-print"
style={{
fontSize: "15px",
marginRight: "3px",
color: "white"
}}
aria-hidden="true"
></i>
Print
</button>
)}
<Modal.Body>
{isCeleb && (
<div
style={{
position: "absolute",
marginLeft: "50px"
}}
>
<img
alt="print img"
width={300}
height={250}
// style={styles.gifCeleb}
src={celebration}
/>
</div>
)}
<p
style={{
fontFamily: "system-ui",
verticalAlign: "baseline",
fontWeight: "500",
color: "#403f3e",
fontSize: "15px"
}}
>
Recipients added here will get a copy of the signed document.
</p>
{emailCount.length > 0 ? (
<>
<div className="addEmail">
<div
<button
className="btn btn-danger btn-sm"
onClick={() => handleDownloadPdf()}
style={{
display: "flex",
flexDirection: "row",
flexWrap: "wrap"
alignItems: "center",
marginLeft: "10px"
}}
>
{emailCount.map((data, ind) => {
return (
<div
className="emailChip"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center"
}}
key={ind}
>
<span
style={{
color: "white",
fontSize: "13px",
marginTop: "2px"
}}
>
{data}
</span>
<img
alt="print img"
onClick={() => removeChip(ind)}
src={close}
width={10}
height={10}
style={{ fontWeight: "600", margin: "0 0 10px 2px" }}
/>
</div>
);
})}
<i
className="fa fa-download"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px"
}}
aria-hidden="true"
></i>
Download
</button>
</div>
</div>
<div style={{ height: "100%", padding: 20 }}>
{isCeleb && (
<div
style={{
position: "absolute",
marginLeft: "50px"
}}
>
<img
alt="print img"
width={300}
height={250}
// style={styles.gifCeleb}
src={celebration}
/>
</div>
{emailCount.length <= 9 && (
)}
<p
style={{
fontFamily: "system-ui",
verticalAlign: "baseline",
fontWeight: "500",
color: "#403f3e",
fontSize: "15px",
marginBottom: "5px"
}}
>
Recipients added here will get a copy of the signed document.
</p>
{emailList.length > 0 ? (
<>
<div className="addEmail">
<div
style={{
display: "flex",
flexDirection: "row",
flexWrap: "wrap"
}}
>
{emailList.map((data, ind) => {
return (
<div
className="emailChip"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center"
}}
key={ind}
>
<span
style={{
color: "white",
fontSize: "13px"
}}
>
{data}
</span>
<span
style={{
color: "white",
fontSize: 13,
fontWeight: 600,
marginLeft: 7,
cursor: "pointer"
}}
onClick={() => removeChip(ind)}
>
<i className="fa-solid fa-xmark"></i>
</span>
</div>
);
})}
</div>
{emailList.length <= 9 && (
<input
type="text"
value={emailValue}
className="addEmailInput"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
onBlur={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
required
/>
)}
</div>
</>
) : (
<div>
<input
type="text"
value={emailValue}
className="addEmailInput"
className="emailInput"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
placeholder="Add the email addresses"
onBlur={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
required
/>
)}
</div>
)}
<span
style={{
cursor: emailValue && "pointer"
}}
onClick={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
>
<i
style={{
backgroundColor: themeColor(),
padding: "5px 7px",
marginTop: "10px",
color: "white",
borderRadius: "2px"
}}
className="fa fa-plus"
aria-hidden="true"
></i>
</span>
<div
style={{
background: "#e3e2e1",
marginTop: "10px",
padding: "5px",
borderRadius: "3px"
}}
>
<span style={{ fontWeight: "700" }}>Note:</span>
<span style={{ fontSize: "15px" }}>
{" "}
You can only send to ten recipients at a time.
</span>
</div>
</>
) : (
<div>
<input
type="text"
value={emailValue}
className="emailInput"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
placeholder="Add the email addresses"
required
/>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginTop: "15px",
marginBottom: "15px"
}}
></div>
<button
disabled={emailList.length === 0 && true}
style={{
background: themeColor(),
color: "white"
}}
type="button"
className={emailList.length === 0 ? "defaultBtn" : "finishBtn"}
onClick={() => sendEmail()}
>
Send
</button>
<button
type="button"
className="finishBtn cancelBtn"
onClick={() => {
setIsEmail(false);
setEmailValue("");
setEmailList([]);
}}
>
Close
</button>
</div>
)}
<span
style={{
cursor: emailValue && "pointer"
}}
onClick={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
>
<i
style={{
backgroundColor: themeColor(),
padding: "2px 10px",
marginTop: "10px",
color: "white"
}}
className="fa fa-plus"
aria-hidden="true"
></i>
</span>
<div
style={{
background: "#e3e2e1",
marginTop: "30px",
padding: "5px",
borderRadius: "3px"
}}
>
<span style={{ fontWeight: "700" }}>Note:</span>
<span style={{ fontSize: "15px" }}>
{" "}
You can only send to ten recipients at a time.
</span>
</div>
</Modal.Body>
<Modal.Footer>
<button
style={{
color: "black"
}}
type="button"
className="finishBtn"
onClick={() => setIsEmail(false)}
>
Close
</button>
<button
disabled={emailCount.length === 0 && true}
style={{
background: themeColor(),
color: "white"
}}
type="button"
className={emailCount.length === 0 ? "defaultBtn" : "finishBtn"}
onClick={() => sendEmail()}
>
Send
</button>
</Modal.Footer>
</Modal>
</div>
)}
</div>
);
}
@@ -0,0 +1,21 @@
import React from "react";
import "../../css/signature.css";
function EmailToast({ isShow }) {
return (
<>
{isShow && (
<div style={{ display: "flex", justifyContent: "center" }}>
<div
className="alert alert-success successBox"
style={{ zIndex: "1051" }}
>
Email sent successfully!
</div>
</div>
)}
</>
);
}
export default EmailToast;
@@ -1,6 +1,6 @@
import React from "react";
import * as Select from "@radix-ui/react-select";
import classnames from "classnames";
import React, { useState } from "react";
import ModalUi from "../../premitives/ModalUi";
import RecipientList from "../../premitives/RecipientList";
function FieldsComponent({
pdfUrl,
@@ -20,7 +20,6 @@ function FieldsComponent({
isDragSignatureSS,
isSignYourself,
addPositionOfSignature,
signersdata,
isSelectListId,
setSignerObjId,
@@ -29,29 +28,20 @@ function FieldsComponent({
isSigners,
dataTut,
dataTut2,
setIsShowEmail,
isMailSend,
selectedEmail,
setSelectedEmail,
handleAddSigner,
setUniqueId,
setRoleName,
handleDeleteUser,
signerPos,
handleRoleChange,
handleOnBlur,
title
}) {
const [isSignersModal, setIsSignersModal] = useState(false);
const signStyle = pdfUrl ? "disableSign" : "signatureBtn";
const isMobile = window.innerWidth <767;
const SelectItem = React.forwardRef(
({ children, className, ...props }, forwardedRef) => {
return (
<Select.Item
className={classnames("SelectItem", className)}
{...props}
ref={forwardedRef}
>
<Select.ItemText>{children}</Select.ItemText>
<Select.ItemIndicator className="SelectItemIndicator"></Select.ItemIndicator>
</Select.Item>
);
}
);
const isMobile = window.innerWidth < 767;
const color = [
"#93a3db",
@@ -65,9 +55,12 @@ function FieldsComponent({
"#cc99ff",
"#ffcc99",
"#66ccff",
"#ffffcc",
"#ffffcc"
];
const handleModal = () => {
setIsSignersModal(!isSignersModal);
};
return (
<>
{isMobile && isSignYourself ? (
@@ -88,102 +81,75 @@ function FieldsComponent({
padding: "10px 20px",
display: "flex",
alignItems: "center",
justifyContent: "center",
justifyContent: "center"
}}
onClick={() => {
// if (signersdata?.length) {
handleModal();
// }
}}
>
<span style={{ fontSize: "18px", fontWeight: "500" }}>
Signer :
</span>
<Select.Root
onValueChange={(obj) => {
const [selectedKey, selectedData] = obj.split("|");
const parseData = JSON.parse(selectedData);
setSignerObjId(parseData.objectId);
setIsSelectId(selectedKey);
setContractName(parseData.className);
setSelectedEmail(true);
<span
style={{
fontSize: "13px",
fontWeight: "700",
textAlign: "center"
}}
>
<Select.Trigger
className={selectedEmail ? "selectEmail": "SelectTrigger"}
style={{
background: isSelectListId
? color[isSelectListId % color.length]
: color[0],
}}
aria-label="Food"
>
<Select.Value
placeholder="Select signer.." />
{!selectedEmail &&
<Select.Icon className="SelectIcon">
<i
style={{
marginTop: "5px",
marginLeft: "5px",
color: "#3b15d1",
fontSize: "20px",
}}
className="fa fa-angle-down"
aria-hidden="true"
></i>
</Select.Icon>}
</Select.Trigger>
<Select.Portal>
<Select.Content
className="SelectContent"
style={{ zIndex: "5000" }}
>
<Select.ScrollUpButton className="SelectScrollButton">
<i
style={{
marginTop: "5px",
marginLeft: "5px",
color: "#3b15d1",
fontSize: "20px",
}}
className="fa fa-angle-down"
aria-hidden="true"
></i>
</Select.ScrollUpButton>
<Select.Viewport className="SelectViewport">
<Select.Group>
{signersdata.Signers.map((obj, ind) => {
return (
<SelectItem
selected
key={ind}
value={`${ind}|${JSON.stringify(obj)}`}
// value={(obj)}
>
{" "}
{obj.Email}
</SelectItem>
);
})}
{/* <SelectItem value="orange">Orange</SelectItem>
<SelectItem value="apple">Apple</SelectItem>
<SelectItem value="grape"></SelectItem> */}
</Select.Group>
</Select.Viewport>
<Select.ScrollDownButton className="SelectScrollButton">
<i
style={{
marginTop: "5px",
marginLeft: "5px",
color: "#3b15d1",
fontSize: "20px",
}}
className="fa fa-angle-down"
aria-hidden="true"
></i>
</Select.ScrollDownButton>
</Select.Content>
</Select.Portal>
</Select.Root>
{title ? title : "Recipient"}
</span>
<span
style={{
fontSize: "13px",
fontWeight: "700",
display: "flex",
alignItems: "center"
}}
>
{signersdata[isSelectListId]?.Role && (
<div>
{signersdata[isSelectListId]?.Name ? (
<>
:{" "}
{signersdata[isSelectListId]?.Name?.length > 12
? `${signersdata[isSelectListId].Name.slice(
0,
12
)}...`
: signersdata[isSelectListId]?.Name}
</>
) : (
<>
:{" "}
{signersdata[isSelectListId]?.Role?.length > 12
? `${signersdata[isSelectListId].Role.slice(
0,
12
)}...`
: signersdata[isSelectListId]?.Role}
</>
)}
</div>
)}
<div style={{ marginLeft: 6, fontSize: 16 }}>
<i className="fa-solid fa-angle-down"></i>
</div>
</span>
</div>
)}
{handleAddSigner && (
<div
data-tut="reactourAddbtn"
style={{
margin: "5px 0 5px 0",
backgroundColor: themeColor(),
color: "white"
}}
className="addSignerBtn"
onClick={() => handleAddSigner()}
>
<i className="fa-solid fa-plus"></i>
<span style={{ marginLeft: 2 }}>Add role</span>
</div>
)}
<div
@@ -192,17 +158,7 @@ function FieldsComponent({
style={{ backgroundColor: themeColor() }}
>
<div
onClick={() => {
if (isSigners) {
if (selectedEmail) {
addPositionOfSignature("onclick", false);
} else {
setIsShowEmail(true);
}
} else {
addPositionOfSignature("onclick", false);
}
}}
onClick={() => addPositionOfSignature("onclick", false)}
ref={(element) => {
dragSignatureSS(element);
if (element) {
@@ -221,24 +177,15 @@ function FieldsComponent({
backgroundSize: "70% 70%",
backgroundRepeat: "no-repeat",
backgroundPosition: "center center",
paddingBottom: "2.2rem",
paddingBottom: "2.2rem"
}}
>
{/* <img
alt="sign img"
style={{
width: "30px",
height: "30px",
background: themeColor(),
}}
src={sign}
/> */}
<span
style={{
color: "white",
fontSize: "12px",
position: "relative",
top: "2.6rem",
top: "2.6rem"
}}
>
Signature
@@ -261,7 +208,7 @@ function FieldsComponent({
backgroundSize: "32px 33px",
backgroundRepeat: "no-repeat",
backgroundPosition: "center center",
paddingBottom: "2.2rem",
paddingBottom: "2.2rem"
}}
>
<span
@@ -269,7 +216,7 @@ function FieldsComponent({
color: "white",
fontSize: "12px",
position: "relative",
top: "2.6rem",
top: "2.6rem"
}}
>
Stamp
@@ -283,8 +230,7 @@ function FieldsComponent({
<div
style={{
background: themeColor(),
padding: "5px",
padding: "5px"
}}
>
<span className="signedStyle">Fields</span>
@@ -299,7 +245,7 @@ function FieldsComponent({
fontWeight: "400",
fontSize: "15px",
padding: "3px 20px 0px 20px",
color: "#bfbfbf",
color: "#bfbfbf"
}}
>
Signature
@@ -310,7 +256,7 @@ function FieldsComponent({
style={{
width: "30px",
height: "28px",
background: "#d3edeb",
background: "#d3edeb"
}}
src={sign}
/>
@@ -321,7 +267,7 @@ function FieldsComponent({
fontWeight: "400",
fontSize: "15px",
padding: "3px 0px 0px 35px",
color: "#bfbfbf",
color: "#bfbfbf"
}}
>
Stamp
@@ -332,7 +278,7 @@ function FieldsComponent({
style={{
width: "25px",
height: "28px",
background: "#d3edeb",
background: "#d3edeb"
}}
src={stamp}
/>
@@ -355,7 +301,7 @@ function FieldsComponent({
style={{
opacity: isDragSign ? 0.5 : 1,
boxShadow:
"0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18)",
"0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18)"
}}
>
<span
@@ -363,7 +309,7 @@ function FieldsComponent({
fontWeight: "400",
fontSize: "15px",
padding: "3px 20px 0px 20px",
color: "black",
color: "black"
}}
>
Signature
@@ -373,7 +319,7 @@ function FieldsComponent({
style={{
width: "30px",
height: "28px",
background: themeColor(),
background: themeColor()
}}
src={sign}
/>
@@ -393,7 +339,7 @@ function FieldsComponent({
style={{
opacity: isDragStamp ? 0.5 : 1,
boxShadow:
"0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18)",
"0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18)"
}}
>
<span
@@ -401,7 +347,7 @@ function FieldsComponent({
fontWeight: "400",
fontSize: "15px",
padding: "3px 0px 0px 35px",
color: !pdfUrl ? "black" : "#bfbfbf",
color: !pdfUrl ? "black" : "#bfbfbf"
}}
>
Stamp
@@ -412,7 +358,7 @@ function FieldsComponent({
style={{
width: "25px",
height: "28px",
background: themeColor(),
background: themeColor()
}}
src={stamp}
/>
@@ -422,6 +368,41 @@ function FieldsComponent({
</div>
</div>
)}
{isSignersModal && (
<ModalUi
title={"Recipients"}
isOpen={isSignersModal}
handleClose={handleModal}
>
{signersdata.length > 0 ? (
<RecipientList
signerPos={signerPos}
signersdata={signersdata}
isSelectListId={isSelectListId}
setSignerObjId={setSignerObjId}
setIsSelectId={setIsSelectId}
setContractName={setContractName}
setUniqueId={setUniqueId}
setRoleName={setRoleName}
handleDeleteUser={handleDeleteUser}
handleRoleChange={handleRoleChange}
handleOnBlur={handleOnBlur}
handleModal={handleModal}
/>
) : (
<div
style={{
padding: 20,
fontSize: 15,
fontWeight: "500",
textAlign: "center"
}}
>
Please add Recipient
</div>
)}
</ModalUi>
)}
</>
);
}
@@ -33,7 +33,10 @@ function Header({
currentSigner,
dataTut4,
alreadySign,
isSignYourself
isSignYourself,
setIsEmail,
completeBtnTitle,
setIsEditTemplate
}) {
const isMobile = window.innerWidth < 767;
const navigate = useNavigate();
@@ -222,10 +225,7 @@ function Header({
);
};
return (
<div
style={{ padding: !isGuestSigner && "5px 0px 5px 0px" }}
className="mobileHead"
>
<div style={{ padding: "5px 0px 5px 0px" }} className="mobileHead">
{isMobile && isShowHeader ? (
<div
id="navbar"
@@ -329,9 +329,29 @@ function Header({
</DropdownMenu.Item>
) : (
isSignYourself && (
<DropdownMenu.Item className="DropdownMenuItem">
<CertificateDropDown />
</DropdownMenu.Item>
<>
<DropdownMenu.Item className="DropdownMenuItem">
<CertificateDropDown />
</DropdownMenu.Item>
<DropdownMenu.Item
className="DropdownMenuItem"
onClick={() => setIsEmail(true)}
>
<div
style={{
display: "flex",
flexDirection: "row"
}}
>
<i
className="fa fa-envelope"
style={{ marginRight: "2px" }}
aria-hidden="true"
></i>
Mail
</div>
</DropdownMenu.Item>
</>
)
)}
<DropdownMenu.Item
@@ -394,7 +414,7 @@ function Header({
}}
data-tut={dataTut4}
>
Send
{completeBtnTitle ? completeBtnTitle : "Send"}
</div>
) : (
<div
@@ -512,17 +532,17 @@ function Header({
) : isPlaceholder ? (
<>
{!isMailSend &&
signersdata.Signers &&
signersdata.Signers.length !== signerPos.length && (
signersdata.length > 0 &&
signersdata.length !== signerPos.length && (
<div>
{signerPos.length === 0 ? (
<span style={{ fontSize: "13px", color: "#f5405e" }}>
Add all {signersdata.Signers.length - signerPos.length}{" "}
recipients signature
Add {signersdata.length - signerPos.length} recipients
signature
</span>
) : (
<span style={{ fontSize: "13px", color: "#f5405e" }}>
Add {signersdata.Signers.length - signerPos.length} more
Add {signersdata.length - signerPos.length} more
recipients signature
</span>
)}
@@ -530,6 +550,18 @@ function Header({
)}
<div>
{setIsEditTemplate && (
<button
onClick={() => setIsEditTemplate(true)}
style={{
border: "none",
outline: "none",
textAlign: "center"
}}
>
<i className="fa-solid fa-gear fa-lg"></i>
</button>
)}
<button
onClick={() => {
navigate(-1);
@@ -552,7 +584,7 @@ function Header({
}}
className={isMailSend ? "sendMail" : "sendMail sendHover"}
>
Send
{completeBtnTitle ? completeBtnTitle : "Send"}
</button>
</div>
</>
@@ -690,6 +722,28 @@ function Header({
></i>
Download
</button>
<button
type="button"
className="defaultBtn mailBtn"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
marginLeft: "10px"
}}
onClick={() => setIsEmail(true)}
>
<i
className="fa fa-envelope"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px"
}}
aria-hidden="true"
></i>
Mail
</button>
</div>
) : (
<div>
@@ -1,13 +1,16 @@
import React from "react";
import Modal from "react-bootstrap/Modal";
import ModalHeader from "react-bootstrap/esm/ModalHeader";
import { useNavigate } from "react-router-dom";
function ModalComponent({ isShow, type, setIsShowEmail }) {
const navigate = useNavigate();
return (
<Modal show={isShow}>
<ModalHeader className="bg-danger" style={{ color: "white" }}>
{type === "signersAlert" ? (
<span>Select signers</span>
) : type === "alreadyPlace" ? (
<span>Already Placed!</span>
) : (
<span>Document Expired!</span>
)}
@@ -16,24 +19,42 @@ function ModalComponent({ isShow, type, setIsShowEmail }) {
<Modal.Body>
{type === "signersAlert" ? (
<p>Please select signer for add placeholder!</p>
) : type === "alreadyPlace" ? (
<p>Already set placeHolder for this document.</p>
) : (
<p>This Document is no longer available.</p>
)}
</Modal.Body>
<Modal.Footer>
{type === "signersAlert" &&(
<button
onClick={() => {
setIsShowEmail(false);
}}
style={{
color: "black"
}}
type="button"
className="finishBtn"
>
Ok
</button>)}
{type === "signersAlert" ? (
<button
onClick={() => {
setIsShowEmail(false);
}}
style={{
color: "black"
}}
type="button"
className="finishBtn"
>
Ok
</button>
) : (
type === "alreadyPlace" && (
<button
onClick={() => {
navigate(-1);
}}
style={{
color: "black"
}}
type="button"
className="finishBtn"
>
Ok
</button>
)
)}
</Modal.Footer>
</Modal>
);
@@ -0,0 +1,32 @@
import React from "react";
import { themeColor } from "../../utils/ThemeColor/backColor";
import { resizeBorderExtraWidth } from "../../utils/Utils";
function PlaceholderBorder(props) {
const getResizeBorderExtraWidth = resizeBorderExtraWidth();
return (
<div
className="borderResize"
style={{
borderColor: themeColor(),
borderStyle: "dashed",
// width: props.pos.Width
// ? props.pos.Width + getResizeBorderExtraWidth
// : 150 + getResizeBorderExtraWidth,
// height: props.pos.Height
// ? props.pos.Height + getResizeBorderExtraWidth
// : 60 + getResizeBorderExtraWidth,
width:
props?.posWidth(props.pos, props?.isSignYourself) +
getResizeBorderExtraWidth,
height:
props?.posHeight(props.pos, props?.isSignYourself) +
getResizeBorderExtraWidth,
borderWidth: "0.2px",
overflow: "hidden"
}}
></div>
);
}
export default PlaceholderBorder;
@@ -10,6 +10,7 @@ function RenderAllPdfPage({
setAllPages,
setPageNumber,
setSignBtnPosition,
pageNumber
}) {
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
@@ -20,75 +21,81 @@ function RenderAllPdfPage({
return (
<div className="showPages">
<div
style={{
display: "flex",
flexDirection: "row",
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
backgroundColor: "white",
height:"100%"
}}
>
<div style={{ width: "140px" }}>
<div
style={{
background: themeColor(),
// color:"white"
}}
className="signedStyle"
>
Pages
</div>
<div
style={{
display: "flex",
flexDirection: "row",
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
backgroundColor: "white",
height: "100%"
}}
>
<div style={{ width: "140px" }}>
<div
style={{
background: themeColor()
// color:"white"
}}
className="signedStyle"
>
Pages
</div>
<div>
<RSC id="RSC-Example" style={{width:"135px",height:window.innerHeight-130+'px'}} >
<Document
onLoadSuccess={onDocumentLoad}
file={pdfUrl ? pdfUrl : signPdfUrl}
// file="https://api.printnode.com/static/test/pdf/multipage.pdf"
<div>
<RSC
id="RSC-Example"
style={{
width: "135px",
height: window.innerHeight - 130 + "px"
}}
>
{Array.from(new Array(allPages), (el, index) => (
<div
key={index}
style={{
width: "100px",
border: "2px solid #878787",
// padding: "5px",
margin: "10px",
<Document
loading={"Loading Document.."}
onLoadSuccess={onDocumentLoad}
file={pdfUrl ? pdfUrl : signPdfUrl}
// file="https://api.printnode.com/static/test/pdf/multipage.pdf"
>
{Array.from(new Array(allPages), (el, index) => (
<div
key={index}
style={{
width: "100px",
border:
pageNumber - 1 === index
? "2px solid red"
: "2px solid #878787",
// padding: "5px",
margin: "10px",
display: "flex",
justifyContent: "center",
alignItems: "center",
contain: "content",
}}
onClick={() => {
setPageNumber(index + 1);
if (setSignBtnPosition) {
setSignBtnPosition([]);
}
}}
>
<Page
key={`page_${index + 1}`}
pageNumber={index + 1}
width={100}
height={100}
scale={1}
renderAnnotationLayer={false}
renderTextLayer={false}
/>
</div>
))}
</Document>
</RSC>
display: "flex",
justifyContent: "center",
alignItems: "center",
contain: "content"
}}
onClick={() => {
setPageNumber(index + 1);
if (setSignBtnPosition) {
setSignBtnPosition([]);
}
}}
>
<Page
key={`page_${index + 1}`}
pageNumber={index + 1}
width={100}
height={100}
scale={1}
renderAnnotationLayer={false}
renderTextLayer={false}
/>
</div>
))}
</Document>
</RSC>
</div>
<hr />
</div>
<hr />
</div>
</div>
</div>
);
}
File diff suppressed because it is too large Load Diff
@@ -4,7 +4,6 @@ import SignatureCanvas from "react-signature-canvas";
import redPen from "../../assests/redPen.png";
import bluePen from "../../assests/bluePen.png";
import blackPen from "../../assests/blackPen.png";
import Modal from "react-bootstrap/Modal";
import { themeColor } from "../../utils/ThemeColor/backColor";
import { useEffect } from "react";
@@ -18,25 +17,57 @@ function SignPad({
isImageSelect,
imageRef,
onImageChange,
onSaveImage,
image,
defaultSign,
setSignature,
setSignature
}) {
const [penColor, setPenColor] = useState("blue");
const allColor = [bluePen, redPen, blackPen];
const canvasRef = useRef(null);
const [isDefaultSign, setIsDefaultSign] = useState(false);
const [isTab, setIsTab] = useState("signature");
const [isTab, setIsTab] = useState("draw");
const [isSignImg, setIsSignImg] = useState("");
//function for clear signature
const handleClear = () => {
if (canvasRef.current) {
canvasRef.current.clear();
}
const [signValue, setSignValue] = useState("");
const [textWidth, setTextWidth] = useState(null);
const [textHeight, setTextHeight] = useState(null);
const fontOptions = [
{ value: "Fasthand" },
{ value: "Dancing Script" },
{ value: "Cedarville Cursive" },
{ value: "Delicious Handrawn" }
// Add more font options as needed
];
const [fontSelect, setFontSelect] = useState(fontOptions[0].value);
setIsSignImg("");
useEffect(() => {
const senderUser =
localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
) &&
localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
);
const jsonSender = JSON.parse(senderUser);
const currentUserName = jsonSender && jsonSender.name;
//function for clear signature
setSignValue(currentUserName);
setFontSelect("Fasthand");
}, []);
//function for clear signature image
const handleClear = () => {
if (isTab === "draw") {
if (canvasRef.current) {
canvasRef.current.clear();
} else if (isStamp) {
setImage("");
}
setIsSignImg("");
} else if (isTab === "uploadImage") {
setImage("");
}
};
//function for set signature url
const handleSignatureChange = (dataURL) => {
@@ -47,14 +78,13 @@ function SignPad({
//save button component
const SaveBtn = () => {
// console.log("isSign",isSignImg,image)
return (
<div>
{!isStamp && !isImageSelect && (
<div style={{ marginTop: "2px" }}>
{(isTab === "draw" || isTab === "uploadImage") && (
<button
style={{
color: "black",
border: "1px solid #ccc"
}}
type="button"
className="finishBtn saveBtn"
@@ -71,8 +101,13 @@ function SignPad({
setIsSignImg("");
onSaveSign(isDefaultSign);
} else {
setIsSignImg("");
onSaveSign();
if (isTab === "type") {
setIsSignImg("");
onSaveSign(false, textWidth, textHeight);
} else {
setIsSignImg("");
onSaveSign();
}
}
setPenColor("blue");
@@ -85,16 +120,20 @@ function SignPad({
setIsImageSelect(false);
setIsDefaultSign(false);
setImage();
setIsTab("signature");
setIsTab("draw");
}}
style={{
background: themeColor(),
color: "white",
color: "white"
}}
disabled={isSignImg || image || isDefaultSign ? false : true}
disabled={
isSignImg || image || isDefaultSign || textWidth ? false : true
}
type="button"
className={
isSignImg || image ? "finishBtn saveBtn" : "disabledFinish saveBtn"
isSignImg || image || isDefaultSign || textWidth
? "finishBtn saveBtn"
: "disabledFinish saveBtn"
}
>
Save
@@ -103,372 +142,457 @@ function SignPad({
);
};
useEffect(() => {
const loadFont = async () => {
try {
await document.fonts.load(`20px ${fontSelect}`);
const selectFontSTyle = fontOptions.find(
(font) => font.value === fontSelect
);
setFontSelect(selectFontSTyle?.value || fontOptions[0].value);
} catch (error) {
console.error("Error loading font:", error);
}
};
loadFont();
}, [fontSelect]);
useEffect(() => {
// Load the default signature after the component mounts
if (canvasRef.current) {
canvasRef.current.fromDataURL(isSignImg);
}
if (isTab === "type") {
convertToImg(fontSelect, signValue);
}
}, [isTab]);
//function for convert input text value in image
const convertToImg = async (fontStyle, text) => {
//get text content to convert in image
const textContent = text;
const fontfamily = fontStyle
? fontStyle
: fontSelect
? fontSelect
: "Fasthand";
//creating span for getting text content width
const span = document.createElement("span");
span.textContent = textContent;
span.style.font = `20px ${fontfamily}`; // here put your text size and font family
span.style.display = "hidden";
document.body.appendChild(span); // Replace 'container' with the ID of the container element
//create canvas to render text in canvas and convert in image
const canvasElement = document.createElement("canvas");
// Draw the text content on the canvas
const ctx = canvasElement.getContext("2d");
const pixelRatio = window.devicePixelRatio || 1;
const width = span.offsetWidth;
const height = span.offsetHeight;
setTextWidth(width);
setTextHeight(height);
const font = span.style["font"];
// Set the canvas dimensions to match the span
canvasElement.width = width * pixelRatio;
canvasElement.height = height * pixelRatio;
// Render the content of the span onto the canvas
// ctx.fillStyle = "white"; // Set the background color of the canvas
// ctx.fillRect(0, 0, width*pixelRatio, height*pixelRatio);
// You can customize text styles if needed
ctx.font = font;
ctx.fillStyle = "black"; // Set the text color
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.scale(pixelRatio, pixelRatio);
// Draw the content of the span onto the canvas
ctx.fillText(span.textContent, width / 2, height / 2); // Adjust the x,y-coordinate as needed
//remove span tag
document.body.removeChild(span);
// Convert the canvas to image data
const dataUrl = canvasElement.toDataURL("image/png");
setSignature(dataUrl);
};
return (
<div>
{/*isSignPad */}
<Modal show={isSignPad}>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
background: "white",
borderBottom: "1.6px solid #ebe6e6",
marginTop: "15px",
}}
>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-around",
alignItems: "end",
gap: 10,
// background: themeColor(),
}}
>
{isStamp ? (
<span style={{ color: themeColor() }} className="signTab">
Upload Image
</span>
) : (
<>
<div>
<span
onClick={() => {
setIsDefaultSign(false);
setIsImageSelect(false);
setIsTab("signature");
setImage();
}}
style={{
color: isTab === "signature" ? themeColor() : "#515252",
marginLeft: "2px",
}}
className="signTab"
>
Signature
</span>
{isSignPad && (
<div className="modaloverlay">
<div className="modalcontainer">
<div
className="modalheader"
style={{ padding: "0 13px", marginTop: "5px" }}
>
<div className="modaltitle">
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
background: "white",
marginTop: "3px"
}}
>
<div
style={{
border:
isTab === "signature"
? "1.5px solid #108783"
: "1.5px solid #ffffff",
display: "flex",
flexDirection: "row",
justifyContent: "space-around",
alignItems: "end",
gap: 10
}}
></div>
</div>
<div>
<span
onClick={() => {
setIsDefaultSign(false);
setIsImageSelect(true);
setIsTab("uploadImage");
}}
style={{
color: isTab === "uploadImage" ? themeColor() : "#515252",
}}
className="signTab"
>
Upload Image
</span>
{isStamp ? (
<span style={{ color: themeColor() }} className="signTab">
Upload stamp image
</span>
) : (
<>
<div>
<span
onClick={() => {
setIsDefaultSign(false);
setIsImageSelect(false);
setIsTab("draw");
setImage();
}}
style={{
color:
isTab === "draw" ? themeColor() : "#515252",
marginLeft: "2px"
}}
className="signTab"
>
Draw
</span>
<div
style={{
border:
isTab === "draw"
? "1.5px solid #108783"
: "1.5px solid #ffffff"
}}
></div>
</div>
<div>
<span
onClick={() => {
setIsDefaultSign(false);
setIsImageSelect(true);
setIsTab("uploadImage");
}}
style={{
color:
isTab === "uploadImage"
? themeColor()
: "#515252"
}}
className="signTab"
>
Upload Image
</span>
<div
style={{
border:
isTab === "uploadImage"
? "1.5px solid #108783"
: "1.5px solid #ffffff"
}}
></div>
</div>
<div>
<span
onClick={() => {
setIsDefaultSign(false);
setIsImageSelect(false);
setIsTab("type");
setImage();
}}
style={{
color:
isTab === "type" ? themeColor() : "#515252",
marginLeft: "2px"
}}
className="signTab"
>
Type
</span>
<div
style={{
border:
isTab === "type"
? "1.5px solid #108783"
: "1.5px solid #ffffff"
}}
></div>
</div>
{defaultSign && (
<div>
<span
onClick={() => {
setIsDefaultSign(true);
setIsImageSelect(true);
setIsTab("mysignature");
setImage();
}}
style={{
color:
isTab === "mysignature"
? themeColor()
: "#515252"
}}
className="signTab"
>
My Signature
</span>
<div
style={{
border:
isTab === "mysignature"
? "1.5px solid #108783"
: "1.5px solid #ffffff"
}}
></div>
</div>
)}
</>
)}
</div>
</div>
</div>
<div
className="closebtn"
style={{ color: "black" }}
onClick={() => {
setPenColor("blue");
setIsSignPad(false);
setIsImageSelect(false);
setIsDefaultSign(false);
setImage();
setIsTab("draw");
}}
>
&times;
</div>
</div>
<div style={{ height: "100%", padding: 20 }}>
{isDefaultSign ? (
<>
<div
style={{
border:
isTab === "uploadImage"
? "1.5px solid #108783"
: "1.5px solid #ffffff",
border: "1px solid black",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
marginBottom: 6,
cursor: "pointer"
}}
></div>
</div>
{defaultSign && (
<div>
<span
onClick={() => {
setIsDefaultSign(true);
setIsImageSelect(true);
setIsTab("mysignature");
setImage();
}}
className="signatureCanvas"
>
<img
alt="stamp img"
style={{
color:
isTab === "mysignature" ? themeColor() : "#515252",
width: "100%",
height: "100%",
background: "rgb(255, 255, 255)",
objectFit: "contain"
}}
className="signTab"
>
My Signature
</span>
src={defaultSign}
/>
</div>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<SaveBtn />
</div>
</>
) : isImageSelect || isStamp ? (
!image ? (
<div
style={{
border: "1px solid black",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
marginBottom: 6,
cursor: "pointer"
}}
className="signatureCanvas"
onClick={() => imageRef.current.click()}
>
<input
type="file"
onChange={onImageChange}
className="filetype"
accept="image/*"
ref={imageRef}
hidden
/>
<i className="fas fa-cloud-upload-alt uploadImgLogo"></i>
<div className="uploadImg">Upload</div>
</div>
) : (
<>
<div
style={{
border:
isTab === "mysignature"
? "1.5px solid #108783"
: "1.5px solid #ffffff",
border: "1px solid black",
marginBottom: 6,
overflow: "hidden"
}}
></div>
</div>
)}
</>
)}
</div>
<button
style={{
border: "0px",
background: "none",
paddingLeft: "7px",
paddingRight: "7px",
marginRight: "5px",
}}
onClick={() => {
setPenColor("blue");
setIsSignPad(false);
setIsImageSelect(false);
setIsDefaultSign(false);
setImage();
setIsTab("signature");
}}
>
X
</button>
</div>
{/* signature modal */}
<Modal.Body className="modalBody">
{isDefaultSign ? (
<>
<div
style={{
border: "1px solid black",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
marginBottom: 6,
cursor: "pointer",
// background:'rgb(255, 255, 255)'
}}
className="signatureCanvas"
>
<img
alt="stamp img"
style={{
width: "100%",
height: "100%",
background: "rgb(255, 255, 255)",
objectFit: "contain",
}}
src={defaultSign}
/>
</div>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<SaveBtn />
</div>
</>
) : isImageSelect || isStamp ? (
!image ? (
<div
style={{
border: "1px solid black",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
marginBottom: 6,
cursor: "pointer",
}}
className="signatureCanvas"
onClick={() => imageRef.current.click()}
>
<input
type="file"
onChange={onImageChange}
className="filetype"
accept="image/*"
ref={imageRef}
hidden
// style={{ display: "none" }}
/>
<i className="fas fa-cloud-upload-alt uploadImgLogo"></i>
<div className="uploadImg">Upload</div>
</div>
) : (
<>
<div
style={{
// position: "relative",
border: "1px solid black",
marginBottom: 6,
// justifyContent:"center"
overflow: "hidden",
}}
className="signatureCanvas"
>
<img
alt="print img"
ref={imageRef}
// alt="preview image"
src={image.src}
style={{
//overflow:"hidden",
objectFit: "contain",
}}
/>
</div>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<SaveBtn />
</div>
</>
)
) : (
<>
{/* {isSignImg ? (
<div
style={{
position: "relative",
border: "2px solid #888",
marginBottom: 6,
}}
className="signatureCanvas"
>
<img
alt="preview image"
src={isSignImg}
style={{
width: "100%",
height: "100%",
objectFit: "contain",
}}
/>
</div>
) : ( */}
<SignatureCanvas
ref={canvasRef}
penColor={penColor}
canvasProps={{
// width: "460px",
// height: "184px",
// width:"280px",
// height:"112px",
className: "signatureCanvas",
}}
backgroundColor="rgb(255, 255, 255)"
onEnd={() =>
handleSignatureChange(canvasRef.current.toDataURL())
}
dotSize={1}
/>
{/* )} */}
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
marginTop:"4px"
}}
>
<div style={{display:"flex",flexDirection:"row"}}>
{allColor.map((data, key) => {
return (
className="signatureCanvas"
>
<img
key={key}
alt="pen img"
alt="print img"
ref={imageRef}
src={image.src}
style={{
border: "none",
margin: "5px",
borderBottom:
key === 0 && penColor === "blue"
? "2px solid blue"
: key === 1 && penColor === "red"
? "2px solid red"
: key === 2 && penColor === "black"
? "2px solid black"
: "2px solid white",
objectFit: "contain",
height: "100%",
width: "100%"
}}
onClick={() => {
if (key === 0) {
setPenColor("blue");
} else if (key === 1) {
setPenColor("red");
} else if (key === 2) {
setPenColor("black");
}
}}
src={data}
width={20}
height={20}
/>
// </button>
);
})}
</div>
<div
style={{ display: "flex", justifyContent: "flex-end" }}
>
<SaveBtn />
</div>
</>
)
) : isTab === "type" ? (
<div>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center"
}}
>
<span className="signatureText">Signature:</span>
<input
maxLength={30}
style={{ fontFamily: fontSelect }}
type="text"
className="signatureInput"
placeholder="Your signature"
value={signValue}
onChange={(e) => {
setSignValue(e.target.value);
convertToImg(fontSelect, e.target.value);
}}
/>
</div>
<div className="fontOptionContainer">
{fontOptions.map((font, ind) => {
return (
<div
key={ind}
style={{
cursor: "pointer",
fontFamily: font.value,
backgroundColor:
fontSelect === font.value && "rgb(206 225 247)"
}}
onClick={() => {
setFontSelect(font.value);
convertToImg(font.value, signValue);
}}
>
<div
style={{
padding: "5px 10px 5px 10px",
fontSize: "20px"
}}
>
{signValue ? signValue : "Your signature"}
</div>
</div>
);
})}
</div>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<SaveBtn />
</div>
</div>
) : (
<>
<SignatureCanvas
ref={canvasRef}
penColor={penColor}
canvasProps={{
className: "signatureCanvas"
}}
backgroundColor="rgb(255, 255, 255)"
onEnd={() =>
handleSignatureChange(canvasRef.current.toDataURL())
}
dotSize={1}
/>
<SaveBtn />
</div>
</>
)}
</Modal.Body>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
marginTop: "10px"
}}
>
<div style={{ display: "flex", flexDirection: "row" }}>
{allColor.map((data, key) => {
return (
<img
key={key}
alt="pen img"
style={{
border: "none",
margin: "5px",
borderBottom:
key === 0 && penColor === "blue"
? "2px solid blue"
: key === 1 && penColor === "red"
? "2px solid red"
: key === 2 && penColor === "black"
? "2px solid black"
: "2px solid white"
}}
onClick={() => {
if (key === 0) {
setPenColor("blue");
} else if (key === 1) {
setPenColor("red");
} else if (key === 2) {
setPenColor("black");
}
}}
src={data}
width={20}
height={20}
/>
);
})}
</div>
{/* <Modal.Footer>
{!isStamp && !isImageSelect && (
<button
style={{
color: "black",
}}
type="button"
className="finishBtn"
onClick={() => handleClear()}
>
Clear
</button>
)}
<button
onClick={() => {
if (!image) {
if (isDefaultSign) {
onSaveSign(isDefaultSign);
} else {
onSaveSign();
}
setPenColor("blue");
} else {
onSaveImage();
}
setIsSignPad(false);
setIsImageSelect(false);
setIsDefaultSign(false);
setImage();
}}
style={{
background: themeColor(),
color: "white",
}}
type="button"
className="finishBtn"
>
Save
</button>
</Modal.Footer> */}
</Modal>
<SaveBtn />
</div>
</>
)}
</div>
</div>
</div>
)}
</div>
);
}
@@ -1,161 +1,34 @@
import React, { useState } from "react";
import check from "../../assests/checkBox.png";
import React from "react";
import { themeColor } from "../../utils/ThemeColor/backColor";
import "../../css/signerListPlace.css";
import RecipientList from "../../premitives/RecipientList";
function SignerListPlace({
signerPos,
signersdata,
isSelectListId,
setSignerObjId,
setIsSelectId,
setContractName
}) {
const color = [
"#93a3db",
"#e6c3db",
"#c0e3bc",
"#bce3db",
"#b8ccdb",
"#ceb8db",
"#ffccff",
"#99ffcc",
"#cc99ff",
"#ffcc99",
"#66ccff",
"#ffffcc",
];
const nameColor = [
"#304fbf",
"#7d5270",
"#5f825b",
"#578077",
"#576e80",
"#6d527d",
"#cc00cc",
"#006666",
"#cc00ff",
"#ff9900",
"#336699",
"#cc9900",
];
const [isHover, setIsHover] = useState();
//function for onhover signer name change background color
const onHoverStyle = (ind) => {
const style = {
background: color[ind % color.length],
padding: "10px",
marginTop: "2px",
display: "flex",
flexDirection: "row",
borderBottom: "1px solid #e3e1e1",
};
return style;
};
//function for onhover signer name remove background color
const nonHoverStyle = (ind) => {
const style = {
// width:"250px",
padding: "10px",
marginTop: "2px",
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
};
return style;
};
const getFirstLetter = (name) => {
const firstLetter = name.charAt(0);
return firstLetter;
};
function SignerListPlace(props) {
return (
<div >
<div>
<div
style={{
background: themeColor(),
padding: "5px",
padding: "5px"
}}
>
<span className="signedStyle">Reicipents</span>
<span className="signedStyle">
{props.title ? props.title : "Recipients"}
</span>
</div>
<div className="signerList">
{signersdata.Signers &&
signersdata.Signers.map((obj, ind) => {
return (
<div
data-tut="reactourFirst"
onMouseEnter={() => setIsHover(ind)}
onMouseLeave={() => setIsHover(null)}
key={ind}
style={
isHover === ind || isSelectListId === ind
? onHoverStyle(ind)
: nonHoverStyle(ind)
}
onClick={() => {
setSignerObjId(obj.objectId);
setIsSelectId(ind);
setContractName(obj.className)
}}
>
<div
style={{
display: "flex",
flexDirection: "row",
}}
>
<div
className="signerStyle"
style={{
background: nameColor[ind % nameColor.length],
width: 20,
height: 20,
display: "flex",
borderRadius: 30 / 2,
justifyContent: "center",
alignItems: "center",
marginRight: "20px",
marginTop: "5px",
}}
>
<span
style={{
fontSize: "8px",
textAlign: "center",
fontWeight: "bold",
}}
>
{" "}
{getFirstLetter(obj.Name)}
</span>
</div>
<div style={{ display: "flex", flexDirection: "column" }}>
<span className="userName">{obj.Name}</span>
<span className="useEmail">{obj.Email}</span>
</div>
</div>
{signerPos.map((data, key) => {
return (
data.signerObjId === obj.objectId && (
<div key={key}>
<img alt="no img" src={check} width={20} height={20} />
</div>
)
);
})}
<hr />
</div>
);
})}
<RecipientList {...props} />
</div>
{props.handleAddSigner && (
<div
data-tut="reactourAddbtn"
className="addSignerBtn"
onClick={() => props.handleAddSigner()}
>
<i className="fa-solid fa-plus"></i>
<span style={{ marginLeft: 2 }}>Add role</span>
</div>
)}
</div>
);
}
@@ -103,7 +103,12 @@ function Login() {
setLoading(false);
} else {
let _user = user.data.result;
const parseId = localStorage.getItem("parseAppId");
localStorage.setItem("UserInformation", JSON.stringify(_user));
localStorage.setItem(
`Parse/${parseId}/currentUser`,
JSON.stringify(_user)
);
localStorage.setItem("username", _user.name);
localStorage.setItem("accesstoken", _user.sessionToken);
//save isGuestSigner true in local to handle login flow header in mobile view
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+7 -4
View File
@@ -1,7 +1,6 @@
import React from "react";
import { Routes, Route } from "react-router-dom";
import SignYourselfPdf from "./Component/SignYourselfPdf";
import RecipientSignPdf from "./Component/recipientSignPdf";
import PlaceHolderSign from "./Component/placeHolderSign";
import ManageSign from "./Component/ManageSign";
import Login from "./Component/login";
@@ -9,7 +8,10 @@ import DraftDocument from "./Component/DraftDocument";
import PdfRequestFiles from "./Component/PdfRequestFiles";
import LegaDrive from "./Component/LegaDrive/LegaDrive";
import PageNotFound from "./Component/PageNotFound";
import TemplatePlaceHolder from "./Component/TemplatePlaceholder";
import Parse from "parse";
Parse.serverURL = localStorage.getItem("baseUrl");
Parse.initialize(localStorage.getItem("parseAppId"));
// `AppRoutes` is used to define route path of app and
// it expose to host app, check moduleFederation.config.js for more
function AppRoutes() {
@@ -24,8 +26,8 @@ function AppRoutes() {
<Route path="/signaturePdf/:docId" element={<SignYourselfPdf />} />
{/* recipient signature route with no rowlevel data using docId from url */}
<Route
path="/recipientSignPdf/:id/:contactBookId"
element={<RecipientSignPdf />}
path="/recipientSignPdf/:docId/:contactBookId"
element={<PdfRequestFiles />}
/>
{/* recipient placeholder set route with rowlevel data */}
<Route path="/placeHolderSign" element={<PlaceHolderSign />} />{" "}
@@ -47,6 +49,7 @@ function AppRoutes() {
{/* lega drive route */}
<Route path="/legadrive" element={<LegaDrive />} />
{/* Page Not Found */}
<Route path="/template/:templateId" element={<TemplatePlaceHolder />} />
<Route path="*" element={<PageNotFound />} />
</Routes>
</div>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 B

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