Compare commits

..
529 Commits
Author SHA1 Message Date
RaktimaNXG 69308e22d8 fix: error in auto-sign feature unexpected issue encountered - something went wrong 2024-08-08 15:06:43 +05:30
prafull-opensignlabsandGitHub f8c9c535a0 Merge pull request #1021 from OpenSignLabs/prafull-opensignlabs-patch-23
fix: not able to create user using add user form
2024-08-08 12:30:18 +05:30
prafull-opensignlabsandGitHub d22322be86 fix: not able to create user using add user form 2024-08-08 12:28:31 +05:30
prafull-opensignlabsandGitHub e931d06ed4 Merge pull request #1018 from OpenSignLabs/validation
fix: something went wrong error in signpdf
2024-08-07 13:56:40 +05:30
prafull-opensignlabs 76b90f9bc0 fix: something went wrong error in signpdf 2024-08-07 13:45:49 +05:30
prafull-opensignlabsandGitHub b4e5fedb51 Merge pull request #1016 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/npm_and_yarn-5105dbd604
build(deps-dev): bump postcss from 8.4.40 to 8.4.41 in /apps/OpenSign in the npm_and_yarn group
2024-08-07 10:09:41 +05:30
dependabot[bot]andGitHub 6a229aabaf build(deps-dev): bump postcss
Bumps the npm_and_yarn group in /apps/OpenSign with 1 update: [postcss](https://github.com/postcss/postcss).


Updates `postcss` from 8.4.40 to 8.4.41
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.40...8.4.41)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-06 16:32:51 +00:00
ZathielandGitHub c55bdba948 Merge pull request #1010 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/lottiefiles/dotlottie-react-0.8.6 2024-08-06 11:10:15 +02:00
ZathielandGitHub 4f2dce0a03 Merge pull request #1014 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/axios-1.7.3 2024-08-06 11:09:51 +02:00
ZathielandGitHub 450a992b26 Merge pull request #1011 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/lint-staged-15.2.8 2024-08-06 11:07:53 +02:00
dependabot[bot]andGitHub 4284b2402b build(deps): bump axios from 1.7.2 to 1.7.3 in /apps/OpenSignServer
Bumps [axios](https://github.com/axios/axios) from 1.7.2 to 1.7.3.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.7.2...v1.7.3)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-06 09:06:27 +00:00
ZathielandGitHub 50c88f82f4 Merge pull request #1012 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/react-tooltip-5.28.0 2024-08-06 11:06:04 +02:00
ZathielandGitHub 7dff3dc658 Merge pull request #1013 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/react-router-dom-6.26.0 2024-08-06 11:04:59 +02:00
ZathielandGitHub adb3864ea9 Merge pull request #1015 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/aws-sdk-2.1667.0 2024-08-06 11:04:20 +02:00
dependabot[bot]andGitHub 65a800701c build(deps): bump aws-sdk in /apps/OpenSignServer
Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1665.0 to 2.1667.0.
- [Release notes](https://github.com/aws/aws-sdk-js/releases)
- [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1665.0...v2.1667.0)

---
updated-dependencies:
- dependency-name: aws-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-05 00:57:47 +00:00
dependabot[bot]andGitHub 36dc1fb3e9 build(deps): bump react-router-dom in /apps/OpenSign
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.25.1 to 6.26.0.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.26.0/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-05 00:28:51 +00:00
dependabot[bot]andGitHub 99305b4185 build(deps): bump react-tooltip from 5.27.1 to 5.28.0 in /apps/OpenSign
Bumps [react-tooltip](https://github.com/ReactTooltip/react-tooltip) from 5.27.1 to 5.28.0.
- [Release notes](https://github.com/ReactTooltip/react-tooltip/releases)
- [Changelog](https://github.com/ReactTooltip/react-tooltip/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ReactTooltip/react-tooltip/compare/v5.27.1...v5.28.0)

---
updated-dependencies:
- dependency-name: react-tooltip
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-05 00:28:35 +00:00
dependabot[bot]andGitHub bd2e8be186 build(deps-dev): bump lint-staged in /apps/OpenSign
Bumps [lint-staged](https://github.com/lint-staged/lint-staged) from 15.2.7 to 15.2.8.
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/master/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v15.2.7...v15.2.8)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-05 00:28:23 +00:00
dependabot[bot]andGitHub dc4c6ceff5 build(deps): bump @lottiefiles/dotlottie-react in /apps/OpenSign
Bumps [@lottiefiles/dotlottie-react](https://github.com/LottieFiles/dotlottie-web/tree/HEAD/packages/react) from 0.8.5 to 0.8.6.
- [Release notes](https://github.com/LottieFiles/dotlottie-web/releases)
- [Changelog](https://github.com/LottieFiles/dotlottie-web/blob/main/packages/react/CHANGELOG.md)
- [Commits](https://github.com/LottieFiles/dotlottie-web/commits/@lottiefiles/dotlottie-react@0.8.6/packages/react)

---
updated-dependencies:
- dependency-name: "@lottiefiles/dotlottie-react"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-05 00:28:12 +00:00
AndrewandGitHub de82188663 Merge pull request #1007 from OpenSignLabs/fix_self_host 2024-08-02 17:19:58 +05:30
prafull-opensignlabs 4aefe775f9 fix: initial routing error in self-hosting 2024-08-02 17:11:02 +05:30
prafull-opensignlabsandGitHub ee9f778725 Merge pull request #1003 from OpenSignLabs/fix_err_signpdf
fix: error handling of signing pdf digitally
2024-08-02 16:39:11 +05:30
prafull-opensignlabs ff0883c8e6 fix: error handling of signpdf function 2024-08-02 16:22:44 +05:30
prafull-opensignlabsandGitHub 375dc86f0a Merge pull request #998 from OpenSignLabs/input_text_darkmode
fix: type initials and signature looks blurry on download pdf
2024-08-01 18:47:01 +05:30
AndrewandGitHub d2f187f6c0 Merge pull request #1001 from OpenSignLabs/multiuser_issue 2024-08-01 18:42:51 +05:30
prafull-opensignlabs 5393ee9ba9 style: remove unncessary themes and change dropbox btn as per theme 2024-08-01 18:40:04 +05:30
AndrewandGitHub d4d2948455 Merge pull request #1000 from OpenSignLabs/multiuser_issue 2024-08-01 18:09:43 +05:30
prafull-opensignlabs 37617c04ad fix: x is not function and security issue 2024-08-01 18:08:34 +05:30
RaktimaNXG 10e0153018 fix: initial type signature bulry issue 2024-08-01 17:56:44 +05:30
RaktimaNXG 42cbe94af8 fix: initial type signature issue 2024-08-01 16:50:48 +05:30
AndrewandGitHub 8f95e53d9d Merge pull request #999 from OpenSignLabs/multiuser_issue 2024-08-01 16:49:44 +05:30
prafull-opensignlabs 0dae21dcf1 build(Deps): update depencencies and overide ws packge to resolve security issue 2024-08-01 16:39:37 +05:30
RaktimaNXG 912efeb5fd refactor-code 2024-08-01 15:50:48 +05:30
AmolandGitHub 3d9307f96d Merge pull request #997 from OpenSignLabs/multiuser_issue 2024-08-01 13:55:24 +05:30
prafull-opensignlabs 873f4b080a build(deps): update depencies 2024-08-01 13:52:07 +05:30
RaktimaNXG e337a79e2e fix: type initials and signature looks blurry on download pdf 2024-08-01 13:32:18 +05:30
AndrewandGitHub 980ce62bf6 Merge pull request #995 from OpenSignLabs/multiuser_issue 2024-07-31 22:10:21 +05:30
prafull-opensignlabs dccf757f56 fix: gmail adapter is not working 2024-07-31 21:26:14 +05:30
prafull-opensignlabsandGitHub 4a6b88328e Merge pull request #993 from OpenSignLabs/input_text_darkmode
fix: display wrong owner's ip address on certificate in bulk-send flow
2024-07-31 20:16:32 +05:30
RaktimaNXG 779a84cf0b fix: display wrong owner's ip addressin certificate in bulk-send flow 2024-07-31 20:15:07 +05:30
prafull-opensignlabsandGitHub aff409ba63 Merge pull request #992 from OpenSignLabs/input_text_darkmode
fix: all types of text widget background color issues in mobile dark mode.
2024-07-31 19:47:13 +05:30
RaktimaNXG 275167c0c4 fix: all types of text widget background color issues in mobile dark mode. 2024-07-31 16:56:11 +05:30
AndrewandGitHub 19b2af7f57 Merge pull request #990 from KrisIsNewxyz/staging 2024-07-31 03:02:57 +05:30
AndrewandGitHub 5050b9ee97 Merge pull request #991 from OpenSignLabs/multiuser_issue 2024-07-30 19:36:40 +05:30
prafull-opensignlabs 23da4be6b1 fix: err invalid protcol while sending file in mail 2024-07-30 18:15:16 +05:30
prafull-opensignlabs 299648b8e0 fix: getaddrinfo ENOTFOUND while creating admin 2024-07-30 16:53:36 +05:30
KrisIsNewxyz 86fa0c87ae repair broken conection to mongodb - Update .env.local_dev 2024-07-30 13:01:55 +02:00
prafull-opensignlabsandGitHub 9619eec40f Merge pull request #980 from OpenSignLabs/raktima-opensignlabs-patch-11
fix: issue with files opening in a new tab on download instead of direct download
2024-07-26 19:24:46 +05:30
RaktimaNXG 886161d65f refactor code 2024-07-26 18:47:57 +05:30
RaktimaNXG d5d646e6e0 fix: issue with files opening in a new tab on download instead of direct download 2024-07-26 18:37:48 +05:30
prafull-opensignlabsandGitHub 494103163c Merge pull request #978 from OpenSignLabs/raktima-opensignlabs-patch-11
fix: ip address missing issue in the completion certificate of document originator using public-sign flow
2024-07-26 15:28:21 +05:30
RaktimaNXG 72e9e4848b refactor code 2024-07-26 14:43:16 +05:30
RaktimaNXG 1181ba6f90 refactor code 2024-07-26 14:40:22 +05:30
RaktimaNXG b8d6ec5fe0 fix: ip address missing of document originator using public-sign 2024-07-26 14:06:47 +05:30
AndrewandGitHub 7335d7df0a Merge pull request #976 from OpenSignLabs/multiuser_issue 2024-07-25 21:01:24 +05:30
prafull-opensignlabs 44754095fb refactor: changes in cloud function 2024-07-25 20:34:44 +05:30
prafull-opensignlabsandGitHub 0f515bae01 Merge pull request #963 from OpenSignLabs/raktima-opensignlabs-patch-11
fix: text widget font size issue in large PDF documents
2024-07-25 16:23:38 +05:30
RaktimaNXG 76a11f6ee6 fix: something went wrong issue in public profile 2024-07-25 14:30:02 +05:30
prafull-opensignlabsandGitHub 5fb28feb65 Merge pull request #974 from OpenSignLabs/multiuser_issue
fix: not able to deactivate teams
2024-07-25 11:03:05 +05:30
prafull-opensignlabs e5f1524b10 fix: not able to deactivate teams 2024-07-25 11:00:55 +05:30
AmolandGitHub 8a875691fb Merge pull request #971 from OpenSignLabs/fix_selfhost 2024-07-25 01:22:00 +05:30
prafull-opensignlabs 0b2710b97d fix: docker config files 2024-07-25 01:20:42 +05:30
AmolandGitHub 57552a32b0 Merge pull request #969 from OpenSignLabs/multiuser_issue 2024-07-24 22:50:21 +05:30
prafull-opensignlabs 572ec3658e fix: teams are not available in dropdown when creating user 2024-07-24 22:49:26 +05:30
AmolandGitHub 6d5c791f61 Merge pull request #968 from OpenSignLabs/multiuser_issue 2024-07-24 17:53:01 +05:30
prafull-opensignlabs 168e479c0c refactor: plan changes 2024-07-24 17:51:32 +05:30
AmolandGitHub 927e1b7ef9 Merge pull request #966 from OpenSignLabs/multiuser_issue
refactor: plan changes
2024-07-24 17:45:56 +05:30
prafull-opensignlabs 76dccf804e refactor: plan changes 2024-07-24 17:42:20 +05:30
RaktimaNXG 4262e0e6eb fix: text input font size isssue in mobile view 2024-07-24 13:42:41 +05:30
RaktimaNXG 7d487420aa Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into raktima-opensignlabs-patch-11 2024-07-24 12:25:28 +05:30
prafull-opensignlabsandGitHub c20611b50b Merge pull request #965 from OpenSignLabs/multiuser_issue
fix: change send email hint, email validation, remove underline from stamp and image modal
2024-07-24 12:00:06 +05:30
prafull-opensignlabs 15d73ee62d fix: change send email hint, email validation, remove underline for stamp modal 2024-07-24 11:58:55 +05:30
AmolandGitHub a334cda9aa Merge pull request #964 from OpenSignLabs/multiuser_issue 2024-07-23 19:44:46 +05:30
prafull-opensignlabs 69d4254b44 feat: add validation for teams and organization 2024-07-23 19:43:36 +05:30
RaktimaNXG c422b11e3a fix: text widget font size issue in large pdf 2024-07-23 15:50:38 +05:30
prafull-opensignlabsandGitHub 95d2794754 Merge pull request #962 from OpenSignLabs/multiuser_issue
fix: updated pdf should be downloadable from reports
2024-07-23 11:28:59 +05:30
prafull-opensignlabs 65ce0d430c fix: updated pdf should be downloadable from reports 2024-07-23 11:27:37 +05:30
prafull-opensignlabsandGitHub e7a98d55f0 Merge pull request #961 from OpenSignLabs/raktima-opensignlabs-patch-11
fix: signer selection removed after clicking widget settings and some widget's issue
2024-07-22 19:17:07 +05:30
RaktimaNXG d247c6d0e7 fix: signer selection removed after clicking widget settings, widget placeholder's name field text getting change issue 2024-07-22 16:18:10 +05:30
prafull-opensignlabsandGitHub 20e0277113 Merge pull request #957 from OpenSignLabs/raktima-opensignlabs-patch-11
fix: switch staging base URL and app ID to production for public-sign.
2024-07-22 09:57:16 +05:30
RaktimaNXG 2ed3609c46 fix: change staging url to production for public-sign 2024-07-20 18:03:01 +05:30
AmolandGitHub 2e41dc20c1 Merge pull request #956 from OpenSignLabs/raktima-opensignlabs-patch-11 2024-07-20 13:02:25 +05:30
RaktimaNXG 50a8f93014 fix: unable to finish document issue in public-sign 2024-07-20 12:54:49 +05:30
RaktimaandGitHub 3803b29835 Merge pull request #955 from OpenSignLabs/multiuser_issue
build(deps): update depenceies
2024-07-19 19:37:20 +05:30
prafull-opensignlabs e18586887e build(deps): update depenceies 2024-07-19 19:35:25 +05:30
prafull-opensignlabsandGitHub d137c081ee Merge pull request #954 from OpenSignLabs/raktima-opensignlabs-patch-11
fix: error of something went wrong on finish button in guest login flow
2024-07-19 18:53:26 +05:30
prafull-opensignlabsandGitHub 62dfe32d32 Merge pull request #953 from OpenSignLabs/multiuser_issue
fix: some tab not available in menu
2024-07-19 18:52:59 +05:30
RaktimaNXG f801192a8c fix: error of something went wrong on finish button in guest login flow 2024-07-19 18:01:47 +05:30
prafull-opensignlabs 13d161e3c8 fix: some tab not available in menu 2024-07-19 18:00:53 +05:30
prafull-opensignlabsandGitHub a249baea66 Merge pull request #952 from OpenSignLabs/raktima-opensignlabs-patch-11
fix: the quick-send flow in-progress report shows the finish button even though the current user isn't a signer
2024-07-19 16:46:22 +05:30
RaktimaNXG f6f5b08d43 fix: the quick-send flow in-progress report shows the finish button even though the current user isn't a signer 2024-07-19 16:31:43 +05:30
prafull-opensignlabsandGitHub a1f4e9ea74 Merge pull request #949 from OpenSignLabs/raktima-opensignlabs-patch-11
fix: add CDN for icons, issue in public-template flow
2024-07-19 11:48:30 +05:30
RaktimaNXG 5eed145f4b fix: refactor code 2024-07-19 11:27:52 +05:30
AmolandGitHub 546a0f8e87 Merge pull request #950 from OpenSignLabs/multiuser_issue 2024-07-19 11:15:53 +05:30
prafull-opensignlabs 975c4b079a fix: alerts are not visible is login screen 2024-07-19 11:13:53 +05:30
RaktimaNXG 09e0ac2415 fix: handle condition when sendInOrder enabled to make public template 2024-07-19 09:52:01 +05:30
RaktimaNXG 6140aea31a fix: refactor code 2024-07-18 21:06:51 +05:30
RaktimaNXG c59c921a8b fix: shift the fonts.css file to CDN, ensure emails are sent to all signers when sendInOrder is set to false in public-sign, and add validation for the sequence of public roles when sendInOrder is enabled 2024-07-18 18:56:42 +05:30
AmolandGitHub 4b1e13d39a Merge pull request #948 from OpenSignLabs/multiuser_issue
fix: subscribe to newsletter is not working
2024-07-18 18:44:04 +05:30
prafull-opensignlabs e33e0be735 fix: subscribe to newsletter is not working 2024-07-18 18:42:39 +05:30
AmolandGitHub 2ff4e372d6 Merge pull request #946 from OpenSignLabs/multiuser_issue
fix: when set USE_LOCAL=true get undefined endpoint error in server
2024-07-18 18:37:20 +05:30
prafull-opensignlabs 9cfffe3fbd fix: when set USE_LOCAL=true get undefined endpoint error in server 2024-07-18 17:20:59 +05:30
AmolandGitHub 82ef278a0e Merge pull request #945 from OpenSignLabs/prafull-opensignlabs-patch-22
Update Docker.yml
2024-07-18 16:30:31 +05:30
prafull-opensignlabsandGitHub 574d2d05a4 Update Docker.yml 2024-07-18 16:29:11 +05:30
AmolandGitHub 38f72c7415 Merge pull request #944 from OpenSignLabs/prafull-opensignlabs-patch-21
build (deps): update node package in docker
2024-07-18 16:19:02 +05:30
prafull-opensignlabsandGitHub e00704a43c build (deps): update node package in docker 2024-07-18 15:59:12 +05:30
prafull-opensignlabsandGitHub 778e28fae0 Merge pull request #942 from OpenSignLabs/raktima-opensignlabs-patch-11
fix: unexpected modal issue when the settings icon is clicked on text input type widgets.
2024-07-17 17:59:04 +05:30
RaktimaNXG 1574f86654 fix: add comment to using base url from local storage 2024-07-17 17:57:06 +05:30
RaktimaNXG df17bdcd68 fix: download and print issue during public sign 2024-07-17 16:38:31 +05:30
RaktimaandGitHub f290fd875f Merge branch 'staging' into raktima-opensignlabs-patch-11 2024-07-17 15:19:03 +05:30
AndrewandGitHub caeb055fc2 Merge pull request #941 from OpenSignLabs/multiuser_issue 2024-07-17 15:14:59 +05:30
prafull-opensignlabs 1eafc113e6 fix: migration function 2024-07-17 15:13:14 +05:30
RaktimaNXG 4e46795e0f fix: unexpected modal issue when the settings icon is clicked on text input widgets. 2024-07-17 15:11:06 +05:30
prafull-opensignlabs f7087dfb29 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into multiuser_issue 2024-07-17 12:25:12 +05:30
prafull-opensignlabsandGitHub e6a7cda3b6 Merge pull request #939 from OpenSignLabs/raktima-opensignlabs-patch-11
fix: wrong docs appears need-your-sign report, tour still appears even click on don't show again in recipientSignPdf flow
2024-07-17 11:35:14 +05:30
RaktimaNXG db120ecda7 fix: remove console 2024-07-17 11:23:16 +05:30
prafull-opensignlabs 9bfe8b0e26 refactor: remove premium alert 2024-07-17 11:19:32 +05:30
RaktimaNXG c1438be9e0 fix: mismatch report in need-your-sign report, unnecessary tour appears after click on don't show again in recipients signature flow 2024-07-17 09:47:30 +05:30
AndrewandGitHub f4d7e33f97 Merge pull request #937 from OpenSignLabs/migrate_db 2024-07-16 17:40:23 +05:30
prafull-opensignlabs 4ec7fdb078 fix: update migration script to setup db 2024-07-16 17:34:14 +05:30
prafull-opensignlabsandGitHub 3413d0914d Merge pull request #934 from OpenSignLabs/raktima-opensignlabs-patch-11
fix: tailwind css not applied on production mode after load public-sign script in public profile
2024-07-16 16:58:17 +05:30
RaktimaNXG 793b6a5550 add comment 2024-07-16 16:19:58 +05:30
RaktimaNXG 77894f6754 fix: handle css file for public-sign script 2024-07-16 16:13:43 +05:30
RaktimaNXG 812928a6a3 fix: tailwind css not applied on production mode after load public-sign script in public profile 2024-07-16 13:31:52 +05:30
prafull-opensignlabsandGitHub bb398d13a2 Merge pull request #933 from OpenSignLabs/multiuser_issue
fix: provide route to upgrade from v1 to v2 for self hosting
2024-07-16 13:15:04 +05:30
prafull-opensignlabs 2d7a893424 fix: provide route to upgrade from v1 to v2 for self hosting 2024-07-16 13:13:08 +05:30
RaktimaandGitHub 62e943161a Merge pull request #922 from OpenSignLabs/multiuser_issue
feat: change manager role with editor, add admin panel for self-hosting
2024-07-12 19:22:47 +05:30
prafull-opensignlabs 2604156c7f feat: change manager role with editot, add admin panel for self-hosting 2024-07-12 19:07:27 +05:30
prafull-opensignlabsandGitHub 1e04bb4dbe Merge pull request #921 from OpenSignLabs/raktima-opensignlabs-patch-11
fix: webpack build error, restrict space in public username
2024-07-12 14:41:24 +05:30
RaktimaNXG 0ac3a70a83 fix: webpack build error, restrict space in public username 2024-07-12 13:00:36 +05:30
prafull-opensignlabsandGitHub 2f1ad45f92 Merge pull request #920 from OpenSignLabs/raktima-opensignlabs-patch-11
fix: public profile user name already exist issue
2024-07-12 11:30:47 +05:30
RaktimaNXG 8263e3247e fix: handle condition to enter username 2024-07-12 11:28:36 +05:30
RaktimaNXG 9666e41880 fix: public profile user name already exist issue 2024-07-12 11:24:49 +05:30
prafull-opensignlabsandGitHub e50f062a91 Merge pull request #915 from OpenSignLabs/raktima-opensignlabs-patch-11
feat : implement public profile functionality and develop script for public sign-in
2024-07-11 10:10:45 +05:30
RaktimaNXG 1c8f401060 fix: change public profile url and console staging url 2024-07-11 09:59:06 +05:30
RaktimaNXG a8e764a62c Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into raktima-opensignlabs-patch-11 2024-07-11 09:55:31 +05:30
AmolandGitHub 43bc1f3e17 Update README.md 2024-07-11 01:22:47 +05:30
RaktimaNXG eebed949cd fix: handle getTemplate cloud function condition 2024-07-10 18:28:45 +05:30
AmolandGitHub c7cd9e56f8 Merge pull request #916 from OpenSignLabs/multiuser_issue 2024-07-10 16:46:08 +05:30
prafull-opensignlabs 1c9fb5ebcb feat: ask reason for decline/revoke document 2024-07-10 16:44:20 +05:30
RaktimaNXG 1339259c3b feat : add cloud function for public sign 2024-07-10 12:36:22 +05:30
RaktimaNXG 27a069e1a2 feat :implement public profile functionality and develop script for public sign-in 2024-07-10 12:35:10 +05:30
AmolandGitHub 7a69537255 Merge pull request #913 from OpenSignLabs/multi_user 2024-07-09 20:13:31 +05:30
prafull-opensignlabs 9569b78e66 refactor: commented unncessary btn in report 2024-07-09 19:37:03 +05:30
AmolandGitHub 266b0f27f5 Merge pull request #911 from OpenSignLabs/multi_user 2024-07-09 18:11:34 +05:30
prafull-opensignlabs 00e5c48828 feat: make profile portion from sidebar redirectable, restrict menu 2024-07-09 18:10:14 +05:30
AmolandGitHub c9e010e993 Update USAGE.md 2024-07-09 12:23:06 +05:30
prafull-opensignlabsandGitHub 5b52825ea6 Merge pull request #910 from OpenSignLabs/multi_user
feat: migration script for multi-user classes
2024-07-09 10:05:22 +05:30
prafull-opensignlabs 100b97cf1a refactor: restricted staging plan 2024-07-08 22:16:28 +05:30
prafull-opensignlabs 7a3216a81c feat: migration script for multi-user classes 2024-07-08 20:39:00 +05:30
AndrewandGitHub c6412be70d Merge pull request #909 from OpenSignLabs/multi_user 2024-07-08 19:08:02 +05:30
prafull-opensignlabs 954dbb3375 fix: teams are not visible in add user form, after upgrade subscription some menu are not visible 2024-07-08 19:06:37 +05:30
AndrewandGitHub c996825665 Merge pull request #908 from OpenSignLabs/multi_user 2024-07-08 17:05:53 +05:30
prafull-opensignlabs 5fc1a58bdb feat: add login validation for user and fix warning message in teams and users report 2024-07-08 17:04:12 +05:30
prafull-opensignlabsandGitHub 5c947181a2 Merge pull request #907 from OpenSignLabs/multi_user
build(deps): update parse package
2024-07-08 11:42:59 +05:30
prafull-opensignlabs 2e8b2fa525 build(deps): update parse package 2024-07-08 11:38:15 +05:30
AndrewandGitHub 1e6e5f9dba Merge pull request #903 from OpenSignLabs/multi_user 2024-07-06 18:28:59 +05:30
prafull-opensignlabs fa2e169df4 build(deps): update dependencies 2024-07-06 18:27:48 +05:30
AndrewandGitHub 174023c62f Merge pull request #902 from OpenSignLabs/multi_user 2024-07-06 17:38:45 +05:30
prafull-opensignlabs 1198460c97 fix: remove unncessary localstorage variables 2024-07-06 17:32:40 +05:30
prafull-opensignlabs 07954c8bb6 fix: remove unnecessary button from shared template 2024-07-06 16:59:14 +05:30
AndrewandGitHub d4d9521c31 Merge pull request #901 from OpenSignLabs/multi_user 2024-07-05 00:18:11 +05:30
prafull-opensignlabs d77477f3d1 fix: team list is not visible and change teams class 2024-07-04 20:56:57 +05:30
AndrewandGitHub ff36faa96c Merge pull request #898 from OpenSignLabs/multi_user 2024-07-03 23:32:38 +05:30
prafull-opensignlabs 450de195a7 refactor: change name from department to team 2024-07-03 20:47:19 +05:30
prafull-opensignlabs 57b23d7f97 feat: add share-with opt in templates as well as restrict non-team user 2024-07-03 18:01:51 +05:30
prafull-opensignlabs a246f74e11 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into multi_user 2024-07-03 15:58:30 +05:30
prafull-opensignlabsandGitHub 89c687ed06 Merge pull request #897 from OpenSignLabs/raktima-opensignlabs-patch-10
fix: incorrect signer is being assigned to widgets
2024-07-03 15:19:18 +05:30
RaktimaNXG f7e2fa8aec fix: incorrect signer is being assigned to widgets 2024-07-03 11:25:52 +05:30
prafull-opensignlabs 8a2960511c feat: add share with functionality of template 2024-07-02 20:54:30 +05:30
prafull-opensignlabs 832e5c2181 fix: multiple user get added with same email 2024-07-02 13:25:28 +05:30
prafull-opensignlabs 00d900c2b2 fix: department not visible realtime in users reports, remove inactive department from dropdown 2024-07-02 12:30:50 +05:30
prafull-opensignlabs 47ef685bcc Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into multi_user 2024-07-02 10:44:35 +05:30
prafull-opensignlabsandGitHub 9f4aff65f2 Merge pull request #896 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/npm_and_yarn-1167fe84be
build(deps): bump the npm_and_yarn group in /apps/OpenSignServer with 2 updates
2024-07-02 10:43:33 +05:30
prafull-opensignlabs 2eddb49b8e Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into multi_user 2024-07-02 10:19:18 +05:30
prafull-opensignlabsandGitHub 63f1bb9fc7 Merge pull request #895 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/npm_and_yarn-4d67123cbe
build(deps-dev): bump postcss from 8.4.38 to 8.4.39 in /apps/OpenSign in the npm_and_yarn group
2024-07-02 10:19:05 +05:30
prafull-opensignlabs e73b055cc2 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into multi_user 2024-07-02 10:16:26 +05:30
prafull-opensignlabs abd7cf9b71 fix: duplicate entries in ancestors array and login issue 2024-07-02 00:27:29 +05:30
dependabot[bot]andGitHub 2dbd41ce65 build(deps): bump the npm_and_yarn group
Bumps the npm_and_yarn group in /apps/OpenSignServer with 2 updates: [parse-server](https://github.com/parse-community/parse-server) and [ws](https://github.com/websockets/ws).


Updates `parse-server` from 7.0.0 to 7.1.0
- [Release notes](https://github.com/parse-community/parse-server/releases)
- [Changelog](https://github.com/parse-community/parse-server/blob/alpha/CHANGELOG.md)
- [Commits](https://github.com/parse-community/parse-server/compare/7.0.0...7.1.0)

Updates `ws` from 7.5.9 to 7.5.10
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.5.9...7.5.10)

---
updated-dependencies:
- dependency-name: parse-server
  dependency-type: direct:production
  dependency-group: npm_and_yarn
- dependency-name: ws
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-01 18:36:29 +00:00
dependabot[bot]andGitHub 25ef7c9f39 build(deps-dev): bump postcss
Bumps the npm_and_yarn group in /apps/OpenSign with 1 update: [postcss](https://github.com/postcss/postcss).


Updates `postcss` from 8.4.38 to 8.4.39
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.38...8.4.39)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-01 18:35:49 +00:00
AmolandGitHub 81a4daa5e8 Merge pull request #894 from pravinOpenSign/patch-2
Update README.md
2024-07-01 20:26:20 +05:30
pravinandGitHub 3f9e6d1f81 Update README.md
OpenSign Images update
2024-07-01 20:10:39 +05:30
AmolandGitHub 1507f113f4 Merge pull request #893 from OpenSignLabs/raktima-opensignlabs-patch-10
fix: font size and font color issue of text box after take another text box
2024-07-01 19:31:19 +05:30
prafull-opensignlabs d46ba8f307 feat: add create department, user form as well as reports for them 2024-07-01 16:47:01 +05:30
RaktimaNXG 2426e7484c fix: font size and font color issue of text box after take another text box 2024-07-01 13:56:29 +05:30
prafull-opensignlabs 17b9fc772e feat: add department and add user form in reports 2024-06-28 21:12:58 +05:30
prafull-opensignlabs 7b2b71fea5 feat: add user from, show deparments, users in pages 2024-06-28 12:48:50 +05:30
prafull-opensignlabs 70a3adebd7 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into multi_user 2024-06-28 12:47:02 +05:30
AndrewandGitHub 9e012ef6c7 Merge pull request #885 from OpenSignLabs/raktima-opensignlabs-patch-10 2024-06-28 12:33:13 +05:30
RaktimaNXG 948e0d3270 remove console 2024-06-28 11:40:07 +05:30
RaktimaNXG 6e4f9ba0e9 remove console 2024-06-28 11:34:05 +05:30
RaktimaNXG a816ceb04b fix: issue displaying expired subscription after password change 2024-06-28 10:59:23 +05:30
RaktimaNXG f864f74f14 fix: not displaying already save font color and font size of text boxes in edit template flow 2024-06-27 19:30:45 +05:30
prafull-opensignlabs 2c715a77a2 feat: add departmentlist and userlist page 2024-06-27 19:00:55 +05:30
RaktimaNXG 9b4cdde80a fix: remove Add text from add recipient in mobile view 2024-06-27 18:45:10 +05:30
RaktimaNXG de2154e6fe fix: change add recipient and role ui design in mobile view and inconsistent font size and color combination in text widgets 2024-06-27 17:30:21 +05:30
RaktimaNXG 76f4ccfcf3 fix: inconsistent font size and color for all type text widgets in the template flow 2024-06-27 13:20:17 +05:30
RaktimaNXG af52bb30f5 fix: signer's list order issue after change order of signers in tamplate and placeholder flow 2024-06-27 12:23:39 +05:30
AmolandGitHub cc398d68e4 Merge pull request #883 from OpenSignLabs/raktima-opensignlabs-patch-10
fix: unnecessary showing message faild to load on send document popup
2024-06-26 18:17:17 +05:30
RaktimaNXG cd4844863e fix: unnecessary showing message faild to load on send document popup 2024-06-26 17:53:46 +05:30
AmolandGitHub 6d4ebf7be5 Merge pull request #882 from OpenSignLabs/raktima-opensignlabs-patch-10
fix: ui design of the share button in the in-progress report and various other UI issues.
2024-06-26 16:06:45 +05:30
RaktimaNXG 18992e0334 refactor: refactor code 2024-06-26 15:51:04 +05:30
RaktimaNXG 0580a18b0d fix: remove solid share button design to outline 2024-06-26 15:33:45 +05:30
RaktimaNXG 5a4114b786 fix: ui of share button in inprogress report, declined document popup hiding the navigation menu in mobile view, add loader to load animation of send request 2024-06-26 14:36:04 +05:30
AmolandGitHub 4fdf2299f8 Merge pull request #881 from OpenSignLabs/raktima-opensignlabs-patch-10 2024-06-26 11:31:29 +05:30
RaktimaNXG f15aa39588 fix: default text selection issue with the signature pad in the sign-yourself flow 2024-06-26 11:29:18 +05:30
AmolandGitHub 694312812a Merge pull request #880 from OpenSignLabs/raktima-opensignlabs-patch-10
fix: exiting user can't receive bulk emails, input widgets's size reduced in request-sign process
2024-06-25 20:15:46 +05:30
RaktimaNXG 2606b58434 fix: change save button to next in template flow 2024-06-25 17:17:20 +05:30
RaktimaNXG 943f9a0673 fix: navigate user on in-progress report after send document to signers. 2024-06-25 16:26:46 +05:30
RaktimaNXG 77622ebea9 fix: exiting user can't receive bulk emails, input widgets's size reduced in request-sign process 2024-06-25 16:07:54 +05:30
prafull-opensignlabsandGitHub 6fb714d565 Merge pull request #879 from OpenSignLabs/raktima-opensignlabs-patch-10
fix: tour messages display issue in all flow
2024-06-24 19:15:06 +05:30
RaktimaNXG f6170e01f6 fix: tour messages display issue in all flow 2024-06-24 19:10:28 +05:30
AmolandGitHub 1e857b615f Merge pull request #878 from OpenSignLabs/raktima-opensignlabs-patch-10
style: update theme color
2024-06-24 16:33:48 +05:30
prafull-opensignlabs b982ca5218 style: update theme color 2024-06-24 16:29:00 +05:30
prafull-opensignlabsandGitHub c83817800e Merge pull request #877 from OpenSignLabs/raktima-opensignlabs-patch-10
fix: update UI design of my signature
2024-06-24 16:17:33 +05:30
prafull-opensignlabs d1992839a8 Merge branch 'raktima-opensignlabs-patch-10' of https://github.com/OpenSignLabs/OpenSign into raktima-opensignlabs-patch-10 2024-06-24 16:14:37 +05:30
prafull-opensignlabs bfb7136c89 styke: make rounded corner in my signature 2024-06-24 16:14:24 +05:30
RaktimaNXG 52b2cc6af4 refactor: refactor code 2024-06-24 16:08:52 +05:30
AmolandGitHub 94d386541d Merge pull request #876 from OpenSignLabs/raktima-opensignlabs-patch-10 2024-06-24 16:08:08 +05:30
RaktimaNXG d85d76c8aa fix: text box widgets issue in mobile view, ui design of request sign flow in mobile view, signature widgets ratio, remove on mail sent celebration effect. 2024-06-24 15:49:27 +05:30
prafull-opensignlabs ade97b972f feat: add tour for webhook and apitoken, update css 2024-06-24 15:36:51 +05:30
prafull-opensignlabs 532780629b style: update send button color in send mail & size of certificate button 2024-06-24 11:32:10 +05:30
prafull-opensignlabs 1f2298f192 fix: dragging icon is not visible and css change 2024-06-24 11:02:32 +05:30
AmolandGitHub ae5d527e4f Merge pull request #870 from OpenSignLabs/raktima-opensignlabs-patch-10 2024-06-22 00:21:39 +05:30
prafull-opensignlabs e59a7e0028 Merge branch 'raktima-opensignlabs-patch-10' of https://github.com/OpenSignLabs/OpenSign into raktima-opensignlabs-patch-10 2024-06-21 20:19:01 +05:30
prafull-opensignlabs 1d6655eafe style: update ui design of my signature page 2024-06-21 20:18:37 +05:30
RaktimaNXG 09b39a467b fix: widgets disappear issue in request sign flow 2024-06-21 20:18:12 +05:30
RaktimaNXG e0e7dd5298 fix: widget's position errors caused by differing page sizes in landscape orientation 2024-06-21 19:28:59 +05:30
prafull-opensignlabs 56d5091b96 fix: miscellaneous folder are visible in folder popup 2024-06-21 19:06:50 +05:30
prafull-opensignlabs 0b28e64111 refactor: removed uncessary css, files 2024-06-21 18:44:17 +05:30
AmolandGitHub 482b75c6a7 Merge pull request #869 from OpenSignLabs/raktima-opensignlabs-patch-10 2024-06-21 17:12:35 +05:30
RaktimaNXG cdff7e252d fix: pagenumber issue 2024-06-21 16:56:43 +05:30
RaktimaNXG a18aee0be1 fix: landscape mode pdf after embed widget's position 2024-06-21 16:55:59 +05:30
prafull-opensignlabs 89f67bfeeb feat: mover sidebarlist from server to local 2024-06-21 16:18:39 +05:30
prafull-opensignlabs e4f0e9cef3 Merge branch 'raktima-opensignlabs-patch-10' of https://github.com/OpenSignLabs/OpenSign into raktima-opensignlabs-patch-10 2024-06-21 13:52:04 +05:30
prafull-opensignlabs 12599c1e5a style: change icon from solid to light 2024-06-21 13:51:38 +05:30
RaktimaNXG 6bb3203417 Merge branch 'raktima-opensignlabs-patch-10' of https://github.com/OpenSignLabs/OpenSign into raktima-opensignlabs-patch-10 2024-06-21 13:11:30 +05:30
RaktimaNXG 0eb2c5ecc4 fix: in landscape mode pdf after embed image,all text type and dropdown widgets position issue 2024-06-21 13:10:51 +05:30
prafull-opensignlabs 01ab19b235 feat: add box number in center of box in debugpdf UI 2024-06-20 20:09:24 +05:30
prafull-opensignlabs ba6b0ce7e5 fix: position of image type widgets on landscape pdf are not correct 2024-06-20 19:34:10 +05:30
prafull-opensignlabs b99d3f643b Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into raktima-opensignlabs-patch-10 2024-06-20 19:33:10 +05:30
nxglabs fea174c48d docs: update instructions to run frontend locally in dev mode 2024-06-20 15:34:13 +05:30
nxglabs 1aa1a602b3 docs: move .env.frontend_dev from root folder to apps/OpenSign folder 2024-06-20 15:31:18 +05:30
prafull-opensignlabs 37b7e50b4c fix: when zoom in tablet widget get disappeared & hide sidbar in tablet when close 2024-06-20 14:30:45 +05:30
prafull-opensignlabs e9fab26ef3 style: updated css in guest login, header, loader, reports & update profile img 2024-06-19 18:36:48 +05:30
prafull-opensignlabs 3216a1d4ae fix: handle zindex of pdf page in signyourself flow 2024-06-19 14:50:32 +05:30
RaktimaNXG eb0941f087 fix: widgets shift slightly in right side after being dropped in the template view. 2024-06-19 14:24:08 +05:30
RaktimaNXG 0a315ef9c7 fix: only add widget on first pageand it show unnecessary on all pages, unable to select widgets in tablet view 2024-06-19 12:45:15 +05:30
RaktimaNXG 134babd070 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into raktima-opensignlabs-patch-10 2024-06-19 11:17:57 +05:30
AmolandGitHub 954ba13f22 Merge pull request #867 from OpenSignLabs/resolve_stage 2024-06-19 10:57:37 +05:30
prafull-opensignlabs 66718fd416 build(deps): update dependecies 2024-06-19 10:52:48 +05:30
RaktimaNXG f4358c5004 fix: ui design issue in mobile view 2024-06-19 10:00:43 +05:30
prafull-opensignlabsandGitHub 63f888b3ec Merge pull request #854 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/eslint-9.5.0
build(deps-dev): bump eslint from 8.57.0 to 9.5.0 in /apps/OpenSign
2024-06-18 19:05:14 +05:30
prafull-opensignlabsandGitHub e066d1d273 Merge pull request #856 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/prettier-3.3.2
build(deps-dev): bump prettier from 3.3.0 to 3.3.2 in /apps/OpenSignServer
2024-06-18 19:04:49 +05:30
AmolandGitHub daddb10030 Merge pull request #864 from OpenSignLabs/resolve_stage 2024-06-18 19:01:00 +05:30
prafull-opensignlabs 6d9090d414 style: change email send popup UI in signrourself 2024-06-18 18:59:35 +05:30
AmolandGitHub 795e8a8ec9 Merge pull request #863 from OpenSignLabs/resolve_stage
feat: update design of signers Ui, style of some buttons and update primary, neutral color
2024-06-18 16:38:41 +05:30
prafull-opensignlabs e8b0b333a1 feat: update design of signers Ui, style of some buttons and update primary , neutral color 2024-06-18 14:41:50 +05:30
RaktimaNXG 93d9a761ca fix: widget's position issue after zoomin and zoomout 2024-06-18 14:38:44 +05:30
RaktimaNXG 3642d4f3a3 refactor: refactor code 2024-06-17 21:17:18 +05:30
RaktimaNXG 08387fc406 feat: optimize design for high-resolution monitors 2024-06-17 21:07:25 +05:30
AmolandGitHub d1d0f40b00 Merge pull request #861 from OpenSignLabs/resolve_stage 2024-06-17 18:35:53 +05:30
prafull-opensignlabs ad4a9e7141 feat: change icons from opensign drive 2024-06-17 18:34:12 +05:30
AmolandGitHub d46cb7dc10 Merge pull request #860 from OpenSignLabs/resolve_stage 2024-06-17 14:09:11 +05:30
prafull-opensignlabs 50b9717cb9 fix: stop loop of mail sent animation 2024-06-17 14:07:45 +05:30
AmolandGitHub 4e83734c5c Merge pull request #859 from OpenSignLabs/resolve_stage
fix: zindex of tooltip, decrease size of loader, remove description from signyourself and requestsign form
2024-06-17 13:47:50 +05:30
prafull-opensignlabs 6eeaea137a fix: zindex of tooltip, decrease size of loader, remove description from signyourseld and requestsign form 2024-06-17 13:42:21 +05:30
dependabot[bot]andGitHub 2c91499232 build(deps-dev): bump prettier in /apps/OpenSignServer
Bumps [prettier](https://github.com/prettier/prettier) from 3.3.0 to 3.3.2.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.3.0...3.3.2)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 00:39:28 +00:00
dependabot[bot]andGitHub e6085eb2c0 build(deps-dev): bump eslint from 8.57.0 to 9.5.0 in /apps/OpenSign
Bumps [eslint](https://github.com/eslint/eslint) from 8.57.0 to 9.5.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.57.0...v9.5.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 00:28:33 +00:00
AmolandGitHub 6fa4c4759b Merge pull request #853 from OpenSignLabs/resolve_stage 2024-06-16 15:13:39 +05:30
prafull-opensignlabs f8d6547c24 style: update css of folder component and remove unncessary css file 2024-06-16 15:12:20 +05:30
AmolandGitHub ffdd952440 Merge pull request #852 from OpenSignLabs/resolve_stage
fix: cannot open pdf in safari < 17.4
2024-06-16 13:37:26 +05:30
prafull-opensignlabs 9594e9438e fix: cannot open pdf in safari < 17.4 2024-06-16 13:36:45 +05:30
AmolandGitHub 08d1e9a360 Merge pull request #848 from OpenSignLabs/resolve_stage 2024-06-15 23:16:00 +05:30
prafull-opensignlabs 74a9d08550 style: update design of invalid session popup 2024-06-15 23:14:59 +05:30
AmolandGitHub 6fc86e026b Merge pull request #847 from OpenSignLabs/revert-846-revert-845-main
Revert "Safari issue patch "
2024-06-15 22:46:38 +05:30
AmolandGitHub 72da56a916 Revert "Revert "Safari issue patch "" 2024-06-15 22:45:55 +05:30
AmolandGitHub 4ba7ffbb1a Merge pull request #846 from OpenSignLabs/revert-845-main
Revert "Safari issue patch "
2024-06-15 22:44:59 +05:30
AmolandGitHub 0d9a0b8bb1 Revert "Safari issue patch " 2024-06-15 22:44:05 +05:30
AmolandGitHub 084aa69702 Merge pull request #845 from OpenSignLabs/main
Safari issue patch
2024-06-15 22:39:36 +05:30
AmolandGitHub 597635800f Merge branch 'staging' into main 2024-06-15 22:38:52 +05:30
AmolandGitHub 8da2c7fad4 Merge pull request #844 from OpenSignLabs/fix_withresolver 2024-06-15 22:33:49 +05:30
prafull-opensignlabs 2b0276ead9 fix: Promise.withResolvers is not function 2024-06-15 22:28:21 +05:30
AmolandGitHub 45a96ece54 Merge pull request #843 from OpenSignLabs/resolve_stage 2024-06-14 21:11:50 +05:30
prafull-opensignlabs 729d19dfd3 style: update css and add email sent gif 2024-06-14 20:47:18 +05:30
AmolandGitHub 29aa123669 Merge pull request #842 from OpenSignLabs/resolve_stage
fix: showing blank screen when try to send document
2024-06-14 19:14:18 +05:30
prafull-opensignlabs f69caf016a fix: showing blank screen when try to send document 2024-06-14 19:13:07 +05:30
AmolandGitHub 48e0e0ee15 fix: change docker branch to main 2024-06-14 18:16:15 +05:30
AmolandGitHub a71278f95c Merge pull request #840 from OpenSignLabs/resolve_stage 2024-06-14 18:07:24 +05:30
prafull-opensignlabs f7bb11ede1 style: update loader and ui design of components 2024-06-14 18:05:10 +05:30
prafull-opensignlabs 6a365f7734 style: update widget detail popups 2024-06-13 20:21:25 +05:30
prafull-opensignlabs e4d946e519 style: update UI of signyourself, edit document, request signature 2024-06-13 19:29:23 +05:30
prafull-opensignlabs 149a16f150 style: update design of template ui 2024-06-13 13:27:06 +05:30
prafull-opensignlabs d8ff3d9faa refactor: resolve eslint warning 2024-06-12 18:41:03 +05:30
prafull-opensignlabs fe34001e42 style: change default theme and ui changes in components 2024-06-12 17:28:03 +05:30
prafull-opensignlabs fcdd7e2758 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into resolve_stage 2024-06-12 17:05:21 +05:30
AndrewandGitHub 025c30b685 Merge pull request #836 from OpenSignLabs/fix_smtp
Fix: smtp is not working
2024-06-12 16:58:42 +05:30
prafull-opensignlabs e742e85f0e Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into fix_smtp 2024-06-12 16:58:21 +05:30
prafull-opensignlabs 476a99feae fix: smtpsecure is not defined 2024-06-12 16:56:28 +05:30
prafull-opensignlabs 29464585b8 fix: SMTP setup is not working 2024-06-12 16:54:09 +05:30
prafull-opensignlabs cdd078699b Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into resolve_stage 2024-06-12 11:15:00 +05:30
AmolandGitHub 9ef1e22fda Merge pull request #835 from OpenSignLabs/fix_linkcontact 2024-06-12 11:11:40 +05:30
prafull-opensignlabsandGitHub 655401e04b "Fix: Third contact is not receiving mail when second contact is non-existent." 2024-06-12 11:10:25 +05:30
prafull-opensignlabs b550c07ca8 style: change ui design of popups 2024-06-11 18:33:47 +05:30
prafull-opensignlabsandGitHub fd72094b8a Merge pull request #833 from OpenSignLabs/staging
fix: Ensure real-time updates to records in reports after actions are performed
2024-06-11 11:40:42 +05:30
AmolandGitHub 4d7348abc2 Merge pull request #832 from OpenSignLabs/fix_actions 2024-06-11 11:34:58 +05:30
prafull-opensignlabsandGitHub ec68479e98 fix: Ensure real-time updates to records in reports after actions are performed 2024-06-11 11:32:37 +05:30
prafull-opensignlabs ac05942e58 Merge branch 'feat_dasyui' of https://github.com/OpenSignLabs/OpenSign into resolve_stage 2024-06-11 11:11:25 +05:30
prafull-opensignlabsandGitHub b387b6b402 Merge pull request #829 from Zathiel/staging
build(deps): minor update
2024-06-11 10:01:54 +05:30
ZathielandGitHub e13baeb2fc Merge pull request #20 from Zathiel/dependabot/npm_and_yarn/apps/OpenSign/babel/runtime-corejs2-7.24.7
build(deps-dev): bump @babel/runtime-corejs2 from 7.24.6 to 7.24.7 in /apps/OpenSign
2024-06-11 00:32:07 +02:00
ZathielandGitHub 52eb8e4a68 Merge pull request #15 from Zathiel/dependabot/npm_and_yarn/apps/OpenSignServer/babel/eslint-parser-7.24.7
build(deps-dev): bump @babel/eslint-parser from 7.24.6 to 7.24.7 in /apps/OpenSignServer
2024-06-11 00:31:19 +02:00
ZathielandGitHub 71189783a8 Merge pull request #18 from Zathiel/dependabot/npm_and_yarn/apps/OpenSignServer/nodemon-3.1.3
build(deps-dev): bump nodemon from 3.1.1 to 3.1.3 in /apps/OpenSignServer
2024-06-11 00:30:31 +02:00
ZathielandGitHub aec9396524 Merge pull request #21 from Zathiel/dependabot/npm_and_yarn/apps/OpenSign/tailwindcss-3.4.4
build(deps-dev): bump tailwindcss from 3.4.3 to 3.4.4 in /apps/OpenSign
2024-06-11 00:29:36 +02:00
ZathielandGitHub d74390b974 Merge pull request #23 from Zathiel/dependabot/npm_and_yarn/apps/OpenSignServer/braces-3.0.3
build(deps): bump braces from 3.0.2 to 3.0.3 in /apps/OpenSignServer
2024-06-11 00:29:03 +02:00
ZathielandGitHub 998fe013c8 Merge pull request #24 from Zathiel/dependabot/npm_and_yarn/braces-3.0.3
build(deps-dev): bump braces from 3.0.2 to 3.0.3
2024-06-11 00:28:48 +02:00
dependabot[bot]andGitHub 06d4c9aeaf build(deps-dev): bump nodemon in /apps/OpenSignServer
Bumps [nodemon](https://github.com/remy/nodemon) from 3.1.1 to 3.1.3.
- [Release notes](https://github.com/remy/nodemon/releases)
- [Commits](https://github.com/remy/nodemon/compare/v3.1.1...v3.1.3)

---
updated-dependencies:
- dependency-name: nodemon
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 22:27:44 +00:00
dependabot[bot]andGitHub bc77a9b0a1 build(deps-dev): bump braces from 3.0.2 to 3.0.3
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 22:27:19 +00:00
dependabot[bot]andGitHub 07c0390401 build(deps): bump braces from 3.0.2 to 3.0.3 in /apps/OpenSignServer
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 22:27:00 +00:00
ZathielandGitHub c50d753d74 Merge pull request #22 from Zathiel/dependabot/npm_and_yarn/apps/OpenSignServer/grpc/grpc-js-1.10.9
build(deps): bump @grpc/grpc-js from 1.10.8 to 1.10.9 in /apps/OpenSignServer
2024-06-11 00:26:56 +02:00
dependabot[bot]andGitHub 65eef5739d build(deps): bump @grpc/grpc-js in /apps/OpenSignServer
Bumps [@grpc/grpc-js](https://github.com/grpc/grpc-node) from 1.10.8 to 1.10.9.
- [Release notes](https://github.com/grpc/grpc-node/releases)
- [Commits](https://github.com/grpc/grpc-node/compare/@grpc/grpc-js@1.10.8...@grpc/grpc-js@1.10.9)

---
updated-dependencies:
- dependency-name: "@grpc/grpc-js"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 22:22:20 +00:00
dependabot[bot]andGitHub 01eed3664b build(deps-dev): bump tailwindcss from 3.4.3 to 3.4.4 in /apps/OpenSign
Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss) from 3.4.3 to 3.4.4.
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/v3.4.4/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/compare/v3.4.3...v3.4.4)

---
updated-dependencies:
- dependency-name: tailwindcss
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 16:00:42 +00:00
dependabot[bot]andGitHub 685e09d406 build(deps-dev): bump @babel/runtime-corejs2 in /apps/OpenSign
Bumps [@babel/runtime-corejs2](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime-corejs2) from 7.24.6 to 7.24.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.24.7/packages/babel-runtime-corejs2)

---
updated-dependencies:
- dependency-name: "@babel/runtime-corejs2"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 16:00:25 +00:00
dependabot[bot]andGitHub 7bacca1f78 build(deps-dev): bump @babel/eslint-parser in /apps/OpenSignServer
Bumps [@babel/eslint-parser](https://github.com/babel/babel/tree/HEAD/eslint/babel-eslint-parser) from 7.24.6 to 7.24.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.24.7/eslint/babel-eslint-parser)

---
updated-dependencies:
- dependency-name: "@babel/eslint-parser"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 15:51:30 +00:00
prafull-opensignlabsandGitHub 3764ab5c30 Merge pull request #827 from OpenSignLabs/resolve_main
fix: conflict resolve
2024-06-10 20:40:07 +05:30
RaktimaNXG 2f7a1d67b6 fix: conflict resolve 2024-06-10 20:38:42 +05:30
prafull-opensignlabs 8726efb0aa style: updated buttons from report and signers input box 2024-06-10 20:37:21 +05:30
prafull-opensignlabsandGitHub e073e83ad6 Merge pull request #824 from OpenSignLabs/raktima-opensignlabs-patch-9
fix: a mismatch permits a signer placeholder to sign any placeholder not allocated to that signer issue in the quick send flow.
2024-06-10 18:42:08 +05:30
RaktimaNXG 69140d2139 fix: a mismatch permits a signer placeholder to sign any placeholder not allocated to that signer issue in the quick send flow. 2024-06-10 18:14:28 +05:30
prafull-opensignlabs aeed48c0ef style: change ui design of login, signup, forgetpassword page 2024-06-10 15:51:52 +05:30
prafull-opensignlabs 1f9504b9cc style: change default theme emerald to cupcake 2024-06-10 15:01:16 +05:30
prafull-opensignlabsandGitHub 5518d6932e Merge pull request #823 from OpenSignLabs/raktima-opensignlabs-patch-9
fix: second non existing signer is not receiving the signature request email in the quick-send process.
2024-06-10 12:19:49 +05:30
RaktimaNXG f14e301b6c fix: change condition of email send 2024-06-10 12:15:48 +05:30
RaktimaNXG 901ddf35bb remove console 2024-06-10 11:43:56 +05:30
RaktimaNXG 9aa3166528 fix: second signer is not receiving the signature request email in the quick-send process. 2024-06-10 11:24:35 +05:30
prafull-opensignlabsandGitHub a90e679228 Merge pull request #813 from OpenSignLabs/raktima-opensignlabs-patch-9
fix: display the list of unsigned signers in the 'Yet to Sign' panel using the QuickSend flow.
2024-06-07 20:16:34 +05:30
RaktimaNXG 90b5e3c860 fix: exist contact not recieving maiin in quick send flow 2024-06-07 19:55:40 +05:30
RaktimaNXG 74f6612271 refactor code 2024-06-07 19:33:28 +05:30
prafull-opensignlabs 2862a97c4e feat: implement daisy-ui in alert, report, drive 2024-06-07 19:32:00 +05:30
RaktimaNXG 5c3f967128 fix: add validation of signature widgetat in quick send flow, update SentToOthers field when document is in inProgress , resolve resend nonexist email issue 2024-06-07 19:07:56 +05:30
prafull-opensignlabs 6fde71e947 feat: implement daisy-ui in all pages 2024-06-07 14:24:15 +05:30
RaktimaNXG 2900464272 fix: display the list of unsigned signers in the 'Yet to Sign' panel using the QuickSend flow. 2024-06-07 14:20:36 +05:30
prafull-opensignlabs 10bac3c11f refactor: change prefix of daisy-ui theme classes 2024-06-07 11:19:08 +05:30
AmolandGitHub 302f38d472 Merge pull request #808 from OpenSignLabs/autoreminder 2024-06-06 19:36:19 +05:30
prafull-opensignlabs 8ecdbc43a3 feat: implement daisy ui in forms 2024-06-06 18:36:31 +05:30
prafull-opensignlabs 6721b334cf refactor: remove unncessary code from dashboard & css changes in sidebar 2024-06-06 14:38:08 +05:30
prafull-opensignlabs 454f557d14 fix: position of cards and reports in dashboard 2024-06-06 11:49:06 +05:30
prafull-opensignlabs 635693b394 fix: position of cards and reports 2024-06-06 11:48:06 +05:30
prafull-opensignlabsandGitHub 0be1816046 Merge pull request #801 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/nodemon-3.1.2
build(deps-dev): bump nodemon from 3.1.1 to 3.1.2 in /apps/OpenSignServer
2024-06-06 11:09:30 +05:30
prafull-opensignlabsandGitHub feb162e03e Merge pull request #809 from Zathiel/staging
build(deps) : react-rnd && mongoose
2024-06-06 11:06:42 +05:30
prafull-opensignlabs c8801846fa feat: implement daisy ui in dashboard 2024-06-05 20:23:50 +05:30
ZathielandGitHub a793fc3722 Merge pull request #1 from Zathiel/dependabot/npm_and_yarn/apps/OpenSign/react-rnd-10.4.11
build(deps): bump react-rnd from 10.4.10 to 10.4.11 in /apps/OpenSign
2024-06-05 14:26:30 +02:00
ZathielandGitHub ffdabe4a00 Merge pull request #13 from Zathiel/dependabot/npm_and_yarn/apps/OpenSignServer/mongoose-8.4.1
build(deps): bump mongoose from 8.4.0 to 8.4.1 in /apps/OpenSignServer
2024-06-05 14:25:43 +02:00
prafull-opensignlabs 5536c99052 feat: implement daisy-ui in sidebar 2024-06-05 17:35:31 +05:30
prafull-opensignlabsandGitHub ba1c3145f3 fix: mail and document count in autoreminder API is not correct 2024-06-05 13:49:20 +05:30
prafull-opensignlabs 0fbe6aeb6c feat: implement dasyui in header, footer & report 2024-06-04 19:38:41 +05:30
AmolandGitHub 4898c4a851 Merge pull request #807 from OpenSignLabs/feat_sso 2024-06-04 10:06:34 +05:30
prafull-opensignlabs 85aa6b2947 fix: update sso url 2024-06-04 10:03:30 +05:30
AmolandGitHub 3b02d2bcdb fix: update SSO url 2024-06-04 01:01:52 +05:30
dependabot[bot]andGitHub ed01f4a7a0 build(deps): bump mongoose from 8.4.0 to 8.4.1 in /apps/OpenSignServer
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.4.0 to 8.4.1.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/8.4.0...8.4.1)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-03 15:38:51 +00:00
AmolandGitHub 1f395cf25f Merge pull request #806 from OpenSignLabs/feat_sso 2024-06-03 18:52:09 +05:30
prafull-opensignlabs cf98e73d13 fix: freeze sign in with sso button after click 2024-06-03 18:50:38 +05:30
AmolandGitHub 10112ac20d Merge pull request #805 from OpenSignLabs/feat_sso 2024-06-03 18:28:12 +05:30
prafull-opensignlabs 9a0183274f fix: Set send_email to false to stop receiving mails through API 2024-06-03 18:27:17 +05:30
AmolandGitHub 6b2e16c21d Merge pull request #804 from OpenSignLabs/feat_sso 2024-06-03 15:49:45 +05:30
prafull-opensignlabs 3c51baf1c9 build(deps): updated nth-check dependency for security 2024-06-03 15:46:24 +05:30
dependabot[bot]andGitHub 3f4be1c4f3 build(deps): bump react-rnd from 10.4.10 to 10.4.11 in /apps/OpenSign
Bumps [react-rnd](https://github.com/bokuweb/react-rnd) from 10.4.10 to 10.4.11.
- [Release notes](https://github.com/bokuweb/react-rnd/releases)
- [Commits](https://github.com/bokuweb/react-rnd/commits)

---
updated-dependencies:
- dependency-name: react-rnd
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-03 09:15:34 +00:00
AmolandGitHub 62b36f58f7 Merge pull request #803 from OpenSignLabs/feat_sso 2024-06-03 14:00:27 +05:30
prafull-opensignlabs ba3591c7bc fix: enable mail send feature for non-quick send documents when sendinorder is true 2024-06-03 13:51:15 +05:30
dependabot[bot]andGitHub 1ec11b8733 build(deps-dev): bump nodemon in /apps/OpenSignServer
Bumps [nodemon](https://github.com/remy/nodemon) from 3.1.1 to 3.1.2.
- [Release notes](https://github.com/remy/nodemon/releases)
- [Commits](https://github.com/remy/nodemon/compare/v3.1.1...v3.1.2)

---
updated-dependencies:
- dependency-name: nodemon
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-03 07:16:39 +00:00
prafull-opensignlabsandGitHub ab89d3b71f Merge pull request #799 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/prettier-3.3.0
build(deps-dev): bump prettier from 3.2.5 to 3.3.0 in /apps/OpenSignServer
2024-06-03 12:45:41 +05:30
prafull-opensignlabsandGitHub 1811173648 Merge pull request #796 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/reactour-1.19.4
build(deps): bump reactour from 1.19.3 to 1.19.4 in /apps/OpenSign
2024-06-03 12:44:34 +05:30
AmolandGitHub b218e96107 Merge pull request #802 from OpenSignLabs/fix_email 2024-06-03 12:39:24 +05:30
prafull-opensignlabs 64a0be8776 fix: cannot read property of undefined 'email' 2024-06-03 12:38:17 +05:30
dependabot[bot]andGitHub 414e2d819c build(deps-dev): bump prettier in /apps/OpenSignServer
Bumps [prettier](https://github.com/prettier/prettier) from 3.2.5 to 3.3.0.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.2.5...3.3.0)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-03 01:11:29 +00:00
dependabot[bot]andGitHub 0769101f28 build(deps): bump reactour from 1.19.3 to 1.19.4 in /apps/OpenSign
Bumps [reactour](https://github.com/elrumordelaluz/reactour) from 1.19.3 to 1.19.4.
- [Release notes](https://github.com/elrumordelaluz/reactour/releases)
- [Commits](https://github.com/elrumordelaluz/reactour/commits)

---
updated-dependencies:
- dependency-name: reactour
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-03 00:25:47 +00:00
AmolandGitHub 5dc86119d3 Merge pull request #794 from OpenSignLabs/feat_sso 2024-05-31 19:28:52 +05:30
prafull-opensignlabs 4999dc2b18 Fix: password field is not visible for non-sso user 2024-05-31 19:27:18 +05:30
AmolandGitHub 962d36c088 Merge pull request #793 from OpenSignLabs/feat_sso 2024-05-31 19:02:40 +05:30
prafull-opensignlabs d071986aac feat: hide password input for sso and restict sso 2024-05-31 19:00:29 +05:30
prafull-opensignlabs afb4de9d0c Feat: create SSO user account on platform 2024-05-31 18:22:16 +05:30
prafull-opensignlabs bc5c8cac33 feat: existing user can sign in with sso 2024-05-31 11:41:53 +05:30
prafull-opensignlabsandGitHub be93e6a214 Merge pull request #777 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/babel/runtime-corejs2-7.24.6
build(deps-dev): bump @babel/runtime-corejs2 from 7.24.5 to 7.24.6 in /apps/OpenSign
2024-05-31 10:40:37 +05:30
prafull-opensignlabsandGitHub 37748057e3 Merge pull request #791 from OpenSignLabs/public_url
fix: incorrect condition implementation for setting template as public based on isEnableSubscription
2024-05-30 18:10:34 +05:30
RaktimaNXG eb3bb77692 fix: incorrect condition implementation for setting template as public based on isEnableSubscription 2024-05-30 18:08:54 +05:30
prafull-opensignlabsandGitHub df0ce3f086 Merge pull request #788 from OpenSignLabs/public_url
feat: create public profile URLs to add username and develop functionality to make public template from report
2024-05-30 17:53:07 +05:30
AmolandGitHub 0a99b5181e Merge pull request #790 from OpenSignLabs/feat_bulksend 2024-05-30 17:37:45 +05:30
prafull-opensignlabs 8a5d3a0368 Fix: not able to create contract from add user icon in PDF UI 2024-05-30 17:35:40 +05:30
RaktimaNXG c00406e401 fix: template list status issue on pagination 2024-05-30 17:24:33 +05:30
RaktimaNXG aeead23c86 fix: change public profile url 2024-05-30 15:57:16 +05:30
RaktimaNXG 83fe88911f fix: public toggle issue,cloud function error handling 2024-05-30 15:55:16 +05:30
prafull-opensignlabsandGitHub 527bca32d2 Merge pull request #789 from Zathiel/staging
FIX : update USE_LOCAL variable
2024-05-30 15:14:09 +05:30
ZathielandGitHub 9bf4940c2e Merge branch 'OpenSignLabs:staging' into staging 2024-05-30 10:46:55 +02:00
ZathielandGitHub a653df6935 FIX : USE_LOCAL variable 2024-05-30 01:45:05 +02:00
RaktimaNXG dfc6da388c fix: add comment 2024-05-29 19:44:17 +05:30
RaktimaNXG 3e2c822bbc fix: handle condition to save username 2024-05-29 19:39:27 +05:30
RaktimaandGitHub 1a20841a94 Merge branch 'staging' into public_url 2024-05-29 19:31:17 +05:30
RaktimaNXG c6be81923b fix: conflict resolved in userProfile 2024-05-29 19:24:04 +05:30
RaktimaNXG 6b47f6a27b fix: add comment 2024-05-29 18:56:17 +05:30
RaktimaNXG 33b0111ed0 fix: remove console 2024-05-29 18:43:24 +05:30
RaktimaNXG 48fd9e52b3 fix: update isEnableSuscription variable nname 2024-05-29 18:20:16 +05:30
RaktimaNXG d85074b127 fix: username issue to get details from GetPublicUserNmae cloud function 2024-05-29 18:17:07 +05:30
AmolandGitHub 5ada9a411b Merge pull request #787 from OpenSignLabs/feat_bulksend 2024-05-29 17:56:43 +05:30
prafull-opensignlabs 6f50de1ef1 fix: make phone field optional for contact 2024-05-29 17:55:22 +05:30
AmolandGitHub 612150cf4b Merge pull request #786 from OpenSignLabs/feat_bulksend 2024-05-29 16:59:49 +05:30
prafull-opensignlabs 634db83e8e fix: duplicate contact are creatable, Update the the header 'Document signed' in the success message popup 2024-05-29 16:58:35 +05:30
RaktimaNXG b32c8068ef fix: merge changes from staging 2024-05-29 16:07:05 +05:30
RaktimaNXG ae464274b0 fix: update ReportJson file 2024-05-29 15:55:07 +05:30
AmolandGitHub c5ceba8d57 Merge pull request #785 from OpenSignLabs/feat_bulksend
fix: issue of something went wrong due to quick send
2024-05-29 13:56:05 +05:30
prafull-opensignlabs 903d626c27 fix: issue of something went wrong due to quick send 2024-05-29 13:05:57 +05:30
prafull-opensignlabsandGitHub e5b4fb123f Merge pull request #782 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/nodemon-3.1.1
build(deps-dev): bump nodemon from 3.1.0 to 3.1.1 in /apps/OpenSignServer
2024-05-28 20:21:00 +05:30
prafull-opensignlabsandGitHub 116893c1b4 Merge pull request #781 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/babel/eslint-parser-7.24.6
build(deps-dev): bump @babel/eslint-parser from 7.24.5 to 7.24.6 in /apps/OpenSignServer
2024-05-28 20:20:36 +05:30
prafull-opensignlabsandGitHub 592254a9a3 Merge pull request #778 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/lint-staged-15.2.5
build(deps-dev): bump lint-staged from 15.2.4 to 15.2.5 in /apps/OpenSign
2024-05-28 20:20:19 +05:30
AmolandGitHub f52c6e24fe Merge pull request #784 from OpenSignLabs/feat_bulksend 2024-05-28 19:23:50 +05:30
prafull-opensignlabs 70ae1e24fc fix: merge conflict 2024-05-28 19:18:41 +05:30
prafull-opensignlabs c491595fc8 Fix: issues in quick send 2024-05-28 18:56:56 +05:30
AmolandGitHub 6875135ede Merge pull request #783 from OpenSignLabs/feat_bulksend
Fix: issues in quick send
2024-05-28 10:42:33 +05:30
RaktimaNXG 662049d878 fix: remove console 2024-05-28 09:50:38 +05:30
RaktimaNXG 1764d7f9ba feat: create public profile URLs for users and develop functionality to make the report template public 2024-05-27 21:08:05 +05:30
prafull-opensignlabs 07933b56b1 Fix: issue of 'something went wrong' err in guest login flow when using quick send 2024-05-27 20:53:38 +05:30
prafull-opensignlabs f6ba4db62d Fix: Role, type are not visible on placeholder for non-exist contact 2024-05-27 20:06:06 +05:30
prafull-opensignlabs 5bd36f91d9 Fix: issue with multiple linking user in quick send 2024-05-27 18:46:37 +05:30
prafull-opensignlabs c199c3019e feat: add message for all signers linked in template for quick send 2024-05-27 14:50:17 +05:30
prafull-opensignlabs facbc8e76e Fix: issue of showing 'Please add Signers or Roles in template' even when roles are already exist in quick send 2024-05-27 12:59:43 +05:30
prafull-opensignlabs c3c6f6bab3 fix: send mail only first signer if sendinorder, takeout quick send btn from 3 dots 2024-05-27 11:59:25 +05:30
prafull-opensignlabsandGitHub f5e216fedc Merge pull request #768 from OpenSignLabs/raktima-opensignlabs-patch-8
feat: add download, certificate & print buttons on the document completion popup
2024-05-27 10:40:31 +05:30
RaktimaandGitHub c40a923388 Merge branch 'staging' into raktima-opensignlabs-patch-8 2024-05-27 10:30:38 +05:30
dependabot[bot]andGitHub a86f4fd9b7 build(deps-dev): bump nodemon in /apps/OpenSignServer
Bumps [nodemon](https://github.com/remy/nodemon) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/remy/nodemon/releases)
- [Commits](https://github.com/remy/nodemon/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: nodemon
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-27 00:27:27 +00:00
dependabot[bot]andGitHub 59f6d022cf build(deps-dev): bump @babel/eslint-parser in /apps/OpenSignServer
Bumps [@babel/eslint-parser](https://github.com/babel/babel/tree/HEAD/eslint/babel-eslint-parser) from 7.24.5 to 7.24.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.24.6/eslint/babel-eslint-parser)

---
updated-dependencies:
- dependency-name: "@babel/eslint-parser"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-27 00:27:04 +00:00
dependabot[bot]andGitHub b7beeee260 build(deps-dev): bump lint-staged in /apps/OpenSign
Bumps [lint-staged](https://github.com/okonet/lint-staged) from 15.2.4 to 15.2.5.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/master/CHANGELOG.md)
- [Commits](https://github.com/okonet/lint-staged/compare/v15.2.4...v15.2.5)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-27 00:14:13 +00:00
dependabot[bot]andGitHub 31c861cbe4 build(deps-dev): bump @babel/runtime-corejs2 in /apps/OpenSign
Bumps [@babel/runtime-corejs2](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime-corejs2) from 7.24.5 to 7.24.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.24.6/packages/babel-runtime-corejs2)

---
updated-dependencies:
- dependency-name: "@babel/runtime-corejs2"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-27 00:13:57 +00:00
AmolandGitHub 6a9408b7b4 docs: add Zathiel as a contributor for security 2024-05-24 19:24:52 +05:30
AmolandGitHub a9fd264a01 Merge pull request #772 from OpenSignLabs/feat_bulksend
Feat: quick send feature to create & send multiple documents at a time
2024-05-24 16:42:08 +05:30
prafull-opensignlabs 6c77bbfe75 feat: quick send feature to create & send multiple documents at a time 2024-05-24 16:29:03 +05:30
prafull-opensignlabs 890c3d2b1f Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into feat_bulksend 2024-05-24 11:34:58 +05:30
AmolandGitHub 3ede441f54 Merge pull request #771 from OpenSignLabs/staging
v1.7.4
2024-05-24 10:29:10 +05:30
AmolandGitHub 2433ad5957 Merge pull request #770 from OpenSignLabs/build_dep 2024-05-24 10:23:10 +05:30
prafull-opensignlabs fffd907d63 Fix: handle owner subscription has expired error in guest login 2024-05-24 10:13:34 +05:30
AmolandGitHub 51edc339cd Merge pull request #769 from OpenSignLabs/staging
v1.7.3
2024-05-23 18:22:49 +05:30
AmolandGitHub bf307abe9a Update plansArr.js 2024-05-23 18:17:00 +05:30
RaktimaNXG 08a97707b7 fix: completion popup design issue in tablet view 2024-05-23 13:46:17 +05:30
RaktimaNXG d99fecd46e feat: add download, certificate & print buttons on the document completion popup 2024-05-23 12:52:10 +05:30
prafull-opensignlabsandGitHub 6c59c0ec9a Merge pull request #767 from OpenSignLabs/raktima-opensignlabs-patch-8
feat: add help button for text validation
2024-05-23 10:35:45 +05:30
RaktimaNXG 32c75d1fc3 feat: add help button for text validation 2024-05-23 10:30:41 +05:30
AmolandGitHub 7f0f81c334 Merge pull request #766 from OpenSignLabs/build_dep
fix: issue in guestlogin of owner subscription has expired
2024-05-22 19:59:23 +05:30
prafull-opensignlabsandGitHub a882f07f57 Merge pull request #765 from OpenSignLabs/tour_message_requestsign
fix: download menu is not wokring inProgress report in mobile view
2024-05-22 19:58:21 +05:30
prafull-opensignlabs 74b81a5363 fix: issue in guestlogin of owner subscription has expired 2024-05-22 19:56:44 +05:30
AmolandGitHub 9b75764717 Merge pull request #764 from OpenSignLabs/build_dep
fix: resend mail not working, create contact API not working
2024-05-22 19:47:11 +05:30
RaktimaNXG c1468112b0 fix: download menu is not wokring inProgress report in mobile view 2024-05-22 19:46:22 +05:30
prafull-opensignlabs 950b74789c fix: create contact API not working 2024-05-22 19:46:09 +05:30
prafull-opensignlabs 7e4f12e41a feat: bulk send is working for exist contact 2024-05-22 19:31:32 +05:30
prafull-opensignlabs d75c1d7c0c fix: resend mail not working 2024-05-22 19:19:33 +05:30
prafull-opensignlabsandGitHub 7eacbedf59 Merge pull request #763 from OpenSignLabs/tour_message_requestsign
feat: add tour messages to request signatures flow
2024-05-22 19:02:12 +05:30
RaktimaNXG 2e5947279f fix:onclick upgrade button navigate user to new window 2024-05-22 18:51:57 +05:30
RaktimaNXG ef5ac7d626 fix: err is not defined 2024-05-22 17:49:24 +05:30
RaktimaNXG 658c37cc4d feat: add tour messages to request signatures flow 2024-05-22 17:48:15 +05:30
prafull-opensignlabs ffc8e4b23e Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into feat_bulksend 2024-05-22 13:44:14 +05:30
prafull-opensignlabsandGitHub 3fb96fc792 Merge pull request #762 from OpenSignLabs/build_dep
build(deps): update dependencies
2024-05-22 12:55:31 +05:30
prafull-opensignlabs 71016ba5e0 build(deps): update dependecies 2024-05-22 12:46:34 +05:30
prafull-opensignlabs cd1a6fdaf6 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into feat_bulksend 2024-05-22 12:11:46 +05:30
prafull-opensignlabsandGitHub c2afeed448 Merge pull request #760 from OpenSignLabs/raktima-opensignlabs-patch-7
fix: unnecessary emails are sent when a signers sign a document via a shared link.
2024-05-22 11:24:15 +05:30
RaktimaNXG 37fd7bbeda fix: update migration script add SendCompletionMail filed in contracts_Document class 2024-05-22 11:22:35 +05:30
RaktimaNXG 71fbde0099 fix: add migration script to add new filed SendMail and handle email sent using share link from inProgress report 2024-05-22 09:50:12 +05:30
prafull-opensignlabs ca6cb60d78 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into feat_bulksend 2024-05-22 09:49:51 +05:30
prafull-opensignlabsandGitHub df1c0ea66c Merge pull request #761 from Zathiel/staging
build(deps): react-redux, autoprefixer , react-datepicker axios, @reduxjs/toolkit, react-tooltip, tailwindcss react-pdf
2024-05-22 09:45:54 +05:30
Zathiel 46279efc2c build(deps): react-redux, autoprefixer , react-datepicker axios, @reduxjs/toolkit, react-tooltip, tailwindcss react-pdf 2024-05-21 15:29:38 +00:00
prafull-opensignlabs aca2848406 add Ui for bulk send, changes in reportjson 2024-05-21 20:26:46 +05:30
prafull-opensignlabsandGitHub eaec3cf607 Merge pull request #750 from Zathiel/staging
build(deps): update @reduxjs/toolkit package
2024-05-21 20:00:00 +05:30
ZathielandGitHub ad25d73f26 Merge branch 'OpenSignLabs:staging' into staging 2024-05-21 16:19:31 +02:00
RaktimaNXG 481b9ac1e0 fix: add send mail false using share link from inprogress report 2024-05-21 17:36:41 +05:30
AmolandGitHub 4cd3791feb Merge pull request #759 from OpenSignLabs/feat_resendmail 2024-05-21 15:18:10 +05:30
RaktimaNXG 7de8699437 fix: unnecessary emails are sent when a user signs a document via a shared link. 2024-05-21 15:08:40 +05:30
prafull-opensignlabsandGitHub 4c162676b1 Merge pull request #753 from OpenSignLabs/raktima-opensignlabs-patch-7
feat:  celebration confetti on document completion
2024-05-21 14:02:28 +05:30
prafull-opensignlabs ca390bdfa6 refactor: remove Signpdf file 2024-05-21 13:56:37 +05:30
prafull-opensignlabs 22d064fd38 build(dep): update node-signpdf pacakge and it's dependencies, remove customsignpdf folder 2024-05-21 13:49:10 +05:30
AmolandGitHub 444c9bbfdf Merge pull request #756 from OpenSignLabs/feat_resendmail 2024-05-21 13:44:07 +05:30
prafull-opensignlabs b289686d42 build(dep): update parse-server package and it's dependencies 2024-05-21 13:42:50 +05:30
RaktimaNXG eeb878b340 refactor:refactor code 2024-05-21 13:40:54 +05:30
RaktimaNXG 7894d69cc9 fix: increase time to show confetti celebration 2024-05-21 13:35:22 +05:30
RaktimaNXG b992d7db24 fix: change celebration effect and add for whole screen 2024-05-21 13:03:51 +05:30
AmolandGitHub 50b72f4d85 Merge pull request #755 from OpenSignLabs/feat_resendmail 2024-05-20 18:43:49 +05:30
prafull-opensignlabs 44639f66b0 fix: autoreminder API not working 2024-05-20 18:42:32 +05:30
RaktimaNXG ae740efced refactor: refactor code 2024-05-20 17:46:07 +05:30
RaktimaNXG 66c020d903 fix: fix celebration ui for mobile view 2024-05-20 17:26:18 +05:30
AmolandGitHub 562a7d6fc8 Merge pull request #754 from OpenSignLabs/feat_resendmail
feat: now user can send automatic reminders
2024-05-20 15:44:54 +05:30
RaktimaNXG 090c17c2c0 refactor: add comment 2024-05-20 15:41:04 +05:30
RaktimaNXG 70637d6143 fix: handle condition to show complete message 2024-05-20 15:39:14 +05:30
prafull-opensignlabs f38e8705de feat: now user can sent automatic reminders 2024-05-20 15:31:20 +05:30
RaktimaNXG ba06ff72a0 fix: mismatch complete message issue in multiple signers flow 2024-05-20 14:01:06 +05:30
RaktimaNXG 82312a1e0d feat: celebration confetti on document completion 2024-05-20 11:42:37 +05:30
ZathielandGitHub 1a8cf11a3e Merge pull request #22 from Zathiel/dependabot/npm_and_yarn/apps/OpenSign/reduxjs/toolkit-2.2.4
build(deps): bump @reduxjs/toolkit from 2.2.1 to 2.2.4 in /apps/OpenSign
2024-05-19 02:18:41 +02:00
ZathielandGitHub 3deacbabc3 Merge pull request #8 from Zathiel/dependabot/npm_and_yarn/apps/OpenSignServer/babel/eslint-parser-7.24.5
build(deps-dev): bump @babel/eslint-parser from 7.24.1 to 7.24.5 in /apps/OpenSignServer
2024-05-19 02:18:23 +02:00
AmolandGitHub c28805add9 Merge pull request #749 from OpenSignLabs/feat_resendmail 2024-05-17 19:22:04 +05:30
prafull-opensignlabs 80fb320ae4 refactor: add mail in resend mail UI 2024-05-17 19:20:17 +05:30
AmolandGitHub 76c9c1fa53 Merge pull request #748 from OpenSignLabs/feat_resendmail 2024-05-17 14:53:57 +05:30
prafull-opensignlabs f38d83dbe0 style: change z-index of alert 2024-05-17 12:05:18 +05:30
AmolandGitHub ee9411729d Merge pull request #747 from OpenSignLabs/feat_resendmail
refactor: change in subject & body of resend mail
2024-05-17 10:57:29 +05:30
prafull-opensignlabs f6f7c6cecd refactor: change in subject & body of resend mail 2024-05-17 10:56:14 +05:30
AmolandGitHub a45fc0dd60 Merge pull request #746 from OpenSignLabs/feat_resendmail
fix: Cannot read properties of undefined (reading 'find') in resend mail & resend mail not available dashboard report
2024-05-17 10:49:06 +05:30
prafull-opensignlabs 348f7810b9 fix: Cannot read properties of undefined (reading 'find') in resend mail & resend mail not available dashboard report 2024-05-17 10:09:15 +05:30
AmolandGitHub 45bec128a9 Merge pull request #744 from OpenSignLabs/feat_resendmail 2024-05-16 19:37:39 +05:30
prafull-opensignlabs 4da307315c feat: add resend mail functionality for inprogress document 2024-05-16 19:34:28 +05:30
AmolandGitHub c87aa415a9 Merge pull request #743 from OpenSignLabs/signPdf
feat: move forget password button in login box
2024-05-15 20:13:38 +05:30
prafull-opensignlabs b1786ec16a feat: move forget password button in login box 2024-05-15 20:03:30 +05:30
AmolandGitHub 6ad35e979e Merge pull request #742 from OpenSignLabs/signPdf 2024-05-15 16:12:25 +05:30
prafull-opensignlabs 9d996d5cb7 feat: add copy icon beside API token 2024-05-15 16:09:11 +05:30
AmolandGitHub 008e3e8783 Merge pull request #741 from OpenSignLabs/signPdf 2024-05-15 14:52:04 +05:30
prafull-opensignlabs 8458906b0b fix: delete foler are still visible 2024-05-15 14:49:36 +05:30
AmolandGitHub 6933aa309b Merge pull request #740 from OpenSignLabs/signPdf 2024-05-15 13:55:49 +05:30
prafull-opensignlabs 067ea68d3b feat: add download button in 3 dots beside finish button 2024-05-15 13:25:13 +05:30
prafull-opensignlabs e4e8a0b721 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into signPdf 2024-05-15 11:10:29 +05:30
prafull-opensignlabs dc392adc1d feat: add delete folder API 2024-05-14 19:19:17 +05:30
AmolandGitHub 741efff1fa Merge pull request #739 from OpenSignLabs/staging
v1.7.2
2024-05-14 18:56:09 +05:30
AmolandGitHub 93b0d00ab0 Merge pull request #738 from OpenSignLabs/signPdf
fix: some webhook event are not working for second signer & add certificate in completed webhook
2024-05-14 18:33:31 +05:30
prafull-opensignlabs d731951159 fix: some webhook event are not working for second signer & add certificate in completed webhook 2024-05-14 18:30:26 +05:30
AmolandGitHub 24bf08c14f Merge pull request #737 from OpenSignLabs/signPdf
fix: resend mail API is not working
2024-05-14 16:44:42 +05:30
prafull-opensignlabs c03819f5a9 fix: resend mail API is not working 2024-05-14 16:36:58 +05:30
prafull-opensignlabsandGitHub 4521d16891 Merge pull request #719 from ugoconsonni/patch-4
Update createDocumentwithCoordinate.js
2024-05-14 13:57:08 +05:30
prafull-opensignlabs f77525cd8b fix: change baseUrl in APIs 2024-05-14 13:55:32 +05:30
AmolandGitHub 38b7311e66 Merge pull request #736 from OpenSignLabs/staging
v1.7.1
2024-05-14 10:45:00 +05:30
AmolandGitHub c934f8ccd6 Merge pull request #735 from OpenSignLabs/signPdf
fix: change  parameter name in updatefolder API
2024-05-14 10:40:30 +05:30
prafull-opensignlabs 4e128e5a5a fix: change parameter name in updatefolder API 2024-05-14 10:40:04 +05:30
AmolandGitHub e0ccf049a6 Merge pull request #734 from OpenSignLabs/staging
v1.7.0
2024-05-14 01:49:55 +05:30
dependabot[bot]andGitHub 1e58b35db5 build(deps): bump @reduxjs/toolkit from 2.2.1 to 2.2.4 in /apps/OpenSign
Bumps [@reduxjs/toolkit](https://github.com/reduxjs/redux-toolkit) from 2.2.1 to 2.2.4.
- [Release notes](https://github.com/reduxjs/redux-toolkit/releases)
- [Commits](https://github.com/reduxjs/redux-toolkit/compare/v2.2.1...v2.2.4)

---
updated-dependencies:
- dependency-name: "@reduxjs/toolkit"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-13 10:51:45 +00:00
ugoconsonniandGitHub 964ec0d422 Update createDocumentwithCoordinate.js
fix: email and api return url server and not front
2024-05-10 15:22:00 +02:00
AmolandGitHub 498bd18630 Merge pull request #717 from OpenSignLabs/staging
v1.6.2
2024-05-10 16:02:39 +05:30
AmolandGitHub b530ef882a Merge pull request #715 from OpenSignLabs/staging
v1.6.1
2024-05-10 11:18:58 +05:30
AmolandGitHub 850d14064a Merge pull request #710 from OpenSignLabs/staging
v1.6.0
2024-05-09 16:38:17 +05:30
prafull-opensignlabsandGitHub 273ada837b Merge pull request #703 from OpenSignLabs/staging
v1.5.9
2024-05-08 16:12:46 +05:30
dependabot[bot]andGitHub 280b812e5b build(deps-dev): bump @babel/eslint-parser in /apps/OpenSignServer
Bumps [@babel/eslint-parser](https://github.com/babel/babel/tree/HEAD/eslint/babel-eslint-parser) from 7.24.1 to 7.24.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.24.5/eslint/babel-eslint-parser)

---
updated-dependencies:
- dependency-name: "@babel/eslint-parser"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 12:51:25 +00:00
275 changed files with 245759 additions and 27500 deletions
-12
View File
@@ -1,12 +0,0 @@
# Clone the repo and rename this file to .env if you want to run the frontend react app locally for some quick contributions to the project.
# When used as it is, this env config will connect to our hosted UAT backend
# Note that any data in staging will get cleared from time to time and you may have to sign up again and again
# Set it to the URL form where the app home page will be accessed
PUBLIC_URL=http://localhost:3000
# Set it to true if you want to generate the Sourcemap for debugging
GENERATE_SOURCEMAP=false
# Set it to the URL from where APIs will be accessible, for local development it should be localhost:3000/api/app (use your local port number instead)
REACT_APP_SERVERURL=https://staging-app.opensignlabs.com/api/app
# A 12 character long random app identifier. The value of this should be same as APP_ID which is a variable used by backend API.
REACT_APP_APPID=opensign
+2 -2
View File
@@ -20,7 +20,7 @@ appName=open_sign_server
# A 12 character long random secret key that allows access to all the data. It is used in Parse dashboard config to view all the data in the database.
MASTER_KEY=XnAadwKxxByMr
# Mongodb URI to connect to
MONGODB_URI=mongodb://mongo:27017/OpenSignDB
MONGODB_URI=mongodb://mongo-container:27017/OpenSignDB
# Path on which APIs should be mounted. Do not change this. This variable shall be removed & value hardcoded in the source code in coming versions.
PARSE_MOUNT=/app
# Set it to the URL from where APIs will be accessible to the NodeJS functions, for local development it should be localhost:3000/api/app (use your local port number instead)
@@ -40,7 +40,7 @@ DO_SECRET_ACCESS_KEY=
# Digital ocean spaces region or AWS s3 region
DO_REGION=us-west
# local storage
USE_LOCAL=TRUE
USE_LOCAL=true
# Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
MAILGUN_API_KEY=
+2 -2
View File
@@ -10,9 +10,9 @@ jobs:
strategy:
matrix:
include:
- image: amolshejole/OpenSign
- image: opensign/opensign
dockerfile: apps/OpenSign/Dockerhubfile
- image: amolshejole/OpenSignServer
- image: opensign/opensignserver
dockerfile: apps/OpenSignServer/Dockerhubfile
steps:
-
+25 -20
View File
@@ -11,7 +11,9 @@
<a href="https://www.opensignlabs.com/">Website</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://www.opensignlabs.com">Docs</a>
<a href="https://docs.opensignlabs.com">Help Docs</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1">API Docs</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://www.opensignlabs.com/blog">Blog</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
@@ -22,7 +24,7 @@
<a href="https://www.linkedin.com/company/opensign%E2%84%A2/about/">LinkedIn</a>
## The open-source document e-signing solution
## The premier open source document signing solution(DocuSign alternative)
---
</div>
@@ -42,29 +44,32 @@ Please star ⭐ the repo to support us! 😀
### Introduction
Welcome to OpenSign, the premier open source docusign alternative - document e-signing solution designed to provide a secure, reliable and free alternative to commercial esign platforms like DocuSign, PandaDoc, SignNow, Adobe Sign, Smartwaiver, SignRequest, HelloSign & Zoho sign. Our mission is to democratize the e-signing process, making it accessible and straightforward for everyone.
Welcome to OpenSign, the premier open source docusign alternative - document e-signing solution designed to provide a secure, reliable and free alternative to commercial esign platforms like DocuSign, PandaDoc, SignNow, Adobe Sign, Smartwaiver, SignRequest, HelloSign & Zoho sign. Our mission is to democratize the document signing process, making it accessible and straightforward for everyone.
---
### Features
- **Secure PDF E-Signing:** With the help of robust encryption algorithms, OpenSign™ ensures maximum security, privacy & compatibility.
- **Annotate Documents:** OpenSign™ allows you to annotate PDF documents with an advanced signing pad that allows hand drawn signatures, uploaded images, typed signatures & saved signatures for the simplest signing experience ever.
- **User-Friendly Interface:** OpenSign™ was built while keeping Intuitive design in mind for ease of use. Features like "Sign yourself", "Templates", "One click signatures" and "OpenSign™ Drive" makes it stand out of the crowd and even makes it better than a lot of so-called industry leaders.
- **Multi-signer Support:** OpenSign's ability to invite multiple signers for signing along with the ability to invite witnesses & being able to enforce signing in a sequence makes it the only open source solution that is fully loaded and allows it to compete head-to-head with established players in e-signature space.
- **Secure PDF E-Signing:** With the help of robust encryption algorithms, OpenSign™ ensures maximum security, privacy & compatibility. Now sign unlimited documents even on the [cloud hosted free version of OpenSign](https://www.opensignlabs.com/).
- **Annotate Documents:** OpenSign™ allows you to annotate PDF documents with an advanced signing pad that allows hand drawn signatures, uploaded images, typed signatures & saved signatures for the simplest open source document signing experience ever.
- **User-Friendly Interface:** OpenSign™ was built while keeping Intuitive design in mind for ease of use. Features like "Sign yourself", "Templates", "One click signatures" and "OpenSign™ Drive" makes it stand out of the crowd and even makes it better than a lot of so-called industry leaders. OpenSign intends to provide the best document signing experience in the open source ecosystem.
- **Multi-signer Support:** OpenSign's ability to invite multiple signers for signing along with the ability to invite by sharing signing links & being able to enforce signing in a sequence makes it the only open source solution that is fully loaded and allows it to compete head-to-head with established players in e-signature space.
- **Email Unique Code(OTP) verification support for guest signers:** With OpenSign™, your documents are fully secure even when being signed by guest users. Guest signers can only sign the document after entering a unique code sent to their email address. 
- **"Expiring Docs" & "Rejection":** You can set documents to expire after certain number of days after which nobody will be able to sign. Not just this, OpenSign™ also allows signers to reject signing a document.
- **Beautiful email templates:** All document signing invitations, completion notifications & reminders are formatted using great looking email templates.
- **"Expiring Docs" & "Rejection":** You can set documents to expire after certain number of days after which nobody will be able to sign. Not just this, OpenSign™ also allows signers to reject signing a document with a reason that will be promptly shared with the sender.
- **Beautiful email templates:** All document signing invitations, completion notifications & reminders are formatted using great looking email templates. Not just this, you are even allowed to customise the email templates making your free document signing invitations look the way you always wanted them to be.
- **PDF Template Creation:** OpenSign™ allows you to create and store PDF document templates for repeated use thereby saving you a lot of time & collect e-signatures seamlessly.
- **OpenSign™ Drive:** It is a centralised secure vault for your digital documents that makes storing, signing, organizing, sharing & achieving your docs a breeze.
- **OpenSign™ Drive:** It is a centralised secure vault for your digital documents that makes storing, signing, organizing, sharing & archieving your docs a breeze.
- **Audit Trails & completion certificate:** Being a security focused solution, OpenSign™ makes it a top priority to save detailed logs for tracking document activities along with time-stamps, IP addresses, email IDs & phone numbers. A completion certificate is generated as soon as document is completed which contains all the document related logs for added safety.
- **API Support:** OpenSign™ API allows seamless integration into existing systems and software. You can generate an API key from the app and refer the [docs](https://docs.opensignlabs.com) to start integrating it in your existing applications.
- **Integrations:** Seamless integrations with various Cloud storage systems, CRMs & enterprise platforms is available. We also have a Zapier integration that allows you to integrate it with virtually any application.
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/b37ff443-7099-4273-9aeb-21c46d7154cf height='200'>
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/86db91b7-6c2f-4885-a33c-58f4fd35ec89 height='200'>
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/56835efd-c40e-42de-a206-20202c293876 height='200'>
- **API Support:** OpenSign™ API allows seamless integration into existing systems and software. You can generate an API key from the app and refer the [official API docs](https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1) to start integrating it in your existing applications.
- **Integrations:** The open source document signing experience becomes even more seamless because of integrations with various Cloud storage systems, CRMs & enterprise platforms. We also have a Zapier integration that allows you to integrate it with virtually any application.
<img alt="Login page" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/8016edb6-7d6e-4185-ab72-82d2c4a16032" height='200' >
<img alt="Dash_board" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/6e7b96f7-3154-4c25-bc1e-caf33925cc47" height='200'>
<img alt="Widgets" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/7edb65bd-c265-4b3d-9758-38e79766c5c2" height='200'>
<img alt="Request Signature" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/1697ae46-dcac-41c9-a081-aded25693846" height='200'>
<img alt="Create template" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/c2060fda-50f1-4116-a532-51b94b48463a" height='200'>
<img alt="Manage_Template" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/90310c74-8271-49bd-8c5f-89daa5a623c4" height='200'>
<img alt="Folders" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/a52207e7-3b0e-497c-b5f6-747bc4e67918" height='200'>
<img alt="OpenSign_Confetti" src="https://github.com/OpenSignLabs/OpenSign/assets/171803164/8f4c6a6e-4a73-439c-9f34-f426044d0a7f" height='200'>
---
@@ -88,13 +93,13 @@ We welcome contributions from the open-source community. For more information on
### License
OpenSign is licensed under the AGPL License. For more details, see the [LICENSE](LICENSE) file.
OpenSign is licensed under the AGPL-3 License. For more details, see the [LICENSE](LICENSE) file.
---
### Acknowledgments
We would like to thank all our contributors and users for their support and feedback. Special thanks to [OpenSignLabs](https://github.com/OpenSignLabs) for spearheading this initiative.
We would like to thank all our contributors and users for their support and feedback. Special thanks to [OpenSignLabs](https://www.opensignlabs.com) for spearheading this initiative.
---
@@ -136,7 +141,7 @@ 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/VikramNagwal"><img src="https://avatars.githubusercontent.com/u/123088024?v=4?s=100" width="100px;" alt="Vikram"/><br /><sub><b>Vikram</b></sub></a><br /><a href="#code-VikramNagwal" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ugoconsonni"><img src="https://avatars.githubusercontent.com/u/13661702?v=4?s=100" width="100px;" alt="ugoconsonni"/><br /><sub><b>ugoconsonni</b></sub></a><br /><a href="#code-ugoconsonni" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/daniel-mutwiri"><img src="https://avatars.githubusercontent.com/u/8936960?v=4?s=100" width="100px;" alt="Daniel Mutwiri"/><br /><sub><b>Daniel Mutwiri</b></sub></a><br /><a href="#code-daniel-mutwiri" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Zathiel"><img src="https://avatars.githubusercontent.com/u/26553418?v=4?s=100" width="100px;" alt="Zathiel"/><br /><sub><b>Zathiel</b></sub></a><br /><a href="#code-Zathiel" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Zathiel"><img src="https://avatars.githubusercontent.com/u/26553418?v=4?s=100" width="100px;" alt="Zathiel"/><br /><sub><b>Zathiel</b></sub></a><br /><a href="#code-Zathiel" title="Code">💻</a><a href="#security-Zathiel" title="Security">🛡️</a></td>
</tr>
</tbody>
</table>
+1 -6
View File
@@ -1,6 +1 @@
The community is working hard to put together a great usage guide.
You will soon see one of the best usage guides here.
Till then you can view the quick promo video by clicking the link below -
[<img src="https://i.ytimg.com/vi/szYaBZhXZNo/maxresdefault.jpg" width="50%">](https://www.youtube.com/watch?v=szYaBZhXZNo "OpenSign promo")
Please visit the official documentation [here](https://docs.opensignlabs.com).
+3
View File
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
presets: ["@babel/preset-env", "@babel/preset-react"]
};
+6268 -4628
View File
File diff suppressed because it is too large Load Diff
+50 -28
View File
@@ -4,21 +4,24 @@
"private": true,
"dependencies": {
"@formkit/auto-animate": "^0.8.2",
"@radix-ui/themes": "^2.0.3",
"@lottiefiles/dotlottie-react": "^0.8.6",
"@radix-ui/themes": "^3.1.1",
"@react-pdf/renderer": "^3.4.4",
"@reduxjs/toolkit": "^2.2.1",
"axios": "^1.6.8",
"@reduxjs/toolkit": "^2.2.7",
"axios": "^1.7.2",
"file-saver": "^2.0.5",
"jwt-decode": "^4.0.0",
"moment": "^2.30.1",
"parse": "^4.3.1",
"nth-check": "^2.1.1",
"parse": "^5.3.0",
"pdf-lib": "^1.17.1",
"print-js": "^1.6.0",
"radix-ui": "^1.0.1",
"react": "^18.2.0",
"react-bootstrap": "^2.10.2",
"react-cookie": "^7.1.4",
"react-datepicker": "^6.4.0",
"react-bootstrap": "^2.10.4",
"react-confetti": "^6.1.0",
"react-cookie": "^7.2.0",
"react-datepicker": "^7.3.0",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dnd-multi-backend": "^8.0.3",
@@ -27,33 +30,35 @@
"react-gtm-module": "^2.0.11",
"react-helmet": "^6.1.0",
"react-konva": "^18.2.10",
"react-modal": "^3.16.1",
"react-pdf": "^7.7.3",
"react-pdf": "^9.1.0",
"react-quill": "^2.0.0",
"react-redux": "^9.1.0",
"react-rnd": "^10.4.10",
"react-router-dom": "^6.22.3",
"react-redux": "^9.1.2",
"react-rnd": "^10.4.11",
"react-router-dom": "^6.26.0",
"react-scripts": "5.0.1",
"react-scrollbars-custom": "^4.1.1",
"react-select": "^5.8.0",
"react-signature-canvas": "^1.0.6",
"react-tooltip": "^5.26.3",
"react-tooltip": "^5.28.0",
"react-web-share": "^2.0.2",
"reactour": "^1.19.3",
"reactour": "^1.19.4",
"redux": "^5.0.1",
"redux-thunk": "^3.1.0",
"regex-parser": "^2.3.0",
"serve": "^14.2.1",
"styled-components": "^4.4.1",
"web-vitals": "^2.1.4"
"serve": "^14.2.3",
"styled-components": "^5.3.0",
"web-vitals": "^4.2.2",
"ws": "^8.18.0"
},
"scripts": {
"build-webpack": "webpack --config webpack.config.js",
"build": "npm run version && npm run build-webpack && react-scripts build",
"build-watch": "webpack --config webpack.config.js --watch",
"start-dev": "concurrently \"npm run build-watch\" \"react-scripts start\"",
"start": "serve -s build",
"start-dev": "react-scripts start",
"version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
"version-win": "powershell -Command \"Invoke-RestMethod -Uri 'https://api.github.com/repos/opensignlabs/opensign/releases/latest' | Select-Object -ExpandProperty tag_name | Out-File -FilePath ./public/version.txt\"",
"build": "npm run version && react-scripts build",
"build-win": "npm run version-win && react-scripts build",
"build-win": "npm run version-win && npm run build-webpack && react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"release": "standard-version",
@@ -83,16 +88,33 @@
}
},
"devDependencies": {
"@babel/runtime-corejs2": "^7.24.5",
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/preset-react": "^7.24.7",
"@babel/runtime-corejs2": "^7.25.0",
"autoprefixer": "^10.4.19",
"babel-loader": "^9.1.3",
"clean-webpack-plugin": "^4.0.0",
"commitizen": "^4.3.0",
"concurrently": "^8.2.2",
"css-loader": "^7.1.2",
"daisyui": "^4.12.10",
"dotenv": "^16.4.5",
"dotenv-webpack": "^8.1.0",
"eslint": "^8.57.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.34.1",
"lint-staged": "^15.2.2",
"postcss": "^8.4.38",
"prettier": "^2.8.8",
"pretty-quick": "^3.3.1",
"tailwindcss": "^3.4.1"
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.34.3",
"lint-staged": "^15.2.8",
"mini-css-extract-plugin": "^2.9.0",
"postcss": "^8.4.41",
"prettier": "^3.3.3",
"pretty-quick": "^4.0.0",
"tailwindcss": "^3.4.7",
"terser-webpack-plugin": "^5.3.10",
"webpack-cli": "^5.1.4"
},
"overrides": {
"nth-check": "$nth-check",
"ws": "$ws"
}
}
+5 -38
View File
@@ -1,53 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<html lang="en" data-theme="opensigncss">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<!-- <link rel="icon" type="image/png"
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC"
sizes="40x40" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="The fastest way to sign PDFs & request signatures from others" />
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> -->
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"
integrity="sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn+CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="manifest" href="/manifest.json" />
<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" />
<link rel="stylesheet" href="https://cdn.opensignlabs.com/fonts.css" />
<title>OpenSign™</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

File diff suppressed because one or more lines are too long
Binary file not shown.
+47 -27
View File
@@ -16,6 +16,10 @@ import PlaceHolderSign from "./pages/PlaceHolderSign";
import PdfRequestFiles from "./pages/PdfRequestFiles";
import LazyPage from "./primitives/LazyPage";
import { isEnableSubscription } from "./constant/const";
import SSOVerify from "./pages/SSOVerify";
import Loader from "./primitives/Loader";
import TeamList from "./pages/TeamList";
import UserList from "./pages/UserList";
const DebugPdf = lazy(() => import("./pages/DebugPdf"));
const ForgetPassword = lazy(() => import("./pages/ForgetPassword"));
const GuestLogin = lazy(() => import("./pages/GuestLogin"));
@@ -28,25 +32,14 @@ const Opensigndrive = lazy(() => import("./pages/Opensigndrive"));
const ManageSign = lazy(() => import("./pages/Managesign"));
const GenerateToken = lazy(() => import("./pages/GenerateToken"));
const Webhook = lazy(() => import("./pages/Webhook"));
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
const AddAdmin = lazy(() => import("./pages/AddAdmin"));
const UpdateExistUserAdmin = lazy(() => import("./pages/UpdateExistUserAdmin"));
const Loader = () => {
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
const AppLoader = () => {
return (
<div
style={{
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
<div className="flex justify-center items-center h-[100vh]">
<Loader />
</div>
);
};
@@ -63,11 +56,9 @@ function App() {
const baseurl = process.env.REACT_APP_SERVERURL
? process.env.REACT_APP_SERVERURL
: window.location.origin + "/api/app";
const appName = "contracts";
try {
localStorage.setItem("baseUrl", `${baseurl}/`);
localStorage.setItem("parseAppId", appId);
localStorage.setItem("domain", appName);
setIsLoading(false);
} catch (error) {
console.log("err ", error);
@@ -75,15 +66,29 @@ function App() {
};
return (
<div className="bg-[#eef1f5]">
<div className="bg-base-200">
{isloading ? (
<Loader />
<AppLoader />
) : (
<BrowserRouter>
<Routes>
<Route element={<ValidateRoute />}>
<Route exact path="/" element={<Login />} />
<Route path="/signup" element={<LazyPage Page={Signup} />} />
{isEnableSubscription && (
<Route path="/signup" element={<LazyPage Page={Signup} />} />
)}
{!isEnableSubscription && (
<>
<Route
path="/addadmin"
element={<LazyPage Page={AddAdmin} />}
/>
<Route
path="/upgrade-2.1"
element={<LazyPage Page={UpdateExistUserAdmin} />}
/>
</>
)}
</Route>
<Route element={<Validate />}>
<Route
@@ -150,11 +155,6 @@ function App() {
path="/managesign"
element={<LazyPage Page={ManageSign} />}
/>
<Route
path="/generatetoken"
element={<LazyPage Page={GenerateToken} />}
/>
<Route path="/webhook" element={<LazyPage Page={Webhook} />} />
<Route
path="/template/:templateId"
element={<TemplatePlaceholder />}
@@ -175,12 +175,32 @@ function App() {
path="/pdfRequestFiles/:docId"
element={<PdfRequestFiles />}
/>
{/* recipient signature route with no rowlevel data using docId from url */}
<Route
path="/recipientSignPdf/:docId/:contactBookId"
element={<PdfRequestFiles />}
/>
<Route
path="/recipientSignPdf/:docId"
element={<PdfRequestFiles />}
/>
{isEnableSubscription && (
<>
<Route path="/teams" element={<TeamList />} />
<Route
path="/generatetoken"
element={<LazyPage Page={GenerateToken} />}
/>
<Route
path="/webhook"
element={<LazyPage Page={Webhook} />}
/>
</>
)}
<Route path="/users" element={<UserList />} />
</Route>
<Route path="/sso" element={<SSOVerify />} />
<Route path="*" element={<PageNotFound />} />
</Routes>
</BrowserRouter>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

+142 -176
View File
@@ -1,7 +1,6 @@
import React, { useState, useEffect } from "react";
import Parse from "parse";
import axios from "axios";
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const";
import Loader from "../primitives/Loader";
const AddSigner = (props) => {
const [name, setName] = useState("");
@@ -10,8 +9,6 @@ const AddSigner = (props) => {
const [addYourself, setAddYourself] = useState(false);
const [isLoader, setIsLoader] = useState(false);
const [isUserExist, setIsUserExist] = useState(false);
const parseBaseUrl = localStorage.getItem("baseUrl");
const parseAppId = localStorage.getItem("parseAppId");
useEffect(() => {
checkUserExist();
@@ -23,7 +20,7 @@ const AddSigner = (props) => {
);
if (savedUserDetails && addYourself) {
setName(savedUserDetails.name);
setPhone(savedUserDetails.phone);
setPhone(savedUserDetails?.phone || "");
setEmail(savedUserDetails.email);
}
}, [addYourself]);
@@ -50,145 +47,137 @@ const AddSigner = (props) => {
e.stopPropagation();
setIsLoader(true);
if (localStorage.getItem("TenantId")) {
try {
const contactQuery = new Parse.Object("contracts_Contactbook");
contactQuery.set("Name", name);
contactQuery.set("Phone", phone);
contactQuery.set("Email", email);
contactQuery.set("UserRole", "contracts_Guest");
contactQuery.set("TenantId", {
__type: "Pointer",
className: "partners_Tenant",
objectId: localStorage.getItem("TenantId")
});
try {
const _users = Parse.Object.extend("User");
const _user = new _users();
_user.set("name", name);
_user.set("username", email);
_user.set("email", email);
_user.set("phone", phone);
_user.set("password", phone);
const user = await _user.save();
if (user) {
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessionToken: localStorage.getItem("accesstoken")
};
const body = {
appName: localStorage.getItem("_appName"),
roleName: "contracts_Guest",
userId: user.id
};
await axios.post(roleurl, body, { headers: headers });
const currentUser = Parse.User.current();
contactQuery.set(
"CreatedBy",
Parse.User.createWithoutData(currentUser.id)
);
contactQuery.set("UserId", user);
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(true);
acl.setReadAccess(currentUser.id, true);
acl.setWriteAccess(currentUser.id, true);
contactQuery.setACL(acl);
const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res));
if (props.details) {
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
}
if (props.closePopup) {
props.closePopup();
}
if (props.handleUserData) {
props.handleUserData(parseData);
const user = Parse.User.current();
const query = new Parse.Query("contracts_Contactbook");
query.equalTo("CreatedBy", user);
query.notEqualTo("IsDeleted", true);
query.equalTo("Email", email);
const res = await query.first();
// console.log(res);
if (!res) {
const contactQuery = new Parse.Object("contracts_Contactbook");
contactQuery.set("Name", name);
if (phone) {
contactQuery.set("Phone", phone);
}
contactQuery.set("Email", email);
contactQuery.set("UserRole", "contracts_Guest");
contactQuery.set("TenantId", {
__type: "Pointer",
className: "partners_Tenant",
objectId: localStorage.getItem("TenantId")
});
try {
const _users = Parse.Object.extend("User");
const _user = new _users();
_user.set("name", name);
_user.set("username", email);
_user.set("email", email);
_user.set("password", email);
if (phone) {
_user.set("phone", phone);
}
const user = await _user.save();
if (user) {
const currentUser = Parse.User.current();
contactQuery.set(
"CreatedBy",
Parse.User.createWithoutData(currentUser.id)
);
contactQuery.set("UserId", user);
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(true);
acl.setReadAccess(currentUser.id, true);
acl.setWriteAccess(currentUser.id, true);
contactQuery.setACL(acl);
const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res));
if (props.details) {
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
}
if (props.closePopup) {
props.closePopup();
}
if (props.handleUserData) {
props.handleUserData(parseData);
}
setIsLoader(false);
// Reset the form fields
setAddYourself(false);
setName("");
setPhone("");
setEmail("");
}
} catch (err) {
console.log("err ", err);
if (err.code === 202) {
const params = { email: email };
const userRes = await Parse.Cloud.run("getUserId", params);
const currentUser = Parse.User.current();
contactQuery.set(
"CreatedBy",
Parse.User.createWithoutData(currentUser.id)
);
contactQuery.set("UserId", {
__type: "Pointer",
className: "_User",
objectId: userRes.id
});
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(true);
acl.setReadAccess(currentUser.id, true);
acl.setWriteAccess(currentUser.id, true);
contactQuery.setACL(acl);
const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res));
if (props.details) {
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
}
if (props.closePopup) {
props.closePopup();
}
if (props.handleUserData) {
props.handleUserData(parseData);
}
setIsLoader(false);
// Reset the form fields
setAddYourself(false);
setName("");
setPhone("");
setEmail("");
}
}
} else {
alert("Contact already exist!");
setIsLoader(false);
// Reset the form fields
setAddYourself(false);
setName("");
setPhone("");
setEmail("");
}
} catch (err) {
console.log("err ", err);
if (err.code === 202) {
const params = { email: email };
const userRes = await Parse.Cloud.run("getUserId", params);
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessionToken: localStorage.getItem("accesstoken")
};
const body = {
appName: localStorage.getItem("_appName"),
roleName: "contracts_Guest",
userId: userRes.id
};
await axios.post(roleurl, body, { headers: headers });
const currentUser = Parse.User.current();
contactQuery.set(
"CreatedBy",
Parse.User.createWithoutData(currentUser.id)
);
contactQuery.set("UserId", {
__type: "Pointer",
className: "_User",
objectId: userRes.id
});
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(true);
acl.setReadAccess(currentUser.id, true);
acl.setWriteAccess(currentUser.id, true);
contactQuery.setACL(acl);
const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res));
if (props.details) {
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
}
if (props.closePopup) {
props.closePopup();
}
if (props.handleUserData) {
props.handleUserData(parseData);
}
setIsLoader(false);
// Reset the form fields
setAddYourself(false);
setName("");
setPhone("");
setEmail("");
}
console.log("err in fetch contact", err);
setIsLoader(false);
alert("something went wrong, please try again later");
}
} catch (err) {
// console.log("err", err);
} else {
setIsLoader(false);
alert("something went wrong!");
}
}else{
alert('something went wrong, please try again later')
alert("something went wrong, please try again later");
}
};
@@ -211,38 +200,29 @@ const AddSigner = (props) => {
<div className="h-full p-[20px]">
{isLoader && (
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30">
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
<Loader />
</div>
)}
<div className="w-full mx-auto p-2">
<div className="w-full mx-auto p-2 text-base-content">
{isUserExist && (
<div className="mb-3">
<div className="mb-3 flex items-center">
<input
type="checkbox"
id="addYourself"
checked={addYourself}
onChange={handleAddYourselfChange}
className="form-checkbox"
className="op-checkbox op-checkbox-sm"
/>
<label htmlFor="addYourself" className="ml-2 text-gray-700">
<label htmlFor="addYourself" className="ml-2 mb-0">
Add Yourself
</label>
</div>
)}
<form onSubmit={handleSubmit}>
<div className="mb-3">
<label
htmlFor="name"
className="block text-xs text-gray-700 font-semibold"
>
<label htmlFor="name" className="block text-xs font-semibold">
Name
<span style={{ color: "red", fontSize: 13 }}> *</span>
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="text"
@@ -251,59 +231,45 @@ const AddSigner = (props) => {
onChange={(e) => setName(e.target.value)}
required
disabled={addYourself}
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="mb-3">
<label
htmlFor="email"
className="block text-xs text-gray-700 font-semibold"
>
<label htmlFor="email" className="block text-xs font-semibold">
Email
<span style={{ color: "red", fontSize: 13 }}> *</span>
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="email"
id="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
onChange={(e) => setEmail(e.target.value?.toLowerCase())}
required
disabled={addYourself}
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="mb-3">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
<label htmlFor="phone" className="block text-xs font-semibold">
Phone
<span style={{ color: "red", fontSize: 13 }}> *</span>
</label>
<input
type="text"
id="phone"
value={phone}
onChange={(e) => setPhone(e.target.value)}
required
disabled={addYourself}
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="mt-4 flex justify-start">
<button
type="submit"
style={{ backgroundColor: modalSubmitBtnColor }}
className="mr-2 px-[20px] py-1.5 text-white rounded shadow-md text-center focus:outline-none "
>
<div className="mt-4 flex gap-x-2 justify-start">
<button type="submit" className="op-btn op-btn-primary">
Submit
</button>
<button
type="button"
onClick={() => handleReset()}
style={{ backgroundColor: modalCancelBtnColor }}
className="px-4 py-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none"
className="op-btn op-btn-secondary"
>
Reset
</button>
+194
View File
@@ -0,0 +1,194 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import Title from "./Title";
import Loader from "../primitives/Loader";
const AddTeam = (props) => {
const [formdata, setFormdata] = useState({
name: "",
team: ""
});
const [isLoader, setIsLoader] = useState(false);
const [teamList, setTeamList] = useState([]);
useEffect(() => {
getTeamList();
}, []);
const getTeamList = async () => {
setIsLoader(true);
try {
const teams = await Parse.Cloud.run("getteams", { active: true });
const teamRes = JSON.parse(JSON.stringify(teams));
if (teamRes.length > 0) {
const _teamRes = JSON.parse(JSON.stringify(teamRes));
const allUsersteam = _teamRes.find((x) => x.Name === "All Users");
if (allUsersteam) {
setFormdata({ team: allUsersteam.objectId });
}
setTeamList(_teamRes);
}
} catch (err) {
console.log("Err in fetch top level teamList", err);
} finally {
setIsLoader(false);
}
};
const handleDropdown = (e) => {
setFormdata((prev) => ({ ...prev, [e.target.name]: e.target.value }));
};
// Define a function to handle form submission
const handleSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
// Extracting values except for the 'name' key
let updatedAncestors = [];
if (formdata.team) {
const Ancestors = teamList.find(
(x) => x.objectId === formdata.team
)?.Ancestors;
if (Ancestors && Ancestors.length > 0) {
updatedAncestors = Ancestors.map((x) => ({
__type: "Pointer",
className: "contracts_Teams",
objectId: x.objectId
}));
} else {
const AllUser = teamList.find((x) => x.objectId === "All Users");
updatedAncestors = [
AllUser,
{
__type: "Pointer",
className: "contracts_Teams",
objectId: formdata.team
}
];
}
}
try {
setIsLoader(true);
let data = { Name: formdata.name };
if (updatedAncestors.length > 0) {
const ParentId = updatedAncestors[updatedAncestors.length - 1];
data["ParentId"] = ParentId?.objectId;
data["Ancestors"] = updatedAncestors;
}
const newTeamRes = await Parse.Cloud.run("addteam", data);
// console.log("teamRes ", newTeamRes);
if (updatedAncestors.length > 0) {
const ParentId = teamList.find((x) => x.objectId === formdata.team);
props.handleTeamInfo({
objectId: newTeamRes.id,
Name: formdata.name,
ParentId: ParentId,
Ancestors: updatedAncestors,
IsActive: true
});
} else {
props.handleTeamInfo({
objectId: newTeamRes.id,
Name: formdata.name,
ParentId: "",
Ancestors: "",
IsActive: true
});
}
if (props.closePopup) {
props.closePopup();
}
setFormdata({ name: "", team: { name: "", objectId: "" } });
props.setIsAlert({ type: "success", msg: "Team created successfully." });
} catch (err) {
console.log("err in save team", err);
if (err.code === 137) {
props.setIsAlert({ type: "danger", msg: "Teams already exists." });
} else if (err.code === 102) {
props.setIsAlert({ type: "warning", msg: "Provide team name." });
} else {
props.setIsAlert({ type: "danger", msg: "Something went wrong." });
}
} finally {
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1500);
setIsLoader(false);
}
};
// Define a function to handle the "add yourself" checkbox
const handleReset = () => {
setFormdata({
name: "",
team: { name: "", objectId: "" }
});
};
const handleChange = (e) => {
setFormdata((prev) => ({ ...prev, [e.target.name]: e.target.value }));
};
return (
<div className="shadow-md rounded-box my-[1px] p-3 bg-base-100 relative">
<Title title="Add Team" />
{isLoader && (
<div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50">
<Loader />
</div>
)}
<div className="w-full mx-auto">
<form onSubmit={handleSubmit}>
{/* <h1 className="text-[20px] font-semibold mb-4">Add User</h1> */}
<div className="mb-3">
<label
htmlFor="name"
className="block text-xs text-gray-700 font-semibold"
>
Name
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="text"
name="name"
value={formdata.name}
onChange={(e) => handleChange(e)}
required
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="mb-3">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
Parent Team
</label>
<select
value={formdata.team}
onChange={(e) => handleDropdown(e)}
name="team"
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
>
{teamList.length > 0 &&
teamList.map((x) => (
<option key={x.objectId} value={x.objectId}>
{x.Name}
</option>
))}
</select>
</div>
<div className="flex items-center mt-3 gap-2 text-white">
<button type="submit" className="op-btn op-btn-primary">
Submit
</button>
<div
type="button"
onClick={() => handleReset()}
className="op-btn op-btn-secondary"
>
Reset
</div>
</div>
</form>
</div>
</div>
);
};
export default AddTeam;
+232 -115
View File
@@ -1,23 +1,55 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import Parse from "parse";
import axios from "axios";
import Title from "./Title";
import Alert from "../primitives/Alert";
import Loader from "../primitives/Loader";
import { copytoData } from "../constant/Utils";
import { isEnableSubscription } from "../constant/const";
function generatePassword(length) {
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
const charactersLength = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
const AddUser = (props) => {
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const [email, setEmail] = useState("");
const [formdata, setFormdata] = useState({
name: "",
phone: "",
email: "",
team: "",
password: "",
role: ""
});
const [isLoader, setIsLoader] = useState(false);
const [isUserExist, setIsUserExist] = useState(false);
const parseBaseUrl = localStorage.getItem("baseUrl");
const parseAppId = localStorage.getItem("parseAppId");
const [teamList, setTeamList] = useState([]);
const role = ["OrgAdmin", "Editor", "User"];
useEffect(() => {
getTeamList();
}, []);
const getTeamList = async () => {
setFormdata((prev) => ({ ...prev, password: generatePassword(12) }));
const teamRes = await Parse.Cloud.run("getteams", { active: true });
if (teamRes.length > 0) {
const _teamRes = JSON.parse(JSON.stringify(teamRes));
setTeamList(_teamRes);
if (!isEnableSubscription) {
const allUserId =
_teamRes.find((x) => x.Name === "All Users")?.objectId || "";
setFormdata((prev) => ({ ...prev, team: allUserId }));
}
}
};
const checkUserExist = async () => {
try {
const res = await Parse.Cloud.run("getUserDetails", {
email: email,
userId: Parse.User.current().id
email: formdata.email
});
if (res) {
return true;
@@ -32,24 +64,46 @@ const AddUser = (props) => {
const handleSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
const localUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
setIsLoader(true);
const res = await checkUserExist();
if (res) {
setIsUserExist(true);
props.setIsAlert({ type: "danger", msg: "User already exist." });
setIsLoader(false);
setTimeout(() => {
setIsUserExist(false);
props.setIsAlert({ type: "success", msg: "" });
}, 1000);
} else {
try {
const contactQuery = new Parse.Object("contracts_Users");
contactQuery.set("Name", name);
contactQuery.set("Phone", phone);
contactQuery.set("Email", email);
contactQuery.set("UserRole", "contracts_User");
const extUser = new Parse.Object("contracts_Users");
extUser.set("Name", formdata.name);
if (formdata.phone) {
extUser.set("Phone", formdata.phone);
}
extUser.set("Email", formdata.email);
extUser.set("UserRole", `contracts_${formdata.role}`);
if (formdata?.team) {
extUser.set("TeamIds", [
{
__type: "Pointer",
className: "contracts_Teams",
objectId: formdata.team
}
]);
}
if (localUser && localUser.OrganizationId) {
extUser.set("OrganizationId", {
__type: "Pointer",
className: "contracts_Organizations",
objectId: localUser.OrganizationId.objectId
});
}
if (localUser && localUser.Company) {
extUser.set("Company", localUser.Company);
}
if (localStorage.getItem("TenantId")) {
contactQuery.set("TenantId", {
extUser.set("TenantId", {
__type: "Pointer",
className: "partners_Tenant",
objectId: localStorage.getItem("TenantId")
@@ -59,87 +113,69 @@ const AddUser = (props) => {
try {
const _users = Parse.Object.extend("User");
const _user = new _users();
_user.set("name", name);
_user.set("username", email);
_user.set("email", email);
_user.set("phone", phone);
_user.set("password", phone);
_user.set("name", formdata.name);
_user.set("username", formdata.email);
_user.set("email", formdata.email);
_user.set("password", formdata.password);
if (formdata.phone) {
_user.set("phone", formdata.phone);
}
const user = await _user.save();
if (user) {
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessionToken: localStorage.getItem("accesstoken")
};
const body = {
appName: localStorage.getItem("_appName"),
roleName: "contracts_User",
userId: user.id
};
await axios.post(roleurl, body, { headers: headers });
const currentUser = Parse.User.current();
contactQuery.set(
extUser.set(
"CreatedBy",
Parse.User.createWithoutData(currentUser.id)
);
contactQuery.set("UserId", user);
extUser.set("UserId", user);
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(true);
acl.setReadAccess(currentUser.id, true);
acl.setWriteAccess(currentUser.id, true);
contactQuery.setACL(acl);
extUser.setACL(acl);
const res = await contactQuery.save();
const res = await extUser.save();
const parseData = JSON.parse(JSON.stringify(res));
if (props.details) {
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
}
if (props.closePopup) {
props.closePopup();
}
if (props.handleUserData) {
if (formdata?.team) {
const team = teamList.find((x) => x.objectId === formdata.team);
parseData.TeamIds = parseData.TeamIds.map((y) =>
y.objectId === team.objectId ? team : y
);
}
props.handleUserData(parseData);
}
setIsLoader(false);
setName("");
setPhone("");
setEmail("");
setFormdata({
name: "",
email: "",
phone: "",
team: "",
role: ""
});
}
} catch (err) {
console.log("err ", err);
if (err.code === 202) {
const params = { email: email };
const params = { email: formdata.email };
const userRes = await Parse.Cloud.run("getUserId", params);
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessionToken: localStorage.getItem("accesstoken")
};
const body = {
appName: localStorage.getItem("_appName"),
roleName: "contracts_User",
userId: userRes.id
};
await axios.post(roleurl, body, { headers: headers });
const currentUser = Parse.User.current();
contactQuery.set(
extUser.set(
"CreatedBy",
Parse.User.createWithoutData(currentUser.id)
);
contactQuery.set("UserId", {
extUser.set("UserId", {
__type: "Pointer",
className: "_User",
objectId: userRes.id
@@ -150,76 +186,90 @@ const AddUser = (props) => {
acl.setReadAccess(currentUser.id, true);
acl.setWriteAccess(currentUser.id, true);
contactQuery.setACL(acl);
const res = await contactQuery.save();
extUser.setACL(acl);
const res = await extUser.save();
const parseData = JSON.parse(JSON.stringify(res));
if (props.details) {
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
}
if (props.closePopup) {
props.closePopup();
}
if (props.handleUserData) {
if (formdata?.team) {
const team = teamList.find((x) => x.objectId === formdata.team);
parseData.TeamIds = parseData.TeamIds.map((y) =>
y.objectId === team.objectId ? team : y
);
}
props.handleUserData(parseData);
}
setIsLoader(false);
setName("");
setPhone("");
setEmail("");
setFormdata({
name: "",
email: "",
phone: "",
team: "",
role: ""
});
}
}
} catch (err) {
// console.log("err", err);
console.log("err", err);
setIsLoader(false);
alert("something went wrong!");
props.setIsAlert({ type: "danger", msg: "something went wrong." });
} finally {
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1500);
}
}
};
// Define a function to handle the "add yourself" checkbox
const handleReset = () => {
setName("");
setPhone("");
setEmail("");
setFormdata({
name: "",
email: "",
phone: "",
team: "",
role: ""
});
if (props.closePopup) {
props.closePopup();
}
};
const handleChange = (e) => {
setFormdata((prev) => ({ ...prev, [e.target.name]: e.target.value }));
};
const copytoclipboard = (text) => {
copytoData(text);
props.setIsAlert({ type: "success", msg: "Copied" });
setTimeout(() => props.setIsAlert({ type: "success", msg: "" }), 1500); // Reset copied state after 1.5 seconds
};
return (
<div className="shadow-md rounded my-2 p-3 bg-[#ffffff] md:border-[1px] md:border-gray-600/50">
<div className="shadow-md rounded-box my-[1px] p-3 bg-[#ffffff]">
<Title title={"Add User"} />
{isUserExist && <Alert type="danger">User already exists!</Alert>}
{isLoader && (
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30 z-50">
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30 z-50 rounded-box">
<Loader />
</div>
)}
<div className="w-full mx-auto">
<form onSubmit={handleSubmit}>
<h1 className="text-[20px] font-semibold mb-4">Add User</h1>
{/* <h1 className="text-[20px] font-semibold mb-4">Add User</h1> */}
<div className="mb-3">
<label
htmlFor="name"
className="block text-xs text-gray-700 font-semibold"
>
Name
<span style={{ color: "red", fontSize: 13 }}> *</span>
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="text"
id="name"
value={name}
onChange={(e) => setName(e.target.value)}
name="name"
value={formdata.name}
onChange={(e) => handleChange(e)}
required
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="mb-3">
@@ -228,48 +278,115 @@ const AddUser = (props) => {
className="block text-xs text-gray-700 font-semibold"
>
Email
<span style={{ color: "red", fontSize: 13 }}> *</span>
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="email"
id="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
name="email"
value={formdata.email}
onChange={(e) => handleChange(e)}
required
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="mb-3">
<label
htmlFor="email"
className="block text-xs text-gray-700 font-semibold"
>
Password
</label>
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm text-base-content w-full h-full text-[13px]">
<div className="break-all">{formdata?.password}</div>
<i
onClick={() => copytoclipboard(formdata?.password)}
className="fa-light fa-copy rounded-full hover:bg-base-300 p-[8px] cursor-pointer "
></i>
</div>
<div className="text-[12px] ml-2 mb-0 text-[red] select-none">
Password will only be generated once; make sure to copy it.
</div>
</div>
<div className="mb-3">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
Phone
<span style={{ color: "red", fontSize: 13 }}> *</span>
{/* <span className="text-[red] text-[13px]"> *</span> */}
</label>
<input
type="text"
id="phone"
value={phone}
onChange={(e) => setPhone(e.target.value)}
required
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
name="phone"
placeholder="optional"
value={formdata.phone}
onChange={(e) => handleChange(e)}
// required
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="flex items-center mt-3 gap-2 text-white">
<button
type="submit"
className="bg-[#1ab6ce] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 focus:outline-none"
{isEnableSubscription && (
<div className="mb-3">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
Team<span className="text-[red] text-[13px]"> *</span>
</label>
<select
value={formdata.team}
onChange={(e) => handleChange(e)}
name="team"
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
required
>
<option defaultValue={""} value={""}>
select
</option>
{teamList.length > 0 &&
teamList.map((x) => (
<option key={x.objectId} value={x.objectId}>
{x.Name}
</option>
))}
</select>
</div>
)}
<div className="mb-3">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
Role<span className="text-[red] text-[13px]"> *</span>
</label>
<select
value={formdata.role}
onChange={(e) => handleChange(e)}
name="role"
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
required
>
<option defaultValue={""} value={""}>
select
</option>
{role.length > 0 &&
role.map((x) => (
<option key={x} value={x}>
{x}
</option>
))}
</select>
</div>
<div className="flex items-center mt-3 gap-2 text-white">
<button type="submit" className="op-btn op-btn-primary">
Submit
</button>
<div
type="button"
onClick={() => handleReset()}
className="bg-[#188ae2] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 text-center ml-[2px] focus:outline-none"
className="op-btn op-btn-secondary"
>
Reset
Cancel
</div>
</div>
</form>
+283
View File
@@ -0,0 +1,283 @@
import React, { useState, useEffect, useRef } from "react";
import axios from "axios";
import SuggestionInput from "./shared/fields/SuggestionInput";
import Loader from "../primitives/Loader";
const BulkSendUi = (props) => {
const [forms, setForms] = useState([]);
const [formId, setFormId] = useState(2);
const formRef = useRef(null);
const [scrollOnNextUpdate, setScrollOnNextUpdate] = useState(false);
const [isSubmit, setIsSubmit] = useState(false);
const [allowedForm, setAllowedForm] = useState(0);
const [isSignatureExist, setIsSignatureExist] = useState();
const allowedSigners = 50;
useEffect(() => {
signatureExist();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
//function to check atleast one signature field exist
const signatureExist = () => {
const getPlaceholder = props.item?.Placeholders;
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
placeholderObj?.placeHolder?.some((holder) =>
holder?.pos?.some((posItem) => posItem?.type === "signature")
)
);
setIsSignatureExist(checkIsSignatureExistt);
};
useEffect(() => {
if (scrollOnNextUpdate && formRef.current) {
formRef.current.scrollIntoView({
behavior: "smooth",
block: "end",
inline: "nearest"
});
setScrollOnNextUpdate(false);
}
}, [forms, scrollOnNextUpdate]);
useEffect(() => {
(() => {
if (props?.Placeholders?.length > 0) {
let users = [];
props?.Placeholders?.forEach((element) => {
if (!element.signerObjId) {
users = [
...users,
{
fieldId: element.Id,
email: "",
label: element.Role,
signer: {}
}
];
}
});
setForms((prevForms) => [...prevForms, { Id: 1, fields: users }]);
const totalForms = Math.floor(allowedSigners / users?.length);
setAllowedForm(totalForms);
}
})();
// eslint-disable-next-line
}, []);
const handleInputChange = (index, signer, fieldIndex) => {
const newForms = [...forms];
newForms[index].fields[fieldIndex].email = signer?.Email
? signer?.Email
: signer || "";
newForms[index].fields[fieldIndex].signer = signer?.objectId ? signer : "";
setForms(newForms);
};
const handleAddForm = (e) => {
e.preventDefault();
// Check if the quick send limit has been reached
if (forms?.length < allowedForm) {
if (props?.Placeholders.length > 0) {
let newForm = [];
props?.Placeholders?.forEach((element) => {
if (!element.signerObjId) {
newForm = [
...newForm,
{
fieldId: element.Id,
email: "",
label: element.Role,
signer: {}
}
];
}
});
setForms([...forms, { Id: formId, fields: newForm }]);
}
setFormId(formId + 1);
setScrollOnNextUpdate(true);
} else {
// If the limit has been reached, throw an error with the appropriate message
alert("Quick send reached limit.");
}
};
const handleRemoveForm = (index) => {
const updatedForms = forms.filter((_, i) => i !== index);
setForms(updatedForms);
};
const handleSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
setIsSubmit(true);
// Create a copy of Placeholders array from props.item
let Placeholders = [...props.item.Placeholders];
// Initialize an empty array to store updated documents
let Documents = [];
// Loop through each form
forms.forEach((form) => {
//checking if user enter email which already exist as a signer then add user in a signers array
let existSigner = [];
form.fields.map((data) => {
if (data.signer) {
existSigner.push(data.signer);
}
});
// Map through the copied Placeholders array to update email values
const updatedPlaceholders = Placeholders.map((placeholder) => {
// Find the field in the current form that matches the placeholder Id
const field = form.fields.find(
(element) => parseInt(element.fieldId) === placeholder.Id
);
// If a matching field is found, update the email value in the placeholder
const signer = field?.signer?.objectId ? field.signer : "";
if (field) {
if (signer) {
return {
...placeholder,
signerObjId: field?.signer?.objectId || "",
signerPtr: signer
};
} else {
return {
...placeholder,
email: field.email,
signerObjId: field?.signer?.objectId || "",
signerPtr: signer
};
}
}
// If no matching field is found, keep the placeholder as is
return placeholder;
});
// Push a new document object with updated Placeholders into the Documents array
if (existSigner?.length > 0) {
Documents.push({
...props.item,
Placeholders: updatedPlaceholders,
Signers: props.item.Signers
? [...props.item.Signers, ...existSigner]
: [...existSigner]
});
} else {
Documents.push({
...props.item,
Placeholders: updatedPlaceholders
});
}
});
//console.log("Documents ", Documents);
await batchQuery(Documents);
};
const batchQuery = async (Documents) => {
const serverUrl = localStorage.getItem("baseUrl");
const functionsUrl = `${serverUrl}functions/batchdocuments`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessionToken: localStorage.getItem("accesstoken")
};
const params = {
Documents: JSON.stringify(Documents)
};
try {
const res = await axios.post(functionsUrl, params, { headers: headers });
// console.log("res ", res);
if (res.data && res.data.result) {
props.handleClose("success", Documents?.length);
}
} catch (err) {
console.log("Err ", err);
props.handleClose("error", 0);
} finally {
setIsSubmit(false);
}
};
return (
<>
{isSubmit && (
<div className="absolute z-[999] h-full w-full flex justify-center items-center bg-black bg-opacity-30">
<Loader />
</div>
)}
{props.Placeholders?.length > 0 ? (
isSignatureExist ? (
<>
{props.Placeholders?.some((x) => !x.signerObjId) ? (
<form onSubmit={handleSubmit}>
<div className="min-h-max max-h-[250px] overflow-y-auto">
{forms?.map((form, index) => (
<div
key={form.Id}
className="p-3 op-card border-[1px] border-gray-400 mt-3 mx-4 mb-4 bg-base-200 text-base-content grid grid-cols-1 md:grid-cols-2 gap-2 relative"
>
{form?.fields?.map((field, fieldIndex) => (
<div className="flex flex-col" key={field.fieldId}>
<label>{field.label}</label>
<SuggestionInput
required
type="email"
value={field.value}
index={fieldIndex}
onChange={(signer) =>
handleInputChange(index, signer, fieldIndex)
}
/>
</div>
))}
{forms?.length > 1 && (
<button
onClick={() => handleRemoveForm(index)}
className="absolute right-3 top-1 text-[red] border-[1px] border-[red] rounded-lg w-[1.7rem] h-[1.7rem]"
>
<i className="fa-light fa-trash"></i>
</button>
)}
<div ref={formRef}></div>
</div>
))}
</div>
<div className="flex flex-col mx-4 mb-4 gap-3">
<button
onClick={handleAddForm}
className="op-btn op-btn-primary focus:outline-none"
>
<i className="fa-light fa-plus"></i> <span>Add new</span>
</button>
<button
type="submit"
className="op-btn op-btn-secondary focus:outline-none"
>
<i className="fa-light fa-paper-plane"></i>{" "}
<span>Send</span>
</button>
</div>
</form>
) : (
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
All roles in this document are currently linked to contacts. To
&apos;quick send&apos; copies of this template to multiple
signers, please ensure that at least one role is not linked to
any contact.
</div>
)}
</>
) : (
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
Please ensure there&#39;s at least one signature widget added for
all recipients.
</div>
)
) : (
<div className="text-black p-3 bg-white w-full text-sm md:text-base flex justify-center items-center">
Please add at least one role to this template in order to &apos;quick
send&apos; copies of it to multiple signers.
</div>
)}
</>
);
};
export default BulkSendUi;
+12 -8
View File
@@ -45,19 +45,23 @@ const Footer = () => {
};
return (
<>
<div className="bg-[#222c3c] text-[#98a6ba] text-center text-[13px] py-3">
All Rights Reserved &copy; {new Date().getFullYear()} &nbsp;
<span onClick={openUrl} className="hover:underline cursor-pointer">
{appName} ( version: {version ? version : `${Package.version} `})
</span>
</div>
<footer className="op-footer op-footer-center py-3 bg-base-300 text-base-content text-center text-[13px]">
<aside>
<p>
All Rights Reserved &copy; {new Date().getFullYear()} &nbsp;
<span onClick={openUrl} className="hover:underline cursor-pointer">
{appName} ( version: {version ? version : `${Package.version} `})
</span>
</p>
</aside>
</footer>
<button
className={`${
showButton ? "block" : "hidden"
} fixed bottom-4 right-4 px-3 p-2 text-xl bg-blue-500 text-white rounded focus:outline-none`}
} fixed bottom-4 right-4 px-3 p-2 text-xl op-bg-secondary text-white rounded focus:outline-none`}
onClick={scrollToTop}
>
<i className="fa-solid fa-angle-up"></i>
<i className="fa-light fa-angle-up"></i>
</button>
</>
);
@@ -67,12 +67,12 @@ const FullScreenButton = () => {
<div className="flex items-center">
<button
onClick={toggleFullScreen}
className="text-black p-2 text-sm focus:outline-none"
className="text-base-content p-2 text-sm focus:outline-none"
>
{isFullScreen ? (
<i className="fa-solid fa-compress"></i>
<i className="fa-light fa-compress"></i>
) : (
<i className="fa fa-maximize"></i>
<i className="fa-light fa-maximize"></i>
)}
</button>
</div>
+103 -75
View File
@@ -4,8 +4,13 @@ import FullScreenButton from "./FullScreenButton";
import { useNavigate } from "react-router-dom";
import Parse from "parse";
import { useWindowSize } from "../hook/useWindowSize";
import { checkIsSubscribed, getAppLogo, openInNewTab } from "../constant/Utils";
import { isEnableSubscription } from "../constant/const";
import {
checkIsSubscribed,
checkIsSubscribedTeam,
getAppLogo,
openInNewTab
} from "../constant/Utils";
import { isEnableSubscription, isStaging } from "../constant/const";
const Header = ({ showSidebar }) => {
const navigate = useNavigate();
@@ -15,6 +20,7 @@ const Header = ({ showSidebar }) => {
const [isOpen, setIsOpen] = useState(false);
const [isSubscribe, setIsSubscribe] = useState(true);
const [isPro, setIsPro] = useState(false);
const [isTeam, setIsTeam] = useState(false);
const [applogo, setAppLogo] = useState(
localStorage.getItem("appLogo") || " "
);
@@ -29,40 +35,42 @@ const Header = ({ showSidebar }) => {
async function checkSubscription() {
if (isEnableSubscription) {
const getIsSubscribe = await checkIsSubscribed();
const getIsTeam = await checkIsSubscribedTeam();
if (getIsSubscribe) {
const applogo = await getAppLogo();
if (applogo) {
setAppLogo(applogo);
if (applogo?.logo) {
setAppLogo(applogo?.logo);
} else {
setAppLogo(localStorage.getItem("appLogo") || "");
}
}
setIsPro(getIsSubscribe);
setIsTeam(getIsTeam);
setIsSubscribe(getIsSubscribe);
}
}
const closeDropdown = () => {
setIsOpen(false);
Parse.User.logOut();
if (Parse?.User?.current()) {
try {
Parse.User.logOut();
} catch (err) {
console.log("Err", err);
}
}
let appdata = localStorage.getItem("userSettings");
let applogo = localStorage.getItem("appLogo");
let appName = localStorage.getItem("appName");
let defaultmenuid = localStorage.getItem("defaultmenuid");
let PageLanding = localStorage.getItem("PageLanding");
let domain = localStorage.getItem("domain");
let _appName = localStorage.getItem("_appName");
let baseUrl = localStorage.getItem("baseUrl");
let appid = localStorage.getItem("parseAppId");
localStorage.clear();
localStorage.setItem("appLogo", applogo);
localStorage.setItem("appName", appName);
localStorage.setItem("_appName", _appName);
localStorage.setItem("defaultmenuid", defaultmenuid);
localStorage.setItem("PageLanding", PageLanding);
localStorage.setItem("domain", domain);
localStorage.setItem("userSettings", appdata);
localStorage.setItem("baseUrl", baseUrl);
localStorage.setItem("parseAppId", appid);
@@ -85,16 +93,24 @@ const Header = ({ showSidebar }) => {
document.removeEventListener("click", closeMenuOnOutsideClick);
};
}, [isOpen]);
const handleConsoleRedirect = () => {
if (isStaging) {
window.open(" https://staging-console.opensignlabs.com/");
} else {
window.open("https://console.opensignlabs.com/");
}
};
return (
<div className="flex flex-row justify-between items-center gap-x-3 md:gap-x-4 bg-white md:px-4 px-2 shadow h-[50px] md:w-full ">
<button
className="cursor-pointer focus:outline-none"
onClick={showSidebar}
>
<i className={`fa-solid fa-bars text-xl `}></i>
</button>
<div className="flex-1">
<div className="op-navbar bg-base-100 shadow">
<div className="flex-none">
<button
className="op-btn op-btn-square op-btn-ghost focus:outline-none hover:bg-transparent op-btn-sm no-animation"
onClick={showSidebar}
>
<i className="fa-light fa-bars text-xl text-base-content"></i>
</button>
</div>
<div className="flex-1 ml-2">
<div className="h-[25px] md:h-[40px] w-auto overflow-hidden">
<img
className="object-contain h-full w-auto"
@@ -103,25 +119,27 @@ const Header = ({ showSidebar }) => {
/>
</div>
</div>
<div
id="profile-menu"
className="flex justify-between items-center gap-x-3"
>
<div id="profile-menu" className="flex-none gap-2">
{!isSubscribe && (
<div>
<button
className="text-xs bg-[#002864] p-2 text-white rounded shadow"
className="text-xs md:text-sm shadow op-btn op-btn-outline op-btn-sm md:op-btn-md op-btn-accent"
onClick={() => navigate("/subscription")}
>
Upgrade Now
</button>
</div>
)}
{isPro && (
<div className="w-[35px] h-[35px] rounded-full ring-[1px] ring-offset-2 ring-[#002862] text-[#002862] overflow-hidden font-semibold flex items-center justify-center">
{!isTeam && isPro && (
<div className="w-[35px] h-[35px] bg-white rounded-full ring-[1px] ring-offset-2 ring-[#002862] text-[#002862] overflow-hidden font-semibold flex items-center justify-center">
PRO
</div>
)}
{isTeam && (
<div className="w-[35px] h-[35px] bg-white rounded-full ring-[1px] text-[13px] ring-offset-2 ring-[#002862] text-[#002862] overflow-hidden font-semibold flex items-center justify-center">
TEAM
</div>
)}
<div>
<FullScreenButton />
</div>
@@ -138,60 +156,70 @@ const Header = ({ showSidebar }) => {
</div>
)}
{width >= 768 && (
<div onClick={toggleDropdown} className="cursor-pointer text-sm">
<div
onClick={toggleDropdown}
className="cursor-pointer text-base-content text-sm"
>
{username && username}
</div>
)}
<div className="relative">
<div className="cursor-pointer">
<i onClick={toggleDropdown} className="fa-solid fa-angle-down"></i>
</div>
<div className="op-dropdown op-dropdown-end" id="profile-menu">
<div
className={`dropdown absolute text-sm text-gray-700 font-light right-0 mt-4 p-1 w-48 bg-white border rounded-lg shadow-lg z-10 ${
isOpen ? "block" : "hidden"
}`}
tabIndex={0}
role="button"
className="op-btn op-btn-ghost op-btn-xs w-[10px] h-[20px] hover:bg-transparent"
>
<ul>
<li
className="hover:bg-gray-100 rounded-t-lg py-1 px-2 cursor-pointer font-normal"
onClick={() => openInNewTab("https://docs.opensignlabs.com")}
>
<i className="fa-solid fa-book"></i> Docs
</li>
<li
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
onClick={() => {
setIsOpen(false);
navigate("/profile");
}}
>
<i className="fa-regular fa-user"></i> Profile
</li>
<li
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
onClick={() => {
setIsOpen(false);
navigate("/changepassword");
}}
>
<i className="fa-solid fa-lock"></i> Change Password
</li>
<li
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
onClick={() => {
window.open("https://console.opensignlabs.com/");
}}
>
<i className="fa-regular fa-id-card"></i> Console
</li>
<li
className="hover:bg-gray-100 rounded-b-lg py-1 px-2 cursor-pointer font-normal"
onClick={closeDropdown}
>
<i className="fa-solid fa-arrow-right-from-bracket"></i> Log Out
</li>
</ul>
<i
tabIndex={0}
role="button"
onClick={toggleDropdown}
className="fa-light fa-angle-down text-base-content"
></i>
</div>
<ul
tabIndex={0}
className="mt-3 z-[1] p-2 shadow op-menu op-menu-sm op-dropdown-content text-base-content bg-base-100 rounded-box w-52"
>
<li onClick={() => openInNewTab("https://docs.opensignlabs.com")}>
<span>
<i className="fa-light fa-book"></i> Docs
</span>
</li>
<li
onClick={() => {
setIsOpen(false);
navigate("/profile");
}}
>
<span>
<i className="fa-light fa-user"></i> Profile
</span>
</li>
<li
onClick={() => {
setIsOpen(false);
navigate("/changepassword");
}}
>
<span>
<i className="fa-light fa-lock"></i> Change Password
</span>
</li>
<li
onClick={() => {
handleConsoleRedirect();
}}
>
<span>
<i className="fa-light fa-id-card"></i> Console
</span>
</li>
<li onClick={closeDropdown}>
<span>
<i className="fa-light fa-arrow-right-from-bracket"></i> Log Out
</span>
</li>
</ul>
</div>
</div>
</div>
+16 -47
View File
@@ -1,5 +1,6 @@
import React, { useState } from "react";
import Parse from "parse";
import Loader from "../primitives/Loader";
// import FacebookLogin from "react-facebook-login";
const LoginFacebook = ({
@@ -49,7 +50,7 @@ const LoginFacebook = ({
const extRes = await Parse.Cloud.run("getUserDetails", params);
// console.log("extRes ", extRes);
if (extRes) {
const params = { ...details, Phone: extRes.get("Phone") };
const params = { ...details, Phone: extRes?.get("Phone") || "" };
const payload = await Parse.Cloud.run("facebooksign", params);
// console.log("payload ", payload);
if (payload && payload.sessiontoken) {
@@ -59,7 +60,7 @@ const LoginFacebook = ({
const LocalUserDetails = {
name: details.Name,
email: details.Email,
phone: extRes.get("Phone"),
phone: extRes?.get("Phone") || "",
company: extRes.get("Company")
};
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
@@ -75,7 +76,7 @@ const LoginFacebook = ({
const handleSubmitbtn = async () => {
if (userDetails.Phone && userDetails.Company) {
setThirdpartyLoader(true);
const params = { ...fBDetails, Phone: userDetails.Phone };
const params = { ...fBDetails, Phone: userDetails?.Phone || "" };
const payload = await Parse.Cloud.run("facebooksign", params);
// console.log("payload ", payload);
@@ -85,7 +86,7 @@ const LoginFacebook = ({
name: userDetails.Name,
email: userDetails.Email,
// "passsword":userDetails.Phone,
phone: userDetails.Phone,
phone: userDetails?.Phone || "",
role: "contracts_User",
company: userDetails.Company
}
@@ -96,7 +97,7 @@ const LoginFacebook = ({
const LocalUserDetails = {
name: userDetails.Name,
email: userDetails.Email,
phone: userDetails.Phone,
phone: userDetails?.Phone || "",
company: userDetails.Company
};
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
@@ -112,29 +113,10 @@ const LoginFacebook = ({
}
};
return (
<div style={{ position: "relative" }}>
<div className="relative">
{thirdpartyLoader && (
<div
style={{
position: "fixed",
width: "100vw",
height: "100vh",
backgroundColor: "rgba(0,0,0,0.2)",
top: 0,
left: 0,
zIndex: 2
}}
>
<div
style={{
position: "fixed",
fontSize: "50px",
color: "#3ac9d6",
top: "50%",
left: "45%"
}}
className="loader-37"
></div>
<div className="fixed flex justify-center items-center inset-0 bg-black bg-opacity-25 z-20 ">
<Loader />
</div>
)}
{/* <FacebookLogin
@@ -146,11 +128,10 @@ const LoginFacebook = ({
/> */}
{isModal && (
<div
className="modal fade show"
className="modal fade show block z-[1]"
id="exampleModal"
tabIndex="-1"
role="dialog"
style={{ display: "block", zIndex: 1 }}
>
<div className="modal-dialog" role="document">
<div className="modal-content">
@@ -163,13 +144,8 @@ const LoginFacebook = ({
<div className="modal-body">
<form>
<div className="form-group">
<label
htmlFor="Phone"
style={{ display: "flex" }}
className="col-form-label"
>
Phone{" "}
<span style={{ fontSize: 13, color: "red" }}>*</span>
<label htmlFor="Phone" className="col-form-label">
Phone <span className="text-[red] text-[13px]">*</span>
</label>
<input
type="tel"
@@ -186,13 +162,8 @@ const LoginFacebook = ({
/>
</div>
<div className="form-group">
<label
htmlFor="Company"
style={{ display: "flex" }}
className="col-form-label"
>
Company{" "}
<span style={{ fontSize: 13, color: "red" }}>*</span>
<label htmlFor="Company" className="col-form-label">
Company <span className="text-[red] text-[13px]">*</span>
</label>
<input
type="text"
@@ -212,16 +183,14 @@ const LoginFacebook = ({
<button
type="button"
onClick={() => handleSubmitbtn()}
className="btn btn-info"
style={{ marginRight: 10 }}
className="btn btn-info mr-[10px]"
>
Sign up
</button>
<button
type="button"
className="btn btn-secondary"
className="btn btn-secondary w-[90px]"
onClick={() => setIsModal(false)}
style={{ width: 90 }}
>
Cancel
</button>
+22 -73
View File
@@ -3,7 +3,7 @@ import Parse from "parse";
import { jwtDecode } from "jwt-decode";
import { useScript } from "../hook/useScript";
import ModalUi from "../primitives/ModalUi";
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const";
import Loader from "../primitives/Loader";
/*
* `GoogleSignInBtn`as it's name indicates it render google sign in button
@@ -51,14 +51,8 @@ const GoogleSignInBtn = ({
let baseUrl = localStorage.getItem("baseUrl");
let appid = localStorage.getItem("parseAppId");
let applogo = localStorage.getItem("appLogo");
let domain = localStorage.getItem("domain");
let appversion = localStorage.getItem("appVersion");
let appTitle = localStorage.getItem("appTitle");
let defaultmenuid = localStorage.getItem("defaultmenuid");
let PageLanding = localStorage.getItem("PageLanding");
let _appName = localStorage.getItem("_appName");
let _app_objectId = localStorage.getItem("_app_objectId");
let appName = localStorage.getItem("appName");
let userSettings = localStorage.getItem("userSettings");
localStorage.clear();
@@ -66,14 +60,8 @@ const GoogleSignInBtn = ({
localStorage.setItem("baseUrl", baseUrl);
localStorage.setItem("parseAppId", appid);
localStorage.setItem("appLogo", applogo);
localStorage.setItem("domain", domain);
localStorage.setItem("appversion", appversion);
localStorage.setItem("appTitle", appTitle);
localStorage.setItem("defaultmenuid", defaultmenuid);
localStorage.setItem("PageLanding", PageLanding);
localStorage.setItem("_appName", _appName);
localStorage.setItem("_app_objectId", _app_objectId);
localStorage.setItem("appName", appName);
localStorage.setItem("userSettings", userSettings);
localStorage.setItem("baseUrl", baseUrl);
localStorage.setItem("parseAppId", appid);
@@ -110,7 +98,7 @@ const GoogleSignInBtn = ({
const extRes = await Parse.Cloud.run("getUserDetails", params);
// console.log("extRes ", extRes);
if (extRes) {
const params = { ...details, Phone: extRes.get("Phone") };
const params = { ...details, Phone: extRes?.get("Phone") || "" };
const payload = await Parse.Cloud.run("googlesign", params);
// console.log("payload ", payload);
if (payload && payload.sessiontoken) {
@@ -121,7 +109,7 @@ const GoogleSignInBtn = ({
const LocalUserDetails = {
name: details.Name,
email: details.Gmail,
phone: extRes.get("Phone"),
phone: extRes?.get("Phone") || "",
company: extRes.get("Company")
};
localStorage.setItem("userDetails", JSON.stringify(LocalUserDetails));
@@ -139,7 +127,7 @@ const GoogleSignInBtn = ({
setThirdpartyLoader(true);
// e.preventDefault()
// console.log("handelSubmit", userDetails);
const params = { ...googleDetails, Phone: userDetails.Phone };
const params = { ...googleDetails, Phone: userDetails?.Phone };
const payload = await Parse.Cloud.run("googlesign", params);
// console.log("payload ", payload);
@@ -149,7 +137,7 @@ const GoogleSignInBtn = ({
name: userDetails.Name,
email: userDetails.Email,
// "passsword":userDetails.Phone,
phone: userDetails.Phone,
phone: userDetails?.Phone || "",
role: "contracts_User",
company: userDetails.Company,
jobTitle: userDetails.Destination
@@ -161,7 +149,7 @@ const GoogleSignInBtn = ({
const LocalUserDetails = {
name: userDetails.Name,
email: userDetails.Email,
phone: userDetails.Phone,
phone: userDetails?.Phone || "",
company: userDetails.Company
// jobTitle: userDetails.JobTitle
};
@@ -186,66 +174,37 @@ const GoogleSignInBtn = ({
let appdata = localStorage.getItem("userSettings");
let applogo = localStorage.getItem("appLogo");
let appName = localStorage.getItem("appName");
let defaultmenuid = localStorage.getItem("defaultmenuid");
let PageLanding = localStorage.getItem("PageLanding");
let domain = localStorage.getItem("domain");
let _appName = localStorage.getItem("_appName");
let baseUrl = localStorage.getItem("baseUrl");
let appid = localStorage.getItem("parseAppId");
localStorage.clear();
localStorage.setItem("appLogo", applogo);
localStorage.setItem("appName", appName);
localStorage.setItem("_appName", _appName);
localStorage.setItem("defaultmenuid", defaultmenuid);
localStorage.setItem("PageLanding", PageLanding);
localStorage.setItem("domain", domain);
localStorage.setItem("userSettings", appdata);
localStorage.setItem("baseUrl", baseUrl);
localStorage.setItem("parseAppId", appid);
};
return (
<div style={{ position: "relative" }}>
<div className="relative">
{thirdpartyLoader && (
<div
style={{
position: "fixed",
width: "100vw",
height: "100vh",
backgroundColor: "rgba(0,0,0,0.2)",
top: 0,
left: 0,
zIndex: 2
}}
>
<div
style={{
position: "fixed",
fontSize: "50px",
color: "#3ac9d6",
top: "50%",
left: "45%"
}}
className="loader-37"
></div>
<div className="fixed flex justify-center items-center inset-0 bg-black bg-opacity-25 z-20 ">
<Loader />
</div>
)}
<div ref={googleBtn} className="text-sm"></div>
<ModalUi showClose={false} isOpen={isModal} title="Sign up form">
<form className="px-4 py-3">
<form className="px-4 py-3 text-base-content">
<div className="mb-3">
<label
htmlFor="Phone"
style={{ display: "flex" }}
className="block text-xs text-gray-700 font-semibold"
>
Phone <span style={{ fontSize: 13, color: "red" }}>*</span>
<label htmlFor="Phone" className="block text-xs font-semibold">
Phone <span className="text-[13px] text-[red]">*</span>
</label>
<input
type="tel"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
id="Phone"
value={userDetails.Phone}
onChange={(e) =>
@@ -258,16 +217,12 @@ const GoogleSignInBtn = ({
/>
</div>
<div className="mb-3">
<label
htmlFor="Company"
style={{ display: "flex" }}
className="block text-xs text-gray-700 font-semibold"
>
Company <span style={{ fontSize: 13, color: "red" }}>*</span>
<label htmlFor="Company" className="block text-xs font-semibold">
Company <span className="text-[13px] text-[red]">*</span>
</label>
<input
type="text"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
id="Company"
value={userDetails.Company}
onChange={(e) =>
@@ -280,16 +235,12 @@ const GoogleSignInBtn = ({
/>
</div>
<div className="mb-3">
<label
htmlFor="JobTitle"
style={{ display: "flex" }}
className="block text-xs text-gray-700 font-semibold"
>
Job Title <span style={{ fontSize: 13, color: "red" }}>*</span>
<label htmlFor="JobTitle" className="block text-xs font-semibold">
Job Title <span className="text-[13px] text-[red]">*</span>
</label>
<input
type="text"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
id="JobTitle"
value={userDetails.Destination}
onChange={(e) =>
@@ -301,20 +252,18 @@ const GoogleSignInBtn = ({
required
/>
</div>
<div>
<div className="flex flex-row gap-2">
<button
type="button"
className="px-3 py-1.5 text-white rounded shadow-md text-center focus:outline-none "
className="op-btn op-btn-primary"
onClick={() => handleSubmitbtn()}
style={{ marginRight: 10, backgroundColor: modalSubmitBtnColor }}
>
Sign up
</button>
<button
type="button"
className="p-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none"
className="op-btn op-btn-ghost"
onClick={handleCloseModal}
style={{ width: 90, backgroundColor: modalCancelBtnColor }}
>
Cancel
</button>
+28 -34
View File
@@ -1,39 +1,19 @@
import React from "react";
import { Document, Page } from "react-pdf";
import { Stage, Layer, Rect } from "react-konva";
import { Stage, Layer, Rect, Text } from "react-konva";
const RenderDebugPdf = (props) => {
return (
<div>
<div
style={{
position: "sticky",
top: 0,
padding: 10,
zIndex: 1,
backgroundColor: "white",
border: "1px solid grey",
margin: "5px 0"
}}
>
<div className="sticky top-0 p-[10px] z-10 bg-white border-[1px] border-[gray] my-[5px]">
{`Co-ordinates: X - ${props.hoverCoordinates.x}, Y - ${props.hoverCoordinates.y}`}
</div>
<div
style={{
flex: 1,
position: "relative",
border: "1px solid grey",
overflow: "auto",
cursor: "crosshair"
}}
className="relative flex-1 cursor-crosshair border-[1px] border-[gray] overflow-auto"
onMouseMove={props.handleMouseMoveDiv}
>
<Document
onLoadError={() => {
const load = {
status: false,
type: "failed"
};
props.setPdfLoadFail(load);
props.setPdfLoadFail(false);
}}
loading={"Loading Document.."}
onLoadSuccess={props.pageDetails}
@@ -57,22 +37,36 @@ const RenderDebugPdf = (props) => {
onMouseUp={props.handleMouseUp}
width={props.pdfDimension.width}
height={props.pdfDimension.height}
style={{ position: "absolute", top: 0, left: 0 }}
className="absolute top-0 right-0"
>
<Layer>
{props.annotations
.filter((value) => value.page === props.pageNumber)
.map((value) => {
const textX = value.x + value.width / 3;
const textY = value.y + value.height / 2.5;
return (
<Rect
key={value.key}
x={value.x}
y={value.y}
width={value.width}
height={value.height}
fill="transparent"
stroke="black"
/>
<React.Fragment key={value.key}>
<Rect
x={value.x}
y={value.y}
width={value.width}
height={value.height}
fill="#cbe9ed"
stroke="black"
/>
<Text
x={textX}
y={textY}
text={
value?.key > 0 ? "box " + value.key.toString() : "box"
}
fontSize={16}
fill="black"
align="center"
verticalAlign="middle"
/>
</React.Fragment>
);
})}
</Layer>
@@ -1,5 +1,4 @@
import React from "react";
import "../../styles/loader.css";
import { useNavigate } from "react-router-dom";
import { openInNewTab } from "../../constant/Utils";
@@ -26,19 +25,17 @@ const DashboardButton = (props) => {
props.Data && props.Data.Redirect_type
? "cursor-pointer"
: "cursor-default"
} w-full px-3 py-2 flex text-white rounded-md shadow overflow-hidden`}
} w-full shadow-md px-3 py-2 op-card bg-base-100`}
>
<div className="flex items-center justify-start gap-5">
<span className="rounded-full bg-black bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
<div className="flex flex-row items-center">
<span className="rounded-full bg-base-content bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
<i
className={`${
props.Icon ? props.Icon : "fa fa-solid fa-info"
props.Icon ? props.Icon : "fa-light fa-info"
} text-[25px] lg:text-[30px]`}
></i>
</span>
<div className="">
<div className="text-base lg:text-lg text-black"> {props.Label}</div>
</div>
<div className=" text-lg ml-3 text-base-content">{props.Label}</div>
</div>
</div>
);
@@ -2,7 +2,6 @@ import React, { useState, useEffect } from "react";
import axios from "axios";
import Parse from "parse";
import getReplacedHashQuery from "../../constant/getReplacedHashQuery";
import "../../styles/loader.css";
import { useNavigate } from "react-router-dom";
import Tooltip from "../../primitives/Tooltip";
@@ -24,17 +23,12 @@ const DashboardCard = (props) => {
sessionToken: localStorage.getItem("accesstoken")
};
let body = {};
let currentUser;
let currentUser1 = Parse.User.current();
currentUser = currentUser1.id;
let res;
if (localStorage.getItem("Extand_Class")) {
let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0];
} else {
res = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
res = await Parse.Cloud.run("getUserDetails");
if (res) res = res.toJSON();
}
if (res) {
@@ -95,9 +89,7 @@ const DashboardCard = (props) => {
let data = JSON.parse(localStorage.getItem("Extand_Class"));
resr = data[0];
} else {
resr = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
resr = await Parse.Cloud.run("getUserDetails");
if (resr) resr = resr.toJSON();
}
@@ -219,15 +211,12 @@ const DashboardCard = (props) => {
if (restr.includes("#")) {
try {
const currentUser = Parse.User.current();
let res;
if (localStorage.getItem("Extand_Class")) {
let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0];
} else {
let resr = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
let resr = await Parse.Cloud.run("getUserDetails");
if (res) res = resr.toJSON();
}
@@ -262,21 +251,14 @@ const DashboardCard = (props) => {
}
}
body = str;
await axios
.post(url, body, { headers: headers })
.then((response) => {
try {
if (response.data.result.length > 0) {
setresponse(response.data.result[0][props.FilterData.key]);
setLoading(false);
} else {
setresponse("0");
setLoading(false);
}
} catch (error) {
setLoading(false);
}
});
const response = await axios.post(url, body, { headers: headers });
if (response.data.result.length > 0) {
setresponse(response.data.result[0][props.FilterData.key]);
setLoading(false);
} else {
setresponse("0");
setLoading(false);
}
} catch (error) {
setLoading(false);
}
@@ -336,25 +318,29 @@ const DashboardCard = (props) => {
props.Data && props.Data.Redirect_type
? "cursor-pointer"
: "cursor-default"
} w-full h-[140px] px-3 pt-4 pb-10 text-white rounded-md shadow overflow-hidden relative`}
}`}
>
<div className="flex items-center justify-start gap-5">
<span className="rounded-full bg-black bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
<div className="flex items-center justify-start gap-5 text-white">
<span className="rounded-full bg-base-300 bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
<i
className={`${
props.Icon ? props.Icon : "fa fa-solid fa-info"
props.Icon ? props.Icon : "fa-light fa-info"
} text-[25px] lg:text-[30px]`}
></i>
</span>
<div className="">
<div className="font-medium">
<div className="text-base lg:text-lg"> {props.Label}</div>
<div className="text-2xl font-light">
{loading ? <div className="loader-01"></div> : setFormat(response)}
</div>
</div>
</div>
<div className="text-xs absolute top-2 right-1">
<Tooltip id={props.Label} iconColor={"white"} message={props?.Data?.tourMessage} />
<div className="text-xs absolute top-3 right-2">
<Tooltip
id={props.Label}
iconColor={"white"}
message={props?.Data?.tourMessage}
/>
</div>
</div>
);
@@ -3,6 +3,7 @@ import Parse from "parse";
import ReportTable from "../../primitives/GetReportDisplay";
import reportJson from "../../json/ReportJson";
import axios from "axios";
import Loader from "../../primitives/Loader";
function DashboardReport(props) {
// console.log("props ", props)
const [List, setList] = useState([]);
@@ -121,21 +122,8 @@ function DashboardReport(props) {
return (
<>
{isLoader ? (
<div
style={{
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
<div className="h-[250px] flex justify-center items-center">
<Loader />
</div>
) : (
<>
@@ -7,62 +7,37 @@ const buttonList = [
label: "Sign yourself",
redirectId: "sHAnZphf69",
redirectType: "Form",
icon: "fas fa-pen-nib"
icon: "fa-light fa-pen-nib"
},
{
label: "Request signature",
redirectId: "8mZzFxbG1z",
redirectType: "Form",
icon: "fa-solid fa-paper-plane"
icon: "fa-light fa-paper-plane"
}
];
const GetDashboard = (props) => {
const Button = ({ label, redirectId, redirectType, icon }) => (
<div className={"bg-white rounded-md shadow w-full"}>
<Suspense
fallback={
<div style={{ height: "300px" }}>
<div
style={{
marginLeft: "45%",
marginTop: "150px",
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
</div>
}
>
<DashboardButton
Icon={icon}
Label={label}
Data={{ Redirect_type: redirectType, Redirect_id: redirectId }}
/>
</Suspense>
</div>
<DashboardButton
Icon={icon}
Label={label}
Data={{ Redirect_type: redirectType, Redirect_id: redirectId }}
/>
);
const renderSwitchWithTour = (col) => {
switch (col.widget.type) {
case "Card":
return (
<div
className={"bg-[#2ed8b6] rounded-md shadow mb-3 md:mb-0"}
className={`${
col?.widget?.bgColor ? col.widget.bgColor : "bg-[#2ed8b6]"
} op-card w-full h-[140px] px-3 pt-4 mb-3 shadow-md`}
data-tut={col.widget.data.tourSection}
style={{ background: col.widget.bgColor }}
>
<Suspense
fallback={
<div style={{ height: "300px" }}>
<div
style={{
marginLeft: "45%",
marginTop: "150px",
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
<div className="h-[150px] w-full flex justify-center items-center">
loading...
</div>
}
>
@@ -72,7 +47,6 @@ const GetDashboard = (props) => {
Format={col.widget.format && col.widget.format}
Data={col.widget.data}
FilterData={col.widget.filter}
DefaultQuery={props.DefaultQuery}
/>
</Suspense>
</div>
@@ -89,7 +63,7 @@ const GetDashboard = (props) => {
);
}
default:
return null;
return <></>;
}
};
const renderSwitch = (col) => {
@@ -97,8 +71,9 @@ const GetDashboard = (props) => {
case "Card":
return (
<div
className={"bg-[#2ed8b6] rounded-md shadow mb-3 md:mb-0"}
style={{ background: col.widget.bgColor }}
className={`${
col?.widget?.bgColor ? col.widget.bgColor : "bg-[#2ed8b6]"
} op-card w-full h-[140px] px-3 pt-4 mb-3 shadow-md"`}
>
<Suspense fallback={<div>please wait</div>}>
<DashboardCard
@@ -107,7 +82,6 @@ const GetDashboard = (props) => {
Format={col.widget.format && col.widget.format}
Data={col.widget.data}
FilterData={col.widget.filter}
DefaultQuery={props.DefaultQuery}
/>
</Suspense>
</div>
@@ -122,7 +96,7 @@ const GetDashboard = (props) => {
);
}
default:
return null;
return <></>;
}
};
return (
@@ -130,7 +104,7 @@ const GetDashboard = (props) => {
<div className="mb-3">
<div
data-tut={"tourbutton"}
className="flex flex-col md:flex-row gap-6 md:gap-8"
className="flex flex-col md:flex-row gap-4"
>
{buttonList.map((btn) => (
<Button
@@ -143,21 +117,19 @@ const GetDashboard = (props) => {
))}
</div>
</div>
{props.dashboard.map((val, key) => (
<div key={"a" + key} className="row">
{val.columns.map((col, i) =>
col.widget.data && col.widget.data.tourSection ? (
<div key={i} className={props.classnameArray[key][i]}>
{renderSwitchWithTour(col)}
</div>
) : (
<div key={i} className={props.classnameArray[key][i]}>
{renderSwitch(col)}
</div>
)
)}
</div>
))}
<div className="grid grid-cols-12 w-full gap-x-4">
{props?.dashboard?.columns?.map((col, i) =>
col.widget.data && col.widget.data.tourSection ? (
<div key={i} className={col?.colsize}>
{renderSwitchWithTour(col)}
</div>
) : (
<div key={i} className={col?.colsize}>
{renderSwitch(col)}
</div>
)
)}
</div>
</div>
);
};
@@ -1,7 +1,5 @@
import React, { useState, useEffect, useRef } from "react";
import folder from "../../assets/images/folder.png";
import "../../styles/opensigndrive.css";
import pdfLogo from "../../assets/images/pdf3.png";
import axios from "axios";
import * as ContextMenu from "@radix-ui/react-context-menu";
import { saveAs } from "file-saver";
@@ -9,7 +7,6 @@ import { useNavigate } from "react-router-dom";
import Table from "react-bootstrap/Table";
import * as HoverCard from "@radix-ui/react-hover-card";
import ModalUi from "../../primitives/ModalUi";
import { themeColor } from "../../constant/const";
import FolderModal from "../shared/fields/FolderModal";
function DriveBody(props) {
@@ -20,10 +17,10 @@ function DriveBody(props) {
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" }
{ type: "Download", icon: "fa-light fa-arrow-down" },
{ type: "Rename", icon: "fa-light fa-font" },
{ type: "Move", icon: "fa-light fa-file-export" },
{ type: "Delete", icon: "fa-light fa-trash" }
];
const navigate = useNavigate();
@@ -73,9 +70,9 @@ function DriveBody(props) {
props.sortingData(null, null, updatedData);
await axios
.put(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document/${docId}`,
`${localStorage.getItem(
"baseUrl"
)}classes/contracts_Document/${docId}`,
updateName,
{
headers: {
@@ -107,7 +104,7 @@ function DriveBody(props) {
const signedUrl = data.SignedUrl;
//checking if document has completed and request signature flow
if (data?.IsCompleted && signerExist?.length > 0) {
navigate(`/pdfRequestFiles/${data.objectId}`);
navigate(`/recipientSignPdf/${data.objectId}`);
}
//checking if document has completed and signyour-self flow
else if (!signerExist && !isPlaceholder) {
@@ -115,7 +112,7 @@ function DriveBody(props) {
}
//checking if document has declined by someone
else if (isDecline) {
navigate(`/pdfRequestFiles/${data.objectId}`);
navigate(`/recipientSignPdf/${data.objectId}`);
//checking draft type document
} else if (
signerExist?.length > 0 &&
@@ -125,8 +122,8 @@ function DriveBody(props) {
navigate(`/placeHolderSign/${data.objectId}`);
}
//Inprogress document
else if (isPlaceholder?.length > 0 && signerExist?.length > 0) {
navigate(`/pdfRequestFiles/${data.objectId}`);
else if (isPlaceholder?.length > 0 && signedUrl) {
navigate(`/recipientSignPdf/${data.objectId}`);
} //placeholder draft document
else if (
(signerExist?.length > 0 &&
@@ -173,9 +170,7 @@ function DriveBody(props) {
await axios
.put(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document/${docId}`,
`${localStorage.getItem("baseUrl")}classes/contracts_Document/${docId}`,
data,
{
headers: {
@@ -222,7 +217,7 @@ function DriveBody(props) {
updateData = {
Folder: {
__type: "Pointer",
className: `${localStorage.getItem("_appName")}_Document`,
className: "contracts_Document",
objectId: moveFolderId
}
};
@@ -234,9 +229,9 @@ function DriveBody(props) {
await axios
.put(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document/${updateDocId}`,
`${localStorage.getItem(
"baseUrl"
)}classes/contracts_Document/${updateDocId}`,
updateData,
{
headers: {
@@ -313,32 +308,26 @@ function DriveBody(props) {
const signersName = () => {
const getSignersName = signerExist.map((data) => data.Name);
const signerName = getSignersName.join(",");
const signerName = getSignersName.join(", ");
return (
<span
className="statusSpan"
style={{ width: "90%", wordWrap: "break-word" }}
>
{signerName}{" "}
<span className="text-[12px] font-medium w-[90%] break-words">
{signerName}
</span>
);
};
return listType === "table" ? (
data.Type === "Folder" ? (
<tr onClick={() => handleOnclikFolder(data)}>
<td
style={{ cursor: "pointer", display: "flex", alignItems: "center" }}
>
<i
className="fa fa-folder"
aria-hidden="true"
style={{ color: "#f0ad26", marginRight: "8px", fontSize: "26px" }}
></i>
<span style={{ fontSize: "12px", fontWeight: "500" }}>
{data.Name}
</span>
<td className="cursor-pointer flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
className="w-[26px] h-[26px] fill-current op-text-secondary"
>
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
</svg>
<span className="text-[12px] font-medium">{data.Name}</span>
</td>
<td>_</td>
<td>Folder</td>
@@ -347,17 +336,15 @@ function DriveBody(props) {
</tr>
) : (
<tr onClick={() => checkPdfStatus(data)}>
<td
style={{ cursor: "pointer", display: "flex", alignItems: "center" }}
>
<i
className="fa fa-file-pdf"
style={{ color: "#ed4d0e", marginRight: "8px", fontSize: "26px" }}
></i>
<span style={{ fontSize: "12px", fontWeight: "500" }}>
{data.Name}
</span>
<td className="cursor-pointer flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 384 512"
className="w-[26px] h-[26px] fill-current op-text-primary"
>
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
</svg>
<span className="text-[12px] font-medium">{data.Name}</span>
</td>
<td>{createddate}</td>
<td>Pdf</td>
@@ -368,32 +355,29 @@ function DriveBody(props) {
e.stopPropagation();
handleMenuItemClick("Download", data);
}}
className="fa fa-download"
className="fa-light fa-download mr-[8px] op-text-primary"
aria-hidden="true"
style={{ color: "#ed280e", marginRight: "8px" }}
></i>
</td>
</tr>
)
) : listType === "list" && data.Type === "Folder" ? (
<div key={ind} className="folderBox">
<div key={ind} className="relative w-[100px] h-[100px] mx-2 my-3">
<ContextMenu.Root>
<ContextMenu.Trigger className="ContextMenuTrigger">
<ContextMenu.Trigger className="flex flex-col justify-center items-center">
{/* folder */}
<div
style={{
display: "flex",
flexDirection: "column",
cursor: "pointer"
}}
data-tut={props.dataTutSeventh}
onClick={() => handleOnclikFolder(data)}
className="cursor-pointer"
>
<img
alt="no img"
onClick={() => handleOnclikFolder(data)}
src={folder}
width={100}
height={103}
/>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
className="w-[100px] h-[100px] fill-current op-text-secondary"
>
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
</svg>
{rename === data.objectId ? (
<input
onFocus={() => {
@@ -411,15 +395,10 @@ function DriveBody(props) {
defaultValue={renameValue}
// value={renameValue}
onChange={(e) => setRenameValue(e.target.value)}
style={{
width: "100px",
border: "1.5px solid black",
borderRadius: "2px",
fontSize: "10px"
}}
className="w-[100px] border-[1.5px] border-black rounded-sm text-[10px]"
/>
) : (
<span className="foldName">{data.Name}</span>
<span className="fileName">{data.Name}</span>
)}
</div>
</ContextMenu.Trigger>
@@ -434,8 +413,8 @@ function DriveBody(props) {
onClick={() => handleMenuItemClick("Rename", data)}
className="ContextMenuItem"
>
<i className="fa-solid fa-font"></i>
<span style={{ marginLeft: "8px" }}>Rename</span>
<i className="fa-light fa-font mr-[8px]"></i>
<span>Rename</span>
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
@@ -446,63 +425,65 @@ function DriveBody(props) {
<HoverCard.Trigger asChild>
<div>
<ContextMenu.Root>
<div className="icon-container">
<ContextMenu.Trigger className="ContextMenuTrigger">
<img
alt="PDF"
className="pdf-icon"
src={pdfLogo}
onClick={() => checkPdfStatus(data)}
<div className="relative w-[100px] h-[100px] mx-2 my-3">
<ContextMenu.Trigger className="flex flex-col justify-center items-center">
{/* pdf */}
<div
data-tut={props.dataTutSixth}
/>
{rename === data.objectId ? (
<input
autoFocus={true}
type="text"
onFocus={() => {
inputRef.current.setSelectionRange(0, 0);
const input = inputRef.current;
if (input) {
input.select();
}
}}
onBlur={() => handledRenameDoc(data)}
onKeyDown={(e) => handleEnterPress(e, data)}
ref={inputRef}
defaultValue={renameValue}
// value={renameValue}
onChange={(e) => setRenameValue(e.target.value)}
style={{
width: "100px",
border: "1.5px solid black",
borderRadius: "2px",
fontSize: "10px"
}}
/>
) : (
<span className="fileName">{data.Name}</span>
)}
onClick={() => checkPdfStatus(data)}
className="cursor-pointer"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 384 512"
className="w-[100px] h-[100px] fill-current op-text-primary"
>
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
</svg>
{rename === data.objectId ? (
<input
autoFocus={true}
type="text"
onFocus={() => {
inputRef.current.setSelectionRange(0, 0);
const input = inputRef.current;
if (input) {
input.select();
}
}}
onBlur={() => handledRenameDoc(data)}
onKeyDown={(e) => handleEnterPress(e, data)}
ref={inputRef}
defaultValue={renameValue}
// value={renameValue}
onChange={(e) => setRenameValue(e.target.value)}
className="w-[100px] border-[1.5px] border-black rounded-sm text-[10px]"
/>
) : (
<span className="fileName">{data.Name}</span>
)}
</div>
</ContextMenu.Trigger>
{status === "Completed" ? (
<div className="status-badge completed">
<i className="fas fa-check-circle"></i>
<i className="fa-light fa-check-circle"></i>
</div>
) : status === "Declined" ? (
<div className="status-badge declined">
<i className="fa fa-thumbs-down"></i>
<i className="fa-light fa-thumbs-down"></i>
</div>
) : status === "Expired" ? (
<div className="status-badge expired">
<i className="fa fa-hourglass-end"></i>
<i className="fa-light fa-hourglass-end"></i>
</div>
) : status === "Draft" ? (
<div className="status-badge draft">
<i className="fa fa-file"></i>
<i className="fa-light fa-file"></i>
</div>
) : (
status === "In Progress" && (
<div className="status-badge in-progress">
<i className="fa fa-paper-plane"></i>
<i className="fa-light fa-paper-plane"></i>
</div>
)
)}
@@ -522,7 +503,7 @@ function DriveBody(props) {
className="ContextMenuItem"
>
<i className={menu.icon}></i>
<span style={{ marginLeft: "8px" }}>{menu.type}</span>
<span className="ml-[8px]">{menu.type}</span>
</ContextMenu.Item>
);
})}
@@ -533,22 +514,18 @@ function DriveBody(props) {
</HoverCard.Trigger>
<HoverCard.Portal>
<HoverCard.Content className="HoverCardContent" sideOffset={5}>
<strong style={{ fontSize: "13px" }}>Title: </strong>
<span className="statusSpan" style={{ marginBottom: "0px" }}>
{" "}
{data.Name}
</span>
<strong className="text-[13px]">Title: </strong>
<span className="text-[12px] font-medium mb-0"> {data.Name}</span>
<br />
<strong style={{ fontSize: "13px" }}>Status: </strong>
<span className="statusSpan"> {status}</span>
<strong className="text-[13px]">Status: </strong>
<span className="text-[12px] font-medium"> {status}</span>
<br />
<strong style={{ fontSize: "13px" }}>Created Date: </strong>
<span className="statusSpan">{createddate}</span>
<strong className="text-[13px]">Created Date: </strong>
<span className="text-[12px] font-medium">{createddate}</span>
<br />
{signerExist && (
<>
<strong style={{ fontSize: "13px" }}>Signers: </strong>
{/* <span className="statusSpan">kjefjjnejkfnkbjs bbfjkdsbjbfjkbjk kscbjkbjkb</span> */}
<strong className="text-[13px]">Signers: </strong>
{signersName()}
</>
)}
@@ -587,13 +564,9 @@ function DriveBody(props) {
</Table>
</div>
) : (
<div className="pdfContainer">
<div className="flex flex-row flex-wrap items-center mt-1 pb-[20px] mx-[5px]">
{props.pdfData.map((data, ind) => {
return (
<div className="box" key={ind}>
{handleFolderData(data, ind, "list")}
</div>
);
return <div key={ind}>{handleFolderData(data, ind, "list")}</div>;
})}
</div>
)}
@@ -609,44 +582,23 @@ function DriveBody(props) {
)}
<ModalUi
isOpen={isDeleteDoc}
headerColor={themeColor}
title={"Delete Document"}
handleClose={() => {
setIsDeleteDoc(false);
}}
handleClose={() => setIsDeleteDoc(false)}
>
<div style={{ height: "100%", padding: 20 }}>
<div className="h-full p-[20px] text-base-content">
<p>Are you sure you want to delete this document?</p>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginTop: "15px",
marginBottom: "15px"
}}
></div>
<div className="h-[1px] w-full bg-[#9f9f9f] my-[15px]"></div>
<button
onClick={() => {
handleDeleteDocument(selectDoc);
}}
style={{
background: themeColor,
color: "white"
}}
onClick={() => handleDeleteDocument(selectDoc)}
type="button"
className="finishBtn"
className="op-btn op-btn-primary mr-2"
>
Yes
</button>
<button
onClick={() => {
setIsDeleteDoc(false);
}}
onClick={() => setIsDeleteDoc(false)}
type="button"
className="finishBtn cancelBtn"
className="op-btn op-btn-neutral"
>
No
</button>
@@ -8,11 +8,8 @@ const AddRoleModal = (props) => {
isOpen={props.isModalRole}
handleClose={props.handleCloseRoleModal}
>
<div className="addusercontainer">
<form
style={{ display: "flex", flexDirection: "column" }}
onSubmit={props.handleAddRole}
>
<div className="h-full py-[10px] px-[20px]">
<form className="flex flex-col" onSubmit={props.handleAddRole}>
<input
value={props.roleName}
onChange={(e) => props.setRoleName(e.target.value)}
@@ -21,39 +18,20 @@ const AddRoleModal = (props) => {
? "User " + (props.signersdata.length + 1)
: "User 1"
}
className="addUserInput"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs mt-1"
/>
<p
style={{
color: "grey",
fontSize: 11,
margin: "10px 0 10px 5px"
}}
>
<p className="text-[gray] text-[11px] mt-[5px] mb-[10px] ml-[10px]">
e.g: Customer, Hr, Director, Manager, Student, etc...
</p>
<div>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginBottom: "15px"
}}
></div>
<button
type="submit"
style={{
background: "#00a2b7"
}}
className="finishBtn"
>
<div className="h-[1px] w-full bg-[#9f9f9f] mb-[10px]"></div>
<button type="submit" className="op-btn op-btn-primary">
Add
</button>
<button
onClick={props.handleCloseRoleModal}
type="button"
className="finishBtn cancelBtn"
className="op-btn op-btn-ghost ml-2"
>
Close
</button>
@@ -3,13 +3,9 @@ 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"
}}
className={`${right ? `-right-[12px]` : "-right-[1px]"} ${
top ? `-bottom-[11px]` : "-bottom-[1px]"
} absolute inline-block w-[14px] h-[14px] hover:cursor-sw-resize border-r-[3px] border-b-[3px] border-[#188ae2]`}
></div>
);
}
@@ -1,5 +1,4 @@
import React from "react";
import { themeColor } from "../../constant/const";
function DefaultSignature({ defaultSignImg, xyPostion, setDefaultSignAlert }) {
const confirmToaddDefaultSign = () => {
if (xyPostion.length > 0) {
@@ -17,55 +16,26 @@ function DefaultSignature({ defaultSignImg, xyPostion, setDefaultSignAlert }) {
};
return (
<div>
<div
style={{
background: themeColor,
color: "white",
padding: "5px",
fontFamily: "sans-serif",
marginTop: "5px"
}}
>
<div data-tut="reactourThird">
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
Signature
</div>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
marginTop: "10px",
fontWeight: "600"
}}
>
<>
<p>Your Signature</p>
<div className="defaultSignBox">
<img
alt="default img"
style={{
width: "100%",
height: "100%",
objectFit: "contain"
}}
src={defaultSignImg}
/>
</div>
<button
style={{
background: themeColor,
color: "white",
marginTop: "20px",
cursor: "pointer",
marginBottom: "10px"
}}
type="button"
className="finishBtn finishnHover"
onClick={() => confirmToaddDefaultSign()}
>
Auto Sign All
</button>
</>
<div className="flex flex-col items-center mt-[10px] font-semibold">
<p className="text-base-content">Your Signature</p>
<div className="op-card shadow-md h-[111px] w-[90%] p-2">
<img
alt="signature"
className="w-full h-full object-contain"
src={defaultSignImg}
/>
</div>
<button
type="button"
className="op-btn op-btn-primary op-btn-sm mt-[10px]"
onClick={() => confirmToaddDefaultSign()}
>
Auto Sign All
</button>
</div>
</div>
);
@@ -1,23 +1,19 @@
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import Loader from "../../primitives/LoaderWithMsg";
import LoaderWithMsg from "../../primitives/LoaderWithMsg";
import { contractDocument } from "../../constant/Utils";
import HandleError from "../../primitives/HandleError";
import { useLocation, useNavigate } from "react-router-dom";
function useQuery() {
return new URLSearchParams(useLocation().search);
}
function DraftDocument() {
const navigate = useNavigate();
const query = useQuery();
const docId = query.get("docId");
const [isLoading, setIsLoading] = useState({
isLoader: true,
message: "This might take some time"
});
const rowLevel =
localStorage.getItem("rowlevel") &&
JSON.parse(localStorage.getItem("rowlevel"));
const docId =
rowLevel && rowLevel?.id
? rowLevel.id
: rowLevel?.objectId && rowLevel.objectId;
useEffect(() => {
getDocumentDetails();
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -53,7 +49,7 @@ function DraftDocument() {
const signedUrl = data.SignedUrl;
//checking if document has completed and request signature flow
if (data?.IsCompleted && signerExist?.length > 0) {
navigate(`/pdfRequestFiles/${data.objectId}`);
navigate(`/recipientSignPdf/${data.objectId}`);
}
//checking if document has completed and signyour-self flow
else if (!signerExist && !isPlaceholder) {
@@ -61,7 +57,7 @@ function DraftDocument() {
}
//checking if document has declined by someone
else if (isDecline) {
navigate(`/pdfRequestFiles/${data.objectId}`);
navigate(`/recipientSignPdf/${data.objectId}`);
//checking draft type document
} else if (
signerExist?.length > 0 &&
@@ -71,8 +67,8 @@ function DraftDocument() {
navigate(`/placeHolderSign/${data.objectId}`);
}
//Inprogress document
else if (isPlaceholder?.length > 0 && signerExist?.length > 0) {
navigate(`/pdfRequestFiles/${data.objectId}`);
else if (isPlaceholder?.length > 0 && signedUrl) {
navigate(`/recipientSignPdf/${data.objectId}`);
} //placeholder draft document
else if (
(signerExist?.length > 0 &&
@@ -86,7 +82,7 @@ function DraftDocument() {
return (
<div>
{isLoading.isLoader ? (
<Loader isLoading={isLoading} />
<LoaderWithMsg isLoading={isLoading} />
) : (
<HandleError handleError={isLoading.message} />
)}
@@ -1,8 +1,7 @@
import React, { useEffect, useState } from "react";
import { isEnableSubscription, themeColor } from "../../constant/const";
import { isEnableSubscription } from "../../constant/const";
import ModalUi from "../../primitives/ModalUi";
import { radioButtonWidget } from "../../constant/Utils";
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
import Upgrade from "../../primitives/Upgrade";
function DropdownWidgetOption(props) {
const [dropdownOptionList, setDropdownOptionList] = useState([
@@ -147,7 +146,7 @@ function DropdownWidgetOption(props) {
return (
<ModalUi isOpen={props.showDropdown} title={props.title} showClose={false}>
<div className="h-full p-[15px]">
<div className="h-full p-[15px] text-base-content">
<form
onSubmit={(e) => {
e.preventDefault();
@@ -155,38 +154,25 @@ function DropdownWidgetOption(props) {
}}
>
<div>
<label style={{ fontSize: "13px", fontWeight: "600" }}>
Name<span style={{ color: "red", fontSize: 13 }}> *</span>
<label className="text-[13px] font-semibold">
Name<span className="text-[red] text-[13px]"> *</span>
</label>
<input
required
defaultValue={dropdownName}
value={dropdownName}
onChange={(e) => setDropdownName(e.target.value)}
className="drodown-input"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
<label
style={{ fontSize: "13px", fontWeight: "600", marginTop: "5px" }}
>
<label className="text-[13px] font-semibold mt-[5px]">
Options
</label>
<div
style={{
display: "flex",
flexDirection: "column"
}}
>
<div className="flex flex-col">
{dropdownOptionList.map((option, index) => (
<div
key={index}
style={{
display: "flex",
flexDirection: "row",
marginBottom: "5px",
alignItems: "center"
}}
className="flex flex-row mb-[5px] items-center"
>
{props.type === "checkbox" && !props.isSignYourself && (
<input
@@ -206,124 +192,97 @@ function DropdownWidgetOption(props) {
setDefaultCheckbox(removeOption);
}
}}
style={{
width: "23px",
height: "19px",
marginRight: "5px"
}}
className="op-checkbox focus:outline-none hover:border-base-content mr-[5px]"
/>
)}
<input
required
className="drodown-input"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
type="text"
value={option}
onChange={(e) => handleInputChange(index, e.target.value)}
/>
<i
className="fa-solid fa-rectangle-xmark"
className="fa-light fa-rectangle-xmark text-[25px] ml-[10px] text-accent cursor-pointer"
onClick={() => handleDeleteInput(index)}
style={{
color: "red",
fontSize: "25px",
marginLeft: "10px"
}}
></i>
</div>
))}
<i
onClick={handleAddInput}
style={{
cursor: "pointer",
color: themeColor,
fontSize: "25px",
marginLeft: "10px"
}}
className="fa-solid fa-square-plus"
className="fa-light fa-square-plus text-[25px] ml-[10px] op-text-primary cursor-pointer"
></i>
<div>
{props.type === "checkbox" && !props.isSignYourself && (
<>
<label
style={{
fontSize: "13px",
fontWeight: "600",
color: !props.isSubscribe && "gray"
}}
>
Minimun check
</label>
{!props.isSubscribe && isEnableSubscription && <Upgrade />}
<input
required
defaultValue={0}
value={minCount}
onChange={(e) => {
const count = handleSetMinMax(e);
setMinCount(count);
}}
className={
props.isSubscribe || !isEnableSubscription
? "drodown-input"
: "disabled drodown-input"
}
/>
<label
style={{
fontSize: "13px",
fontWeight: "600",
color: !props.isSubscribe && "gray"
}}
>
Maximum check
</label>
<input
required
defaultValue={0}
value={maxCount}
onChange={(e) => {
const count = handleSetMinMax(e);
setMaxCount(count);
}}
className={
props.isSubscribe || !isEnableSubscription
? "drodown-input"
: "disabled drodown-input"
}
/>
</>
)}
</div>
{isEnableSubscription && (
<div>
{props.type === "checkbox" && !props.isSignYourself && (
<>
<label
className={`${
!props.isSubscribe ? "text-[gray]" : ""
} text-[13px] font-semibold`}
>
Minimun check
</label>
{!props.isSubscribe && isEnableSubscription && (
<Upgrade />
)}
<input
required
defaultValue={0}
value={minCount}
disabled={props.isSubscribe ? false : true}
onChange={(e) => {
const count = handleSetMinMax(e);
setMinCount(count);
}}
className={`${
props.isSubscribe ? "" : "pointer-events-none"
} op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs`}
/>
<label
className={`${
!props.isSubscribe ? "text-[gray]" : ""
} text-[13px] font-semibold`}
>
Maximum check
</label>
<input
required
defaultValue={0}
value={maxCount}
disabled={props.isSubscribe ? false : true}
onChange={(e) => {
const count = handleSetMinMax(e);
setMaxCount(count);
}}
className={`${
props.isSubscribe ? "" : "pointer-events-none"
} op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs`}
/>
</>
)}
</div>
)}
</div>
{["dropdown", radioButtonWidget].includes(props.type) && (
<>
<label
style={{
fontSize: "13px",
fontWeight: "600",
marginTop: "5px"
}}
>
<label className="text-[13px] font-semibold mt-[5px]">
Default value
</label>
<select
onChange={(e) => setDefaultValue(e.target.value)}
className="drodown-input"
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
name="defaultvalue"
value={defaultValue}
placeholder="select default value"
>
<option value="" disabled hidden style={{ fontSize: "13px" }}>
<option value="" disabled hidden className="text-[13px]">
Select...
</option>
{dropdownOptionList.map((data, ind) => {
return (
<option
style={{ fontSize: "13px" }}
key={ind}
value={data}
>
<option className="text-[13px]" key={ind} value={data}>
{data}
</option>
);
@@ -333,35 +292,21 @@ function DropdownWidgetOption(props) {
)}
{props.type !== "checkbox" && props.type !== radioButtonWidget && (
<>
<div
style={{
display: "flex",
flexDirection: "row",
gap: 10,
marginTop: "0.5rem"
}}
>
<div className="flex flex-row gap-[10px] mt-[0.5rem]">
{statusArr.map((data, ind) => {
return (
<div
key={ind}
style={{
display: "flex",
flexDirection: "row",
gap: 5,
alignItems: "center"
}}
className="flex flex-row gap-[5px] items-center"
>
<input
style={{ accentColor: "red" }}
className="op-radio op-radio-xs my-1"
type="radio"
name="status"
onChange={() => setStatus(data.toLowerCase())}
checked={status.toLowerCase() === data.toLowerCase()}
/>
<div style={{ fontSize: "13px", fontWeight: "500" }}>
{data}
</div>
<div className="text-[13px] font-500">{data}</div>
</div>
);
})}
@@ -369,48 +314,37 @@ function DropdownWidgetOption(props) {
</>
)}
{["checkbox", radioButtonWidget].includes(props.type) && (
<div className="flex flex-row gap-5 mt-2 items-center text-center">
<div className="flex flex-row gap-5 my-2 items-center text-center">
{!props.isSignYourself && (
<div>
<div className="flex items-center">
<input
id="isreadonly"
type="checkbox"
checked={isReadOnly}
onChange={(e) => {
setIsReadOnly(e.target.checked);
}}
className="op-checkbox op-checkbox-sm"
onChange={(e) => setIsReadOnly(e.target.checked)}
/>
<label className="ml-1" htmlFor="isreadonly">
<label className="ml-1 mb-0" htmlFor="isreadonly">
Is read only
</label>
</div>
)}
<div>
<div className="flex items-center">
<input
id="ishidelabel"
type="checkbox"
checked={isHideLabel}
onChange={(e) => {
setIsHideLabel(e.target.checked);
}}
className="op-checkbox op-checkbox-sm"
onChange={(e) => setIsHideLabel(e.target.checked)}
/>
<label className="ml-1" htmlFor="ishidelabel">
<label className="ml-1 mb-0" htmlFor="ishidelabel">
Hide labels
</label>
</div>
</div>
)}
</div>
{props.type === "checkbox" &&
!props.isSignYourself &&
!isEnableSubscription && (
<PremiumAlertHeader
message={
"Field validations are free in beta, this feature will incur a fee later."
}
/>
)}
<div
className={`${
props.type === "checkbox" && !props.isSignYourself
@@ -421,19 +355,15 @@ function DropdownWidgetOption(props) {
<button
disabled={dropdownOptionList.length === 0 && true}
style={{
background: themeColor,
color: "white"
}}
type="submit"
className={"finishBtn"}
className="op-btn op-btn-primary"
>
Save
</button>
{props.currWidgetsDetails?.options?.values?.length > 0 && (
<button
type="submit"
className="finishBtn cancelBtn"
className="op-btn op-btn-ghost ml-1"
onClick={() => {
props.handleClose && props.handleClose();
resetState();
+101 -55
View File
@@ -1,6 +1,7 @@
import React, { useState } from "react";
import "../../styles/AddUser.css";
import { getFileName } from "../../constant/Utils";
import React, { useState, useEffect } from "react";
import { checkIsSubscribed, getFileName } from "../../constant/Utils";
import Upgrade from "../../primitives/Upgrade";
import { isEnableSubscription } from "../../constant/const";
// import SelectFolder from "../../premitives/SelectFolder";
const EditTemplate = ({ template, onSuccess }) => {
@@ -9,9 +10,21 @@ const EditTemplate = ({ template, onSuccess }) => {
Name: template?.Name || "",
Note: template?.Note || "",
Description: template?.Description || "",
SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false"
SendinOrder: template?.SendinOrder ? `${template?.SendinOrder}` : "false",
AutomaticReminders: template?.AutomaticReminders || false,
RemindOnceInEvery: template?.RemindOnceInEvery || 5
});
const [isSubscribe, setIsSubscribe] = useState(false);
useEffect(() => {
fetchSubscription();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const fetchSubscription = async () => {
if (isEnableSubscription) {
const getIsSubscribe = await checkIsSubscribed();
setIsSubscribe(getIsSubscribe);
}
};
const handleStrInput = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
@@ -25,34 +38,40 @@ const EditTemplate = ({ template, onSuccess }) => {
e.preventDefault();
e.stopPropagation();
const isChecked = formData.SendinOrder === "true" ? true : false;
const data = { ...formData, SendinOrder: isChecked };
const AutoReminder = formData?.AutomaticReminders || false;
let reminderDate = {};
if (AutoReminder) {
const RemindOnceInEvery = parseInt(formData?.RemindOnceInEvery);
const ReminderDate = new Date(template?.createdAt);
ReminderDate.setDate(ReminderDate.getDate() + RemindOnceInEvery);
reminderDate = { NextReminderDate: ReminderDate };
}
const data = { ...formData, SendinOrder: isChecked, ...reminderDate };
onSuccess(data);
};
const handleAutoReminder = () => {
setFormData((prev) => ({
...prev,
AutomaticReminders: !formData.AutomaticReminders
}));
};
return (
<div className="addusercontainer">
<div className="form-wrapper">
<div className="max-h-[300px] md:max-h-[400px] overflow-y-scroll p-[10px]">
<div className="text-base-content">
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="name" style={{ fontSize: 13 }}>
<div className="mb-[0.35rem]">
<label htmlFor="name" className="text-[13px]">
File
</label>
<div
style={{
padding: "0.5rem 0.75rem",
border: "1px solid #d1d5db",
borderRadius: "0.375rem",
fontSize: "0.75rem",
fontWeight: "700"
}}
>
<div className="op-input op-input-bordered op-input-sm focus:outline-none py-2 font-semibold w-full text-xs">
{getFileName(template.URL)}
</div>
</div>
<div className="form-section">
<label htmlFor="name" style={{ fontSize: 13 }}>
<div className="mb-[0.35rem]">
<label htmlFor="name" className="text-[13px]">
Name
<span style={{ color: "red", fontSize: 13 }}> *</span>
<span className="text-[13px] text-[red]"> *</span>
</label>
<input
type="text"
@@ -60,11 +79,11 @@ const EditTemplate = ({ template, onSuccess }) => {
value={formData.Name}
onChange={(e) => handleStrInput(e)}
required
className="addUserInput"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="form-section">
<label htmlFor="Note" style={{ fontSize: 13 }}>
<div className="mb-[0.35rem]">
<label htmlFor="Note" className="text-[13px]">
Note
</label>
<input
@@ -73,11 +92,11 @@ const EditTemplate = ({ template, onSuccess }) => {
id="Note"
value={formData.Note}
onChange={(e) => handleStrInput(e)}
className="addUserInput"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="form-section">
<label htmlFor="Description" style={{ fontSize: 13 }}>
<div className="mb-[0.35rem]">
<label htmlFor="Description" className="text-[13px]">
Description
</label>
<input
@@ -86,51 +105,78 @@ const EditTemplate = ({ template, onSuccess }) => {
id="Description"
value={formData.Description}
onChange={(e) => handleStrInput(e)}
className="addUserInput"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="form-section">
<label style={{ fontSize: 13 }}>Send In Order</label>
<div
style={{
display: "flex",
alignItems: "center",
gap: 8,
marginLeft: 8,
marginBottom: 5
}}
>
<div className="mb-[0.35rem]">
<label className="text-[13px]">Send In Order</label>
<div className="flex items-center gap-[8px] ml-[8px] mb-[5px]">
<input
type="radio"
value={"true"}
className="op-radio op-radio-xs"
name="SendinOrder"
checked={formData.SendinOrder === "true"}
onChange={handleStrInput}
/>
<div style={{ fontSize: 12 }}>Yes</div>
<div className="text-[12px]">Yes</div>
</div>
<div
style={{
display: "flex",
alignItems: "center",
gap: 8,
marginLeft: 8,
marginBottom: 5
}}
>
<div className="flex items-center gap-[8px] ml-[8px] mb-[5px]">
<input
type="radio"
value={"false"}
name="SendinOrder"
className="op-radio op-radio-xs"
checked={formData.SendinOrder === "false"}
onChange={handleStrInput}
/>
<div style={{ fontSize: 12 }}>No</div>
<div className="text-[12px]">No</div>
</div>
</div>
{/* <SelectFolder onSuccess={handleFolder} folderCls={"contracts_Template"} /> */}
<div className="buttoncontainer">
<button type="submit" className="submitbutton">
{isEnableSubscription && (
<div className="text-xs mt-2">
<span
className={
isSubscribe ? "font-semibold" : "font-semibold text-gray-300"
}
>
Auto reminder{" "}
{!isSubscribe && isEnableSubscription && <Upgrade />}
</span>
<label
className={`${
isSubscribe
? "cursor-pointer "
: "pointer-events-none opacity-50"
} relative block items-center mb-0`}
>
<input
checked={formData.AutomaticReminders}
onChange={handleAutoReminder}
type="checkbox"
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white mt-2"
/>
</label>
</div>
)}
{isSubscribe && formData?.AutomaticReminders === true && (
<div className="text-xs mt-2">
<label className="block">
Remind once in every (Days)
<span className="text-red-500 text-[13px]">*</span>
</label>
<input
type="number"
value={formData.RemindOnceInEvery}
name="RemindOnceInEvery"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
onChange={handleStrInput}
required
/>
</div>
)}
<div className="mt-[1rem] flex justify-start">
<button type="submit" className="op-btn op-btn-primary">
Submit
</button>
</div>
+30 -40
View File
@@ -1,52 +1,42 @@
import React from "react";
import Tooltip from "../../primitives/Tooltip";
import ReactQuill from "react-quill";
import "react-quill/dist/quill.snow.css";
import EditorToolbar, { module1, formats } from "./EditorToolbar";
export function EmailBody(props) {
return (
<React.Fragment>
<div className={`flex justify-center py-1 p-2`}>
<div className=" flex flex-col">
<form>
<div className="text-lg font-normal text-black">
<div className=" m-2 md:m-10 p-3 md:p-10 shadow-md hover:shadow-lg border-[1px] border-indigo-800 rounded-md">
<label className="text-sm ml-2">
Subject <Tooltip message={"email subject"} />
</label>
<input
required
value={props.requestSubject}
onChange={(e) => props.setRequestSubject(e.target.value)}
placeholder='${senderName} has requested you to sign "${documentName}"'
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
/>
<label className="text-sm ml-2 mt-3">
Body <Tooltip message={"email body"} />
</label>
<div className="px-3 py-2 w-full focus:outline-none text-xs">
<EditorToolbar containerId="toolbar1" />
<ReactQuill
theme="snow"
value={props.requestBody}
// value={typedText}
placeholder="add body of email "
// readOnly={loading}
// onChangeSelection={handleTextSelection} // Listen for text selection
ref={props.editorRef}
modules={module1}
formats={formats}
onChange={props.handleOnchangeRequest}
/>
</div>
</div>
</div>
</form>
<form className="flex flex-col text-base-content text-lg font-normal">
<div className="m-2 md:m-10 p-3 md:p-10 shadow-md hover:shadow-lg border-[1px] border-indigo-800 rounded-md">
<label className="text-sm ml-2">
Subject <Tooltip message={"email subject"} />
</label>
<input
required
value={props.requestSubject}
onChange={(e) => props.setRequestSubject(e.target.value)}
placeholder='${senderName} has requested you to sign "${documentName}"'
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
<label className="text-sm ml-2 mt-3">
Body <Tooltip message={"email body"} />
</label>
<div className="px-3 py-2 w-full focus:outline-none text-xs">
<EditorToolbar containerId="toolbar1" />
<ReactQuill
theme="snow"
value={props.requestBody}
// value={typedText}
placeholder="add body of email "
// readOnly={loading}
// onChangeSelection={handleTextSelection} // Listen for text selection
ref={props.editorRef}
modules={module1}
formats={formats}
onChange={props.handleOnchangeRequest}
/>
</div>
</div>
</React.Fragment>
</form>
);
}
+153 -304
View File
@@ -1,29 +1,30 @@
import React, { useState } from "react";
import { saveAs } from "file-saver";
import celebration from "../../assets/images/newCeleb.gif";
import axios from "axios";
import { getBase64FromUrl } from "../../constant/Utils";
import { themeColor } from "../../constant/const";
import printModule from "print-js";
import loader from "../../assets/images/loader2.gif";
import { handleDownloadPdf, handleToPrint } from "../../constant/Utils";
import { themeColor, emailRegex } from "../../constant/const";
import Loader from "../../primitives/Loader";
import ModalUi from "../../primitives/ModalUi";
function EmailComponent({
isEmail,
pdfUrl,
isCeleb,
setIsEmail,
setSuccessEmail,
pdfName,
pdfDetails,
sender,
setIsAlert,
extUserId,
activeMailAdapter
}) {
const [emailList, setEmailList] = useState([]);
const [emailValue, setEmailValue] = useState();
const [emailValue, setEmailValue] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [emailErr, setEmailErr] = useState(false);
const [isDownloading, setIsDownloading] = useState("");
const isAndroid = /Android/i.test(navigator.userAgent);
//function for send email
const sendEmail = async () => {
const pdfName = pdfDetails[0]?.Name;
setIsLoading(true);
let sendMail;
@@ -112,320 +113,168 @@ function EmailComponent({
//function for get email value
const handleEmailValue = (e) => {
const value = e.target.value;
setEmailErr(false);
setEmailValue(value);
};
//function for save email in array after press enter
const handleEnterPress = (e) => {
const pattern = emailRegex;
const validate = emailValue?.match(pattern);
if (e.key === "Enter" && emailValue) {
setEmailList((prev) => [...prev, emailValue]);
setEmailValue("");
if (validate) {
const emailLowerCase = emailValue?.toLowerCase();
setEmailList((prev) => [...prev, emailLowerCase]);
setEmailValue("");
} else {
setEmailErr(true);
}
} else if (e === "add" && emailValue) {
setEmailList((prev) => [...prev, emailValue]);
setEmailValue("");
if (validate) {
const emailLowerCase = emailValue?.toLowerCase();
setEmailList((prev) => [...prev, emailLowerCase]);
setEmailValue("");
} else {
setEmailErr(true);
}
}
};
// function for print signed pdf
const handleToPrint = async (event) => {
event.preventDefault();
const pdf = await getBase64FromUrl(pdfUrl);
const isAndroidDevice = navigator.userAgent.match(/Android/i);
const isAppleDevice =
(/iPad|iPhone|iPod/.test(navigator.platform) ||
(navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1)) &&
!window.MSStream;
if (isAndroidDevice || isAppleDevice) {
const byteArray = Uint8Array.from(
atob(pdf)
.split("")
.map((char) => char.charCodeAt(0))
);
const blob = new Blob([byteArray], { type: "application/pdf" });
const blobUrl = URL.createObjectURL(blob);
window.open(blobUrl, "_blank");
} else {
printModule({ printable: pdf, type: "pdf", base64: true });
}
};
//handle download signed pdf
const handleDownloadPdf = () => {
saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
};
const sanitizeFileName = (pdfName) => {
// Replace spaces with underscore
return pdfName.replace(/ /g, "_");
};
const isAndroid = /Android/i.test(navigator.userAgent);
return (
<div>
{/* isEmail */}
{isEmail && (
<div className="modaloverlay">
<div className="modalcontainer">
{isLoading && (
<div
style={{
position: "absolute",
height: "100%",
width: "100%",
display: "flex",
justifyContent: "center",
flexDirection: "column",
alignItems: "center",
zIndex: "20",
backgroundColor: "#e6f2f2",
opacity: 0.8
}}
>
<img
alt="no img"
src={loader}
style={{ width: "70px", height: "70px" }}
/>
<span style={{ fontSize: "12px", fontWeight: "bold" }}>
This might take some time
</span>
</div>
)}
<div style={{ background: "#32a3ac" }} className="modalheader">
<span style={{ color: "white" }}>Successfully signed!</span>
<div style={{ display: "flex", flexDirection: "row" }}>
<div></div>
{!isAndroid && (
<button
onClick={handleToPrint}
style={{
display: "flex",
flexDirection: "row",
alignItems: "center"
}}
className="btn btn-primary btn-sm"
>
<i
className="fa fa-print"
style={{
fontSize: "15px",
marginRight: "3px",
color: "white"
}}
aria-hidden="true"
></i>
Print
</button>
)}
<button
className="btn btn-danger btn-sm"
onClick={() => handleDownloadPdf()}
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
marginLeft: "10px"
}}
>
<i
className="fa fa-download"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px"
}}
aria-hidden="true"
></i>
Download
</button>
</div>
</div>
<div style={{ height: "100%", padding: 20 }}>
{isCeleb && (
<div
style={{
position: "absolute",
marginLeft: "50px"
}}
>
<img
alt="print img"
width={300}
height={250}
// style={styles.gifCeleb}
src={celebration}
/>
</div>
)}
<p
style={{
fontFamily: "system-ui",
verticalAlign: "baseline",
fontWeight: "500",
color: "#403f3e",
fontSize: "15px",
marginBottom: "5px"
}}
>
Recipients added here will get a copy of the signed document.
</p>
{emailList.length > 0 ? (
<>
<div className="addEmail">
<div
style={{
display: "flex",
flexDirection: "row",
flexWrap: "wrap"
}}
>
{emailList.map((data, ind) => {
return (
<div
className="emailChip"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center"
}}
key={ind}
>
<span
style={{
color: "white",
fontSize: "13px"
}}
>
{data}
</span>
<span
style={{
color: "white",
fontSize: 13,
fontWeight: 600,
marginLeft: 7,
cursor: "pointer"
}}
onClick={() => removeChip(ind)}
>
<i className="fa-solid fa-xmark"></i>
</span>
</div>
);
})}
</div>
{emailList.length <= 9 && (
<input
type="text"
value={emailValue}
className="addEmailInput"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
onBlur={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
required
/>
)}
</div>
</>
) : (
<div>
<input
type="text"
value={emailValue}
className="emailInput"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
placeholder="Add the email addresses"
onBlur={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
required
/>
</div>
)}
<span
style={{
cursor: emailValue && "pointer"
}}
onClick={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
>
<i
style={{
backgroundColor: themeColor,
padding: "5px 7px",
marginTop: "10px",
color: "white",
borderRadius: "2px"
}}
className="fa fa-plus"
aria-hidden="true"
></i>
<ModalUi isOpen showHeader={false}>
{isLoading && (
<div className="absolute w-full h-full flex flex-col justify-center items-center z-[20] bg-[#e6f2f2]/70">
<Loader />
<span className="text-[12px] text-base-content">
This might take some time
</span>
<div
style={{
background: "#e3e2e1",
marginTop: "10px",
padding: "5px",
borderRadius: "3px"
}}
>
<span style={{ fontWeight: "700" }}>Note:</span>
<span style={{ fontSize: "15px" }}>
{" "}
You can only send to ten recipients at a time.
</span>
</div>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginTop: "15px",
marginBottom: "15px"
}}
></div>
</div>
)}
{isDownloading === "pdf" && (
<div className="fixed z-[200] inset-0 flex justify-center items-center bg-black bg-opacity-30">
<Loader />
</div>
)}
<div className="flex justify-between items-center py-[10px] px-[20px] border-b-[1px] border-base-content">
<span className="text-base-content font-semibold">
Successfully signed!
</span>
<div className="flex flex-row">
{!isAndroid && (
<button
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
className="op-btn op-btn-neutral op-btn-sm text-[15px]"
>
<i className="fa-light fa-print" aria-hidden="true"></i>
Print
</button>
)}
<button
disabled={emailList.length === 0 && true}
style={{
background: themeColor,
color: "white"
}}
type="button"
className={emailList.length === 0 ? "defaultBtn" : "finishBtn"}
onClick={() => sendEmail()}
className="op-btn op-btn-primary op-btn-sm text-[15px] ml-2"
onClick={() =>
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
}
>
Send
</button>
<button
type="button"
className="finishBtn cancelBtn"
onClick={() => {
setIsEmail(false);
setEmailValue("");
setEmailList([]);
}}
>
Close
<i className="fa-light fa-download" aria-hidden="true"></i>
Download
</button>
</div>
</div>
</div>
<div className="h-full p-[20px]">
<p className="font-medium text-[15px] mb-[5px] text-base-content align-baseline">
Recipients added here will get a copy of the signed document.
</p>
{emailList.length > 0 ? (
<div className="p-0 border-[1.5px] op-border-primary rounded w-full text-[15px]">
<div className="flex flex-row flex-wrap">
{emailList.map((data, ind) => {
return (
<div
className="flex flex-row items-center op-bg-primary m-[4px] rounded-md py-[5px] px-[10px]"
key={ind}
>
<span className="text-base-100 text-[13px]">
{data}
</span>
<span
className="text-base-100 text-[13px] font-semibold ml-[7px] cursor-pointer"
onClick={() => removeChip(ind)}
>
<i className="fa-light fa-xmark"></i>
</span>
</div>
);
})}
</div>
{emailList.length <= 9 && (
<input
type="email"
value={emailValue}
className="p-[10px] pb-[20px] rounded w-full text-[15px] bg-transparent outline-none"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
onBlur={() => emailValue && handleEnterPress("add")}
required
/>
)}
</div>
) : (
<div>
<input
type="email"
value={emailValue}
className="p-[10px] pb-[20px] rounded w-full text-[15px] outline-none bg-transparent border-[1.5px] op-border-primary"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
placeholder="Add an email address and hit enter"
onBlur={() => emailValue && handleEnterPress("add")}
required
/>
</div>
)}
{emailErr && (
<p className="text-xs text-[red] ml-1.5 mt-0.5">
please provide correct email address
</p>
)}
<button
className={`${
emailValue ? "cursor-pointer" : "cursor-default"
} op-btn op-btn-primary op-btn-sm m-2 shadow-md`}
onClick={() => emailValue && handleEnterPress("add")}
>
<i className="fa-light fa-plus" aria-hidden="true"></i>
</button>
<div className="bg-[#e3e2e1] mt-[10px] p-[5px] rounded">
<span className="font-bold">Note: </span>
<span className="text-[15px]">
You can only send to ten recipients at a time.
</span>
</div>
<hr className="w-full my-[15px] bg-base-content" />
<button
type="button"
className="op-btn op-btn-secondary"
onClick={() => emailList.length > 0 && sendEmail()}
>
Send
</button>
<button
type="button"
className="op-btn op-btn-ghost ml-2"
onClick={() => {
setIsEmail(false);
setEmailValue("");
setEmailList([]);
}}
>
Close
</button>
</div>
</ModalUi>
)}
</div>
);
+189 -329
View File
@@ -1,15 +1,14 @@
import React, { useState } from "react";
import PrevNext from "./PrevNext";
import printModule from "print-js";
import { getBase64FromUrl } from "../../constant/Utils";
import { saveAs } from "file-saver";
import {
handleDownloadCertificate,
handleDownloadPdf,
handleToPrint
} from "../../constant/Utils";
import "../../styles/signature.css";
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
import { useNavigate } from "react-router-dom";
import { themeColor } from "../../constant/const";
import axios from "axios";
import ModalUi from "../../primitives/ModalUi";
import { appInfo } from "../../constant/appinfo";
import Loader from "../../primitives/Loader";
function Header({
isPdfRequestFiles,
@@ -29,155 +28,27 @@ function Header({
isShowHeader,
decline,
currentSigner,
dataTut4,
alreadySign,
isSignYourself,
setIsEmail,
completeBtnTitle,
setIsEditTemplate
setIsEditTemplate,
isPublicTemplate
}) {
const filterPrefill =
signerPos && signerPos?.filter((data) => data.Role !== "prefill");
const isMobile = window.innerWidth < 767;
const navigate = useNavigate();
const [isCertificate, setIsCertificate] = useState(false);
const [isDownloading, setIsDownloading] = useState("");
const isGuestSigner = localStorage.getItem("isGuestSigner");
//for go to previous page
function previousPage() {
changePage(-1);
}
//for go to next page
function nextPage() {
changePage(1);
}
//function for show decline alert
const handleDeclinePdfAlert = async () => {
const currentDecline = {
currnt: "Sure",
isDeclined: true
};
const currentDecline = { currnt: "Sure", isDeclined: true };
setIsDecline(currentDecline);
};
//function for print digital sign pdf
const handleToPrint = async (event) => {
event.preventDefault();
try {
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
const axiosRes = await axios.post(
`${appInfo.baseUrl}/functions/getsignedurl`,
{ url: pdfUrl },
{
headers: {
"content-type": "Application/json",
"X-Parse-Application-Id": appInfo.appId,
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
);
const url = axiosRes.data.result;
const pdf = await getBase64FromUrl(url);
const isAndroidDevice = navigator.userAgent.match(/Android/i);
const isAppleDevice =
(/iPad|iPhone|iPod/.test(navigator.platform) ||
(navigator.platform === "MacIntel" &&
navigator.maxTouchPoints > 1)) &&
!window.MSStream;
if (isAndroidDevice || isAppleDevice) {
const byteArray = Uint8Array.from(
atob(pdf)
.split("")
.map((char) => char.charCodeAt(0))
);
const blob = new Blob([byteArray], { type: "application/pdf" });
const blobUrl = URL.createObjectURL(blob);
window.open(blobUrl, "_blank");
} else {
printModule({ printable: pdf, type: "pdf", base64: true });
}
} catch (err) {
console.log("err in getsignedurl", err);
alert("something went wrong, please try again later.");
}
};
//handle download signed pdf
const handleDownloadPdf = async () => {
const pdfName = pdfDetails[0] && pdfDetails[0].Name;
try {
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
const axiosRes = await axios.post(
`${appInfo.baseUrl}/functions/getsignedurl`,
{ url: pdfUrl },
{
headers: {
"content-type": "Application/json",
"X-Parse-Application-Id": appInfo.appId,
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
);
const url = axiosRes.data.result;
saveAs(url, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
} catch (err) {
console.log("err in getsignedurl", err);
alert("something went wrong, please try again later.");
}
};
const sanitizeFileName = (pdfName) => {
// Replace spaces with underscore
return pdfName.replace(/ /g, "_");
};
//handle download signed pdf
const handleDownloadCertificate = async () => {
if (pdfDetails?.length > 0 && pdfDetails[0]?.CertificateUrl) {
try {
await fetch(pdfDetails[0] && pdfDetails[0]?.CertificateUrl);
const certificateUrl = pdfDetails[0] && pdfDetails[0]?.CertificateUrl;
saveAs(certificateUrl, `Certificate_signed_by_OpenSign™.pdf`);
} catch (err) {
console.log("err in download in certificate", err);
}
} else {
setIsCertificate(true);
try {
const data = {
docId: pdfDetails[0]?.objectId
};
const docDetails = await axios.post(
`${localStorage.getItem("baseUrl")}functions/getDocument`,
data,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessionToken: localStorage.getItem("accesstoken")
}
}
);
if (docDetails.data && docDetails.data.result) {
const doc = docDetails.data.result;
if (doc?.CertificateUrl) {
await fetch(doc?.CertificateUrl);
const certificateUrl = doc?.CertificateUrl;
saveAs(certificateUrl, `Certificate_signed_by_OpenSign™.pdf`);
setIsCertificate(false);
} else {
setIsCertificate(true);
}
}
} catch (err) {
console.log("err in download in certificate", err);
alert("something went wrong, please try again later.");
}
}
};
return (
<div style={{ padding: "5px 0px 5px 0px" }} className="mobileHead">
<div className="flex py-[5px]">
{isMobile && isShowHeader ? (
<div
id="navbar"
@@ -188,57 +59,26 @@ function Header({
: window.innerWidth - 30 + "px"
}}
>
<div className="preBtn2">
<div onClick={() => navigate(-1)}>
<div className="flex justify-between items-center py-[5px] px-[10px] ">
<div onClick={() => window.history.go(-2)}>
<i
className="fa fa-arrow-left"
className="fa-light fa-arrow-left text-base-content"
aria-hidden="true"
style={{ color: themeColor, cursor: "pointer" }}
></i>
</div>
<div>
<i
onClick={() => {
if (pageNumber > 1) {
previousPage();
}
}}
className="fa fa-backward"
style={{ color: "gray", cursor: "pointer" }}
></i>
<span
style={{
fontSize: "13px",
fontWeight: "600",
marginLeft: "10px",
marginRight: "10px"
}}
>
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
</span>
<i
onClick={() => {
if (pageNumber < allPages) {
nextPage();
}
}}
className="fa fa-forward"
style={{ color: "gray", cursor: "pointer" }}
></i>
</div>
<PrevNext
pageNumber={pageNumber}
allPages={allPages}
changePage={changePage}
/>
{pdfUrl && alreadySign ? (
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild>
<div
style={{
color: themeColor,
border: "none",
fontWeight: "650",
fontSize: "16px",
padding: "0px 3px 0px 5px"
}}
>
<i className="fa fa-ellipsis-v" aria-hidden="true"></i>
<div className="op-link op-link-primary no-underline text-[16px] font-semibold pr-[3px] pl-[5px]">
<i
className="fa-light fa-ellipsis-v"
aria-hidden="true"
></i>
</div>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
@@ -248,18 +88,14 @@ function Header({
>
<DropdownMenu.Item
className="DropdownMenuItem"
onClick={() => handleDownloadPdf()}
onClick={() =>
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
}
>
<div
style={{
display: "flex",
flexDirection: "row"
}}
>
<div className="flex flex-row">
<i
className="fa fa-arrow-down"
className="fa-light fa-arrow-down mr-[3px]"
aria-hidden="true"
style={{ marginRight: "2px" }}
></i>
Download
</div>
@@ -267,17 +103,16 @@ function Header({
{isCompleted && (
<DropdownMenu.Item
className="DropdownMenuItem"
onClick={() => handleDownloadCertificate()}
onClick={() =>
handleDownloadCertificate(
pdfDetails,
setIsDownloading
)
}
>
<div
style={{
border: "none",
backgroundColor: "#fff"
}}
>
<div className="border-none bg-[#fff]">
<i
className="fa-solid fa-award"
style={{ marginRight: "2px" }}
className="fa-light fa-award mr-[3px]"
aria-hidden="true"
></i>
Certificate
@@ -289,15 +124,9 @@ function Header({
className="DropdownMenuItem"
onClick={() => setIsEmail(true)}
>
<div
style={{
display: "flex",
flexDirection: "row"
}}
>
<div className="flex flex-row">
<i
className="fa fa-envelope"
style={{ marginRight: "2px" }}
className="fa-light fa-envelope mr-[3px]"
aria-hidden="true"
></i>
Mail
@@ -306,18 +135,14 @@ function Header({
)}
<DropdownMenu.Item
className="DropdownMenuItem"
onClick={handleToPrint}
onClick={(e) =>
handleToPrint(e, pdfUrl, setIsDownloading)
}
>
<div
style={{
display: "flex",
flexDirection: "row"
}}
>
<div className="flex flex-row">
<i
className="fa fa-print"
className="fa-light fa-print mr-[3px]"
aria-hidden="true"
style={{ marginRight: "2px" }}
></i>
Print
</div>
@@ -326,24 +151,16 @@ function Header({
</DropdownMenu.Portal>
</DropdownMenu.Root>
) : (
<div style={{ display: "flex", justifyContent: "space-around" }}>
<div className="flex justify-around items-center">
{/* current signer is checking user send request and check status of pdf sign than if current
user exist than show finish button else no
*/}
{currentSigner && (
<>
<div className="flex items-center" data-tut="reactourFifth">
{decline && (
<div
onClick={() => {
handleDeclinePdfAlert();
}}
style={{
color: "red",
border: "none",
fontWeight: "650",
fontSize: "16px",
marginRight: "10px"
}}
onClick={() => handleDeclinePdfAlert()}
className="text-[red] border-none font-[650] text-[14px] mr-2"
>
Decline
</div>
@@ -355,13 +172,10 @@ function Header({
alertSendEmail();
}
}}
style={{
color: isMailSend ? "gray" : themeColor,
border: "none",
fontWeight: "650",
fontSize: "16px"
}}
data-tut={dataTut4}
className={`${
isMailSend ? "" : "op-link-primary"
} op-link no-underline font-[650] text-[14px]`}
data-tut="headerArea"
>
{completeBtnTitle ? completeBtnTitle : "Send"}
</div>
@@ -375,24 +189,52 @@ function Header({
embedWidgetsData();
}
}}
style={{
color: themeColor,
border: "none",
fontWeight: "650",
fontSize: "16px"
}}
className="border-none font-[650] text-[14px] op-link op-link-primary no-underline"
>
Finish
</div>
)}
</>
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild>
<div className="font-[650] text-[18px] px-2 ml-[4px] text-base-content no-underline">
<i
className="fa-light fa-ellipsis-v"
aria-hidden="true"
></i>
</div>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content
className="bg-white shadow-md rounded-full px-3 py-2"
sideOffset={5}
>
<DropdownMenu.Item
className="flex flex-row justify-center items-center text-[13px] focus:outline-none cursor-pointer"
onClick={() =>
handleDownloadPdf(
pdfDetails,
pdfUrl,
setIsDownloading
)
}
>
<i
className="fa-light fa-arrow-down mr-[3px]"
aria-hidden="true"
></i>
<span className="font-[500]">Download</span>
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
</div>
)}
</div>
)}
</div>
</div>
) : (
<div className="flex flex-wrap justify-between items-center mt-[5px]">
<div className="flex flex-wrap justify-between items-center w-full gap-y-1 ml-1">
<PrevNext
pageNumber={pageNumber}
allPages={allPages}
@@ -406,12 +248,12 @@ function Header({
signersdata.length !== filterPrefill.length && (
<div>
{filterPrefill.length === 0 ? (
<span style={{ fontSize: "13px", color: "#f5405e" }}>
<span className="text-[13px] text-[#f5405e]">
Add {signersdata.length - filterPrefill.length}{" "}
recipients signature
</span>
) : (
<span style={{ fontSize: "13px", color: "#f5405e" }}>
<span className="text-[13px] text-[#f5405e]">
Add {signersdata.length - filterPrefill.length} more
recipients signature
</span>
@@ -423,166 +265,176 @@ function Header({
{setIsEditTemplate && (
<button
onClick={() => setIsEditTemplate(true)}
className="outline-none border-none text-center mr-[5px]"
className="outline-none border-none text-center mr-[3px]"
>
<i className="fa-solid fa-gear fa-lg"></i>
<i className="fa-light fa-gear fa-lg"></i>
</button>
)}
<button
onClick={() => navigate(-1)}
onClick={() => window.history.go(-2)}
type="button"
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-black font-[500] text-sm mr-[5px] bg-white"
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
>
Back
</button>
<button
disabled={isMailSend && true}
data-tut="reactourFour"
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] font-[500] text-sm mr-[5px]"
style={{
background: isMailSend ? "rgb(203, 203, 203)" : "#188ae2",
color: isMailSend ? "rgb(77, 75, 75)" : "white"
}}
onClick={() => {
alertSendEmail();
}}
data-tut="headerArea"
className="op-btn op-btn-primary op-btn-sm mr-[3px]"
onClick={() => alertSendEmail()}
>
{completeBtnTitle
? completeBtnTitle
: isMailSend
? "Sent"
: "Send"}
? "Sent"
: "Send"}
</button>
</div>
</>
) : isPdfRequestFiles ? (
alreadySign ? (
<div style={{ display: "flex", flexDirection: "row" }}>
<div className="flex flex-row">
<button
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
type="button"
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
>
<i
className="fa-light fa-print py-[3px]"
aria-hidden="true"
></i>
<span className="hidden lg:block">Print</span>
</button>
{isCompleted && (
<button
type="button"
onClick={() => handleDownloadCertificate()}
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#08bc66]"
onClick={() =>
handleDownloadCertificate(pdfDetails, setIsDownloading)
}
className="op-btn op-btn-secondary op-btn-sm mr-[3px] shadow"
>
<i
className="fa-solid fa-award py-[3px]"
className="fa-light fa-award py-[3px]"
aria-hidden="true"
></i>
<span className="hidden lg:block ml-1">Certificate</span>
<span className="hidden lg:block">Certificate</span>
</button>
)}
<button
onClick={handleToPrint}
type="button"
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#188ae2]"
>
<i className="fa fa-print py-[3px]" aria-hidden="true"></i>
<span className="hidden lg:block ml-1">Print</span>
</button>
<button
type="button"
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#f14343]"
onClick={() => handleDownloadPdf()}
className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow"
onClick={() =>
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
}
>
<i className="fa fa-download py-[3px]" aria-hidden="true"></i>
<span className="hidden lg:block ml-1">Download</span>
<i
className="fa-light fa-download py-[3px]"
aria-hidden="true"
></i>
<span className="hidden lg:block">Download</span>
</button>
</div>
) : (
<div className="flex">
<div className="flex" data-tut="reactourFifth">
<button
onClick={() => navigate(-1)}
onClick={() => window.history.go(-2)}
type="button"
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-black font-[500] text-sm mr-[5px] bg-white"
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
>
Back
</button>
{currentSigner && (
<>
<button
style={{ background: "#de4337" }}
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-white font-[500] text-[13px] mr-[5px] bg-[#f14343]"
onClick={() => {
handleDeclinePdfAlert();
}}
className="op-btn op-btn-secondary op-btn-sm mr-[3px] shadow"
onClick={() => handleDeclinePdfAlert()}
>
Decline
</button>
<button
style={{
background: "#188ae2"
}}
type="button"
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-white font-[500] text-[13px] mr-[5px] bg-[#188ae2]"
onClick={() => {
embedWidgetsData();
}}
className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow"
onClick={() => embedWidgetsData()}
>
Finish
</button>
<button
type="button"
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
onClick={() =>
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
}
>
<i className="fa-light fa-arrow-down font-semibold lg:hidden"></i>
<span className="hidden lg:block">Download</span>
</button>
</>
)}
</div>
)
) : isCompleted ? (
<div style={{ display: "flex", flexDirection: "row" }}>
<div className="flex flex-row">
{isCompleted && (
<button
type="button"
onClick={() => handleDownloadCertificate()}
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#08bc66]"
onClick={() =>
handleDownloadCertificate(pdfDetails, setIsDownloading)
}
className="op-btn op-btn-secondary op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
>
<i
className="fa-solid fa-award py-[3px]"
aria-hidden="true"
></i>
<i className="fa-light fa-award" aria-hidden="true"></i>
<span className="hidden lg:block ml-1">Certificate</span>
</button>
)}
<button
onClick={handleToPrint}
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
type="button"
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#188ae2]"
className="op-btn op-btn-neutral op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
>
<i className="fa fa-print py-[3px]" aria-hidden="true"></i>
<i className="fa-light fa-print" aria-hidden="true"></i>
<span className="hidden lg:block ml-1">Print</span>
</button>
<button
type="button"
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#f14343]"
onClick={() => handleDownloadPdf()}
className="op-btn op-btn-primary op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
onClick={() =>
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
}
>
<i className="fa fa-download py-[3px]" aria-hidden="true"></i>
<i className="fa-light fa-download" aria-hidden="true"></i>
<span className="hidden lg:block ml-1">Download</span>
</button>
<button
type="button"
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[11px] text-white font-[500] text-[13px] mr-[5px] bg-[#3ba7e5]"
className="op-btn op-btn-info op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
onClick={() => setIsEmail(true)}
>
<i className="fa fa-envelope py-[3px]" aria-hidden="true"></i>
<i className="fa-light fa-envelope" aria-hidden="true"></i>
<span className="hidden lg:block ml-1">Mail</span>
</button>
</div>
) : isPublicTemplate ? (
<div className="flex">
<button
type="button"
className="op-btn op-btn-primary op-btn-sm shadow"
onClick={() => embedWidgetsData()}
>
Sign Now
</button>
</div>
) : (
<div className="flex">
<button
onClick={() => {
navigate(-1);
}}
onClick={() => window.history.go(-2)}
type="button"
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-black font-[500] text-sm mr-[5px] bg-white"
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
>
Back
</button>
<button
style={{
background: "#188ae2"
}}
type="button"
className="flex flex-row items-center shadow rounded-[3px] py-[3px] px-[18px] text-white font-[500] text-[13px] mr-[5px] bg-[#188ae2]"
className="op-btn op-btn-primary op-btn-sm mr-[3px]"
onClick={() => {
if (!pdfUrl) {
embedWidgetsData();
@@ -595,18 +447,26 @@ function Header({
)}
</div>
)}
{isDownloading === "pdf" && (
<div className="fixed z-[200] inset-0 flex justify-center items-center bg-black bg-opacity-30">
<Loader />
</div>
)}
<ModalUi
isOpen={isCertificate}
title={"Generating certificate"}
handleClose={() => setIsCertificate(false)}
isOpen={isDownloading === "certificate"}
title={
isDownloading === "certificate"
? "Generating certificate"
: "PDF Download"
}
handleClose={() => setIsDownloading("")}
>
<div className="p-3 md:p-5 text-[13px] md:text-base text-center">
<div className="p-3 md:p-5 text-[13px] md:text-base text-center text-base-content">
{isDownloading === "certificate"}{" "}
<p>
Your completion certificate is being generated. Please wait
momentarily.
</p>
<p>
If the download doesn&apos;t start shortly, click the button again.
momentarily. If the download doesn&apos;t start shortly, click the
button again.
</p>
</div>
</ModalUi>
@@ -0,0 +1,53 @@
import React from "react";
function PdfZoom(props) {
const onClickZoomIn = () => {
props.setScale(props.scale + 0.1 * props.scale);
props.setZoomPercent(props.zoomPercent + 10);
};
const onClickZoomOut = () => {
if (props.zoomPercent > 0) {
if (props.zoomPercent === 10) {
props.setScale(1);
} else {
props.setScale(props.scale - 0.1 * props.scale);
}
props.setZoomPercent(props.zoomPercent - 10);
}
};
const handleReset = () => {
props.setScale(1);
props.setZoomPercent(0);
};
return (
// md:mt-[41px] xl:mt-[63px]mt=[]
<span className="hidden md:flex flex-col gap-1 text-center md:w-[5%] mt-[50px] 2xl:mt-[63px]">
<span
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
onClick={onClickZoomIn}
title="Zoom in"
>
<i className="fa-light fa-magnifying-glass-plus text-gray-500 2xl:text-[30px]"></i>
</span>
<span
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
onClick={handleReset}
title="Reset"
>
<i className="fa-light fa-magnifying-glass-arrows-rotate text-gray-500 2xl:text-[30px]"></i>
</span>
<span
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px]"
onClick={onClickZoomOut}
style={{
cursor: props.zoomPercent > 0 ? "pointer" : "default"
}}
title="Zoom out"
>
<i className="fa-light fa-magnifying-glass-minus text-gray-500 2xl:text-[30px]"></i>
</span>
</span>
);
}
export default PdfZoom;
+244 -70
View File
@@ -4,8 +4,9 @@ import PlaceholderBorder from "./PlaceholderBorder";
import { Rnd } from "react-rnd";
import {
defaultWidthHeight,
getContainerScale,
handleCopyNextToWidget,
isMobile,
isTabAndMobile,
onChangeInput,
radioButtonWidget,
textInputWidget,
@@ -88,8 +89,10 @@ const getDefaultdate = (selectedDate, format = "dd-MM-yyyy") => {
const getDefaultFormat = (dateFormat) => dateFormat || "MM/dd/yyyy";
function Placeholder(props) {
const [placeholderBorder, setPlaceholderBorder] = useState({ w: 0, h: 0 });
const [isDraggingEnabled, setDraggingEnabled] = useState(true);
const [isShowDateFormat, setIsShowDateFormat] = useState(false);
const [containerScale, setContainerScale] = useState();
const [selectDate, setSelectDate] = useState({
date:
props.pos.type === "date"
@@ -119,6 +122,14 @@ function Placeholder(props) {
width: null,
height: null
});
useEffect(() => {
const getPdfPageWidth = props.pdfOriginalWH.find(
(data) => data.pageNumber === props.pageNumber
);
setContainerScale(props.containerWH.width / getPdfPageWidth.width);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.containerWH.width, props.pdfOriginalWH]);
const dateFormatArr = [
"L",
"DD-MM-YYYY",
@@ -224,25 +235,29 @@ function Placeholder(props) {
setDraggingEnabled(false);
}
if ((props.isNeedSign || props.isSignYourself) && !props.isDragging) {
if (props.pos.type) {
if (
props.pos.type === "signature" ||
props.pos.type === "stamp" ||
props.pos.type === "image"
) {
props.setIsSignPad(true);
props.setSignKey(props.pos.key);
props.setIsStamp(props.pos.isStamp);
} else if (props.pos.type === "initials") {
props.setIsSignPad(true);
props.setSignKey(props.pos.key);
props.setIsStamp(props.pos.isStamp);
props.setIsInitial(true);
}
if (props?.ispublicTemplate) {
props.handleUserDetails();
} else {
props.setIsSignPad(true);
props.setSignKey(props.pos.key);
props.setIsStamp(props.pos?.isStamp ? props.pos.isStamp : false);
if (props.pos.type) {
if (
props.pos.type === "signature" ||
props.pos.type === "stamp" ||
props.pos.type === "image"
) {
props.setIsSignPad(true);
props.setSignKey(props.pos.key);
props.setIsStamp(props.pos.isStamp);
} else if (props.pos.type === "initials") {
props.setIsSignPad(true);
props.setSignKey(props.pos.key);
props.setIsStamp(props.pos.isStamp);
props.setIsInitial(true);
}
} else {
props.setIsSignPad(true);
props.setSignKey(props.pos.key);
props.setIsStamp(props.pos?.isStamp ? props.pos.isStamp : false);
}
}
} else if (
props.isPlaceholder &&
@@ -252,6 +267,10 @@ function Placeholder(props) {
if (props.pos.key === props.selectWidgetId) {
props.handleLinkUser(props.data.Id);
props.setUniqueId(props.data.Id);
const checkIndex = props.xyPostion.findIndex(
(data) => data.Id === props.data.Id
);
props.setIsSelectId(checkIndex || 0);
}
} else if (!props.pos.type) {
if (
@@ -281,6 +300,12 @@ function Placeholder(props) {
}
if (props.isNeedSign && props.data?.signerObjId === props.signerObjId) {
handleWidgetIdandPopup();
} else if (
props?.isNeedSign &&
props?.uniqueId &&
props.data?.Id === props?.uniqueId
) {
handleWidgetIdandPopup();
} else if (props.isPlaceholder || props.isSignYourself) {
handleWidgetIdandPopup();
}
@@ -293,12 +318,43 @@ function Placeholder(props) {
props?.setShowDropdown(true);
} else if (props.pos.type === "checkbox") {
props?.setIsCheckbox(true);
}
//condition to handle setting icon for signyour-self flow for all type text widgets
else if (
[
textInputWidget,
textWidget,
"name",
"company",
"job title",
"email"
].includes(props.pos.type) &&
props.isSignYourself
) {
props.handleTextSettingModal(true);
} else {
props?.handleNameModal(true);
props?.handleNameModal && props?.handleNameModal(true);
}
if (props.isPlaceholder && props.type !== textWidget) {
props.setUniqueId(props.data.Id);
//condition for only placeholder and template flow
if (props.data && props?.pos?.type !== textWidget) {
props.setSignerObjId(props?.data?.signerObjId);
props.setUniqueId(props?.data?.Id);
const checkIndex = props.xyPostion.findIndex(
(data) => data.Id === props.data.Id
);
props.setIsSelectId(checkIndex || 0);
}
//condition to handle in placeholder and template flow for text widget signerId for text widgets i have to set uniqueId in tempSignerId because
//it does not have any signer user and any signerobjId
else if (props.data && props.pos.type === textWidget) {
props.setTempSignerId(props.uniqueId);
props.setUniqueId(props?.data?.Id);
const checkIndex = props.xyPostion.findIndex(
(data) => data.Id === props.data.Id
);
props.setIsSelectId(checkIndex || 0);
}
props.setSignKey(props.pos.key);
props.setWidgetType(props.pos.type);
@@ -315,10 +371,19 @@ function Placeholder(props) {
if (props.data && props?.pos?.type !== textWidget) {
props.setSignerObjId(props?.data?.signerObjId);
props.setUniqueId(props?.data?.Id);
const checkIndex = props.xyPostion.findIndex(
(data) => data.Id === props.data.Id
);
props.setIsSelectId(checkIndex || 0);
} else if (props.data && props.pos.type === textWidget) {
props.setTempSignerId(props.uniqueId);
props.setSignerObjId(props?.data?.signerObjId);
props.setUniqueId(props?.data?.Id);
const checkIndex = props.xyPostion.findIndex(
(data) => data.Id === props.data.Id
);
props.setIsSelectId(checkIndex || 0);
}
//checking widget's type and open widget copy modal for required widgets
@@ -375,7 +440,18 @@ function Placeholder(props) {
<>
{(props.isPlaceholder || props.isSignYourself) && (
<>
{props.pos.type === "checkbox" && props.isSignYourself ? (
{/* condition to add setting icon for signyour-self flow for particular text widgets
and also it have diffrent position
*/}
{[
"checkbox",
textInputWidget,
textWidget,
"name",
"company",
"job title",
"email"
].includes(props.pos.type) && props.isSignYourself ? (
<i
onClick={(e) => {
e.stopPropagation();
@@ -385,7 +461,7 @@ function Placeholder(props) {
e.stopPropagation();
handleOnClickSettingIcon();
}}
className="fa-solid fa-gear settingIcon"
className="fa-light fa-gear icon"
style={{
color: "#188ae2",
right: "29px",
@@ -393,11 +469,10 @@ function Placeholder(props) {
}}
></i>
) : (
/* condition to add setting icon for placeholder & template flow for all widgets except signature and date */
((!props?.pos?.type && props.pos.isStamp) ||
(props?.pos?.type &&
!["date", textWidget, "signature"].includes(
props.pos.type
) &&
!["date", "signature"].includes(props.pos.type) &&
!props.isSignYourself)) && (
<i
onClick={(e) => {
@@ -408,31 +483,44 @@ function Placeholder(props) {
e.stopPropagation();
handleOnClickSettingIcon();
}}
className="fa-solid fa-gear settingIcon"
style={{ color: "#188ae2", right: "47px", top: "-19px" }}
className="fa-light fa-gear icon"
style={{
color: "#188ae2",
right: props?.pos?.type === textWidget ? "32px" : "47px",
top: "-19px"
}}
></i>
)
)}
{/* condition for usericon for all widgets except text widgets and signyour-self flow */}
{props.pos.type !== textWidget && !props.isSignYourself && (
<i
data-tut="assignSigner"
className="fa-regular fa-user signUserIcon"
className="fa-light fa-user icon"
onClick={(e) => {
e.stopPropagation();
props.handleLinkUser(props.data.Id);
props.setUniqueId(props.data.Id);
const checkIndex = props.xyPostion.findIndex(
(data) => data.Id === props.data.Id
);
props.setIsSelectId(checkIndex || 0);
}}
onTouchEnd={(e) => {
e.stopPropagation();
props.handleLinkUser(props.data.Id);
props.setUniqueId(props.data.Id);
const checkIndex = props.xyPostion.findIndex(
(data) => data.Id === props.data.Id
);
props.setIsSelectId(checkIndex || 0);
}}
style={{ color: "#188ae2", right: "32px", top: "-18px" }}
></i>
)}
</>
)}
{/* setting icon only for date widgets */}
{props.pos.type === "date" && selectDate && (
<div
id="menu-container"
@@ -441,17 +529,17 @@ function Placeholder(props) {
top: "-19px",
right: props.isPlaceholder ? "60px" : "44px"
}}
className={
isShowDateFormat
? "dropdown signUserIcon show"
: "dropdown signUserIcon"
}
className={`${isShowDateFormat ? "show" : ""} dropdown icon`}
onClick={(e) => {
setIsShowDateFormat(!isShowDateFormat);
e.stopPropagation();
if (props.data) {
props.setSignKey(props.pos.key);
props.setUniqueId(props.data.Id);
const checkIndex = props.xyPostion.findIndex(
(data) => data.Id === props.data.Id
);
props.setIsSelectId(checkIndex || 0);
}
}}
onTouchEnd={(e) => {
@@ -460,11 +548,15 @@ function Placeholder(props) {
if (props.data) {
props.setSignKey(props.pos.key);
props.setUniqueId(props.data.Id);
const checkIndex = props.xyPostion.findIndex(
(data) => data.Id === props.data.Id
);
props.setIsSelectId(checkIndex || 0);
}
}}
>
<i
className="fa-solid fa-gear settingIcon"
className="fa-light fa-gear icon"
style={{
color: "#188ae2",
fontSize: "14px"
@@ -492,8 +584,7 @@ function Placeholder(props) {
setSelectDate(data);
handleSaveDate(data);
}}
className="dropdown-item itemColor"
style={{ fontSize: "12px" }}
className="dropdown-item text-[13px]"
>
{data?.date ? data?.date : "nodata"}
</span>
@@ -502,29 +593,37 @@ function Placeholder(props) {
</div>
</div>
)}
{/* copy icon for all widgets */}
<i
className="fa-regular fa-copy signCopy"
className="fa-light fa-copy icon"
onClick={(e) => handleCopyPlaceholder(e)}
onTouchEnd={(e) => handleCopyPlaceholder(e)}
style={{ color: "#188ae2", right: "12px", top: "-18px" }}
></i>
{/* delete icon for all widgets */}
<i
className="fa-regular fa-circle-xmark signCloseBtn"
className="fa-light fa-circle-xmark icon"
onClick={(e) => {
e.stopPropagation();
//condition for template and placeholder flow
if (props.data) {
props.handleDeleteSign(props.pos.key, props.data.Id);
} else {
}
//condition for signyour-self flow
else {
props.handleDeleteSign(props.pos.key);
props.setIsStamp(false);
}
}}
//for mobile and tablet touch event
onTouchEnd={(e) => {
e.stopPropagation();
//condition for template and placeholder flow
if (props.data) {
props.handleDeleteSign(props.pos.key, props.data?.Id);
} else {
}
//condition for signyour-self flow
else {
props.handleDeleteSign(props.pos.key);
props.setIsStamp(false);
}
@@ -535,14 +634,83 @@ function Placeholder(props) {
)
);
};
const xPos = (pos, signYourself) => {
const containerScale = getContainerScale(
props.pdfOriginalWH,
props.pageNumber,
props.containerWH
);
const resizePos = pos.xPosition;
if (signYourself) {
return resizePos * containerScale * props.scale;
} else {
//checking both condition mobile and desktop view
if (pos.isMobile && pos.scale) {
if (props.scale > 1) {
return resizePos * pos.scale * containerScale * props.scale;
} else {
return resizePos * pos.scale * containerScale;
}
} else {
// if (pos.scale === containerScale) {
// return resizePos * pos.scale * props.scale;
// } else {
return resizePos * containerScale * props.scale;
// }
}
}
};
const yPos = (pos, signYourself) => {
const containerScale = getContainerScale(
props.pdfOriginalWH,
props.pageNumber,
props.containerWH
);
const resizePos = pos.yPosition;
if (signYourself) {
return resizePos * containerScale * props.scale;
} else {
//checking both condition mobile and desktop view
if (pos.isMobile && pos.scale) {
if (props.scale > 1) {
return resizePos * pos.scale * containerScale * props.scale;
} else {
return resizePos * pos.scale * containerScale;
}
}
// else if (pos.scale === containerScale) {
// if (props.scale > 1) {
// return resizePos * pos.scale * props.scale;
// } else {
// return resizePos * pos.scale;
// }
// }
else {
return resizePos * containerScale * props.scale;
}
}
};
const getCursor = () => {
if (props.data && props.isNeedSign) {
if (props?.signerObjId && props.data?.signerObjId === props.signerObjId) {
return "pointer";
} else if (props?.uniqueId && props.data?.Id === props.uniqueId) {
return "pointer";
} else {
return "not-allowed";
}
} else {
return "all-scroll";
}
};
return (
<Rnd
id={props.pos.key}
data-tut={props.pos.key === props.unSignedWidgetId ? "IsSigned" : ""}
key={props.pos.key}
lockAspectRatio={
// props.pos.type !== textWidget
![
textWidget,
"email",
@@ -586,12 +754,7 @@ function Placeholder(props) {
props.pos.type !== "company" &&
props.pos.type !== "job title" &&
"center",
cursor:
props.data && props.isNeedSign
? props.data?.signerObjId === props.signerObjId
? "pointer"
: "not-allowed"
: "all-scroll",
cursor: getCursor(),
zIndex:
props.pos.type === "date"
? props.pos.key === props.selectWidgetId
@@ -620,8 +783,20 @@ function Placeholder(props) {
setDraggingEnabled(true);
props.setIsResize && props.setIsResize(true);
}}
onResizeStop={() => {
onResizeStop={(e, direction, ref) => {
props.setIsResize && props.setIsResize(false);
props.handleSignYourselfImageResize &&
props.handleSignYourselfImageResize(
ref,
props.pos.key,
props.xyPostion,
props.setXyPostion,
props.index,
containerScale,
props.scale,
props.data && props.data.Id,
props.isResize
);
}}
disableDragging={
props.isNeedSign
@@ -634,21 +809,15 @@ function Placeholder(props) {
props.handleStop &&
props.handleStop(event, dragElement, props.data?.Id, props.pos?.key)
}
default={{
x: props.xPos(props.pos, props.isSignYourself),
y: props.yPos(props.pos, props.isSignYourself)
position={{
x: xPos(props.pos, props.isSignYourself),
y: yPos(props.pos, props.isSignYourself)
}}
onResize={(e, direction, ref) => {
props.handleSignYourselfImageResize &&
props.handleSignYourselfImageResize(
ref,
props.pos.key,
props.xyPostion,
props.setXyPostion,
props.index,
props.data && props.data.Id,
false
);
setPlaceholderBorder({
w: ref.offsetWidth / (props.scale * containerScale),
h: ref.offsetHeight / (props.scale * containerScale)
});
}}
onClick={() => handleOnClickPlaceholder()}
>
@@ -677,20 +846,22 @@ function Placeholder(props) {
pos={props.pos}
isPlaceholder={props.isPlaceholder}
getCheckboxRenderWidth={getCheckboxRenderWidth}
scale={props.scale}
containerScale={containerScale}
placeholderBorder={placeholderBorder}
/>
)}
{isMobile ? (
{isTabAndMobile ? (
<div
className="flex items-stretch"
style={{
left: props.xPos(props.pos, props.isSignYourself),
top: props.yPos(props.pos, props.isSignYourself),
left: xPos(props.pos, props.isSignYourself),
top: yPos(props.pos, props.isSignYourself),
width:
props.pos.type === radioButtonWidget ||
props.pos.type === "checkbox"
? "auto"
: props.posWidth(props.pos, props.isSignYourself),
// "auto", //props.posWidth(props.pos, props.isSignYourself),
// height: props.posHeight(props.pos, props.isSignYourself),
height:
props.pos.type === radioButtonWidget ||
props.pos.type === "checkbox"
@@ -699,6 +870,7 @@ function Placeholder(props) {
zIndex: "10"
}}
onTouchEnd={() => handleOnClickPlaceholder()}
onClick={() => handleOnClickPlaceholder()}
>
{props.pos.key === props.selectWidgetId && <PlaceholderIcon />}
@@ -723,6 +895,7 @@ function Placeholder(props) {
setStartDate={setStartDate}
startDate={startDate}
handleSaveDate={handleSaveDate}
xPos={props.xPos}
/>
</div>
) : (
@@ -749,6 +922,7 @@ function Placeholder(props) {
setStartDate={setStartDate}
startDate={startDate}
handleSaveDate={handleSaveDate}
xPos={props.xPos}
/>
</>
)}
@@ -11,23 +11,34 @@ function PlaceholderBorder(props) {
const getResizeBorderExtraWidth = resizeBorderExtraWidth();
const defaultWidth = defaultWidthHeight(props.pos.type).width;
const defaultHeight = defaultWidthHeight(props.pos.type).height;
const width = () => {
const getWidth =
props.placeholderBorder.w || props.pos.Width || defaultWidth;
return (
getWidth * props.scale * props.containerScale + getResizeBorderExtraWidth
);
};
const height = () => {
const getHeight =
props.placeholderBorder.h || props.pos.Height || defaultHeight;
return (
getHeight * props.scale * props.containerScale + getResizeBorderExtraWidth
);
};
const handleMinWidth = () => {
if (props.pos.type === "checkbox" || props.pos.type === radioButtonWidget) {
return props.getCheckboxRenderWidth.width + getResizeBorderExtraWidth;
} else {
return props.pos.Width
? props.pos.Width + getResizeBorderExtraWidth
: defaultWidth + getResizeBorderExtraWidth;
return width();
}
};
const handleMinHeight = () => {
if (props.pos.type === "checkbox" || props.pos.type === radioButtonWidget) {
return props.getCheckboxRenderWidth.height + getResizeBorderExtraWidth;
} else {
return props.pos.Height
? props.pos.Height + getResizeBorderExtraWidth
: defaultHeight + getResizeBorderExtraWidth;
return height();
}
};
return (
@@ -36,14 +47,11 @@ function PlaceholderBorder(props) {
onTouchEnd={() =>
props.pos.type === textWidget && props?.setDraggingEnabled(true)
}
className="borderResize"
className="absolute inline-block w-[14px] h-[14px] border-[0.2px] overflow-hidden border-dashed"
style={{
borderColor: themeColor,
borderStyle: "dashed",
minWidth: handleMinWidth(),
minHeight: handleMinHeight(),
borderWidth: "0.2px",
overflow: "hidden"
minWidth: handleMinWidth() || 0,
minHeight: handleMinHeight() || 0
}}
></div>
);
@@ -1,12 +1,10 @@
import React, { useState } from "react";
import { themeColor } from "../../constant/const";
import ModalUi from "../../primitives/ModalUi";
import { randomId, textWidget } from "../../constant/Utils";
function PlaceholderCopy(props) {
const copyType = ["All pages", "All pages but last", "All pages but first"];
const [selectCopyType, setSelectCopyType] = useState("");
//function for get copy placeholder position
const getCopyPlaceholderPosition = (
type,
@@ -191,17 +189,15 @@ function PlaceholderCopy(props) {
<ModalUi
isOpen={props.isPageCopy}
title={"Copy to all pages"}
handleClose={() => {
props.setIsPageCopy(false);
}}
handleClose={() => handleUniqueId()}
>
<div style={{ height: "100%", padding: 20 }}>
<div className="h-full p-[20px] text-base-content">
{copyType.map((data, key) => {
return (
<div key={key} style={{ display: "flex", flexDirection: "column" }}>
<label key={key} style={{ fontSize: "16px", fontWeight: "500" }}>
<div key={key} className="flex flex-col">
<label className="text-[16px] font-medium">
<input
style={{ accentColor: "red", marginRight: "10px" }}
className="mr-[8px] op-radio op-radio-xs"
type="radio"
value={data}
onChange={() => setSelectCopyType(data)}
@@ -214,33 +210,22 @@ function PlaceholderCopy(props) {
);
})}
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginTop: "15px",
marginBottom: "15px"
}}
></div>
<div className="flex bg-[#9f9f9f] w-full my-[15px]"></div>
<button
onClick={() => {
handleApplyCopy();
handleUniqueId();
}}
style={{ background: themeColor }}
type="button"
disabled={!selectCopyType}
className="finishBtn"
className="op-btn op-btn-primary"
>
Apply
</button>
<button
type="button"
className="finishBtn cancelBtn"
onClick={() => {
handleUniqueId();
}}
className="op-btn op-btn-ghost"
onClick={() => handleUniqueId()}
>
Cancel
</button>
@@ -2,7 +2,6 @@ import React, { useEffect, useState, forwardRef, useRef } from "react";
import {
getMonth,
getYear,
isMobile,
onChangeHeightOfTextArea,
onChangeInput,
radioButtonWidget,
@@ -14,7 +13,11 @@ import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import "../../styles/signature.css";
import RegexParser from "regex-parser";
import { emailRegex } from "../../constant/const";
const textWidgetCls =
"w-full h-full md:min-w-full md:min-h-full z-[999] text-[12px] rounded-[2px] border-[1px] border-[#007bff] overflow-hidden resize-none outline-none text-base-content item-center whitespace-pre-wrap bg-white";
const selectWidgetCls =
"w-full h-full absolute left-0 top-0 border-[1px] border-[#007bff] rounded-[2px] focus:outline-none text-base-content";
function PlaceholderType(props) {
const type = props?.pos?.type;
const [selectOption, setSelectOption] = useState("");
@@ -59,7 +62,7 @@ function PlaceholderType(props) {
if (validateType && validateType !== "text") {
switch (validateType) {
case "email":
regexValidation = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
regexValidation = emailRegex;
validateExpression(regexValidation);
break;
case "number":
@@ -137,13 +140,12 @@ function PlaceholderType(props) {
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
<div
className="inputPlaceholder"
style={{ overflow: "hidden", fontSize: calculateFontSize() }}
className={`${selectWidgetCls} text-[12px] overflow-hidden`}
onClick={onClick}
ref={ref}
>
{value}
<i className="fa-regular fa-calendar" style={{ marginLeft: "5px" }}></i>
<i className="fa-light fa-calendar ml-[5px]"></i>
</div>
));
ExampleCustomInput.displayName = "ExampleCustomInput";
@@ -169,12 +171,6 @@ function PlaceholderType(props) {
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [type]);
const calculateFontSize = () => {
const fontSize = 10 + Math.min(props.pos.Width, props.pos.Height) * 0.1;
const size = fontSize ? fontSize : 12;
return size + "px";
};
//function for show checked checkbox
const selectCheckbox = (ind) => {
const res = props.pos.options?.response;
@@ -304,17 +300,13 @@ function PlaceholderType(props) {
case "signature":
return props.pos.SignUrl ? (
<img
alt="signimg"
alt="signature"
draggable="false"
src={props.pos.SignUrl}
style={{
width: "99%",
height: "100%",
objectFit: "contain"
}}
className="w-full h-full "
/>
) : (
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
{props?.handleUserName &&
props?.handleUserName(
props?.data?.Id,
@@ -326,17 +318,13 @@ function PlaceholderType(props) {
case "stamp":
return props.pos.SignUrl ? (
<img
alt="signimg"
alt="stamp"
draggable="false"
src={props.pos.SignUrl}
style={{
width: "99%",
height: "100%",
objectFit: "contain"
}}
className="w-full h-full"
/>
) : (
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
{props?.handleUserName &&
props?.handleUserName(
props?.data?.Id,
@@ -352,12 +340,9 @@ function PlaceholderType(props) {
return (
<div key={ind} className="flex items-center text-center gap-0.5">
<input
style={{
// width: props.pos.Width,
display: "flex",
justifyContent: "center",
marginTop: ind === 0 ? 0 : "5px"
}}
className={`${
ind === 0 ? "mt-0" : "mt-[5px]"
} flex justify-center op-checkbox op-checkbox-xs rounded-[0.350rem]`}
onBlur={handleInputBlur}
disabled={
props.isNeedSign &&
@@ -420,19 +405,23 @@ function PlaceholderType(props) {
false
);
}}
className={
isMobile
? "labelTextArea labelWidthMobile"
: "labelTextArea labelWidthDesktop"
}
style={{ whiteSpace: "pre-wrap" }}
className={textWidgetCls}
style={{
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black"
}}
cols="50"
/>
) : (
<div
style={{
color: "black",
fontSize: calculateFontSize()
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black",
overflow: "hidden"
}}
>
<span>{type}</span>
@@ -441,9 +430,8 @@ function PlaceholderType(props) {
case "dropdown":
return props.data?.signerObjId === props.signerObjId ? (
<select
className="inputPlaceholder"
className={`${selectWidgetCls} text-[12px] bg-inherit`}
id="myDropdown"
style={{ fontSize: "12px" }}
value={selectOption}
onChange={(e) => {
setSelectOption(e.target.value);
@@ -463,7 +451,7 @@ function PlaceholderType(props) {
{props?.pos?.options?.name}
</option>
{props.pos?.options?.values.map((data, ind) => {
{props.pos?.options?.values?.map((data, ind) => {
return (
<option key={ind} value={data}>
{data}
@@ -472,27 +460,20 @@ function PlaceholderType(props) {
})}
</select>
) : (
<div
className="inputPlaceholder"
style={{ fontSize: calculateFontSize() }}
>
<div className="text-[12px] overflow-hidden">
{props.pos?.options?.name ? props.pos.options.name : type}
</div>
);
case "initials":
return props.pos.SignUrl ? (
<img
alt="signimg"
alt="initials"
draggable="false"
src={props.pos.SignUrl}
style={{
width: "99%",
height: "100%",
objectFit: "contain"
}}
className="w-full h-full"
/>
) : (
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
{props?.handleUserName &&
props?.handleUserName(
props?.data?.Id,
@@ -523,19 +504,24 @@ function PlaceholderType(props) {
isDefault
);
}}
className={
isMobile
? "labelTextArea labelWidthMobile"
: "labelTextArea labelWidthDesktop"
}
style={{ whiteSpace: "pre-wrap" }}
className={textWidgetCls}
style={{
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black"
}}
cols="50"
/>
) : (
<div
style={{
color: "black",
fontSize: calculateFontSize()
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black",
fontFamily: "Arial, sans-serif",
overflow: "hidden"
}}
>
<span>{type}</span>
@@ -562,19 +548,24 @@ function PlaceholderType(props) {
false
);
}}
className={
isMobile
? "labelTextArea labelWidthMobile"
: "labelTextArea labelWidthDesktop"
}
style={{ whiteSpace: "pre-wrap" }}
className={textWidgetCls}
style={{
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black"
}}
cols="50"
/>
) : (
<div
style={{
color: "black",
fontSize: calculateFontSize()
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black",
overflow: "hidden",
fontFamily: "Arial, sans-serif"
}}
>
<span>{type}</span>
@@ -601,26 +592,32 @@ function PlaceholderType(props) {
false
);
}}
className={
isMobile
? "labelTextArea labelWidthMobile"
: "labelTextArea labelWidthDesktop"
}
style={{ whiteSpace: "pre-wrap" }}
className={textWidgetCls}
style={{
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black"
}}
cols="50"
/>
) : (
<div
style={{
color: "black",
fontSize: calculateFontSize()
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black",
fontFamily: "Arial, sans-serif",
overflow: "hidden"
}}
>
<span>{type}</span>
</div>
);
case "date":
return (
return props.isSignYourself ||
(props.isNeedSign && props.data?.signerObjId === props.signerObjId) ? (
<div>
<DatePicker
renderCustomHeader={({ date, changeYear, changeMonth }) => (
@@ -658,8 +655,7 @@ function PlaceholderType(props) {
}
onBlur={handleInputBlur}
closeOnScroll={true}
className="inputPlaceholder"
style={{ outlineColor: "#007bff" }}
className={`${selectWidgetCls} outline-[#007bff]`}
selected={
props?.startDate
? props?.startDate
@@ -678,21 +674,27 @@ function PlaceholderType(props) {
}
/>
</div>
) : (
<div className="text-[12px] text-black items-center overflow-hidden">
<span>
{props.selectDate
? props.selectDate?.format
: props.pos?.options?.validation?.format
? props.pos?.options?.validation?.format
: "MM/dd/yyyy"}
</span>
</div>
);
case "image":
return props.pos.SignUrl ? (
<img
alt="signimg"
alt="image"
draggable="false"
src={props.pos.SignUrl}
style={{
width: "99%",
height: "100%",
objectFit: "contain"
}}
className="w-full h-full"
/>
) : (
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
{props?.handleUserName &&
props?.handleUserName(
props?.data?.Id,
@@ -723,19 +725,25 @@ function PlaceholderType(props) {
false
);
}}
className={
isMobile
? "labelTextArea labelWidthMobile"
: "labelTextArea labelWidthDesktop"
}
style={{ whiteSpace: "pre-wrap" }}
className={textWidgetCls}
style={{
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black",
fontFamily: "Arial, sans-serif"
}}
cols="50"
/>
) : (
<div
style={{
color: "black",
fontSize: calculateFontSize()
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black",
fontFamily: "Arial, sans-serif",
overflow: "hidden"
}}
>
<span>{type}</span>
@@ -748,12 +756,9 @@ function PlaceholderType(props) {
return (
<div key={ind} className="flex items-center text-center gap-0.5">
<input
style={{
width: props.pos.Width,
display: "flex",
justifyContent: "center",
marginTop: ind === 0 ? 0 : "5px"
}}
className={`${
ind === 0 ? "mt-0" : "mt-[5px]"
} ${"w-[15px] h-[15px]"} flex justify-center op-radio`}
type="radio"
disabled={
props.isNeedSign &&
@@ -795,37 +800,29 @@ function PlaceholderType(props) {
false
);
}}
className={
isMobile
? "labelTextArea labelWidthMobile"
: "labelTextArea labelWidthDesktop"
}
style={{ whiteSpace: "pre-wrap", overflow: "hidden" }}
className={textWidgetCls}
style={{
fontFamily: "Arial, sans-serif",
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black"
}}
cols="50"
/>
);
default:
return props.pos.SignUrl ? (
<div style={{ pointerEvents: "none" }}>
<div className="pointer-events-none">
<img
alt="signimg"
alt="image"
draggable="false"
src={props.pos.SignUrl}
style={{
width: "99%",
height: "100%",
objectFit: "contain"
}}
className="w-full h-full"
/>
</div>
) : (
<div
style={{
fontSize: "10px",
color: "black",
justifyContent: "center"
}}
>
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
{props.pos.isStamp ? <div>stamp</div> : <div>signature</div>}
{props?.handleUserName &&
props?.handleUserName(props?.data?.Id, props?.data?.Role)}
+23 -34
View File
@@ -1,5 +1,4 @@
import React from "react";
import { themeColor } from "../../constant/const";
function PrevNext({ pageNumber, allPages, changePage }) {
//for go to previous page
@@ -12,40 +11,30 @@ function PrevNext({ pageNumber, allPages, changePage }) {
}
return (
<div>
<div className="preBtn1">
<button
className="py-[3px] px-[10px] text-xs bg-[#d3edeb] font-[600] mr-[5px]"
disabled={pageNumber <= 1}
onClick={previousPage}
>
<span className="block lg:hidden">
<i
className="fa fa-backward"
aria-hidden="true"
style={{ color: themeColor, cursor: "pointer" }}
></i>
</span>
<span className="lg:block hidden">Prev</span>
</button>
<span className="text-xs font-[500]">
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
<div className="flex items-center">
<button
className="op-btn op-btn-neutral op-btn-xs md:op-btn-sm font-semibold text-xs"
disabled={pageNumber <= 1}
onClick={previousPage}
>
<span className="block lg:hidden">
<i className="fa-light fa-backward" aria-hidden="true"></i>
</span>
<button
className="py-[3px] px-[10px] text-xs bg-[#d3edeb] font-[600] ml-[5px]"
disabled={pageNumber >= allPages}
onClick={nextPage}
>
<span className="block lg:hidden">
<i
className="fa fa-forward"
aria-hidden="true"
style={{ color: themeColor, cursor: "pointer" }}
></i>
</span>
<span className="lg:block hidden">Next</span>
</button>
</div>
<span className="lg:block hidden 2xl:text-[30px]">Prev</span>
</button>
<span className="text-xs text-base-content font-medium mx-2 2xl:text-[30px]">
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
</span>
<button
className="op-btn op-btn-neutral op-btn-xs md:op-btn-sm font-semibold text-xs"
disabled={pageNumber >= allPages}
onClick={nextPage}
>
<span className="block lg:hidden">
<i className="fa-light fa-forward" aria-hidden="true"></i>
</span>
<span className="lg:block hidden 2xl:text-[30px]">Next</span>
</button>
</div>
);
}
+111 -129
View File
@@ -7,37 +7,14 @@ import {
isMobile,
nameColor
} from "../../constant/Utils";
const cursor =
"cursor-[url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAASElEQVR4nGNgwAMkJSUbpKSkOvCpIaT5PxSTbogUQjMYMwxeIIXmVFIxA8UGDDyQGg0DnIDi6JKUlCxHMqCeZAOghjSAMD5FAKfeaURdUFxCAAAAAElFTkSuQmCC'),_pointer]";
const RecipientList = (props) => {
const [animationParent] = useAutoAnimate();
const [isHover, setIsHover] = useState();
const [isEdit, setIsEdit] = useState(false);
//function for onhover signer name change background color
const inputRef = useRef(null);
const onHoverStyle = (ind, blockColor) => {
const style = {
background: blockColor ? blockColor : color[ind % color.length],
padding: "10px",
marginTop: "2px",
display: "flex",
flexDirection: "row",
borderBottom: "1px solid #e3e1e1",
alignItems: "center"
};
return style;
};
//function for onhover signer name remove background color
const nonHoverStyle = () => {
const style = {
padding: "10px",
marginTop: "2px",
display: "flex",
flexDirection: "row",
borderBottom: "1px solid #e3e1e1",
alignItems: "center"
};
return style;
};
const isWidgetExist = (Id) => {
return props.signerPos.some((x) => x.Id === Id);
};
@@ -84,17 +61,28 @@ const RecipientList = (props) => {
);
//splice method is used to replace or add new value in array at specific index
remainingItems.splice(index, 0, ...draggedItem);
//set current draggable recipient details,objectId,index,contract_className ... after replace recipient list
props.setSignersData(remainingItems);
props.setSignerObjId(remainingItems[index]?.objectId || "");
props.setIsSelectId(index);
props.setContractName(remainingItems[index]?.className || "");
props.setUniqueId(remainingItems[index]?.Id);
props.setRoleName(remainingItems[index]?.Role);
props.setBlockColor(remainingItems[index]?.blockColor);
};
props?.setSignersData(remainingItems);
props?.setSignerObjId(remainingItems[index]?.objectId || "");
props?.setIsSelectId(index);
props?.setContractName(remainingItems[index]?.className || "");
props?.setUniqueId(remainingItems[index]?.Id);
props?.setRoleName(remainingItems[index]?.Role);
props?.setBlockColor(remainingItems[index]?.blockColor);
//change order of placeholder's list using sorting method
//`remainingItems` is correct order of signers after change order
const changeOrderSignerList = props?.signerPos.sort((a, b) => {
//`indexA` and `indexB` is to get element position using index in correct order array
const indexA = remainingItems.findIndex((item) => item.Id === a.Id);
const indexB = remainingItems.findIndex((item) => item.Id === b.Id);
//and then compare `indexA - indexB` value
//if positive it means indexB element comes before indexA then need to sorting
//if negative it means indexA element is on correct position do not need to sorting
return indexA - indexB;
});
props?.setSignerPos(changeOrderSignerList);
};
return (
<>
{props.signersdata.length > 0 &&
@@ -113,21 +101,24 @@ const RecipientList = (props) => {
onDrop={(e) =>
props.sendInOrder && !isMobile && handleChangeSequence(e, ind)
}
data-tut="reactourFirst"
data-tut="recipientArea"
onMouseEnter={() => setIsHover(ind)}
onMouseLeave={() => setIsHover(null)}
className={
className={`${
props.sendInOrder
? props.isMailSend
? "disabled"
: "dragCursor"
: props.isMailSend && "disabled"
}
style={
(!isMobile && isHover === ind) || props.isSelectListId === ind
? onHoverStyle(ind, obj?.blockColor)
: nonHoverStyle(ind)
}
? "pointer-events-none bg-opacity-80"
: `text-[12px] font-bold ${cursor}`
: props.isMailSend && "pointer-events-none bg-opacity-80"
} flex flex-row rounded-xl px-2 py-[10px] mt-1 mx-1 items-center last:mb-0.5`}
style={{
background:
(!isMobile && isHover === ind) || props.uniqueId === obj.Id
? obj?.blockColor
? obj?.blockColor
: color[ind % color.length]
: "transparent"
}}
onClick={(e) => {
e.preventDefault();
props.setSignerObjId(obj?.objectId || "");
@@ -141,40 +132,18 @@ const RecipientList = (props) => {
}
}}
>
<div
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
width: "100%"
}}
>
<div className="flex flex-row items-center w-full">
<div
className="flex w-[30px] h-[30px] rounded-full items-center justify-center mr-2"
style={{
background: obj?.blockColor
? darkenColor(obj?.blockColor, 0.4)
: nameColor[ind % nameColor.length],
width: 30,
height: 30,
display: "flex",
borderRadius: 30 / 2,
justifyContent: "center",
alignItems: "center",
marginRight: "12px"
: nameColor[ind % nameColor.length]
}}
>
<span
className={props.sendInOrder && "dragCursor"}
style={{
fontSize: "12px",
textAlign: "center",
fontWeight: "bold",
color: "white",
textTransform: "uppercase"
}}
>
<span className="text-white uppercase font-bold text-center text-[12px]">
{isWidgetExist(obj.Id) ? (
<i className="fa-solid fa-check"></i>
<i className="fa-light fa-check"></i>
) : (
<>
{obj.Name
@@ -185,67 +154,74 @@ const RecipientList = (props) => {
</span>
</div>
<div
style={{
display: "flex",
flexDirection: obj.Name ? "column" : "row",
alignItems: "center"
}}
className={`${
obj.Name ? "flex-col" : "flex-row"
} flex items-center`}
>
{obj.Name ? (
<span className={"userName"}>{obj.Name}</span>
<span
className={`${
(!isMobile && isHover === ind) ||
props.isSelectListId === ind
? "text-[#424242]"
: "text-base-content"
} text-[12px] font-bold w-[100px] whitespace-nowrap overflow-hidden text-ellipsis`}
>
{obj.Name}
</span>
) : (
<>
<span
className="userName"
style={{ cursor: "pointer" }}
onClick={() => {
setIsEdit({ [obj.Id]: true });
props.setRoleName(obj.Role);
}}
>
{isEdit?.[obj.Id] && props.handleRoleChange ? (
<input
ref={inputRef}
style={{
backgroundColor: "transparent",
width: "inherit",
padding: "3px"
}}
value={obj.Role}
onChange={(e) => props.handleRoleChange(e, obj.Id)}
onBlur={() => {
setIsEdit({});
props.handleOnBlur(obj.Role, obj.Id);
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
inputRef.current.blur();
}
}}
/>
) : (
<span style={{ padding: "3px" }}>{obj.Role}</span>
)}
</span>
</>
<span
className={`${
(!isMobile && isHover === ind) ||
props.isSelectListId === ind
? "text-[#424242]"
: "text-base-content"
} text-[12px] font-bold w-[100px] whitespace-nowrap overflow-hidden text-ellipsis cursor-pointer`}
onClick={() => {
setIsEdit({ [obj.Id]: true });
props.setRoleName(obj.Role);
}}
>
{isEdit?.[obj.Id] && props.handleRoleChange ? (
<input
ref={inputRef}
className="bg-transparent p-[3px]"
value={obj.Role}
onChange={(e) => props.handleRoleChange(e, obj.Id)}
onBlur={() => {
setIsEdit({});
props.handleOnBlur(obj.Role, obj.Id);
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
inputRef.current.blur();
}
}}
/>
) : (
<span className="text-[13px] 2xl:text-[25px]">
{obj.Role}
</span>
)}
</span>
)}
{obj.Name && (
<span className={"useEmail"}>
<span
className={` ${
(!isMobile && isHover === ind) ||
props.isSelectListId === ind
? "text-[#424242]"
: "text-base-content"
} text-[10px] font-medium w-[100px] whitespace-nowrap overflow-hidden text-ellipsis`}
>
{obj?.Role || obj?.Email}
</span>
)}
</div>
</div>
{isMobile && props.sendInOrder && (
<div
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
gap: 5
}}
>
<div className="flex flex-row items-center gap-[5px] mr-2">
<div
onClick={(e) => {
if (ind !== 0) {
@@ -253,7 +229,7 @@ const RecipientList = (props) => {
handleChangeSequence(e, ind, "up");
}
}}
style={{ color: ind === 0 ? "gray" : "black" }}
className={ind === 0 ? "text-[gray]" : "text-black"}
>
</div>
@@ -264,10 +240,11 @@ const RecipientList = (props) => {
handleChangeSequence(e, ind, null, "down");
}
}}
style={{
color:
ind === props.signersdata.length - 1 ? "gray" : "black"
}}
className={
ind === props.signersdata.length - 1
? "text-[gray]"
: "text-black"
}
>
</div>
@@ -279,9 +256,14 @@ const RecipientList = (props) => {
e.stopPropagation();
props.handleDeleteUser(obj.Id);
}}
style={{ cursor: "pointer", marginLeft: "5px" }}
className={`${
(!isMobile && isHover === ind) ||
props.isSelectListId === ind
? "text-[#424242]"
: "text-base-content"
} cursor-pointer`}
>
<i className="fa-regular fa-trash-can"></i>
<i className="fa-light fa-trash-can 2xl:text-[30px]"></i>
</div>
)}
<hr />
@@ -1,7 +1,6 @@
import React, { useState } from "react";
import RSC from "react-scrollbars-custom";
import React, { useEffect, useRef, useState } from "react";
import { Document, Page } from "react-pdf";
import { themeColor } from "../../constant/const";
import { useSelector } from "react-redux";
function RenderAllPdfPage({
signPdfUrl,
@@ -11,7 +10,8 @@ function RenderAllPdfPage({
setSignBtnPosition,
pageNumber,
signerPos,
signerObjectId
signerObjectId,
containerWH
}) {
const [signPageNumber, setSignPageNumber] = useState([]);
const [bookmarkColor, setBookmarkColor] = useState("");
@@ -34,21 +34,28 @@ function RenderAllPdfPage({
}
}
}
const pageContainer = useRef();
const isHeader = useSelector((state) => state.showHeader);
const [pageWidth, setPageWidth] = useState("");
useEffect(() => {
const updateSize = () => {
if (pageContainer.current) {
setPageWidth(pageContainer.current.offsetWidth);
}
};
// Use setTimeout to wait for the transition to complete
const timer = setTimeout(updateSize, 100); // match the transition duration
return () => clearTimeout(timer);
}, [isHeader, pageContainer, containerWH]);
//'function `addSignatureBookmark` is used to display the page where the user's signature is located.
const addSignatureBookmark = (index) => {
const ispageNumber = signPageNumber.includes(index + 1);
return (
ispageNumber && (
<div
style={{
position: "absolute",
zIndex: 2,
top: -12,
right: -7,
transform: "translate(50% -50%)"
}}
>
<div className="absolute z-20 top-[1px] -right-[13px] -translate-x-1/2 -translate-y-1/2">
<i
style={{ color: bookmarkColor || "red" }}
className="fa-solid fa-bookmark"
@@ -58,91 +65,47 @@ function RenderAllPdfPage({
);
};
return (
<div className="showPages">
<div ref={pageContainer} className="hidden w-[20%] bg-base-100 md:block">
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
Pages
</div>
<div
style={{
display: "flex",
flexDirection: "row",
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
backgroundColor: "white",
height: "100%"
}}
className={`flex h-[90%] flex-col items-center m-2
autoSignScroll hide-scrollbar max-h-[100vh] `}
>
<div style={{ width: "140px" }}>
<div
style={{
background: themeColor
// color:"white"
}}
className="signedStyle"
>
Pages
</div>
<div>
<RSC
id="RSC-Example"
style={{
width: "135px",
height: window.innerHeight - 130 + "px"
<Document
loading={"Loading Document.."}
onLoadSuccess={onDocumentLoad}
file={signPdfUrl}
>
{Array.from(new Array(allPages), (el, index) => (
<div
key={index}
className={`${
pageNumber - 1 === index ? "border-[red]" : "border-[#878787]"
} border-2 m-[10px] flex justify-center items-center relative`}
onClick={() => {
setPageNumber(index + 1);
if (setSignBtnPosition) {
setSignBtnPosition([]);
}
}}
>
<Document
loading={"Loading Document.."}
onLoadSuccess={onDocumentLoad}
file={signPdfUrl}
>
{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",
{signerPos && addSignatureBookmark(index)}
display: "flex",
justifyContent: "center",
alignItems: "center",
position: "relative"
}}
onClick={() => {
setPageNumber(index + 1);
if (setSignBtnPosition) {
setSignBtnPosition([]);
}
}}
>
{signerPos && addSignatureBookmark(index)}
<div
style={{
position: "relative",
zIndex: 1,
overflow: "hidden"
}}
>
<Page
key={`page_${index + 1}`}
pageNumber={index + 1}
width={100}
height={100}
scale={1}
renderAnnotationLayer={false}
renderTextLayer={false}
/>
</div>
</div>
))}
</Document>
</RSC>
</div>
<hr />
</div>
<div className="relative z-[1] overflow-hidden">
<Page
key={`page_${index + 1}`}
pageNumber={index + 1}
width={pageWidth - 60}
scale={1}
renderAnnotationLayer={false}
renderTextLayer={false}
/>
</div>
</div>
))}
</Document>
</div>
</div>
);
+207 -283
View File
@@ -3,6 +3,7 @@ import RSC from "react-scrollbars-custom";
import { Document, Page } from "react-pdf";
import {
defaultWidthHeight,
getContainerScale,
handleImageResize,
handleSignYourselfImageResize
} from "../../constant/Utils";
@@ -11,8 +12,6 @@ import Alert from "../../primitives/Alert";
function RenderPdf({
pageNumber,
pdfOriginalWidth,
pdfNewWidth,
drop,
signerPos,
successEmail,
@@ -26,15 +25,13 @@ function RenderPdf({
pdfDetails,
xyPostion,
pdfUrl,
numPages,
pageDetails,
pdfRequest,
setCurrentSigner,
signerObjectId,
signedSigners,
setPdfLoadFail,
pdfLoad,
setPdfLoad,
placeholder,
pdfLoadFail,
setSignerPos,
setXyPostion,
index,
@@ -57,183 +54,109 @@ function RenderPdf({
unSignedWidgetId,
setIsCheckbox,
handleNameModal,
handleTextSettingModal,
setTempSignerId,
uniqueId
uniqueId,
pdfOriginalWH,
scale,
setIsSelectId,
ispublicTemplate,
handleUserDetails
}) {
const isMobile = window.innerWidth < 767;
const newWidth = containerWH.width;
const scale = isMobile ? pdfOriginalWidth / newWidth : 1;
//check isGuestSigner is present in local if yes than handle login flow header in mobile view
const isGuestSigner = localStorage.getItem("isGuestSigner");
// handle signature block width and height according to screen
const posWidth = (pos, signYourself) => {
const containerScale = getContainerScale(
pdfOriginalWH,
pageNumber,
containerWH
);
const defaultWidth = defaultWidthHeight(pos.type).width;
const posWidth = pos.Width ? pos.Width : defaultWidth;
let width;
if (signYourself) {
width = posWidth;
return width;
return posWidth * scale * containerScale;
} else {
if (isMobile) {
if (!pos.isMobile) {
if (pos.IsResize) {
width = posWidth ? posWidth : defaultWidth;
return width;
if (pos.isMobile && pos.scale) {
if (pos.IsResize) {
if (scale > 1) {
return posWidth * pos.scale * containerScale * scale;
} else {
width = (posWidth || defaultWidth) / scale;
return width;
return posWidth * containerScale;
}
} else {
width = posWidth;
return width;
if (scale > 1) {
return posWidth * pos.scale * containerScale * scale;
} else {
return posWidth * pos.scale * containerScale;
}
}
} else {
if (pos.isMobile) {
if (pos.IsResize) {
width = posWidth ? posWidth : defaultWidth;
return width;
} else {
width = (posWidth || defaultWidth) * pos.scale;
return width;
}
} else {
width = posWidth ? posWidth : defaultWidth;
return width;
}
return posWidth * scale * containerScale;
}
}
};
const posHeight = (pos, signYourself) => {
let height;
const posHeight = pos.Height;
const defaultHeight = defaultWidthHeight(pos.type).height;
if (signYourself) {
height = posHeight ? posHeight : defaultHeight;
return height;
} else {
if (isMobile) {
if (!pos.isMobile) {
if (pos.IsResize) {
height = posHeight ? posHeight : defaultHeight;
return height;
} else {
height = (posHeight || defaultHeight) / scale;
return height;
}
} else {
height = posHeight ? posHeight : defaultHeight;
return height;
}
} else {
if (pos.isMobile) {
if (pos.IsResize) {
height = posHeight ? posHeight : defaultHeight;
return height;
} else {
height = (posHeight || defaultHeight) * pos.scale;
return height;
}
} else {
height = posHeight ? posHeight : defaultHeight;
return height;
}
}
}
};
const xPos = (pos, signYourself) => {
const resizePos = pos.xPosition;
if (signYourself) {
return resizePos;
} else {
//checking both condition mobile and desktop view
if (isMobile) {
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
if (!pos.isMobile) {
return resizePos / scale;
}
//pos.isMobile true -- placeholder save from mobile view(small device) handle position in mobile view(small screen) view divided by scale
else {
return resizePos * (pos.scale / scale);
}
} else {
//else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale
if (pos.isMobile) {
return pos.scale && resizePos * pos.scale;
}
//else placeholder save from desktop(bigscreen) and show in desktop(bigscreen)
else {
return resizePos;
}
}
}
};
const yPos = (pos, signYourself) => {
const resizePos = pos.yPosition;
if (signYourself) {
return resizePos;
} else {
//checking both condition mobile and desktop view
if (isMobile) {
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
if (!pos.isMobile) {
return resizePos / scale;
}
//pos.isMobile true -- placeholder save from mobile view(small device) handle position in mobile view(small screen) view divided by scale
else {
return resizePos * (pos.scale / scale);
}
} else {
//else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale
if (pos.isMobile) {
return pos.scale && resizePos * pos.scale;
}
//else placeholder save from desktop(bigscreen) and show in desktop(bigscreen)
else {
return resizePos;
}
}
}
};
//function for render placeholder block over pdf document
const checkSignedSignes = (data) => {
const checkSign = signedSigners.filter(
(sign) => sign.objectId === data.signerObjId
const containerScale = getContainerScale(
pdfOriginalWH,
pageNumber,
containerWH
);
if (data.signerObjId === signerObjectId) {
setCurrentSigner(true);
const posHeight = pos.Height || defaultWidthHeight(pos.type).height;
if (signYourself) {
return posHeight * scale * containerScale;
} else {
if (pos.isMobile && pos.scale) {
if (pos.IsResize) {
if (scale > 1) {
return posHeight * pos.scale * containerScale * scale;
} else {
return posHeight * containerScale;
}
} else {
if (scale > 1) {
return posHeight * pos.scale * containerScale * scale;
} else {
return posHeight * pos.scale * containerScale;
}
}
} else {
return posHeight * scale * containerScale;
}
}
const handleAllUserName = (Id, Role, type) => {
return pdfDetails[0].Signers.map((signerData, key) => {
return (
signerData.objectId === data.signerObjId && (
<React.Fragment key={key}>
{signerData?.Name && (
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
{signerData.Name}
</div>
)}
{type && (
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
)}
{Role && (
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
{`(${Role})`}
</div>
)}
</React.Fragment>
)
);
});
};
};
//function for render placeholder block over pdf document
const checkSignedSigners = (data) => {
let checkSign = [];
//condition to handle quick send flow and using normal request sign flow
checkSign = signedSigners
? signedSigners?.filter(
(sign) =>
sign?.Id === data?.Id || sign?.objectId === data?.signerObjId
)
: [];
const handleAllUserName = (Id, Role, type) => {
return (
<React.Fragment>
<div className="text-black text-[8px] font-bold">
{
pdfDetails[0].Signers?.find(
(signer) => signer.objectId === data.signerObjId
)?.Name
}
</div>
{type && <div className="text-[11px] font-bold">{type}</div>}
{Role && (
<div className="text-black text-[8px] font-medium">
{`(${Role})`}
</div>
)}
</React.Fragment>
);
};
return (
checkSign.length === 0 &&
data.placeHolder.map((placeData, key) => {
@@ -260,8 +183,6 @@ function RenderPdf({
isShowDropdown={true}
isNeedSign={true}
isSignYourself={false}
xPos={xPos}
yPos={yPos}
posWidth={posWidth}
posHeight={posHeight}
handleUserName={handleAllUserName}
@@ -273,6 +194,13 @@ function RenderPdf({
setSelectWidgetId={setSelectWidgetId}
selectWidgetId={selectWidgetId}
setCurrWidgetsDetails={setCurrWidgetsDetails}
uniqueId={uniqueId}
scale={scale}
containerWH={containerWH}
pdfOriginalWH={pdfOriginalWH}
pageNumber={pageNumber}
ispublicTemplate={ispublicTemplate}
handleUserDetails={handleUserDetails}
/>
</React.Fragment>
)
@@ -283,6 +211,7 @@ function RenderPdf({
})
);
};
//function for render placeholder block over pdf document
const handleUserName = (Id, Role, type) => {
if (Id) {
@@ -290,14 +219,12 @@ function RenderPdf({
if (checkSign?.Name) {
return (
<>
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
<div className="text-black text-[8px] font-medium">
{checkSign?.Name}
</div>
{type && (
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
)}
{type && <div className="text-[11px] font-bold">{type}</div>}
{Role && (
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
<div className="text-black text-[8px] font-medium">
{`(${Role})`}
</div>
)}
@@ -306,47 +233,39 @@ function RenderPdf({
} else {
return (
<>
{type && (
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
)}
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
{Role}
</div>
{type && <div className="text-[11px] font-bold">{type}</div>}
<div className="text-black text-[8px] font-medium">{Role}</div>
</>
);
}
} else {
return (
<>
{type && (
<div style={{ fontWeight: "700", fontSize: 11 }}>{type}</div>
)}
<div style={{ color: "black", fontSize: 8, fontWeight: "500" }}>
{Role}
</div>
{type && <div className="text-[11px] font-bold">{type}</div>}
<div className="text-black text-[8px] font-medium">{Role}</div>
</>
);
}
};
return (
<>
{successEmail && <Alert type={"success"}>Email sent successfully!</Alert>}
{isMobile && scale ? (
{isMobile ? (
<div
style={{
border: "0.1px solid #ebe8e8",
marginTop: isGuestSigner && "30px"
}}
data-tut="reactourForth"
className={`${
isGuestSigner ? "30px" : ""
} border-[0.1px] border-[#ebe8e8]`}
ref={drop}
id="container"
>
{pdfLoadFail.status &&
{containerWH?.width &&
pdfOriginalWH.length > 0 &&
(pdfRequest
? signerPos.map((data, key) => {
return (
<React.Fragment key={key}>
{checkSignedSignes(data)}
{checkSignedSigners(data)}
</React.Fragment>
);
})
@@ -385,8 +304,6 @@ function RenderPdf({
handleLinkUser={handleLinkUser}
handleUserName={handleUserName}
isSignYourself={false}
xPos={xPos}
yPos={yPos}
posWidth={posWidth}
posHeight={posHeight}
isDragging={isDragging}
@@ -402,6 +319,14 @@ function RenderPdf({
handleNameModal={handleNameModal}
setTempSignerId={setTempSignerId}
uniqueId={uniqueId}
handleTextSettingModal={
handleTextSettingModal
}
scale={scale}
containerWH={containerWH}
pdfOriginalWH={pdfOriginalWH}
pageNumber={pageNumber}
setIsSelectId={setIsSelectId}
/>
</React.Fragment>
);
@@ -433,13 +358,10 @@ function RenderPdf({
index={index}
xyPostion={xyPostion}
setXyPostion={setXyPostion}
pdfOriginalWidth={pdfOriginalWidth}
containerWH={containerWH}
setIsSignPad={setIsSignPad}
isShowBorder={true}
isSignYourself={true}
xPos={xPos}
yPos={yPos}
posWidth={posWidth}
posHeight={posHeight}
pdfDetails={pdfDetails[0]}
@@ -452,6 +374,12 @@ function RenderPdf({
setIsCheckbox={setIsCheckbox}
setValidateAlert={setValidateAlert}
setCurrWidgetsDetails={setCurrWidgetsDetails}
handleTextSettingModal={
handleTextSettingModal
}
scale={scale}
pdfOriginalWH={pdfOriginalWH}
pageNumber={pageNumber}
/>
)
);
@@ -461,16 +389,10 @@ function RenderPdf({
}))}
{/* this component for render pdf document is in middle of the component */}
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
<div className="flex items-center justify-center">
<Document
onLoadError={() => {
setPdfLoadFail(true);
setPdfLoad(false);
}}
loading={"Loading Document.."}
onLoadSuccess={pageDetails}
@@ -488,19 +410,16 @@ function RenderPdf({
: pdfDetails[0].URL
}
>
{Array.from(new Array(numPages), (el, index) => (
<Page
key={index}
pageNumber={pageNumber}
width={containerWH.width}
height={containerWH.height}
renderAnnotationLayer={false}
renderTextLayer={false}
onGetAnnotationsError={(error) => {
console.log("annotation error", error);
}}
/>
))}
<Page
key={index}
pageNumber={pageNumber}
width={containerWH.width}
renderAnnotationLayer={false}
renderTextLayer={false}
onGetAnnotationsError={(error) => {
console.log("annotation error", error);
}}
/>
</Document>
</div>
</div>
@@ -509,31 +428,31 @@ function RenderPdf({
style={{
position: "relative",
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
width:
pdfOriginalWidth > pdfNewWidth ? pdfNewWidth : pdfOriginalWidth,
height: window.innerHeight - 110 + "px"
height: window.innerHeight + "px",
zIndex: 0
}}
noScrollY={false}
noScrollX={pdfNewWidth < pdfOriginalWidth ? false : true}
noScrollX={scale === 1 ? true : false}
>
<div
style={{
border: "0.1px solid #ebe8e8",
width: pdfOriginalWidth
width: containerWH?.width && containerWH?.width * scale
}}
ref={drop}
id="container"
>
{pdfLoadFail.status &&
(pdfRequest
? signerPos.map((data, key) => {
{pdfLoad &&
containerWH?.width &&
pdfOriginalWH.length > 0 &&
(pdfRequest //pdf request sign flow
? signerPos?.map((data, key) => {
return (
<React.Fragment key={key}>
{checkSignedSignes(data)}
{checkSignedSigners(data)}
</React.Fragment>
);
})
: placeholder
: placeholder //placeholder and template flow
? signerPos.map((data, ind) => {
return (
<React.Fragment key={ind}>
@@ -568,8 +487,6 @@ function RenderPdf({
handleLinkUser={handleLinkUser}
handleUserName={handleUserName}
isSignYourself={false}
xPos={xPos}
yPos={yPos}
posWidth={posWidth}
posHeight={posHeight}
isDragging={isDragging}
@@ -585,6 +502,14 @@ function RenderPdf({
handleNameModal={handleNameModal}
setTempSignerId={setTempSignerId}
uniqueId={uniqueId}
handleTextSettingModal={
handleTextSettingModal
}
scale={scale}
containerWH={containerWH}
pdfOriginalWH={pdfOriginalWH}
pageNumber={pageNumber}
setIsSelectId={setIsSelectId}
/>
</React.Fragment>
);
@@ -596,53 +521,55 @@ function RenderPdf({
);
})
: xyPostion.map((data, ind) => {
// signyourself flow
return (
<React.Fragment key={ind}>
{data.pageNumber === pageNumber &&
data.pos.map((pos) => {
return (
pos && (
<React.Fragment key={pos.key}>
<Placeholder
pos={pos}
setIsPageCopy={setIsPageCopy}
setSignKey={setSignKey}
handleDeleteSign={handleDeleteSign}
setIsStamp={setIsStamp}
handleTabDrag={handleTabDrag}
handleStop={(event, dragElement) =>
handleStop(event, dragElement, pos.type)
}
handleSignYourselfImageResize={
handleSignYourselfImageResize
}
index={index}
xyPostion={xyPostion}
setXyPostion={setXyPostion}
pdfOriginalWidth={pdfOriginalWidth}
containerWH={containerWH}
setIsSignPad={setIsSignPad}
isShowBorder={true}
isSignYourself={true}
xPos={xPos}
yPos={yPos}
posWidth={posWidth}
posHeight={posHeight}
pdfDetails={pdfDetails[0]}
isDragging={isDragging}
setIsInitial={setIsInitial}
setWidgetType={setWidgetType}
setSelectWidgetId={setSelectWidgetId}
selectWidgetId={selectWidgetId}
handleUserName={handleUserName}
setIsCheckbox={setIsCheckbox}
setValidateAlert={setValidateAlert}
setCurrWidgetsDetails={
setCurrWidgetsDetails
}
/>
</React.Fragment>
)
<React.Fragment key={pos.key}>
<Placeholder
pos={pos}
setIsPageCopy={setIsPageCopy}
setSignKey={setSignKey}
handleDeleteSign={handleDeleteSign}
setIsStamp={setIsStamp}
handleTabDrag={handleTabDrag}
handleStop={(event, dragElement) =>
handleStop(event, dragElement, pos.type)
}
handleSignYourselfImageResize={
handleSignYourselfImageResize
}
index={index}
xyPostion={xyPostion}
setXyPostion={setXyPostion}
setIsSignPad={setIsSignPad}
isShowBorder={true}
isSignYourself={true}
posWidth={posWidth}
posHeight={posHeight}
pdfDetails={pdfDetails[0]}
isDragging={isDragging}
setIsInitial={setIsInitial}
setWidgetType={setWidgetType}
setSelectWidgetId={setSelectWidgetId}
selectWidgetId={selectWidgetId}
handleUserName={handleUserName}
setIsCheckbox={setIsCheckbox}
setValidateAlert={setValidateAlert}
setCurrWidgetsDetails={
setCurrWidgetsDetails
}
handleTextSettingModal={
handleTextSettingModal
}
scale={scale}
containerWH={containerWH}
pdfOriginalWH={pdfOriginalWH}
pageNumber={pageNumber}
/>
</React.Fragment>
);
})}
</React.Fragment>
@@ -652,11 +579,7 @@ function RenderPdf({
{/* this component for render pdf document is in middle of the component */}
<Document
onLoadError={() => {
const load = {
status: false,
type: "failed"
};
setPdfLoadFail(load);
setPdfLoad(false);
}}
loading={"Loading Document.."}
onLoadSuccess={pageDetails}
@@ -674,17 +597,18 @@ function RenderPdf({
: pdfDetails[0].URL
}
>
{Array.from(new Array(numPages), (el, index) => (
<Page
key={index}
pageNumber={pageNumber}
renderAnnotationLayer={false}
renderTextLayer={false}
onGetAnnotationsError={(error) => {
console.log("annotation error", error);
}}
/>
))}
<Page
key={index}
width={containerWH.width}
scale={scale || 1}
className={"-z-[1]"} // when user zoom-in in tablet widgets move backward that's why pass -z-[1]
pageNumber={pageNumber}
renderAnnotationLayer={false}
renderTextLayer={false}
onGetAnnotationsError={(error) => {
console.log("annotation error", error);
}}
/>
</Document>
</div>
</RSC>
+96 -191
View File
@@ -1,7 +1,5 @@
import React, { useRef, useState, useEffect } from "react";
import SignatureCanvas from "react-signature-canvas";
import { themeColor } from "../../constant/const";
function SignPad({
isSignPad,
isStamp,
@@ -62,7 +60,6 @@ function SignPad({
} else if (isStamp) {
setImage("");
}
setIsSignImg("");
} else if (isTab === "uploadImage") {
setImage("");
@@ -70,29 +67,23 @@ function SignPad({
// setIsInitial(false);
};
//function for set signature url
const handleSignatureChange = () => {
setSignature(canvasRef.current.toDataURL());
setIsSignImg(canvasRef.current.toDataURL());
const handleSignatureChange = (data) => {
setSignature(data);
setIsSignImg(data);
};
//save button component
const SaveBtn = () => {
return (
<div style={{ marginTop: "2px" }}>
<div>
{(isTab === "draw" || isTab === "uploadImage") && (
<button
style={{
color: "black",
border: "1px solid #ccc"
}}
type="button"
className="finishBtn saveBtn"
className="op-btn op-btn-ghost mr-1 mt-[2px]"
onClick={() => handleClear()}
>
Clear
</button>
)}
<button
onClick={() => {
setCurrWidgetsDetails({});
@@ -107,8 +98,15 @@ function SignPad({
} else {
if (isTab === "type") {
setIsSignImg("");
onSaveSign(null, false, textWidth, textHeight);
onSaveSign(
null,
false,
!isInitial && textWidth > 150 ? 150 : textWidth,
!isInitial && textHeight > 35 ? 35 : textHeight
);
} else {
setIsSignImg("");
canvasRef.current.clear();
onSaveSign(signatureType);
}
}
@@ -127,18 +125,21 @@ function SignPad({
setSignValue("");
setIsStamp(false);
}}
style={{
background: themeColor,
color: "white"
}}
disabled={
isSignImg || image || isDefaultSign || textWidth ? false : true
}
type="button"
className={
className={`${
isSignImg || image || isDefaultSign || textWidth
? "finishBtn saveBtn"
: "disabledFinish saveBtn"
? ""
: "pointer-events-none"
} op-btn op-btn-primary shadow-lg`}
disabled={
(isTab === "draw" && isSignImg) ||
(isTab === "image" && image) ||
(isTab === "mysignature" && isDefaultSign) ||
(isTab === "type" && textWidth)
? false
: image
? false
: true
}
>
Save
@@ -152,7 +153,6 @@ function SignPad({
const isWidgetType = currWidgetsDetails?.type;
const signatureType = currWidgetsDetails?.signatureType;
const url = currWidgetsDetails?.SignUrl;
//checking widget type and draw type signature url
if (isInitial) {
if (isWidgetType === "initials" && signatureType === "draw" && url) {
@@ -167,8 +167,8 @@ function SignPad({
}
}
const trimmedName = currentUserName.trim();
const firstCharacter = trimmedName.charAt(0);
const trimmedName = currentUserName && currentUserName.trim();
const firstCharacter = trimmedName?.charAt(0);
const userName = isInitial ? firstCharacter : currentUserName;
setSignValue(userName);
setFontSelect("Fasthand");
@@ -206,7 +206,6 @@ function SignPad({
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isTab]);
//function for convert input text value in image
const convertToImg = async (fontStyle, text, color) => {
//get text content to convert in image
@@ -214,13 +213,13 @@ function SignPad({
const fontfamily = fontStyle
? fontStyle
: fontSelect
? fontSelect
: "Fasthand";
? fontSelect
: "Fasthand";
const fontSizeValue = "40px";
//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.font = `${fontSizeValue} ${fontfamily}`; // here put your text size and font family
span.style.color = color ? color : penColor;
span.style.display = "hidden";
document.body.appendChild(span); // Replace 'container' with the ID of the container element
@@ -230,7 +229,8 @@ function SignPad({
// Draw the text content on the canvas
const ctx = canvasElement.getContext("2d");
const pixelRatio = window.devicePixelRatio || 1;
const width = span.offsetWidth;
const addExtraWidth = isInitial ? 10 : 50;
const width = span.offsetWidth + addExtraWidth;
const height = span.offsetHeight;
setTextWidth(width);
setTextHeight(height);
@@ -256,7 +256,7 @@ function SignPad({
const PenColorComponent = (props) => {
return (
<div style={{ display: "flex", flexDirection: "row" }}>
<div className="flex flex-row items-start">
{allColor.map((data, key) => {
return (
<i
@@ -267,10 +267,10 @@ function SignPad({
key === 0 && penColor === "blue"
? "2px solid blue"
: key === 1 && penColor === "red"
? "2px solid red"
: key === 2 && penColor === "black"
? "2px solid black"
: "2px solid white"
? "2px solid red"
: key === 2 && penColor === "black"
? "2px solid black"
: "2px solid white"
}}
onClick={() => {
props?.convertToImg &&
@@ -284,7 +284,7 @@ function SignPad({
}
}}
key={key}
className="fa solid fa-pen-nib"
className="fa-light fa-pen-nib"
width={20}
height={20}
></i>
@@ -296,34 +296,16 @@ function SignPad({
return (
<div>
{isSignPad && (
<div className="modaloverlay">
<div className="modalcontainer">
<div
className="modalheader"
style={{ padding: "0 13px", marginTop: "5px" }}
>
<div className="modaltitle">
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
background: "white",
marginTop: "3px"
}}
>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-around",
alignItems: "end",
gap: 10
}}
>
<div className="op-modal op-modal-open">
<div className="op-modal-box px-[13px] pt-2 pb-0">
<div className="flex justify-between text-base-content items-center">
<div className="text-[1.2rem]">
<div className="flex flex-row justify-between mt-[3px]">
<div className="flex flex-row justify-between gap-[5px] md:gap-[8px] text-[11px] md:text-base">
{isStamp ? (
<span style={{ color: themeColor }} className="signTab">
{widgetType === "image"
<span className="text-base-content font-bold text-lg">
{widgetType === "image" ||
currWidgetsDetails?.type === "image"
? "Upload image"
: "Upload stamp image"}
</span>
@@ -336,24 +318,18 @@ function SignPad({
setIsImageSelect(false);
setIsTab("draw");
setImage();
if (isSignImg) {
setSignature(isSignImg);
}
}}
style={{
color: isTab === "draw" ? themeColor : "#515252",
marginLeft: "2px"
}}
className="signTab"
className={`${
isTab === "draw"
? "op-link-primary"
: "no-underline"
} op-link underline-offset-8 ml-[2px]`}
>
Draw
</span>
<div
style={{
border:
isTab === "draw"
? "1.5px solid #108783"
: "1.5px solid #ffffff"
}}
></div>
</div>
<div>
<span
@@ -363,22 +339,14 @@ function SignPad({
setIsTab("uploadImage");
setSignatureType("");
}}
style={{
color:
isTab === "uploadImage" ? themeColor : "#515252"
}}
className="signTab"
className={`${
isTab === "uploadImage"
? "op-link-primary"
: "no-underline"
} op-link underline-offset-8 ml-[2px]`}
>
Upload Image
</span>
<div
style={{
border:
isTab === "uploadImage"
? "1.5px solid #108783"
: "1.5px solid #ffffff"
}}
></div>
</div>
<div>
<span
@@ -389,23 +357,14 @@ function SignPad({
setSignatureType("");
setImage();
}}
style={{
color: isTab === "type" ? themeColor : "#515252",
marginLeft: "2px"
}}
className="signTab"
className={`${
isTab === "type"
? "op-link-primary"
: "no-underline"
} op-link underline-offset-8 ml-[2px]`}
>
Type
</span>
<div
style={{
border:
isTab === "type"
? "1.5px solid #108783"
: "1.5px solid #ffffff"
}}
></div>
</div>
{!isInitial && defaultSign ? (
<div>
@@ -417,24 +376,14 @@ function SignPad({
setSignatureType("");
setImage();
}}
style={{
color:
isTab === "mysignature"
? themeColor
: "#515252"
}}
className="signTab"
className={`${
isTab === "mysignature"
? "op-link-primary"
: "no-underline"
} op-link underline-offset-8 ml-[2px]`}
>
My Signature
</span>
<div
style={{
border:
isTab === "mysignature"
? "1.5px solid #108783"
: "1.5px solid #ffffff"
}}
></div>
</div>
) : (
isInitial &&
@@ -448,24 +397,14 @@ function SignPad({
setSignatureType("");
setImage();
}}
style={{
color:
isTab === "mysignature"
? themeColor
: "#515252"
}}
className="signTab"
className={`${
isTab === "mysignature"
? "op-link-primary"
: "no-underline"
} op-link underline-offset-8 ml-[2px]`}
>
My Initials
</span>
<div
style={{
border:
isTab === "mysignature"
? "1.5px solid #108783"
: "1.5px solid #ffffff"
}}
></div>
</div>
)
)}
@@ -475,8 +414,7 @@ function SignPad({
</div>
</div>
<div
className="closebtn"
style={{ color: "black" }}
className="text-[1.5rem] cursor-pointer"
onClick={() => {
setPenColor("blue");
setIsSignPad(false);
@@ -493,10 +431,10 @@ function SignPad({
&times;
</div>
</div>
<div style={{ height: "100%", padding: 20 }}>
<div className="p-[20px] h-full">
{isDefaultSign ? (
<>
<div style={{ display: "flex", justifyContent: "center" }}>
<div className="flex justify-center">
<div
style={{
border: "1.3px solid #007bff",
@@ -514,24 +452,19 @@ function SignPad({
>
<img
alt="stamp img"
style={{
width: "100%",
height: "100%",
background: "rgb(255, 255, 255)",
objectFit: "contain"
}}
className="w-full h-full object-contain bg-white"
draggable="false"
src={isInitial ? myInitial : defaultSign}
/>
</div>
</div>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<div className="flex justify-end">
<SaveBtn />
</div>
</>
) : isImageSelect || isStamp ? (
!image ? (
<div style={{ display: "flex", justifyContent: "center" }}>
<div className="flex justify-center">
<div
style={{
border: "1.3px solid #007bff",
@@ -556,13 +489,13 @@ function SignPad({
ref={imageRef}
hidden
/>
<i className="fas fa-cloud-upload-alt uploadImgLogo"></i>
<div className="uploadImg">Upload</div>
<i className="fa-light fa-cloud-upload-alt uploadImgLogo"></i>
<div className="text-[10px]">Upload</div>
</div>
</div>
) : (
<>
<div style={{ display: "flex", justifyContent: "center" }}>
<div className="flex justify-center">
<div
style={{
border: "1.3px solid #007bff",
@@ -581,39 +514,26 @@ function SignPad({
ref={imageRef}
src={image.src}
draggable="false"
style={{
objectFit: "contain",
height: "100%",
width: "100%"
}}
className=" object-contain h-full w-full"
/>
</div>
</div>
<div
style={{ display: "flex", justifyContent: "flex-end" }}
>
<div className="flex justify-end">
<SaveBtn />
</div>
</>
)
) : isTab === "type" ? (
<div>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center"
}}
>
<span className="signatureText">
<div className="flex justify-between items-center">
<span className="mr-[5px] text-[12px]">
{isInitial ? "Initials" : "Signature"}:
</span>
<input
maxLength={isInitial ? 3 : 30}
style={{ fontFamily: fontSelect, color: penColor }}
type="text"
className="signatureInput"
className="ml-1 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-[20px]"
placeholder="Your signature"
value={signValue}
onChange={(e) => {
@@ -622,8 +542,7 @@ function SignPad({
}}
/>
</div>
<div className="fontOptionContainer">
<div className="border-[1px] border-[#d6d3d3] mt-[10px] ml-[5px]">
{fontOptions.map((font, ind) => {
return (
<div
@@ -653,21 +572,14 @@ function SignPad({
})}
</div>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
marginTop: "10px"
}}
>
<div className="flex flex-row justify-between mt-[10px]">
<PenColorComponent convertToImg={convertToImg} />
<SaveBtn />
</div>
</div>
) : (
<>
<div style={{ display: "flex", justifyContent: "center" }}>
<div className="flex justify-center">
<SignatureCanvas
ref={canvasRef}
penColor={penColor}
@@ -682,19 +594,12 @@ function SignPad({
}}
backgroundColor="rgb(255, 255, 255)"
onEnd={() =>
handleSignatureChange(canvasRef.current.toDataURL())
handleSignatureChange(canvasRef.current?.toDataURL())
}
dotSize={1}
/>
</div>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
marginTop: "10px"
}}
>
<div className="flex flex-row justify-between mt-[10px]">
<PenColorComponent />
<SaveBtn />
</div>
+13 -42
View File
@@ -1,5 +1,4 @@
import React from "react";
import { themeColor } from "../../constant/const";
import "../../styles/signature.css";
function Signedby({ pdfDetails }) {
const getFirstLetter = (name) => {
@@ -8,52 +7,24 @@ function Signedby({ pdfDetails }) {
};
return (
<div className="signerComponent">
<div
style={{
background: themeColor,
color: "white"
}}
className="signedStyle"
>
<div className="hidden md:block w-full h-full bg-base-100">
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
Signed By
</div>
<div style={{ marginTop: "2px", background: "white" }}>
<div
style={{
display: "flex",
flexDirection: "row",
padding: "10px",
background: "#93a3db"
}}
>
<div
className="signerStyle"
style={{
background: "#abd1d0",
width: 20,
height: 20,
display: "flex",
borderRadius: 30 / 2,
justifyContent: "center",
alignItems: "center",
marginRight: "20px",
marginTop: "5px"
}}
>
<span
style={{
fontSize: "8px",
textAlign: "center",
fontWeight: "bold"
}}
>
<div className="mt-[2px] bg-base-100">
<div className="bg-[#93a3db] rounded-xl mx-1 flex flex-row items-center py-[10px]">
<div className="bg-[#576081] flex w-[30px] h-[30px] rounded-full justify-center items-center mx-1">
<span className="text-[12px] text-center font-bold text-white uppercase">
{getFirstLetter(pdfDetails.ExtUserPtr.Name)}
</span>
</div>
<div style={{ display: "flex", flexDirection: "column" }}>
<span className="userName">{pdfDetails.ExtUserPtr.Name}</span>
<span className="useEmail">{pdfDetails.ExtUserPtr.Email}</span>
<div className="flex flex-col">
<span className="text-[12px] font-bold text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
{pdfDetails.ExtUserPtr.Name}
</span>
<span className="text-[10px] font-medium text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
{pdfDetails.ExtUserPtr.Email}
</span>
</div>
</div>
</div>
@@ -0,0 +1,55 @@
import React from "react";
import { darkenColor, getFirstLetter } from "../../constant/Utils";
function SignerListComponent(props) {
const checkSignerBackColor = (obj) => {
if (obj) {
let data = "";
if (obj?.Id) {
data = props.signerPos.filter((data) => data.Id === obj.Id);
} else {
data = props.signerPos.filter(
(data) => data.signerObjId === obj.objectId
);
}
return data && data.length > 0 && data[0].blockColor;
}
};
const checkUserNameColor = (obj) => {
const getBackColor = checkSignerBackColor(obj);
if (getBackColor) {
const color = darkenColor(getBackColor, 0.4);
return color;
} else {
return "#abd1d0";
}
};
return (
<div
className="rounded-xl mx-1 flex flex-row items-center py-[10px] mt-1"
style={{ background: checkSignerBackColor(props.obj) }}
>
<div
style={{ background: checkUserNameColor(props.obj) }}
className="flex w-[30px] h-[30px] rounded-full justify-center items-center mx-1"
>
<span className="text-[12px] text-center font-bold text-black uppercase">
{getFirstLetter(
props.obj?.Name || props.obj?.email || props.obj?.Role
)}
</span>
</div>
<div className="flex flex-col">
<span className="text-[12px] font-bold text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
{props.obj?.Name || props?.obj?.Role}
</span>
<span className="text-[10px] font-medium text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
{props.obj?.Email || props.obj?.email}
</span>
</div>
</div>
);
}
export default SignerListComponent;
@@ -1,39 +1,26 @@
import React from "react";
import { themeColor } from "../../constant/const";
import RecipientList from "./RecipientList";
import { Tooltip } from "react-tooltip";
function SignerListPlace(props) {
return (
<div>
<div
style={{
background: themeColor,
padding: "5px"
}}
>
<span className="signedStyle">
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
<span className="relative">
{props.title ? props.title : "Recipients"}
<span className="absolute text-xs z-[30] mt-1 ml-0.5">
{props?.title === "Roles" && (
<>
<a data-tooltip-id="my-tooltip">
<sup>
<i
className="fa-solid fa-question rounded-full"
style={{
borderColor: "white",
color: "white",
fontSize: 11,
borderWidth: 1.5,
padding: "1px 3px"
}}
></i>
<i className="fa-light fa-question rounded-full border-[1px] border-base-content text-[11px] py-[1px] px-[3px]"></i>
</sup>
</a>
<Tooltip id="my-tooltip">
<div className="max-w-[450px]">
<p className="font-bold">What are template roles?</p>
<Tooltip id="my-tooltip" className="z-[100]">
<div className="max-w-[450px] 2xl:max-w-[500px] 2xl:text-[20px] p-[1px]">
<p className="font-bold pb-[1px]">
What are template roles?
</p>
<p>
Begin by specifying each role needed for the completion of
the document. Think about the parties involved in the
@@ -68,36 +55,32 @@ function SignerListPlace(props) {
</span>
</span>
</div>
<div className="signerList">
<div className="overflow-auto hide-scrollbar max-h-[180px]">
<RecipientList {...props} />
</div>
{props.handleAddSigner ? (
<div
data-tut="reactourAddbtn"
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
onClick={() => props.handleAddSigner()}
style={{
opacity: props.isMailSend && "0.5",
pointerEvents: props.isMailSend && "none"
}}
>
<i className="fa-solid fa-plus"></i>
<span style={{ marginLeft: 2 }}>Add role</span>
</div>
) : (
<div
data-tut="reactourAddbtn"
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
onClick={() => props.setIsAddSigner(true)}
style={{
opacity: props.isMailSend && "0.5",
pointerEvents: props.isMailSend && "none"
}}
>
<i className="fa-solid fa-plus"></i>
<span style={{ marginLeft: 2 }}>Add recipients</span>
</div>
)}
<div className="mx-1">
{props.handleAddSigner ? (
<div
role="button"
data-tut="reactourAddbtn"
disabled={props?.isMailSend ? true : false}
className="op-btn op-btn-accent op-btn-outline w-full mt-[14px]"
onClick={() => props.handleAddSigner()}
>
<i className="fa-light fa-plus"></i> Add role
</div>
) : (
<div
role="button"
data-tut="addRecipient"
className="op-btn op-btn-accent op-btn-outline w-full mt-[14px]"
disabled={props?.isMailSend ? true : false}
onClick={() => props.setIsAddSigner(true)}
>
<i className="fa-light fa-plus"></i> Add recipients
</div>
)}
</div>
</div>
);
}
@@ -0,0 +1,77 @@
import React from "react";
import ModalUi from "../../primitives/ModalUi";
import { fontColorArr, fontsizeArr } from "../../constant/Utils";
function TextFontSetting(props) {
return (
<ModalUi
headerColor={"#dc3545"}
isOpen={props.isTextSetting}
reduceWidth={"max-w-[350px]"}
title={"Text field"}
handleClose={() => props.setIsTextSetting(false)}
>
<div className="h-full p-[20px]">
<div className="flex items-center">
<span>Font size:</span>
<select
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
value={
props.fontSize ||
props.currWidgetsDetails?.options?.fontSize ||
"12"
}
onChange={(e) => props.setFontSize(e.target.value)}
>
{fontsizeArr.map((size, ind) => {
return (
<option className="text-[13px]" value={size} key={ind}>
{size}
</option>
);
})}
</select>
<div className="flex flex-row gap-1 items-center ml-4">
<span>color: </span>
<select
value={
props.fontColor ||
props.currWidgetsDetails?.options?.fontColor ||
"black"
}
onChange={(e) => props.setFontColor(e.target.value)}
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
>
{fontColorArr.map((color, ind) => {
return (
<option value={color} key={ind}>
{color}
</option>
);
})}
</select>
<span
style={{
background:
props.fontColor ||
props.currWidgetsDetails?.options?.fontColor
}}
className="w-5 h-[19px] ml-1"
></span>
</div>
</div>
<div className="h-[1px] bg-[#9f9f9f] w-full mt-[15px] mb-2"></div>
<button
onClick={() => props.handleSaveFontSize()}
type="button"
className="op-btn op-btn-primary mt-2"
>
save
</button>
</div>
</ModalUi>
);
}
export default TextFontSetting;
+15 -33
View File
@@ -1,16 +1,13 @@
import React from "react";
import { rejectBtn, submitBtn, themeColor } from "../../constant/const";
import Loader from "../../primitives/Loader";
function VerifyEmail(props) {
return (
<div className="bg-black bg-opacity-[75%] absolute z-[999] flex flex-col items-center justify-center w-full h-full rounded">
<div className="bg-white rounded outline-none md:w-[40%] w-[80%]">
<div
style={{ backgroundColor: themeColor }}
className=" text-white p-[10px] rounded-t"
>
<dialog className="op-modal op-modal-open absolute z-[1999]">
<div className="md:w-[40%] w-[80%] op-modal-box p-0 overflow-y-auto hide-scrollbar text-sm">
<h3 className="font-bold text-lg pt-[15px] px-[20px] text-base-content">
OTP verification
</div>
</h3>
{props.isVerifyModal ? (
<form
onSubmit={(e) => {
@@ -18,25 +15,24 @@ function VerifyEmail(props) {
props.handleVerifyEmail(e);
}}
>
<div className="px-6 py-3">
<div className="px-6 py-3 text-base-content">
<label className="mb-2">Enter OTP</label>
<input
required
type="tel"
pattern="[0-9]{4}"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
placeholder="Enter OTP received over email"
value={props.otp}
onChange={(e) => props.setOtp(e.target.value)}
/>
</div>
<hr />
<div className="px-6 my-3">
<button type="submit" className={submitBtn}>
<button type="submit" className="op-btn op-btn-primary">
Verify
</button>
<button
className={`${rejectBtn} ml-2`}
className="op-btn op-btn-secondary ml-2"
onClick={(e) => props.handleResend(e)}
>
Resend
@@ -44,29 +40,15 @@ function VerifyEmail(props) {
</div>
</form>
) : props.otpLoader ? (
<div
style={{
height: "150px",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
<div className="h-[150px] flex items-center justify-center">
<Loader />
</div>
) : (
<div className="px-6 py-3">
<p className="mb-2">Please verify your email !</p>
<hr />
<div className="px-6 py-3 text-base-content">
<p className="mb-2 text-sm">Please verify your email !</p>
<div className="px-0 mt-3">
<button
className={submitBtn}
className="op-btn op-btn-primary"
type="submit"
onClick={() => {
props.handleVerifyBtn();
@@ -78,7 +60,7 @@ function VerifyEmail(props) {
</div>
)}
</div>
</div>
</dialog>
);
}
@@ -9,7 +9,6 @@ import {
textWidget,
widgets
} from "../../constant/Utils";
import { themeColor } from "../../constant/const";
function WidgetComponent({
dragSignature,
signRef,
@@ -38,11 +37,10 @@ function WidgetComponent({
sendInOrder,
isTemplateFlow,
setBlockColor,
blockColor,
setIsAddSigner
setIsAddSigner,
uniqueId
}) {
const [isSignersModal, setIsSignersModal] = useState(false);
const [, dropdown] = useDrag({
type: "BOX",
item: {
@@ -188,7 +186,6 @@ function WidgetComponent({
const isMobile = window.innerWidth < 767;
const scrollContainerRef = useRef(null);
const [widget, setWidget] = useState([]);
const color = [
"#93a3db",
"#e6c3db",
@@ -246,127 +243,72 @@ function WidgetComponent({
? textWidgetData
: widget;
const handleSelectRecipient = () => {
if (
signersdata[isSelectListId]?.Email ||
signersdata[isSelectListId]?.Role
) {
const userData =
signersdata[isSelectListId]?.Name || signersdata[isSelectListId]?.Role;
const name =
userData?.length > 20 ? `${userData.slice(0, 20)}...` : userData;
return name;
}
};
return (
<>
{isMobile ? (
!isMailSend && (
<div
data-tut={dataTut}
id="navbar"
className="stickyfooter"
style={{ width: window.innerWidth + "px" }}
>
<div id="navbar" className="fixed z-[99] bottom-0 right-0 w-full">
{isSigners && (
<div
data-tut={dataTut}
style={{
background: blockColor
? blockColor
: isSelectListId
? color[isSelectListId % color.length]
: color[0],
padding: "10px 20px",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
onClick={() => handleModal()}
>
<span
style={{
fontSize: "13px",
fontWeight: "700",
textAlign: "center"
}}
>
{title ? title : "Recipient"}
</span>
<span
style={{
fontSize: "13px",
fontWeight: "700",
display: "flex",
alignItems: "center"
}}
>
{signersdata[isSelectListId]?.Role && (
<div>
{signersdata[isSelectListId]?.Name ? (
<>
:{" "}
{signersdata[isSelectListId]?.Name?.length > 12
? `${signersdata[isSelectListId].Name.slice(
0,
12
)}...`
: signersdata[isSelectListId]?.Name}
</>
) : (
<>
:{" "}
{signersdata[isSelectListId]?.Role?.length > 12
? `${signersdata[isSelectListId].Role.slice(
0,
12
)}...`
: signersdata[isSelectListId]?.Role}
</>
)}
</div>
)}
<div style={{ marginLeft: 6, fontSize: 16 }}>
<i className="fa-solid fa-angle-down"></i>
</div>
</span>
</div>
)}
{handleAddSigner ? (
<div
data-tut="reactourAddbtn"
style={{
margin: "5px 0 5px 0",
backgroundColor: themeColor,
color: "white"
}}
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
onClick={() => handleAddSigner()}
>
<i className="fa-solid fa-plus"></i>
<span style={{ marginLeft: 2 }}>Add role</span>
</div>
) : (
setIsAddSigner && (
<div
data-tut="reactourAddbtn"
style={{
margin: "5px 0 5px 0",
backgroundColor: themeColor,
color: "white"
}}
className="p-[10px] my-[2px] flex flex-row items-center justify-center border-[1px] border-[#47a3ad] hover:bg-[#47a3ad] text-[#47a3ad] hover:text-white cursor-pointer"
onClick={() => setIsAddSigner(true)}
>
<i className="fa-solid fa-plus"></i>
<span style={{ marginLeft: 2 }}>Add recipients</span>
<div className="w-full mb-[5px] flex justify-center items-center gap-1">
<div className="w-full ml-[5px]" onClick={() => handleModal()}>
<select
data-tut="recipientArea"
className="w-full op-select op-select-bordered pointer-events-none"
value={handleSelectRecipient()}
style={{
backgroundColor: isSelectListId
? color[isSelectListId % color.length]
: color[0]
}}
>
<option value={handleSelectRecipient()}>
{handleSelectRecipient()}
</option>
</select>
</div>
)
<div className="w-[18%]">
{handleAddSigner ? (
<button
data-tut="reactourAddbtn"
onClick={() => handleAddSigner()}
className="op-btn op-btn-accent"
>
<i className="fa-light fa-plus "></i>
</button>
) : (
setIsAddSigner && (
<button
data-tut="addRecipient"
onClick={() => setIsAddSigner(true)}
className="op-btn op-btn-accent"
>
<i className="fa-light fa-plus"></i>
</button>
)
)}
</div>
</div>
)}
<div
data-tut="addWidgets"
ref={scrollContainerRef}
style={{
background: "white",
borderTop: `2px solid ${themeColor}`
}}
className="bg-base-100 border-[2px] border-t-primary"
>
<div
style={{
display: "flex",
overflowX: "scroll",
whiteSpace: "nowrap",
padding: "10px 5px 10px 1px"
}}
>
<div className="flex whitespace-nowrap overflow-x-scroll pt-[10px] pb-[5px] pr-[5px]">
<WidgetList
updateWidgets={updateWidgets}
handleDivClick={handleDivClick}
@@ -383,20 +325,18 @@ function WidgetComponent({
) : (
<div
data-tut={dataTut}
className={
isMailSend ? "disabled signerComponent " : "signerComponent"
}
className={`${
isMailSend ? "bg-opacity-50 pointer-events-none" : ""
} hidden md:block h-full bg-base-100`}
>
<div
style={{
background: themeColor,
padding: "5px"
}}
>
<span className="signedStyle">Fields</span>
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
<span>Fields</span>
</div>
<div className="signLayoutContainer1">
<div
className="p-[15px] flex flex-col pt-4 2xl:m-5"
data-tut="addWidgets"
>
<WidgetList
updateWidgets={updateWidgets}
handleDivClick={handleDivClick}
@@ -413,7 +353,7 @@ function WidgetComponent({
handleClose={handleModal}
>
{signersdata.length > 0 ? (
<div style={{ maxHeight: "600px", overflow: "auto" }}>
<div className="max-h-[600px] overflow-auto pb-1">
<RecipientList
signerPos={signerPos}
signersdata={signersdata}
@@ -430,17 +370,11 @@ function WidgetComponent({
sendInOrder={sendInOrder}
setSignersData={setSignersData}
setBlockColor={setBlockColor}
uniqueId={uniqueId}
/>
</div>
) : (
<div
style={{
padding: 20,
fontSize: 15,
fontWeight: "500",
textAlign: "center"
}}
>
<div className=" p-[20px] text-[15px] font-medium text-center">
Please add a {title ? title : "recipients"}
</div>
)}
@@ -4,9 +4,9 @@ import { getWidgetType } from "../../constant/Utils";
function WidgetList(props) {
return props.updateWidgets.map((item, ind) => {
return (
<div key={ind} style={{ marginBottom: "5px" }}>
<div className="2xl:p-3 mb-[5px]" key={ind}>
<div
className="widgets"
className="select-none mx-[2px] md:mx-0 cursor-all-scroll"
onClick={() => {
props.addPositionOfSignature &&
props.addPositionOfSignature("onclick", item);
@@ -22,11 +22,10 @@ function WidgetList(props) {
}
}}
onMouseMove={props?.handleDivClick}
onMouseDown={() => {
props?.handleMouseLeave();
}}
onMouseDown={() => props?.handleMouseLeave()}
onTouchStart={props?.handleDivClick}
>
{item.ref && getWidgetType(item, props?.marginLeft)}
{item.ref && getWidgetType(item)}
</div>
</div>
);
@@ -2,10 +2,11 @@ import React, { useEffect, useState } from "react";
import ModalUi from "../../primitives/ModalUi";
import "../../styles/AddUser.css";
import RegexParser from "regex-parser";
import { textInputWidget } from "../../constant/Utils";
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
import { textInputWidget, textWidget } from "../../constant/Utils";
import Upgrade from "../../primitives/Upgrade";
import { isEnableSubscription } from "../../constant/const";
import Tooltip from "../../primitives/Tooltip";
import { fontColorArr, fontsizeArr } from "../../constant/Utils";
const WidgetNameModal = (props) => {
const [formdata, setFormdata] = useState({
@@ -22,7 +23,7 @@ const WidgetNameModal = (props) => {
useEffect(() => {
if (props.defaultdata) {
setFormdata({
name: props.defaultdata?.options?.name || props?.widgetName || "",
name: props.defaultdata?.options?.name || "",
defaultValue: props.defaultdata?.options?.defaultValue || "",
status: props.defaultdata?.options?.status || "required",
hint: props.defaultdata?.options?.hint || "",
@@ -34,11 +35,11 @@ const WidgetNameModal = (props) => {
} else {
setFormdata({
...formdata,
name: props.defaultdata?.options?.name || props?.widgetName || ""
name: props.defaultdata?.options?.name || ""
});
}
// eslint-disable-next-line
}, [props.defaultdata, props.widgetName]);
}, [props.defaultdata]);
const handleSubmit = (e) => {
e.preventDefault();
if (props.handleData) {
@@ -105,106 +106,96 @@ const WidgetNameModal = (props) => {
handleClose={props.handleClose && props.handleClose}
title={"Widget info"}
>
{(props.defaultdata?.type === textInputWidget ||
props.widgetName === textInputWidget) &&
!isEnableSubscription && (
<PremiumAlertHeader
message={
"Field validations are free in beta, this feature will incur a fee later."
}
/>
)}
<form
onSubmit={handleSubmit}
className={`${
props.defaultdata?.type === textInputWidget ||
props.widgetName === textInputWidget
? "pt-0"
: ""
} p-[20px]`}
props.defaultdata?.type === textInputWidget ? "pt-0" : ""
} p-[20px] text-base-content`}
>
<div className="form-section">
<label htmlFor="name" style={{ fontSize: 13 }}>
<div className="mb-[0.75rem] text-[13px]">
<label htmlFor="name">
Name
<span style={{ color: "red", fontSize: 13 }}> *</span>
<span className="text-[red]"> *</span>
</label>
<input
className="addUserInput"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
name="name"
value={formdata.name}
onChange={(e) => handleChange(e)}
required
/>
</div>
{(props.defaultdata?.type === textInputWidget ||
props.widgetName === textInputWidget) && (
{props.defaultdata?.type === textInputWidget && (
<>
<div className="form-section">
<label
htmlFor="textvalidate"
className={
!props.isSubscribe && isEnableSubscription && "disabled"
}
style={{ fontSize: 13 }}
>
Validation
</label>
{!props.isSubscribe && isEnableSubscription && <Upgrade />}
<div
className={
!props.isSubscribe && isEnableSubscription && "disabled"
}
style={{
display: "flex",
flexDirection: "row",
gap: 10,
marginBottom: "0.5rem"
}}
>
<div style={{ width: "100%", position: "relative" }}>
<input
className="relative z-20 w-[87%] md:w-[92%] p-2.5 border-[1px] border-[#d1d5db] rounded-l-md outline-none text-xs"
name="textvalidate"
placeholder="Enter custom expression"
value={formdata.textvalidate}
onChange={(e) => handleChange(e)}
// onBlur={() => handleBlurRegex()}
/>
<select
className="validationlist addUserInput"
name="textvalidate"
value={formdata.textvalidate}
onChange={(e) => handleChange(e)}
onBlur={() => handleBlurRegex()}
{isEnableSubscription && (
<div className="mb-[0.75rem]">
<div className="flex items-center gap-1">
<label
htmlFor="textvalidate"
className={`${
!props.isSubscribe && isEnableSubscription
? "bg-opacity-50 pointer-events-none"
: ""
} text-[13px]`}
>
<option
disabled={formdata?.textvalidate}
style={{ fontSize: "13px" }}
Validation
</label>
<Tooltip
url={"https://www.w3schools.com/jsref/jsref_obj_regexp.asp"}
/>
{!props.isSubscribe && isEnableSubscription && <Upgrade />}
</div>
<div
className={`${
!props.isSubscribe && isEnableSubscription
? "bg-opacity-50 pointer-events-none"
: ""
} flex flex-row gap-[10px] mb-[0.5rem]`}
>
<div className="w-full relative group">
<input
className="z-20 relative op-input op-input-bordered rounded-r-none op-input-sm focus:outline-none group-hover:border-base-content w-[87%] md:w-[92%] text-xs"
name="textvalidate"
placeholder="Enter custom regular expression"
value={formdata.textvalidate}
onChange={(e) => handleChange(e)}
// onBlur={() => handleBlurRegex()}
/>
<select
className="validationlist op-input op-input-bordered op-input-sm focus:outline-none group-hover:border-base-content w-full text-xs"
name="textvalidate"
value={formdata.textvalidate}
onChange={(e) => handleChange(e)}
onBlur={() => handleBlurRegex()}
>
Select...
</option>
{inputOpt.map((data, ind) => {
return (
<option
style={{ fontSize: "13px" }}
key={ind}
value={data}
>
{data}
</option>
);
})}
</select>
<option
disabled={formdata?.textvalidate}
className="text-[13px]"
>
Select...
</option>
{inputOpt.map((data, ind) => {
return (
<option
className="text-[13px]"
key={ind}
value={data}
>
{data}
</option>
);
})}
</select>
</div>
</div>
</div>
</div>
<div className="form-section">
<label htmlFor="name" style={{ fontSize: 13 }}>
)}
<div className="mb-[0.75rem]">
<label htmlFor="name" className="text-[13px]">
Default value
</label>
<input
className="addUserInput"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
name="defaultValue"
value={formdata.defaultValue}
onChange={(e) => handledefaultChange(e)}
@@ -222,37 +213,22 @@ const WidgetNameModal = (props) => {
style={{ fontSize: 12 }}
>
<i
className="fas fa-exclamation-circle"
style={{ color: "#fab005", fontSize: 15 }}
></i>{" "}
className="fa-light fa-exclamation-circle text-[15px]"
style={{ color: "#fab005" }}
></i>
invalid default value
</div>
)}
</div>
</>
)}
<div className="form-section">
<div
style={{
display: "flex",
flexDirection: "row",
gap: 10,
marginBottom: "0.5rem"
}}
>
<div className="mb-[0.75rem]">
<div className="flex flex-row gap-[10px] mb-[0.5rem]">
{statusArr.map((data, ind) => {
return (
<div
key={ind}
style={{
display: "flex",
flexDirection: "row",
gap: 5,
alignItems: "center"
}}
>
<div key={ind} className="flex flex-row gap-[5px] items-center">
<input
style={{ accentColor: "red", marginRight: "10px" }}
className="mr-[2px] op-radio op-radio-xs"
type="radio"
name="status"
onChange={() =>
@@ -262,45 +238,84 @@ const WidgetNameModal = (props) => {
formdata.status.toLowerCase() === data.toLowerCase()
}
/>
<div style={{ fontSize: "13px", fontWeight: "500" }}>
{data}
</div>
<div className="text-[13px] font-medium">{data}</div>
</div>
);
})}
</div>
</div>
{(props.defaultdata?.type === textInputWidget ||
props?.widgetName === textInputWidget) && (
<div className="form-section">
<label htmlFor="hint" style={{ fontSize: 13 }}>
{props.defaultdata?.type === textInputWidget && (
<div className="mb-[0.75rem]">
<label htmlFor="hint" className="text-[13px]">
Hint
</label>
<input
className="addUserInput"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
name="hint"
value={formdata.hint}
onChange={(e) => handleChange(e)}
/>
</div>
)}
<div
style={{
height: 1,
backgroundColor: "#b7b3b3",
width: "100%",
marginBottom: "16px"
}}
></div>
<button
style={{
color: "white",
padding: "5px 20px",
backgroundColor: "#32a3ac"
}}
type="submit"
className="finishBtn"
>
{[
textInputWidget,
textWidget,
"name",
"company",
"job title",
"email"
].includes(props.defaultdata?.type) && (
<div className="flex items-center mb-[0.75rem]">
<span>Font size:</span>
<select
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
value={
props.fontSize || props.defaultdata?.options?.fontSize || "12"
}
onChange={(e) => props.setFontSize(e.target.value)}
>
{fontsizeArr.map((size, ind) => {
return (
<option className="text-[13px]" value={size} key={ind}>
{size}
</option>
);
})}
</select>
<div className="flex flex-row gap-1 items-center ml-4">
<span>color: </span>
<select
value={
props.fontColor ||
props.defaultdata?.options?.fontColor ||
"black"
}
onChange={(e) => props.setFontColor(e.target.value)}
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
>
{fontColorArr.map((color, ind) => {
return (
<option value={color} key={ind}>
{color}
</option>
);
})}
</select>
<span
style={{
background:
props.fontColor ||
props.defaultdata?.options?.fontColor ||
"black"
}}
className="w-5 h-[19px] ml-1"
></span>
</div>
</div>
)}
<div className="h-[1px] w-full mb-[16px] bg-[#b7b3b3]"></div>
<button type="submit" className="op-btn op-btn-primary">
Save
</button>
</form>
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import Alert from "../../../primitives/Alert";
import Loader from "../../../primitives/Loader";
const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
const folderPtr = {
@@ -25,9 +26,13 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
if (parentFolderId) {
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
FolderQuery.notEqualTo("IsArchive", true);
FolderQuery.equalTo("CreatedBy", Parse.User.current());
} else {
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
FolderQuery.notEqualTo("IsArchive", true);
FolderQuery.equalTo("CreatedBy", Parse.User.current());
}
const res = await FolderQuery.find();
@@ -49,6 +54,7 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
const exsitQuery = new Parse.Query(folderCls);
exsitQuery.equalTo("Name", name);
exsitQuery.equalTo("Type", "Folder");
exsitQuery.notEqualTo("IsArchive", true);
if (parentFolderId) {
exsitQuery.equalTo("Folder", folderPtr);
}
@@ -110,20 +116,17 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
{isAlert && <Alert type={alert.type}>{alert.message}</Alert>}
<div id="createFolder" className="relative">
{isLoader && (
<div className="absolute h-full w-full flex justify-center items-center ">
<div
style={{ fontSize: "45px", color: "#3dd3e0" }}
className="loader-37"
></div>
<div className="absolute h-full w-full flex justify-center items-center">
<Loader />
</div>
)}
<h1 className="text-base font-semibold">Create Folder</h1>
<h1 className="text-base font-semibold mt-[0.4rem]">Create Folder</h1>
<div className="text-xs mt-2">
<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"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={name}
onChange={(e) => setName(e.target.value)}
required
@@ -134,7 +137,7 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
<select
value={selectedParent}
onChange={handleOptions}
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
>
<option>select</option>
{folderList.length > 0 &&
@@ -149,9 +152,9 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
<button
onClick={handleCreateFolder}
disabled={isLoader}
className="flex items-center rounded p-2 bg-[#32a3ac] text-white mt-3"
className="op-btn op-btn-primary op-btn-sm mt-3"
>
<i className="fa-solid fa-plus mr-1"></i>
<i className="fa-light fa-plus"></i>
<span>Create</span>
</button>
</div>
@@ -54,7 +54,7 @@ export default function DropboxChooser({ children, onSuccess, onCancel }) {
return (
<div onClick={handleChoose}>
{children || (
<button className="px-2 py-[2px] text-2xl rounded border-[1px] text-blue-400 border-gray-300 w-full">
<button className="cursor-pointer op-input op-input-bordered focus:outline-none hover:border-base-content max-h-[35px] max-w-[45px] flex justify-center items-center">
<i className="fa-brands fa-dropbox"></i>
</button>
)}
@@ -24,10 +24,14 @@ const FolderModal = (props) => {
const FolderQuery = new Parse.Query(props.folderCls);
if (folderPtr) {
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
FolderQuery.descending("Type");
FolderQuery.notEqualTo("IsArchive", true);
FolderQuery.equalTo("CreatedBy", Parse.User.current());
} else {
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
FolderQuery.descending("Type");
FolderQuery.notEqualTo("IsArchive", true);
FolderQuery.equalTo("CreatedBy", Parse.User.current());
}
const res = await FolderQuery.find();
@@ -141,14 +145,14 @@ const FolderModal = (props) => {
handleCreate();
};
return (
<div className="text-xs mt-2 ">
<div className="text-xs mt-2">
<ModalUi
title={"Select Folder"}
isOpen={props.isOpenModal}
handleClose={handleCancel}
>
<div className="w-full min-w-[300px] md:min-w-[500px] max-w-[500px] px-3">
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
<div className="pt-1 text-[#ac4848] text-[14px] font-[500]">
<span
className="cursor-pointer"
title="OpenSign™ Drive"
@@ -169,27 +173,50 @@ const FolderModal = (props) => {
{" / "}
</React.Fragment>
))}
<hr />
<hr className="bg-[#8a8a8a] mt-[0.750rem]" />
</div>
<div className="mt-2 mb-3">
<div className="max-h-[210px] overflow-auto">
{!isAdd &&
folderList.length > 0 &&
folderList.map((folder) => (
<div
key={folder.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>
{!isAdd && folderList.length > 0
? folderList.map((folder) => (
<div
key={folder.objectId}
className={`${
folder.Type === "Folder"
? "cursor-pointer"
: "cursor-default"
} border-b-[1px] border-[#8a8a8a] py-2 mb-0.5"`}
onClick={() =>
folder.Type === "Folder" && handleSelect(folder)
}
>
<div className="flex items-center gap-2">
{folder.Type === "Folder" ? (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
className="w-[1.4rem] h-[1.4rem] fill-current op-text-secondary"
>
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
</svg>
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 384 512"
className="w-[1.4rem] h-[1.4rem] fill-current op-text-primary"
>
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
</svg>
)}
<span className="font-semibold">{folder.Name}</span>
</div>
</div>
</div>
))}
))
: !isLoader && (
<div className="text-base-content text-center my-2">
No data found
</div>
)}
</div>
{isAdd && (
<CreateFolder
@@ -199,8 +226,8 @@ const FolderModal = (props) => {
/>
)}
{isLoader && (
<div className="flex justify-center">
<i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i>
<div className="flex justify-center my-4">
<i className="fa-light fa-spinner fa-spin-pulse text-[30px]"></i>
</div>
)}
</div>
@@ -208,22 +235,28 @@ const FolderModal = (props) => {
<hr />
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
<div
className="text-[30px] cursor-pointer text-[#32a3ac]"
className="op-btn op-btn-seconday op-btn-sm"
title="Save Here"
onClick={handleCreate}
>
{isAdd ? (
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
<>
<i className="fa-light fa-arrow-left" aria-hidden="true"></i>
<span className="text-xs">Back</span>
</>
) : (
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
<>
<i className="fa-light fa-square-plus" aria-hidden="true"></i>
<span className="">Add folder</span>
</>
)}
</div>
<div
className="text-[30px] cursor-pointer"
className="op-btn op-btn-primary op-btn-sm"
title="Save Here"
onClick={handleSubmit}
>
<i className="fas fa-save" aria-hidden="true"></i>
<i className="fa-light fa-save" aria-hidden="true"></i>Save here
</div>
</div>
</ModalUi>
@@ -44,10 +44,14 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
const FolderQuery = new Parse.Query(folderCls);
if (folderPtr) {
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
FolderQuery.notEqualTo("IsArchive", true);
FolderQuery.descending("Type");
FolderQuery.equalTo("CreatedBy", Parse.User.current());
} else {
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
FolderQuery.notEqualTo("IsArchive", true);
FolderQuery.descending("Type");
FolderQuery.equalTo("CreatedBy", Parse.User.current());
}
const res = await FolderQuery.find();
@@ -172,14 +176,16 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
<div className="relative max-w-sm">
<div
onClick={() => SetIsOpen(true)}
className=" cursor-pointer rounded px-[20px] py-[20px] bg-white border border-gray-200 shadow flex max-w-sm gap-8 items-center"
className="cursor-pointer rounded px-[20px] py-[20px] bg-base-100 border-[1px] border-base-200 shadow flex max-w-sm gap-8 items-center"
>
<div>
<i
className="far fa-folder-open text-[40px] text-[#33bbff]"
style={{ fontSize: "40px" }}
aria-hidden="true"
></i>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
className="w-[40px] h-[40px] fill-current op-text-secondary"
>
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
</svg>
</div>
<div className="font-semibold ">
<div className="flex items-center gap-2">
@@ -188,12 +194,9 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
? selectFolder.Name
: "OpenSign™ Drive"}
</p>
<div
className="text-black text-sm"
// onClick={() => SetIsOpen(true)}
>
<div className="text-black text-sm">
<i
className="fa fa-pencil cursor-pointer"
className="fa-light fa-pencil cursor-pointer"
title="Select Folder"
aria-hidden="true"
></i>
@@ -218,7 +221,7 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
handleClose={handleCancel}
>
<div className="w-full min-w-[300px] md:min-w-[500px] max-w-[500px] px-3">
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
<div className="pt-1 text-[#ac4848] text-[14px] font-[500]">
<span
className="cursor-pointer"
title="OpenSign™ Drive"
@@ -239,27 +242,50 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
{" / "}
</React.Fragment>
))}
<hr />
<hr className="bg-[#8a8a8a] mt-[0.750rem]" />
</div>
<div className="mt-2 mb-3">
<div className="mb-2">
<div className="max-h-[210px] overflow-auto">
{!isAdd &&
folderList.length > 0 &&
folderList.map((folder) => (
<div
key={folder.Name}
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer "
onClick={() => handleSelect(folder)}
>
<div className="flex items-center gap-2">
<i
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
aria-hidden="true"
></i>
<span className="font-semibold">{folder.Name}</span>
{!isAdd && folderList.length > 0
? folderList.map((folder) => (
<div
key={folder.objectId}
className={`${
folder.Type === "Folder"
? "cursor-pointer"
: "cursor-default"
} border-b-[1px] border-[#8a8a8a] py-2 mb-0.5"`}
onClick={() =>
folder.Type === "Folder" && handleSelect(folder)
}
>
<div className="flex items-center gap-2">
{folder.Type === "Folder" ? (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
className="w-[1.4rem] h-[1.4rem] fill-current op-text-secondary"
>
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
</svg>
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 384 512"
className="w-[1.4rem] h-[1.4rem] fill-current op-text-primary"
>
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
</svg>
)}
<span className="font-semibold">{folder.Name}</span>
</div>
</div>
</div>
))}
))
: !isLoader && (
<div className="text-base-content text-center my-2">
No data found
</div>
)}
</div>
{isAdd && (
<CreateFolder
@@ -269,8 +295,8 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
/>
)}
{isLoader && (
<div className="flex justify-center">
<i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i>
<div className="flex justify-center my-4">
<i className="fa-light fa-spinner fa-spin-pulse text-[30px]"></i>
</div>
)}
</div>
@@ -278,22 +304,28 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
<hr />
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
<div
className="text-[30px] cursor-pointer text-[#32a3ac]"
className="op-btn op-btn-seconday op-btn-sm"
title="Save Here"
onClick={handleCreate}
>
{isAdd ? (
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
<>
<i className="fa-light fa-arrow-left" aria-hidden="true"></i>
<span className="text-xs">Back</span>
</>
) : (
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
<>
<i className="fa-light fa-square-plus" aria-hidden="true"></i>
<span className="">Add folder</span>
</>
)}
</div>
<div
className="text-[30px] cursor-pointer"
className="op-btn op-btn-primary op-btn-sm"
title="Save Here"
onClick={handleSubmit}
>
<i className="fas fa-save" aria-hidden="true"></i>
<i className="fa-light fa-save" aria-hidden="true"></i>Save here
</div>
</div>
</ModalUi>
@@ -1,18 +1,7 @@
import React, { useState } from "react";
import Parse from "parse";
import "../../../styles/AddUser.css";
import AsyncSelect from "react-select/async";
const customStyles = {
control: (provided) => ({
...provided,
fontSize: "13px" // Font size for the control
}),
option: (provided) => ({
...provided,
fontSize: "13px" // Font size for the options
})
};
const SelectSigners = (props) => {
const [userList, setUserList] = useState([]);
const [selected, setSelected] = useState();
@@ -79,32 +68,44 @@ const SelectSigners = (props) => {
};
return (
<div className="addusercontainer">
<div className="form-wrapper">
<div className="form-section" style={{ marginBottom: 0 }}>
<label style={{ fontSize: 14, fontWeight: "700" }}>Choose User</label>
<div className="h-full px-[20px] py-[10px] text-base-content">
<div className="w-full mx-auto p-[8px]">
<div className="mb-0">
<label className="text-[14px] font-bold">Choose from contacts</label>
<AsyncSelect
cacheOptions
defaultOptions
value={selected}
loadingMessage={() => "Loading..."}
noOptionsMessage={() => "User not Found"}
noOptionsMessage={() => "Contact not found"}
loadOptions={loadOptions}
onChange={handleOptions}
styles={customStyles}
unstyled
classNames={{
control: () =>
"op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full h-full text-[11px]",
valueContainer: () =>
"flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]",
multiValue: () => "op-badge op-badge-primary h-full text-[11px]",
multiValueLabel: () => "mb-[2px]",
menu: () =>
"mt-1 shadow-md rounded-lg bg-base-200 text-base-content",
menuList: () => "shadow-md rounded-lg overflow-hidden",
option: () =>
"bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2",
noOptionsMessage: () => "p-2 bg-base-200 rounded-lg m-1 p-2"
}}
/>
</div>
{isError ? (
<p style={{ color: "red", fontSize: "12px", margin: "5px" }}>
Please select signer
</p>
) : (
<p style={{ color: "transparent", fontSize: "12px", margin: "5px" }}>
.
</p>
)}
<p
className={`${
isError ? "text-[red]" : "text-transparent"
} text-[11px] ml-[6px] my-[2px]`}
>
Please select signer
</p>
<div>
<button className="submitbutton" onClick={() => handleAdd()}>
<button className="op-btn op-btn-primary" onClick={() => handleAdd()}>
Submit
</button>
</div>
@@ -1,15 +1,30 @@
import React, { useState, useEffect } from "react";
import Select from "react-select";
import AddSigner from "../../AddSigner";
import Modal from "react-modal";
import Parse from "parse";
import Tooltip from "../../../primitives/Tooltip";
import { createPortal } from "react-dom";
function arrayMove(array, from, to) {
array = array.slice();
array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]);
return array;
}
const AddSignerModal = ({ isOpen, children }) => {
if (!isOpen) {
return null;
}
return createPortal(
<div className="op-modal op-modal-open">
<div className="op-modal-box p-0 min-w-[90%] md:min-w-[500px] max-h-90 overflow-y-auto hide-scrollbar text-sm">
{children}
</div>
</div>,
document.body
);
};
/**
* react-sortable-hoc is depcreated not usable from react 18.x.x
* need to replace it with @dnd-kit
@@ -17,7 +32,6 @@ function arrayMove(array, from, to) {
*/
const SignersInput = (props) => {
Modal.setAppElement("body");
const [state, setState] = useState(undefined);
// const [editFormData, setEditFormData] = useState([]);
const [selected, setSelected] = useState([]);
@@ -108,15 +122,17 @@ const SignersInput = (props) => {
<label className="block relative">
Signers
{props.required && <span className="text-red-500 text-[13px]">*</span>}
<span className="absolute ml-1 text-xs z-50">
<span className="absolute ml-1 text-xs z-30">
<Tooltip
id={"signer-tooltip"}
message={"Begin typing a contact's name to see suggested signers from your saved contacts or add new ones. Arrange the signing order by adding signers in the desired sequence. Use the '+' button to include signers and the 'x' to remove them. Each signer will receive an email prompt to sign the document in the order listed."}
message={
"Begin typing a contact's name to see suggested signers from your saved contacts or add new ones. Arrange the signing order by adding signers in the desired sequence. Use the '+' button to include signers and the 'x' to remove them. Each signer will receive an email prompt to sign the document in the order listed."
}
/>
</span>
</label>
<div style={{ display: "flex", gap: 5 }}>
<div style={{ flexWrap: "wrap", width: "100%" }}>
<div className="flex gap-x-[5px]">
<div className="w-full">
<Select
onSortEnd={onSortEnd}
distance={4}
@@ -126,6 +142,22 @@ const SignersInput = (props) => {
onChange={onChange}
closeMenuOnSelect={false}
required={props.required}
noOptionsMessage={() => "Contact not found"}
unstyled
classNames={{
control: () =>
"op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full h-full text-[11px]",
valueContainer: () =>
"flex flex-row gap-x-[2px] gap-y-[2px] md:gap-y-0 w-full my-[2px]",
multiValue: () => "op-badge op-badge-primary h-full text-[11px]",
multiValueLabel: () => "mb-[2px]",
menu: () =>
"mt-1 shadow-md rounded-lg bg-base-200 text-base-content",
menuList: () => "shadow-md rounded-lg overflow-hidden",
option: () =>
"bg-base-200 text-base-content rounded-lg m-1 hover:bg-base-300 p-2",
noOptionsMessage: () => "p-2 bg-base-200 rounded-lg m-1 p-2"
}}
/>
</div>
<div
@@ -133,66 +165,29 @@ const SignersInput = (props) => {
setIsModel(true);
openModal();
}}
style={{
cursor: "pointer",
borderRadius: 4,
border: "1px solid #ccc",
minHeight: 38,
minWidth: 48,
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
className="cursor-pointer op-input op-input-bordered focus:outline-none hover:border-base-content max-h-[38px] min-w-[48px] flex justify-center items-center"
>
<i className="fas fa-plus"></i>
<i className="fa-light fa-plus"></i>
</div>
<Modal
isOpen={modalIsOpen}
onRequestClose={handleModalCloseClick}
shouldCloseOnOverlayClick={false}
id="modal1"
contentLabel="Modal"
style={{
content: {
top: "50%",
left: "50%",
right: "auto",
bottom: "auto",
transform: "translate(-50%, -50%)",
border: "1px transparent",
padding: 0
},
overlay: {
width: "100%",
backgroundColor: "rgba(0, 0, 0, 0.75)",
zIndex: 50
}
}}
>
<div className="min-w-full md:min-w-[500px]">
<div
className="flex justify-between rounded-t items-center py-[10px] px-[20px] text-white"
style={{ background: "#32a3ac" }}
>
<div className="text-[1.2rem] font-normal">Add Signer</div>
<button
onClick={handleModalCloseClick}
className="text-[1.5rem] cursor-pointer focus:outline-none"
>
&times;
</button>
</div>
{isModal && (
<AddSigner
valueKey={"objectId"}
displayKey={"Name"}
details={handleNewDetails}
closePopup={handleModalCloseClick}
/>
)}
</div>
</Modal>
<AddSignerModal isOpen={modalIsOpen}>
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
Add Signer
</h3>
<button
onClick={handleModalCloseClick}
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2"
>
</button>
{isModal && (
<AddSigner
valueKey={"objectId"}
displayKey={"Name"}
details={handleNewDetails}
closePopup={handleModalCloseClick}
/>
)}
</AddSignerModal>
</div>
</div>
);
@@ -0,0 +1,92 @@
import React, { useState, useEffect, useRef } from "react";
import { findContact } from "../../../constant/Utils";
const SuggestionInput = (props) => {
const [inputValue, setInputValue] = useState(props?.value || "");
const [suggestions, setSuggestions] = useState([]);
const [showSuggestions, setShowSuggestions] = useState(false);
const ref = useRef(null);
useEffect(() => {
document.addEventListener("mousedown", Clickout);
return () => {
document.removeEventListener("mousedown", Clickout);
};
}, []);
const Clickout = (event) => {
if (ref.current && !ref.current.contains(event.target)) {
setShowSuggestions(false);
}
};
// create debounce to avoid unnecessay api calls
useEffect(() => {
let timer;
if (inputValue) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
(async () => {
const res = await findContact(inputValue);
if (res?.length > 0) {
setSuggestions(res);
setShowSuggestions(true);
} else {
setSuggestions(res);
setShowSuggestions(false);
}
})();
}, 1000);
}
return () => clearTimeout(timer);
}, [inputValue]);
const handleInputChange = async (e) => {
const value = e.target.value;
setInputValue(value?.toLowerCase());
if (props.onChange) {
props.onChange(value);
}
if (value.trim() === "") {
setSuggestions([]);
setShowSuggestions(false);
return;
}
};
const handleSuggestionClick = (suggestion) => {
setInputValue(suggestion.Email);
setSuggestions([]);
setShowSuggestions(false);
if (props.onChange) {
props.onChange(suggestion);
}
};
return (
<div className="flex flex-col items-center relative text-base-content">
<input
type={props?.type || "text"}
value={inputValue}
onChange={handleInputChange}
placeholder="Enter Email..."
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs lowercase"
required={props.required}
/>
{showSuggestions && (
<ul
ref={ref}
className="absolute z-50 left-0 top-[2.55rem] w-full max-h-[100px] overflow-auto bg-base-200 border border-gray-300 rounded shadow-md"
>
{suggestions.map((suggestion, index) => (
<li
key={index}
className="py-2 px-2 w-full text-sm cursor-pointer hover:bg-base-300"
onClick={() => handleSuggestionClick(suggestion)}
>
{suggestion.Email}
</li>
))}
</ul>
)}
</div>
);
};
export default SuggestionInput;
+6 -2
View File
@@ -3,14 +3,18 @@ import { NavLink } from "react-router-dom";
const Menu = ({ item, isOpen, closeSidebar }) => {
return (
<li key={item.title} role="none">
<li key={item.title} role="none" className="my-0.5">
<NavLink
to={
item.pageType
? `/${item.pageType}/${item.objectId}`
: `/${item.objectId}`
}
className="mx-auto flex items-center hover:bg-[#eef1f5] p-3 lg:p-4 cursor-pointer focus:text-[#0056b3] focus:bg-[#eef1f5]"
className={({ isActive }) =>
`${
isActive ? " bg-base-300 text-base-content" : ""
} flex items-center text-left p-3 lg:p-4 text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none`
}
onClick={closeSidebar}
tabIndex={isOpen ? 0 : -1}
role="menuitem"
+119 -20
View File
@@ -1,17 +1,21 @@
import React, { useState, useEffect } from "react";
import Menu from "./Menu";
import Submenu from "./SubMenu";
import SocialMedia from "./SocialMedia";
import Parse from "parse";
import dp from "../../assets/images/dp.png";
import sidebarList from "../../json/menuJson";
import { useNavigate } from "react-router-dom";
import { isEnableSubscription } from "../../constant/const";
const Sidebar = ({ isOpen, closeSidebar }) => {
const navigate = useNavigate();
const [menuList, setmenuList] = useState([]);
let username = localStorage.getItem("username");
const [submenuOpen, setSubmenuOpen] = useState(false);
const username = localStorage.getItem("username");
const image = localStorage.getItem("profileImg") || dp;
const tenantname = localStorage.getItem("TenantName");
const tenantname = localStorage.getItem("Extand_Class")
? JSON.parse(localStorage.getItem("Extand_Class"))?.[0]?.Company
: "";
useEffect(() => {
if (localStorage.getItem("accesstoken")) {
@@ -21,25 +25,105 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
const menuItem = async () => {
try {
var sideMenu = Parse.Object.extend("w_menu");
var query = new Parse.Query(sideMenu);
query.equalTo("objectId", localStorage.getItem("defaultmenuid"));
const results = await query.first();
const resultjson = results.toJSON();
let result = resultjson;
setmenuList(result.menuItems);
if (localStorage.getItem("defaultmenuid")) {
const Extand_Class = localStorage.getItem("Extand_Class");
const extClass = Extand_Class && JSON.parse(Extand_Class);
// console.log("extClass ", extClass);
let userRole = "contracts_User";
if (extClass && extClass.length > 0) {
userRole = extClass[0].UserRole;
}
if (
userRole === "contracts_Admin" ||
userRole === "contracts_OrgAdmin"
) {
const newSidebarList = sidebarList.map((item) => {
if (item.title === "Settings") {
// Make a shallow copy of the item
const newItem = { ...item };
if (isEnableSubscription) {
newItem.children = [
...newItem.children,
{
icon: "fa-light fa-building-memo",
title: "Teams",
target: "_self",
pageType: "",
description: "",
objectId: "teams"
},
{
icon: "fa-light fa-users fa-fw",
title: "Users",
target: "_self",
pageType: "",
description: "",
objectId: "users"
}
];
} else {
const arr = newItem.children.slice(0, 1);
newItem.children = [
...arr,
{
icon: "fa-light fa-users fa-fw",
title: "Users",
target: "_self",
pageType: "",
description: "",
objectId: "users"
}
];
}
return newItem;
}
return item;
});
setmenuList(newSidebarList);
} else {
if (!isEnableSubscription) {
const newSidebarList = sidebarList.map((item) => {
if (item.title === "Settings") {
// Make a shallow copy of the item
const newItem = { ...item };
const arr = newItem.children.slice(0, 1);
newItem.children = arr;
return newItem;
}
return item;
});
setmenuList(newSidebarList);
} else {
setmenuList(sidebarList);
}
}
}
} catch (e) {
console.error("Problem", e);
}
};
const toggleSubmenu = (title) => {
setSubmenuOpen({ [title]: !submenuOpen[title] });
};
const handleMenuItem = () => {
closeSidebar();
setSubmenuOpen({});
};
const handleProfile = () => {
navigate("/profile");
};
return (
<aside
className={`bg-white text-[#444] h-screen w-full md:w-[300px] overflow-y-auto transform transition-transform z-40 md:translate-x-0
${isOpen ? "translate-x-0 block" : "-translate-x-full hidden"}`}
className={`absolute lg:relative bg-base-100 h-screen overflow-y-auto transition-all z-[500] shadow-lg hide-scrollbar
${isOpen ? "w-full md:w-[300px]" : "w-0"}`}
>
<div className="flex px-2 py-3 gap-2 items-center shadow-md">
<div className="w-[75px] h-[75px] rounded-full ring-[2px] ring-offset-2 ring-gray-400 overflow-hidden">
<div
onClick={() => handleProfile()}
className="w-[75px] h-[75px] rounded-full ring-[2px] ring-offset-2 ring-gray-400 overflow-hidden cursor-pointer"
>
<img
className="w-full h-full object-contain"
src={image}
@@ -47,13 +131,26 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
/>
</div>
<div>
<p className="text-[14px] font-bold">{username}</p>
<p className={`text-[12px] ${tenantname ? "mt-2" : ""}`}>
<p
onClick={handleProfile}
className="text-[14px] font-bold text-base-content cursor-pointer"
>
{username}
</p>
<p
onClick={handleProfile}
className={`cursor-pointer text-[12px] text-base-content ${
tenantname ? "mt-2" : ""
}`}
>
{tenantname}
</p>
</div>
</div>
<nav aria-label="OpenSign Sidebar Navigation">
<nav
className="op-menu op-menu-sm"
aria-label="OpenSign Sidebar Navigation"
>
<ul
className="text-sm"
role="menubar"
@@ -65,19 +162,21 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
key={item.title}
item={item}
isOpen={isOpen}
closeSidebar={closeSidebar}
closeSidebar={handleMenuItem}
/>
) : (
<Submenu
key={item.title}
item={item}
closeSidebar={closeSidebar}
toggleSubmenu={toggleSubmenu}
submenuOpen={submenuOpen}
/>
)
)}
</ul>
</nav>
<footer className="mt-4 flex justify-center items-center text-[25px] text-black gap-3">
<footer className="mt-4 flex justify-center items-center text-[25px] text-base-content gap-3">
<SocialMedia />
</footer>
</aside>
+15 -15
View File
@@ -1,19 +1,13 @@
import React, { useState } from "react";
import React from "react";
import { NavLink } from "react-router-dom";
const Submenu = ({ item, closeSidebar }) => {
const [submenuOpen, setSubmenuOpen] = useState(false);
const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
const { title, icon, children } = item;
const toggleSubmenu = () => {
setSubmenuOpen(!submenuOpen);
};
return (
<li role="none">
<li role="none" className="my-0.5">
<button
onClick={toggleSubmenu}
className="w-full flex items-center text-left text-[#444] p-3 lg:p-4 hover:bg-[#eef1f5] focus:outline-none focus:text-[#0056b3] focus:bg-[#eef1f5]"
onClick={() => toggleSubmenu(item.title)}
className="flex items-center text-left p-3 lg:p-4 text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none "
aria-expanded={submenuOpen}
aria-haspopup="true"
aria-controls={`submenu-${title}`}
@@ -23,23 +17,29 @@ const Submenu = ({ item, closeSidebar }) => {
<span className="ml-3 lg:ml-4">{title}</span>
<i
className={`${
submenuOpen ? "fa-solid fa-angle-down" : "fa-solid fa-angle-right"
submenuOpen[item.title]
? "fa-light fa-angle-down"
: "fa-light fa-angle-right"
}`}
aria-hidden="true"
></i>
</div>
</button>
{submenuOpen && (
{submenuOpen[item.title] && (
<ul id={`submenu-${title}`} role="menu" aria-label={`${title} submenu`}>
{children.map((childItem) => (
<li key={childItem.title} role="none">
<li key={childItem.title} role="none" className="my-0.5">
<NavLink
to={
childItem.pageType
? `/${childItem.pageType}/${childItem.objectId}`
: `/${childItem.objectId}`
}
className="block pl-6 md:pl-8 py-2 text-sm text-gray-700 hover:bg-blue-500 hover:text-white focus:text-[#0056b3] focus:bg-[#eef1f5] cursor-pointer"
className={({ isActive }) =>
`${
isActive ? "bg-base-300 text-base-content" : ""
} flex items-center text-left pl-6 md:pl-8 py-2 text-sm cursor-pointer text-base-content hover:text-base-content focus:bg-base-300 hover:bg-base-300 hover:no-underline focus:outline-none`
}
onClick={closeSidebar}
role="menuitem"
tabIndex={submenuOpen ? 0 : -1}
File diff suppressed because it is too large Load Diff
+22 -12
View File
@@ -1,8 +1,6 @@
import logo from "../assets/images/logo.png";
export const appInfo = {
appTitle: "contracts",
applogo: logo,
appname: "contracts",
appId: process.env.REACT_APP_APPID ? process.env.REACT_APP_APPID : "opensign",
baseUrl: process.env.REACT_APP_SERVERURL
? process.env.REACT_APP_SERVERURL
@@ -18,22 +16,34 @@ export const appInfo = {
: "",
metaDescription:
"The fastest way to sign PDFs & request signatures from others.",
objectId: "aIPmIvMzGM",
settings: [
{
role: "contracts_User",
menuId: "H9vRfEYKhT",
pageType: "dashboard",
pageId: "35KBoSgoAK",
extended_class: "contracts_Users"
},
{
role: "contracts_Admin",
menuId: "VPh91h0ZHk",
pageType: "dashboard",
pageId: "35KBoSgoAK",
extended_class: "contracts_Users"
},
{
role: "contracts_OrgAdmin",
menuId: "VPh91h0ZHk",
pageType: "dashboard",
pageId: "35KBoSgoAK",
extended_class: "contracts_Users"
},
{
role: "contracts_Editor",
menuId: "H9vRfEYKhT",
pageType: "dashboard",
pageId: "35KBoSgoAK",
extended_class: "contracts_Users"
},
{
role: "contracts_User",
menuId: "H9vRfEYKhT",
pageType: "dashboard",
pageId: "35KBoSgoAK",
extended_class: "contracts_Users"
}
],
version: "0.1"
]
};
+8 -7
View File
@@ -1,12 +1,13 @@
export const contactCls = "contracts_Contactbook";
export const templateCls = "contracts_Template";
export const documentCls = "contracts_Document";
export const rejectBtn =
"bg-[#ffffff] rounded-sm shadow-md text-[12px] font-semibold uppercase text-black py-1.5 px-4 focus:outline-none text-center border-[1px] border-[#b4b4b4]";
export const submitBtn =
"bg-[#32a3ac] rounded-sm shadow-md text-[12px] font-semibold uppercase text-white py-1.5 px-4 focus:outline-none text-center";
export const modalSubmitBtnColor = "#17a2b8";
export const modalCancelBtnColor = "white";
export const themeColor = "#47a3ad";
export const iconColor = "#686968";
export const isEnableSubscription = process.env.REACT_APP_ENABLE_SUBSCRIPTION;
export const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
export const isEnableSubscription =
process.env.REACT_APP_ENABLE_SUBSCRIPTION &&
process.env.REACT_APP_ENABLE_SUBSCRIPTION?.toLowerCase() === "true"
? true
: false;
export const isStaging =
window.location.origin === "https://staging-app.opensignlabs.com";
+64 -9
View File
@@ -2,17 +2,72 @@
@tailwind components;
@tailwind utilities;
body{
background-color: white;
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 */
display: none;
}
.hide-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
/* below css class replace bootstrap background color with daisy */
.op-bg-primary {
@apply bg-primary;
}
.op-bg-secondary {
@apply bg-secondary;
}
.op-bg-info {
@apply bg-info;
}
.op-bg-success{
@apply bg-success;
}
.op-bg-warning {
@apply bg-warning;
}
/* below css class replace bootstrap text color with daisy */
.op-text-primary {
@apply text-primary;
}
.op-text-secondary {
@apply text-secondary;
}
.op-text-info {
@apply text-info;
}
.op-text-success{
@apply text-success;
}
.op-text-warning {
@apply text-warning;
}
.op-border-primary{
@apply border-primary
}
/* CSS for scrollbar customization */
* {
scrollbar-width: thin; /* For Firefox */
scrollbar-color: gray; /* For Firefox */
}
/* For webkit-based browsers like Chrome, Safari */
*::-webkit-scrollbar {
width: 5px;
}
*::-webkit-scrollbar-track {
background-color: transparent;
}
*::-webkit-scrollbar-thumb {
background-color: gray;
border-radius: 10px;
}
+1
View File
@@ -16,6 +16,7 @@ import {
import DragElement from "./components/pdf/DragElement";
import TagManager from "react-gtm-module";
import Parse from "parse";
import './polyfills'
const appId = process.env.REACT_APP_APPID
? process.env.REACT_APP_APPID
: "opensign";
+161 -111
View File
@@ -1,9 +1,18 @@
export default function reportJson(id) {
// console.log("json ", json);
const head = ["Sr.No", "Title", "Note", "Folder", "File", "Owner", "Signers"];
const declineHead = [
"Sr.No",
"Title",
"Reason",
"Folder",
"File",
"Owner",
"Signers"
];
const contactbook = ["Sr.No", "Title", "Email", "Phone"];
const dashboardReportHead = ["Title", "File", "Owner", "Signers"];
const templateReport = ["Sr.No", "Title", "File", "Owner", "Signers"];
switch (id) {
// draft documents report
case "ByHuevtCFY":
@@ -14,18 +23,16 @@ export default function reportJson(id) {
{
btnId: "1231",
hoverLabel: "Edit",
btnColor: "#4bd396",
textColor: "white",
btnIcon: "fa-solid fa-pen",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-pen",
redirectUrl: "draftDocument",
action: "redirect"
},
{
btnId: "2142",
hoverLabel: "Delete",
btnColor: "#ff4848",
textColor: "white",
btnIcon: "fa fa-trash",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -43,10 +50,9 @@ export default function reportJson(id) {
btnId: "4536",
btnLabel: "sign",
hoverLabel: "Sign",
btnColor: "#3ac9d6",
textColor: "white",
btnIcon: "fa-solid fa-signature",
redirectUrl: "pdfRequestFiles",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-signature",
redirectUrl: "draftDocument",
action: "redirect"
}
],
@@ -62,34 +68,40 @@ export default function reportJson(id) {
{
btnId: "8901",
hoverLabel: "Share",
btnColor: "#4bd396",
textColor: "white",
btnIcon: "fa-solid fa-share",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-share",
redirectUrl: "",
action: "share"
},
{
btnId: "1588",
hoverLabel: "View",
btnColor: "#3ac9d6",
textColor: "white",
btnIcon: "fa fa-eye",
redirectUrl: "pdfRequestFiles",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-eye",
redirectUrl: "draftDocument",
action: "redirect"
},
{
btnId: "2234",
hoverLabel: "option",
btnColor: "transparent",
btnColor: "",
textColor: "black",
btnIcon: "fa-solid fa-ellipsis-vertical fa-lg",
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
action: "option",
subaction: [
{
btnId: "1630",
btnLabel: "Resend",
hoverLabel: "Resend",
btnIcon: "fa-light fa-envelope",
redirectUrl: "",
action: "resend"
},
{
btnId: "1688",
btnLabel: "Revoke",
hoverLabel: "Revoke",
btnIcon: "fa-solid fa-file-circle-xmark",
btnIcon: "fa-light fa-file-circle-xmark",
redirectUrl: "",
action: "revoke"
},
@@ -97,7 +109,7 @@ export default function reportJson(id) {
btnId: "1488",
btnLabel: "Delete",
hoverLabel: "Delete",
btnIcon: "fa fa-trash",
btnIcon: "fa-light fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -116,18 +128,16 @@ export default function reportJson(id) {
{
btnId: "1378",
hoverLabel: "Edit",
btnColor: "#4bd396",
textColor: "white",
btnIcon: "fa fa-eye",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-eye",
redirectUrl: "draftDocument",
action: "redirect"
},
{
btnId: "1278",
hoverLabel: "Delete",
btnColor: "#ff4848",
textColor: "white",
btnIcon: "fa fa-trash",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -139,23 +149,21 @@ export default function reportJson(id) {
case "UPr2Fm5WY3":
return {
reportName: "Declined Documents",
heading: head,
heading: declineHead,
actions: [
{
btnId: "1458",
hoverLabel: "View",
btnColor: "#4bd396",
textColor: "white",
btnIcon: "fa fa-eye",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-eye",
redirectUrl: "draftDocument",
action: "redirect"
},
{
btnId: "1358",
hoverLabel: "Delete",
btnColor: "#ff4848",
textColor: "white",
btnIcon: "fa fa-trash",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -172,18 +180,16 @@ export default function reportJson(id) {
{
btnId: "1898",
hoverLabel: "View",
btnColor: "#4bd396",
textColor: "white",
btnIcon: "fa fa-eye",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-eye",
redirectUrl: "draftDocument",
action: "redirect"
},
{
btnId: "1998",
hoverLabel: "Delete",
btnColor: "#ff4848",
textColor: "white",
btnIcon: "fa fa-trash",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -200,34 +206,40 @@ export default function reportJson(id) {
{
btnId: "1999",
hoverLabel: "Share",
btnColor: "#4bd396",
textColor: "white",
btnIcon: "fa-solid fa-share",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-share",
redirectUrl: "",
action: "share"
},
{
btnId: "1999",
hoverLabel: "View",
btnColor: "#3ac9d6",
textColor: "white",
btnIcon: "fa fa-eye",
redirectUrl: "pdfRequestFiles",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-eye",
redirectUrl: "draftDocument",
action: "redirect"
},
{
btnId: "2234",
hoverLabel: "option",
btnColor: "transparent",
btnColor: "",
textColor: "black",
btnIcon: "fa-solid fa-ellipsis-vertical fa-lg",
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
action: "option",
subaction: [
{
btnId: "1631",
btnLabel: "Resend",
hoverLabel: "Resend",
btnIcon: "fa-light fa-envelope",
redirectUrl: "",
action: "resend"
},
{
btnId: "6788",
btnLabel: "Revoke",
hoverLabel: "Revoke",
btnIcon: "fa-solid fa-file-circle-xmark",
btnIcon: "fa-light fa-file-circle-xmark",
redirectUrl: "",
action: "revoke"
},
@@ -235,7 +247,7 @@ export default function reportJson(id) {
btnId: "2000",
btnLabel: "Delete",
hoverLabel: "Delete",
btnIcon: "fa fa-trash",
btnIcon: "fa-light fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -253,10 +265,9 @@ export default function reportJson(id) {
btnId: "2001",
btnLabel: "sign",
hoverLabel: "Sign",
btnColor: "#3ac9d6",
textColor: "white",
btnIcon: "fa-solid fa-signature",
redirectUrl: "pdfRequestFiles",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-signature",
redirectUrl: "draftDocument",
action: "redirect"
}
]
@@ -270,18 +281,16 @@ export default function reportJson(id) {
{
btnId: "2003",
hoverLabel: "Edit",
btnColor: "#4bd396",
textColor: "white",
btnIcon: "fa-solid fa-pen",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-pen",
redirectUrl: "draftDocument",
action: "redirect"
},
{
btnId: "2004",
hoverLabel: "Delete",
btnColor: "#ff4848",
textColor: "white",
btnIcon: "fa fa-trash",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -296,9 +305,8 @@ export default function reportJson(id) {
{
btnId: "2204",
hoverLabel: "Delete",
btnColor: "#f55a42",
textColor: "white",
btnIcon: "fa-solid fa-trash",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-trash",
action: "delete"
}
],
@@ -307,57 +315,99 @@ export default function reportJson(id) {
"This is a list of contacts/signers added by you. These will appear as suggestions when you try to add signers to a new document."
};
// template report
case "6TeaPr321t":
case "6TeaPr321t": {
const templateAct = [
{
btnId: "2234",
btnLabel: "Use",
hoverLabel: "Use",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-plus",
redirectUrl: "placeHolderSign",
action: "redirect",
selector: "reactourSecond",
message:
"Click the 'Use' button to create a new document from an existing template. "
},
{
btnId: "1631",
btnLabel: "Quick send",
hoverLabel: "Quick send",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-envelope",
redirectUrl: "",
action: "bulksend",
selector: "tourbulksend",
message:
"To quickly create and send multiple documents using an existing template, click the 'Quick Send' button."
},
{
btnId: "2234",
hoverLabel: "option",
btnColor: "",
textColor: "black",
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
action: "option",
selector: "reactourThird",
message:
"This menu reveals more options such as Edit & Delete. Use the 'Edit' button to add signer roles, modify fields, and update your template. Changes will apply to all future documents created from this template but wont affect existing documents.Use the Delete button you can delete template. ",
subaction: [
{
btnId: "2434",
btnLabel: "Edit",
hoverLabel: "Edit",
btnIcon: "fa-light fa-pen",
redirectUrl: "template",
action: "redirect"
},
{
btnId: "1834",
btnLabel: "Delete",
hoverLabel: "Delete",
btnIcon: "fa-light fa-trash",
redirectUrl: "",
action: "delete"
}
]
}
];
const Extand_Class = localStorage.getItem("Extand_Class");
const extClass = Extand_Class && JSON.parse(Extand_Class);
// console.log("extClass ", extClass);
let templateActions = templateAct;
if (extClass && extClass.length > 0) {
if (extClass?.[0]?.UserRole !== "contracts_User") {
templateActions = templateAct.map((item) => {
if (item.action === "option") {
// Make a shallow copy of the item
const newItem = { ...item };
newItem.subaction = [
{
btnId: "1873",
btnLabel: "Share with team",
hoverLabel: "Share with team",
btnIcon: "fa-light fa-share-nodes",
redirectUrl: "",
action: "sharewith"
},
...newItem.subaction
];
return newItem;
}
return item;
});
}
}
return {
reportName: "Templates",
heading: head,
actions: [
{
btnId: "2234",
btnLabel: "Use",
hoverLabel: "Use",
btnColor: "#4bd396",
textColor: "white",
btnIcon: "fa fa-plus",
redirectUrl: "placeHolderSign",
action: "redirect",
selector: "reactourSecond",
message:
"Click the 'Use' button to create a new document from an existing template. "
},
{
btnId: "2234",
hoverLabel: "option",
btnColor: "transparent",
textColor: "black",
btnIcon: "fa-solid fa-ellipsis-vertical fa-lg",
action: "option",
selector: "reactourThird",
message:
"This menu reveals more options such as Edit & Delete. Use the 'Edit' button to add signer roles, modify fields, and update your template. Changes will apply to all future documents created from this template but wont affect existing documents.Use the Delete button you can delete template. ",
subaction: [
{
btnId: "2434",
btnLabel: "Edit",
hoverLabel: "Edit",
btnIcon: "fa-solid fa-pen",
redirectUrl: "template",
action: "redirect"
},
{
btnId: "1834",
btnLabel: "Delete",
hoverLabel: "Delete",
btnIcon: "fa fa-trash",
redirectUrl: "",
action: "delete"
}
]
}
],
heading: templateReport,
actions: templateActions,
helpMsg:
"This is a list of templates that are available to you for creating documents. You can click the 'use' button to create a new document using a template, modify the document & add signers in the next step."
};
}
default:
return null;
}
+90
View File
@@ -0,0 +1,90 @@
const dashboardJson = [
{
id: "35KBoSgoAK",
columns: [
{
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
widget: {
type: "Card",
icon: "fa-light fa-signature",
bgColor: "op-bg-primary",
label: "Need your Signature",
description: null,
data: {
id: "e04ee9dc-932d-6b80-0202-703fd154eb74",
queryType: "",
class: "contracts_Document",
query:
'where={"$and":[{"AuditTrail.UserPtr":{"$ne":{"__type":"Pointer","className": "contracts_Users","objectId":"#objectId#"}}},{"AuditTrail.Activity":{"$ne":"Signed"}}],"Signers":{"$in":[{"__type":"Pointer","className":"contracts_Users","objectId":"#objectId#"}]},"IsDeclined":{"$ne":true},"IsCompleted":{"$ne":true},"Type":{"$ne":"Folder"},"Placeholders":{"$ne":null},"ExpiryDate":{"#*gt":{"__type":"#Date#","iso":"#today#"}}}&count=1',
key: "count",
Redirect_type: "Report",
Redirect_id: "4Hhwbp482K",
tourSection: "tourcard1",
tourMessage:
"Clicking on this card will take you to the list of documents awaiting your review."
}
}
},
{
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
widget: {
type: "Card",
icon: "fa-light fa-sign-out-alt",
bgColor: "op-bg-secondary",
label: "Out for signatures",
description: null,
data: {
id: "c1935cc0-28d4-3d73-b72a-8c1e3d18a17f",
queryType: "",
class: "contracts_Document",
query:
'where={"Type":{"#*ne":"Folder"},"Signers":{"#*exists":true,"#*ne":[]},"Placeholders":{"#*ne":null},"IsCompleted":{"#*ne":true},"IsDeclined":{"#*ne":true},"IsArchive":{"#*ne":true},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"#UserId.objectId#"},"ExpiryDate":{"#*gt":{"__type":"#Date#","iso":"#today#"}}}&count=1',
key: "count",
Redirect_type: "Report",
Redirect_id: "1MwEuxLEkF",
tourSection: "tourcard2",
tourMessage:
"Clicking on this card will take you to a list of documents awaiting signature."
}
}
},
{
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
widget: {
type: "report",
reportId: "5Go51Q7T8r",
data: {
tourSection: "tourreport1",
tourMessage:
"This is a list of documents that are waiting for your signature."
}
}
},
{
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
widget: {
type: "report",
reportId: "d9k3UfYHBc",
data: {
tourSection: "tourreport2",
tourMessage:
"This is a list of documents you've sent to other parties for signature."
}
}
},
{
colsize: "col-span-12 md:col-span-12 lg:col-span-12",
widget: {
type: "report",
reportId: "kC5mfynCi4",
data: {
tourSection: "tourreport3",
tourMessage:
"This are documents you have started but have not finalized for sending."
}
}
}
]
}
];
export default dashboardJson;
+161
View File
@@ -0,0 +1,161 @@
const sidebarList = [
{
icon: "fa-light fa-tachometer-alt",
title: "Dashboard",
target: "",
pageType: "dashboard",
description: "",
objectId: "35KBoSgoAK"
},
{
icon: "fa-light fa-pen-nib",
title: "Sign yourself",
target: "_self",
pageType: "form",
description: "",
objectId: "sHAnZphf69"
},
{
icon: "fa-light fa-paper-plane",
title: "Request signatures",
target: "_self",
pageType: "form",
description: "",
objectId: "8mZzFxbG1z"
},
{
icon: "fa-light fa-newspaper",
title: "Templates",
target: "_self",
pageType: null,
description: null,
objectId: null,
children: [
{
icon: "fa-light fa-file-signature",
title: "Create template",
target: "_self",
pageType: "form",
description: "",
objectId: "template"
},
{
icon: "fa-light fa-file-contract",
title: "Manage templates",
target: "_self",
pageType: "report",
description: "",
objectId: "6TeaPr321t"
}
]
},
{
icon: "fa-light fa-folder",
title: "OpenSign™ Drive",
target: "_self",
pageType: "",
description: "",
objectId: "opensigndrive"
},
{
icon: "fa-light fa-address-card",
title: "Reports",
target: "_self",
pageType: null,
description: "",
objectId: null,
children: [
{
icon: "fa-light fa-signature",
title: "Need your sign",
target: "_self",
pageType: "report",
description: "",
objectId: "4Hhwbp482K"
},
{
icon: "fa-light fa-tasks",
title: "In Progress",
target: "_self",
pageType: "report",
description: "",
objectId: "1MwEuxLEkF"
},
{
icon: "fa-light fa-check-circle",
title: "Completed",
target: "_self",
pageType: "report",
description: "",
objectId: "kQUoW4hUXz"
},
{
icon: "fa-light fa-edit",
title: "Drafts",
target: "_self",
pageType: "report",
description: "",
objectId: "ByHuevtCFY"
},
{
icon: "fa-light fa-times-circle",
title: "Declined",
target: "_self",
pageType: "report",
description: "",
objectId: "UPr2Fm5WY3"
},
{
icon: "fa-light fa-hourglass-end",
title: "Expired",
target: "_self",
pageType: "report",
description: "",
objectId: "zNqBHXHsYH"
},
{
icon: "fa-light fa-address-book",
title: "Contactbook",
target: "_self",
pageType: "report",
description: "",
objectId: "5KhaPr482K"
}
]
},
{
icon: "fa-light fa-cog",
title: "Settings",
target: "_self",
pageType: null,
description: "",
objectId: null,
children: [
{
icon: "fa-light fa-pen-fancy",
title: "My Signature",
target: "_self",
pageType: "",
description: "",
objectId: "managesign"
},
{
icon: "fa-light fa-key",
title: "API Token",
target: "_self",
pageType: "",
description: "",
objectId: "generatetoken"
},
{
icon: "fa-light fa-globe",
title: "Webhook",
target: "_self",
pageType: "",
description: "",
objectId: "webhook"
}
]
}
];
export default sidebarList;
+111 -15
View File
@@ -1,11 +1,14 @@
import { isStaging } from "../constant/const";
const plans = [
{
planName: "OPENSIGN™ FREE",
img: "free.png",
currency: "",
monthlyPrice: "Free",
yearlyPrice: "Free",
subtitle: "Free Unlimited E-signatures, Forever.",
btnText: "Subscribe",
btn: { text: "Subscribe", color: "op-btn-primary" },
url: "",
target: "_blank",
benefits: [
@@ -23,24 +26,44 @@ const plans = [
"Decline document support",
"Email notifications",
"Recipient authentication using OTP",
"Bulk send (upto 5 docs)",
"Public profiles",
"And much more"
],
yearlyBenefits: [
"Unlimited envelopes",
"Sign documents yourself",
"Request signatures from others",
"14 field types",
"Automatic e-signatures",
"Completion certificates",
"Send in order",
"Document templates",
"Import from Dropbox",
"Contact book",
"Document expiry support",
"Decline document support",
"Email notifications",
"Recipient authentication using OTP",
"Bulk send (upto 5 docs)",
"Public profiles",
"And much more"
]
},
{
planName: "OPENSIGN™ PROFESSIONAL",
img: "professional.png",
currency: "$",
monthlyPrice: "29.99",
yearlyPrice: "329.99",
yearlyPrice: `9.99<sup style="font-size: 17px;">/month</sup>`,
subtitle: "Exclusive Access to advanced features.",
btnText: "Subscribe",
url:
window.location.origin === "https://staging-app.opensignlabs.com"
? "https://billing.zoho.in/subscribe/9627f62a09df1c8ce500f2f4dc8328dd84ecda20eeae13878ce581d60240f206/pro-weekly"
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d1a09dfa8085585cdd4ec4d7f32137f3/professional-monthly",
yearlyUrl:
window.location.origin === "https://staging-app.opensignlabs.com"
? "https://billing.zoho.in/subscribe/9627f62a09df1c8ce500f2f4dc8328ddc184411129224f1f29ed84f6cef3b862/pro-yearly"
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d8ad1135190dff951330360e47585a71/professional-yearly",
btn: { text: "Subscribe", color: "op-btn-primary" },
url: isStaging
? "https://billing.zoho.in/subscribe/9627f62a09df1c8ce500f2f4dc8328dd84ecda20eeae13878ce581d60240f206/pro-weekly"
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d1a09dfa8085585cdd4ec4d7f32137f3/professional-monthly",
yearlyUrl: isStaging
? "https://billing.zoho.in/subscribe/9627f62a09df1c8ce500f2f4dc8328ddc184411129224f1f29ed84f6cef3b862/pro-yearly"
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901d8ad1135190dff951330360e47585a71/professional-yearly",
target: "_self",
benefits: [
"Everything in OpenSign™ free",
@@ -51,17 +74,74 @@ const plans = [
"Zapier integration",
"API Access",
"100 API signatures included",
"Custom email templates",
"Auto reminders",
"Bulk send (upto 20 docs)",
"Premium Public profile usernames",
"Embedding (coming soon)"
],
yearlyBenefits: [
"Everything in OpenSign™ free",
"Field validations",
"Regular expression validations",
"Organize docs in OpenSign™ Drive",
"Webhooks",
"Zapier integration",
"API Access",
"240 API signatures included",
"Custom email templates",
"Auto reminders",
"Bulk send (upto 20 docs)",
"Premium Public profile usernames",
"Embedding (coming soon)"
]
},
{
planName: "OPENSIGN™ TEAMS",
img: "teams.png",
currency: "$",
monthlyPrice: `39.99<sup style="font-size: 17px;">/user</sup>`,
yearlyPrice: `19.99<sup style="font-size: 17px;">/user/month</sup>`,
subtitle: "Exclusive Access to advanced features.",
btn: { text: "Subscribe", color: "op-btn-accent" },
url: isStaging
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/team-weekly"
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af901237d0702bfaa959406306635d80f138c/teams-monthly",
yearlyUrl: isStaging
? "https://billing.zoho.in/subscribe/ed8097273a82b6bf39892c11a3bb3c381eb2705736014cfbdbde1ccf1c7a189d/team-weekly"
: "https://billing.opensignlabs.com/subscribe/ef798486e6a0a11ea65f2bae8f2af9011a864994bbeeec71fcf106188630199d/teams-yearly",
target: "_self",
benefits: [
"Everything in OpenSign™ professional",
"100 API signatures included",
"Teams and Organizations",
"Share Templates with teams",
"Share Templates with individuals",
"DocumentId removal from signed docs",
"Custom email templates"
"Bulk send (upto 50 docs)",
"Request Payments (coming soon)",
"Mobile app (coming soon)"
],
yearlyBenefits: [
"Everything in OpenSign™ professional",
"500 API signatures included",
"Teams and Organizations",
"Share Templates with teams",
"Share Templates with individuals",
"DocumentId removal from signed docs",
"Bulk send (upto 50 docs)",
"Request Payments (coming soon)",
"Mobile app (coming soon)"
]
},
{
planName: "OPENSIGN™ ENTERPRISE",
img: "enterprise.png",
currency: "",
monthlyPrice: "Request Price",
yearlyPrice: "Request Price",
monthlyPrice: `<p style="font-size: 22px;">Request Price</p>`,
yearlyPrice: `<p style="font-size: 22px;">Request Price</p>`,
subtitle: "Scalable Features with priority support.",
btnText: "Contact us",
btn: { text: "Contact us", color: "op-btn-primary" },
url: "https://www.opensignlabs.com/contact-us",
target: "_blank",
benefits: [
@@ -71,8 +151,24 @@ const plans = [
"Uptime SLA",
"SSO support",
"Priority support"
],
yearlyBenefits: [
"All features",
"Custom domain",
"Custom branding",
"Uptime SLA",
"SSO support",
"Priority support"
]
}
];
export const validplan = {
"team-weekly": true,
"team-yearly": true,
"teams-monthly": true,
"teams-yearly": true,
"enterprise-monthly": true,
"enterprise-yearly": true
};
export default plans;
+28 -38
View File
@@ -5,17 +5,20 @@ import Sidebar from "../components/sidebar/Sidebar";
import { useWindowSize } from "../hook/useWindowSize";
import Tour from "reactour";
import axios from "axios";
import { useSelector } from "react-redux";
import { useDispatch, useSelector } from "react-redux";
import Parse from "parse";
import ModalUi from "../primitives/ModalUi";
import { useNavigate, useLocation, Outlet } from "react-router-dom";
import { isEnableSubscription } from "../constant/const";
import { useCookies } from "react-cookie";
import { fetchSubscription } from "../constant/Utils";
import Loader from "../primitives/Loader";
import { showHeader } from "../redux/reducers/showHeader";
const HomeLayout = () => {
const navigate = useNavigate();
const location = useLocation();
const dispatch = useDispatch();
const { width } = useWindowSize();
const [isOpen, setIsOpen] = useState(true);
const arr = useSelector((state) => state.TourSteps);
@@ -37,7 +40,7 @@ const HomeLayout = () => {
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, {
const user = await userQuery.get(Parse?.User?.current()?.id, {
sessionToken: localStorage.getItem("accesstoken")
});
if (user) {
@@ -64,6 +67,8 @@ const HomeLayout = () => {
const indexOfFirstDot = domainName.indexOf(".");
// Remove the first dot and get the substring starting from the next character
const updateDomain = domainName.substring(indexOfFirstDot); //.opensignlabs.com
const serverUrl = localStorage.getItem("baseUrl");
const parseAppId = localStorage.getItem("parseAppId");
setCookie("accesstoken", localStorage.getItem("accesstoken"), {
secure: true,
domain: updateDomain
@@ -72,6 +77,14 @@ const HomeLayout = () => {
secure: true,
domain: updateDomain
});
setCookie("server_url", serverUrl, {
secure: true,
domain: updateDomain
});
setCookie("parse_app_id", parseAppId, {
secure: true,
domain: updateDomain
});
};
async function checkIsSubscribed() {
@@ -97,6 +110,7 @@ const HomeLayout = () => {
}
const showSidebar = () => {
setIsOpen((value) => !value);
dispatch(showHeader(!isOpen));
};
useEffect(() => {
if (width && width <= 768) {
@@ -105,11 +119,7 @@ const HomeLayout = () => {
}, [width]);
useEffect(() => {
if (
localStorage.getItem("domain") === "contracts" &&
arr &&
arr.length > 0
) {
if (arr && arr.length > 0) {
handleDynamicSteps();
} else {
setIsTour(false);
@@ -167,7 +177,6 @@ const HomeLayout = () => {
setIsTour(false);
const serverUrl = localStorage.getItem("baseUrl");
const appId = localStorage.getItem("parseAppId");
const extUserClass = localStorage.getItem("extended_class");
const json = JSON.parse(localStorage.getItem("Extand_Class"));
const extUserId = json && json.length > 0 && json[0].objectId;
// console.log("extUserId ", extUserId)
@@ -189,7 +198,7 @@ const HomeLayout = () => {
// console.log("updatedTourStatus ", updatedTourStatus);
await axios.put(
serverUrl + "classes/" + extUserClass + "/" + extUserId,
serverUrl + "classes/contracts_Users/" + extUserId,
{
TourStatus: updatedTourStatus
},
@@ -203,10 +212,7 @@ const HomeLayout = () => {
};
async function checkTourStatus() {
const currentUser = Parse.User.current();
const cloudRes = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
const cloudRes = await Parse.Cloud.run("getUserDetails");
const res = { data: cloudRes.toJSON() };
if (res.data && res.data.TourStatus && res.data.TourStatus.length > 0) {
const tourStatus = res.data.TourStatus;
@@ -230,14 +236,14 @@ const HomeLayout = () => {
}
const closeSidebar = () => {
if (width <= 768) {
if (width <= 1023) {
setIsOpen(false);
}
};
const handleLoginBtn = () => {
try {
Parse.User.logOut();
Parse?.User?.logOut();
} catch (err) {
console.log("err ", err);
} finally {
@@ -247,27 +253,14 @@ const HomeLayout = () => {
};
return (
<div>
<div className="sticky top-0 z-50">
<div className="sticky top-0 z-[501]">
{!isLoader && <Header showSidebar={showSidebar} />}
</div>
{isUserValid ? (
<>
{isLoader ? (
<div
style={{
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
<div className="flex h-[100vh] justify-center items-center">
<Loader />
</div>
) : (
<>
@@ -277,7 +270,7 @@ const HomeLayout = () => {
id="renderList"
className="relative h-screen flex flex-col justify-between w-full overflow-y-auto"
>
<div className="bg-[#eef1f5] p-3">{<Outlet />}</div>
<div className="bg-base-200 p-3">{<Outlet />}</div>
<div className="z-30">
<Footer />
</div>
@@ -298,13 +291,10 @@ const HomeLayout = () => {
)}
</>
) : (
<ModalUi title={"Session Expired"} isOpen={true} showClose={false}>
<ModalUi showHeader={false} isOpen={true} showClose={false}>
<div className="flex flex-col justify-center items-center py-4 md:py-5 gap-5">
<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]"
>
<p className="text-xl font-medium">Your session has expired.</p>
<button onClick={handleLoginBtn} className="op-btn op-btn-neutral">
Login
</button>
</div>
+451
View File
@@ -0,0 +1,451 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import { appInfo } from "../constant/appinfo";
import { NavLink, useNavigate } from "react-router-dom";
import { getAppLogo, openInNewTab } from "../constant/Utils";
import { useDispatch } from "react-redux";
import { showTenant } from "../redux/reducers/ShowTenant";
import Loader from "../primitives/Loader";
import Title from "../components/Title";
const AddAdmin = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const [showPassword, setShowPassword] = useState(false);
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const [password, setPassword] = useState("");
const [email, setEmail] = useState("");
const [company, setCompany] = useState("");
const [jobTitle, setJobTitle] = useState("");
const [lengthValid, setLengthValid] = useState(false);
const [caseDigitValid, setCaseDigitValid] = useState(false);
const [specialCharValid, setSpecialCharValid] = useState(false);
const [isAuthorize, setIsAuthorize] = useState(false);
const [isSubscribeNews, setIsSubscribeNews] = useState(false);
const [errMsg, setErrMsg] = useState("");
const [state, setState] = useState({
loading: false,
alertType: "success",
alertMsg: ""
});
const togglePasswordVisibility = () => setShowPassword(!showPassword);
useEffect(() => {
checkUserExist();
// eslint-disable-next-line
}, []);
const checkUserExist = async () => {
setState((prev) => ({ ...prev, loading: true }));
try {
const app = await getAppLogo();
if (app?.user === "exist") {
setErrMsg("Admin already exist.");
}
} catch (err) {
setErrMsg("Something went wrong.");
console.log("err in check user exist", err);
} finally {
setState((prev) => ({ ...prev, loading: false }));
}
};
const clearStorage = async () => {
if (Parse.User.current()) {
await Parse.User.logOut();
}
const baseUrl = localStorage.getItem("baseUrl");
const appid = localStorage.getItem("parseAppId");
const applogo = localStorage.getItem("appLogo");
const defaultmenuid = localStorage.getItem("defaultmenuid");
const PageLanding = localStorage.getItem("PageLanding");
const userSettings = localStorage.getItem("userSettings");
localStorage.clear();
localStorage.setItem("baseUrl", baseUrl);
localStorage.setItem("parseAppId", appid);
localStorage.setItem("appLogo", applogo);
localStorage.setItem("defaultmenuid", defaultmenuid);
localStorage.setItem("PageLanding", PageLanding);
localStorage.setItem("userSettings", userSettings);
localStorage.setItem("baseUrl", baseUrl);
localStorage.setItem("parseAppId", appid);
};
const handleSubmit = async (event) => {
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 {
event.preventDefault();
const user = new Parse.User();
user.set("name", name);
user.set("email", email);
user.set("password", password);
user.set("phone", phone);
user.set("username", email);
const userRes = await user.save();
if (userRes) {
const params = {
userDetails: {
jobTitle: jobTitle,
company: company,
name: name,
email: email,
phone: phone,
role: "contracts_Admin"
}
};
try {
const usersignup = await Parse.Cloud.run("addadmin", params);
if (usersignup) {
if (isSubscribeNews) {
subscribeNewsletter();
}
handleNavigation(userRes.getSessionToken());
}
} catch (err) {
alert(err.message);
setState({ loading: false });
}
}
} catch (error) {
console.log("err ", error);
if (error.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 {
// console.log("state.email ", email);
try {
await Parse.User.requestPasswordReset(email).then(
async function (res) {
if (res.data === undefined) {
alert("Verification mail has been sent to your E-mail!");
}
}
);
} catch (err) {
console.log(err);
}
setState({ loading: false });
}
} else {
alert(error.message);
setState({ loading: false });
}
}
}
};
const handleNavigation = async (sessionToken) => {
const res = await Parse.User.become(sessionToken);
if (res) {
const _user = JSON.parse(JSON.stringify(res));
// console.log("_user ", _user);
localStorage.setItem("accesstoken", sessionToken);
localStorage.setItem("UserInformation", JSON.stringify(_user));
localStorage.setItem("accesstoken", _user.sessionToken);
localStorage.setItem("scriptId", true);
if (_user.ProfilePic) {
localStorage.setItem("profileImg", _user.ProfilePic);
} else {
localStorage.setItem("profileImg", "");
}
// Check extended class user role and tenentId
try {
const userSettings = appInfo.settings;
const extUser = await Parse.Cloud.run("getUserDetails");
if (extUser) {
const IsDisabled = extUser?.get("IsDisabled") || false;
if (!IsDisabled) {
const userRole = extUser?.get("UserRole");
const menu =
userRole && userSettings.find((menu) => menu.role === userRole);
if (menu) {
const _currentRole = userRole;
const _role = _currentRole.replace("contracts_", "");
localStorage.setItem("_user_role", _role);
const extInfo_stringify = JSON.stringify([extUser]);
localStorage.setItem("Extand_Class", extInfo_stringify);
const extInfo = JSON.parse(JSON.stringify(extUser));
localStorage.setItem("userEmail", extInfo?.Email);
localStorage.setItem("username", extInfo?.Name);
if (extInfo?.TenantId) {
const tenant = {
Id: extInfo?.TenantId?.objectId || "",
Name: extInfo?.TenantId?.TenantName || ""
};
localStorage.setItem("TenantId", tenant?.Id);
dispatch(showTenant(tenant?.Name));
localStorage.setItem("TenantName", tenant?.Name);
}
localStorage.setItem("PageLanding", menu.pageId);
localStorage.setItem("defaultmenuid", menu.menuId);
localStorage.setItem("pageType", menu.pageType);
setState({
loading: false,
alertType: "success",
alertMsg: "Registered user successfully."
});
navigate(`/${menu.pageType}/${menu.pageId}`);
} else {
setState({
loading: false,
alertType: "danger",
alertMsg: "Role not found."
});
}
} else {
setState({
loading: false,
alertType: "danger",
alertMsg: "You don't have access, please contact the admin."
});
}
}
} catch (error) {
console.log("error in fetch extuser", error);
const msg = error.message || "Something went wrong.";
setState({ loading: false, alertType: "danger", alertMsg: msg });
} finally {
setTimeout(() => setState({ loading: false, alertMsg: "" }), 2000);
}
}
};
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));
};
const subscribeNewsletter = async () => {
try {
const params = { name: name, email: email, domain: window.location.host };
await Parse.Cloud.run("newsletter", params);
// console.log("newsletter ", newsletter);
} catch (err) {
console.log("err in subscribeNewsletter", err);
}
};
return (
<div className="h-screen flex justify-center">
<Title title={"Add admin"} />
{state.loading ? (
<div className="text-[grey] flex justify-center items-center text-lg md:text-2xl">
<Loader />
</div>
) : (
<>
{errMsg ? (
<div className="text-[grey] flex justify-center items-center text-lg md:text-2xl">
{errMsg}
</div>
) : (
<div className="w-[95%] md:w-[500px]">
<form onSubmit={handleSubmit}>
<div className="w-full my-4 op-card bg-base-100 shadow-md outline outline-1 outline-slate-300/50">
<h2 className="text-[30px] text-center mt-3 font-medium">
Opensign Setup
</h2>
<NavLink
to="https://discord.com/invite/xe9TDuyAyj"
target="_blank"
rel="noopener noreferrer"
className="text-center text-sm mt-1 text-[blue] cursor-pointer"
>
Join our discord server
<i
aria-hidden="true"
className="fa-brands fa-discord ml-1"
></i>
{/* <span className="fa-sr-only">OpenSign&apos;s Discord</span> */}
</NavLink>
<div className="px-6 py-3 text-xs">
<label className="block ">
Name <span className="text-[red] text-[13px]">*</span>
</label>
<input
type="text"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
<hr className="my-2 border-none" />
<label>
Email <span className="text-[red] text-[13px]">*</span>
</label>
<input
id="email"
type="email"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={email}
onChange={(e) => setEmail(e.target.value?.toLowerCase())}
required
/>
<hr className="my-2 border-none" />
<label>
Phone <span className="text-[red] text-[13px]">*</span>
</label>
<input
type="tel"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={phone}
onChange={(e) => setPhone(e.target.value)}
required
/>
<hr className="my-2 border-none" />
<label>
Company <span className="text-[red] text-[13px]">*</span>
</label>
<input
type="text"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={company}
onChange={(e) => setCompany(e.target.value)}
required
/>
<hr className="my-2 border-none" />
<label>
Job Title{" "}
<span className="text-[red] text-[13px]">*</span>
</label>
<input
type="text"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={jobTitle}
onChange={(e) => setJobTitle(e.target.value)}
required
/>
<hr className="my-2 border-none" />
<label>
Password <span className="text-[red] text-[13px]">*</span>
</label>
<div className="relative">
<input
type={showPassword ? "text" : "password"}
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
name="password"
value={password}
onChange={(e) => handlePasswordChange(e)}
required
/>
<span
className={`absolute top-[50%] right-[10px] -translate-y-[50%] cursor-pointer text-base-content`}
onClick={togglePasswordVisibility}
>
{showPassword ? (
<i className="fa fa-eye-slash" /> // Close eye icon
) : (
<i className="fa fa-eye" /> // Open eye icon
)}
</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 className="mt-2.5 ml-1 flex flex-row items-center">
<input
type="checkbox"
className="op-checkbox op-checkbox-sm"
id="termsandcondition"
checked={isAuthorize}
onChange={(e) => setIsAuthorize(e.target.checked)}
required
/>
<label
className="text-xs cursor-pointer ml-1 mb-0"
htmlFor="termsandcondition"
>
I agree to the
</label>
<span
className="underline cursor-pointer ml-1"
onClick={() =>
openInNewTab(
"https://www.opensignlabs.com/terms-and-conditions"
)
}
>
Terms of Service
</span>
<span>.</span>
</div>
<div className="mt-2.5 ml-1 flex flex-row items-center">
<input
type="checkbox"
className="op-checkbox op-checkbox-sm"
id="termsandcondition"
checked={isSubscribeNews}
onChange={(e) => setIsSubscribeNews(e.target.checked)}
/>
<label
className="text-xs cursor-pointer ml-1 mb-0"
htmlFor="termsandcondition"
>
Subscribe to OpenSign newsletter
</label>
</div>
</div>
<div className="mx-4 text-center text-xs font-bold mb-3">
<button
type="submit"
className="op-btn op-btn-primary w-full"
disabled={state.loading}
>
{state.loading ? "Loading..." : "Next"}
</button>
</div>
</div>
</form>
</div>
)}
</>
)}
</div>
);
};
export default AddAdmin;
+13 -9
View File
@@ -21,7 +21,12 @@ function ChangePassword() {
user.set("password", newpassword);
user
.save()
.then(() => {
.then(async () => {
let _user = user.toJSON();
if (_user) {
await Parse.User.become(_user.sessionToken);
localStorage.setItem("accesstoken", _user.sessionToken);
}
alert("Password updated successfully.");
})
.catch((error) => {
@@ -32,7 +37,6 @@ function ChangePassword() {
} else {
alert("Your current password is missing or incorrect.");
}
console.log("Logged in user", user);
})
.catch((error) => {
alert("Your current password is missing or incorrect.");
@@ -49,13 +53,13 @@ function ChangePassword() {
return <Navigate to="/" />;
}
return (
<div className="w-full bg-white shadow rounded p-2">
<Title title={"Change Password"} />
<div className="w-full bg-base-100 text-base-content shadow rounded-box p-2">
<Title title="Change Password" />
<div className="text-xl font-bold border-b-[1px] border-gray-300">
Change Password
</div>
<div className="m-2">
<form onSubmit={handleSubmit}>
<form onSubmit={handleSubmit} className=" flex flex-col gap-y-2">
<div>
<label htmlFor="currentpassword" className="block text-xs ml-1">
Current Password
@@ -65,7 +69,7 @@ function ChangePassword() {
name="currentpassword"
value={currentpassword}
onChange={(e) => setCurrentPassword(e.target.value)}
className="px-3 py-2 mb-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm text-xs w-full"
placeholder="Current Password"
required
/>
@@ -79,7 +83,7 @@ function ChangePassword() {
name="newpassword"
value={newpassword}
onChange={(e) => setnewpassword(e.target.value)}
className="px-3 py-2 mb-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm text-xs w-full"
placeholder="New Password"
required
/>
@@ -91,7 +95,7 @@ function ChangePassword() {
<input
type="password"
name="confirmpassword"
className="px-3 py-2 mb-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm text-xs w-full"
value={confirmpassword}
onChange={(e) => setconfirmpassword(e.target.value)}
placeholder="Confirm Password"
@@ -100,7 +104,7 @@ function ChangePassword() {
</div>
<button
type="submit"
className="bg-[#188ae2] m-2 px-4 py-3 rounded-sm shadow-md text-white text-xs font-semibold uppercase"
className="op-btn op-btn-primary shadow-md mt-2"
>
Change Password
</button>
+15 -83
View File
@@ -1,20 +1,18 @@
import React, { useState, useEffect } from "react";
import Parse from "parse";
import "../styles/loader.css";
import GetDashboard from "../components/dashboard/GetDashboard";
import { useNavigate, useParams } from "react-router-dom";
import Title from "../components/Title";
import { useDispatch } from "react-redux";
import { saveTourSteps } from "../redux/reducers/TourStepsReducer";
import dashboardJson from "../json/dashboardJson";
import Loader from "../primitives/Loader";
const Dashboard = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const { id } = useParams();
const [dashboard, setdashboard] = useState([]);
const [classnameArray, setclassnameArray] = useState([]);
const [loading, setloading] = useState(false);
const [defaultQuery, setDefaultQuery] = useState("");
const [dashboard, setdashboard] = useState({});
const [loading, setloading] = useState(true);
useEffect(() => {
if (localStorage.getItem("accesstoken")) {
@@ -30,53 +28,10 @@ const Dashboard = () => {
}, [id]);
const getDashboard = async (id) => {
setloading(true);
try {
var forms = Parse.Object.extend("w_dashboard");
var query = new Parse.Query(forms);
query.equalTo("objectId", id);
const results = await query.first();
const resultjson = results.toJSON();
let classArray = [];
let DefaultQuery = "";
resultjson.rows.forEach((x) => {
let col_lg = "",
col_md = "",
col_xs = "",
col_sm = "",
col_ = "",
obj = {};
let subItem = [];
let item = "";
x.columns.forEach((y) => {
if (y.widget.type === "customeHtml") {
DefaultQuery = y.widget.data[0].default;
}
if (Number(y["collg"]) > 0) {
col_lg = "col-lg-" + y["collg"];
}
if (Number(y["colmd"]) > 0) {
col_md = "col-md-" + y["colmd"];
}
if (Number(y["colxs"]) > 0) {
col_xs = "col-xs-" + y["colxs"];
}
if (Number(y["colsm"]) > 0) {
col_sm = "col-sm-" + y["colsm"];
}
if (Number(y["col"]) > 0) {
col_ = "col-" + y["col"];
}
item =
col_lg + " " + col_md + " " + col_xs + " " + col_sm + " " + col_;
subItem.push(item);
});
obj = subItem;
classArray.push(obj);
});
setdashboard(resultjson.rows);
// console.log("resultjson.rows ", resultjson.rows);
const arr = resultjson.rows[0].columns
const dashboard = dashboardJson.find((x) => x.id === id);
setdashboard(dashboard);
const dashboardTour = dashboard.columns
.filter((col) => {
if (col.widget.data && col.widget.data.tourSection) {
return col;
@@ -90,14 +45,7 @@ const Dashboard = () => {
// style: { backgroundColor: "#abd4d2" },
};
});
dispatch(saveTourSteps(arr));
// console.log("arr ", arr);
setclassnameArray(classArray);
if (localStorage.getItem("DashboardDefaultFilter")) {
setDefaultQuery(localStorage.getItem("DashboardDefaultFilter"));
} else {
setDefaultQuery(DefaultQuery);
}
dispatch(saveTourSteps(dashboardTour));
setloading(false);
} catch (e) {
console.error("Problem", e);
@@ -105,32 +53,16 @@ const Dashboard = () => {
}
};
let _dash = (
<GetDashboard
dashboard={dashboard}
classnameArray={classnameArray}
DefaultQuery={defaultQuery}
/>
);
if (loading) {
_dash = (
<div style={{ height: "300px", backgroundColor: "white" }}>
<div
style={{
marginLeft: "45%",
marginTop: "150px",
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
</div>
);
}
return (
<React.Fragment>
<Title title="Dashboard" />
{_dash}
{loading ? (
<div className="h-[300px] w-full bg-white flex justify-center items-center rounded-md">
<Loader />
</div>
) : (
<GetDashboard dashboard={dashboard} />
)}
</React.Fragment>
);
};
+31 -109
View File
@@ -1,7 +1,5 @@
import React, { useEffect, useState } from "react";
import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage";
import "../styles/signature.css";
import "../styles/AddUser.css";
import Title from "../components/Title";
import RenderDebugPdf from "../components/RenderDebugPdf";
import { pdfjs } from "react-pdf";
@@ -58,7 +56,7 @@ const DebugPdf = () => {
const fetchPdfMetadata = async () => {
try {
const pdfDataURL = URL.createObjectURL(pdf); // Convert File to data URL
console.log("pdfDataURL ", pdfDataURL);
// console.log("pdfDataURL ", pdfDataURL);
const pdfInfo = await pdfjs.getDocument({ url: pdfDataURL }).promise;
const pdfType = await inferPdfType(pdfInfo);
setPdfDetails((prevDetails) => ({
@@ -76,7 +74,7 @@ const DebugPdf = () => {
const inferPdfType = async (pdf) => {
try {
const firstPage = await pdf.getPage(1);
const firstPage = await pdf.getPage(2);
const scale = 1;
const { width, height } = firstPage.getViewport({ scale });
setPdfDimension({ width: width, height: height });
@@ -217,14 +215,18 @@ const DebugPdf = () => {
};
return (
<div>
{copied && <Alert type="success">Copied</Alert>}
{copied && (
<Alert type="success">
<span className="ml-3">Copied</span>
</Alert>
)}
<Title title={"Debug Pdf"} />
{width < 800 ? (
<HandleError handleError={"Debug PDF only availble for PC"} />
) : (
<>
{!isModal && (
<div className="signatureContainer">
<div className="flex flex-row justify-between">
{/* this component used to render all pdf pages in left side */}
<RenderAllPdfPage
signPdfUrl={pdf}
@@ -253,126 +255,68 @@ const DebugPdf = () => {
/>
</div>
</div>
<div style={{ backgroundColor: "white", width: 220 }}>
<div
style={{
fontSize: 18,
fontWeight: 500,
padding: "10px 12px",
borderBottom: "1px solid grey"
}}
>
<div className="w-[220px] bg-base-100">
<div className="text-[18px] font-medium py-[10px] px-[12px] border-b-[1px] border-[gray]">
PDF details
</div>
<div style={{ fontSize: 14, padding: "5px 12px" }}>
<div className="text-[14px] py-[5px] px-[12px]">
Name: {pdfDetails?.name}
</div>
<div style={{ fontSize: 14, padding: "5px 12px" }}>
<div className="text-[14px] py-[5px] px-[12px]">
Pdf type: {pdfDetails?.pdftype}
</div>
<div style={{ fontSize: 14, padding: "5px 12px" }}>
<div className="text-[14px] py-[5px] px-[12px]">
Total Pages: {pdfDetails?.totalPages}
</div>
<div style={{ fontSize: 14, padding: "5px 12px" }}>
<div className="text-[14px] py-[5px] px-[12px]">
Current Page: {pdfDetails?.currentPage}
</div>
<div style={{ fontSize: 14, padding: "5px 12px" }}>
<div className="text-[14px] py-[5px] px-[12px]">
Base64 : {pdfDetails?.base64.slice(0, 10)}...
<span
style={{
borderRadius: 4,
padding: "3px 5px",
border: "1px solid gray",
fontSize: 12,
margin: 2,
cursor: "pointer"
}}
className="op-btn op-btn-outline op-btn-primary op-btn-xs rounded-md w-[25px] h-[25px] text-[12px] m-[2px] "
onClick={() => copytoclipboard(pdfDetails?.base64)}
>
<i className="fa-solid fa-copy"></i>
<i className="fa-light fa-copy"></i>
</span>
</div>
<div
style={{
fontSize: 18,
fontWeight: 500,
padding: "10px 12px",
borderBottom: "1px solid grey"
}}
>
<div className="text-[18px] font-medium py-[10px] px-[12px] border-b-[1px] border-[gray]">
Last click
</div>
<div style={{ fontSize: 14, padding: "5px 12px" }}>
<div className="text-[14px] py-[5px] px-[12px]">
x co-ordinate: {pdfDetails?.x}
</div>
<div style={{ fontSize: 14, padding: "5px 12px" }}>
<div className="text-[14px] py-[5px] px-[12px]">
y co-ordinate: {pdfDetails?.y}
</div>
<div
style={{
fontSize: 18,
fontWeight: 500,
padding: "10px 12px",
borderBottom: "1px solid grey",
borderTop: "1px solid grey"
}}
>
<div className="text-[18px] font-medium py-[10px] px-[12px] border-y-[1px] border-[gray]">
Annotation
</div>
<ul
style={{
listStyle: "none",
padding: 10,
height: 500,
overflowY: "auto",
scrollbarWidth: 5
}}
>
<ul className=" list-none p-[10px] h-[500px] overflow-y-auto">
{annotations.map((coord, index) => (
<li key={index}>
<span style={{ fontSize: 13, fontWeight: 500 }}>{`Box ${
<span className="text-[13px] font-medium">{`Box ${
index + 1
}:`}</span>
<code
style={{
fontSize: 12,
color: "black",
cursor: "pointer"
}}
>
<code className="text-[12px] text-base-content select-none">
{` ["page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]`}
</code>
<div>
<span
style={{
borderRadius: 4,
padding: "3px 5px",
border: "1px solid gray",
fontSize: 12,
margin: 2,
cursor: "pointer"
}}
className="op-btn op-btn-outline op-btn-primary op-btn-xs rounded-md w-[23px] h-[20px] text-[12px] m-[2px] "
onClick={() =>
copytoclipboard(
`"page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}`
)
}
>
<i className="fa-solid fa-copy"></i>
<i className="fa-light fa-copy"></i>
</span>
<span
style={{
borderRadius: 4,
padding: "3px 5px",
border: "1px solid gray",
fontSize: 12,
margin: 2,
cursor: "pointer"
}}
className="op-btn op-btn-outline op-btn-error op-btn-xs rounded-md w-[23px] h-[20px] text-[12px] m-[2px] "
onClick={() => handleDelete(coord.key)}
>
<i className="fa-solid fa-trash-can"></i>
<i className="fa-light fa-trash-can"></i>
</span>
</div>
</li>
@@ -382,38 +326,16 @@ const DebugPdf = () => {
</div>
)}
<ModalUi title={"Select PDF"} isOpen={isModal}>
<form onSubmit={handleSubmit} style={{ margin: "10px" }}>
<form onSubmit={handleSubmit} className="m-[10px]">
<input
type="file"
onChange={(e) => handleFileChange(e.target.files)}
style={{
width: "100%",
border: "1px solid grey",
borderRadius: "4px",
padding: "5px",
fontSize: 12
}}
className="op-file-input op-file-input-bordered op-file-input-sm focus:outline-none hover:border-base-content w-full h-[40px] text-xs"
accept=".pdf"
required
/>
<div
style={{ borderTop: "1px solid grey", margin: "10px 0" }}
></div>
<button
style={{
background: "#32a3ac",
borderRadius: "2px",
boxShadow:
"0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18)",
border: "none",
textTransform: "uppercase",
fontSize: "13px",
fontWeight: "600",
padding: "0.375rem 0.75rem",
textAlign: "center",
color: "#ffffff",
outline: "none"
}}
className="op-btn op-btn-primary w-full mt-3 mb-1"
type="submit"
>
Submit
+39 -27
View File
@@ -1,21 +1,26 @@
import React, { useEffect, useState } from "react";
import Title from "../components/Title";
import { NavLink } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import login_img from "../assets/images/login_img.svg";
import Parse from "parse";
import Alert from "../primitives/Alert";
import { appInfo } from "../constant/appinfo";
import { useDispatch } from "react-redux";
import { fetchAppInfo } from "../redux/reducers/infoReducer";
import { isEnableSubscription } from "../constant/const";
import { getAppLogo } from "../constant/Utils";
function ForgotPassword() {
const dispatch = useDispatch();
const navigate = useNavigate();
const [state, setState] = useState({
email: "",
password: "",
hideNav: ""
});
const [sentStatus, setSentStatus] = useState("");
const [image, setImage] = useState();
const handleChange = (event) => {
const { name, value } = event.target;
setState({ ...state, [name]: value });
@@ -31,9 +36,6 @@ function ForgotPassword() {
const handleSubmit = async (event) => {
event.preventDefault();
localStorage.setItem("appLogo", appInfo.applogo);
localStorage.setItem("appName", appInfo.appname);
// localStorage.setItem("defaultmenuid", props.appInfo.defaultmenuid);
// localStorage.setItem("PageLanding", props.appInfo.LandingPageId);
localStorage.setItem("userSettings", JSON.stringify(appInfo.settings));
if (state.email) {
const username = state.email;
@@ -51,15 +53,26 @@ function ForgotPassword() {
useEffect(() => {
dispatch(fetchAppInfo());
saveLogo();
resize();
window.addEventListener("resize", resize);
return () => window.removeEventListener("resize", resize);
// eslint-disable-next-line
}, []);
let image = appInfo.applogo;
const saveLogo = async () => {
if (isEnableSubscription) {
const app = await getAppLogo();
if (app?.logo) {
setImage(app?.logo);
} else {
setImage(appInfo?.applogo || undefined);
}
} else {
setImage(appInfo?.applogo || undefined);
}
};
return (
<div className="bg-white">
<div>
<Title title="Forgot password page" />
{sentStatus === "success" && (
<Alert type="success">
@@ -69,29 +82,31 @@ function ForgotPassword() {
{sentStatus === "failed" && (
<Alert type={"danger"}>Please setup email adapter </Alert>
)}
<div>
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
<div className="w-[250px] h-[66px] inline-block">
{state.hideNav ? (
<img src={image} width="100%" alt="" />
) : (
<img src={image} width="100%" alt="" />
<div className="md:p-10 lg:p-16">
<div className="md:p-4 lg:p-10 p-4 bg-base-100 text-base-content op-card">
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
{image && (
<img
src={image}
className="object-contain h-full"
alt="applogo"
/>
)}
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-2">
<div className="">
<div>
<form onSubmit={handleSubmit}>
<h2 className="text-[30px] mt-6">Welcome Back !</h2>
<span className="text-[12px] text-[#878787]">
Reset Your Password
</span>
<div className="shadow-md rounded my-4">
<div className="w-full my-4 op-card bg-base-100 shadow-md outline outline-1 outline-slate-300/50">
<div className="px-6 py-4">
<label className="block text-xs">Email</label>
<input
type="text"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
type="email"
name="email"
className="op-input op-input-bordered op-input-sm w-full"
value={state.email}
onChange={handleChange}
required
@@ -99,19 +114,16 @@ function ForgotPassword() {
<hr className="my-2 border-none" />
</div>
</div>
<div className="flex justify-between items-center px-4">
<button
type="submit"
className="rounded-sm bg-[#3ac9d6] text-white px-4 py-3 text-xs font-semibold shadow uppercase"
>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-center text-xs font-bold">
<button type="submit" className="op-btn op-btn-primary">
Submit
</button>
<NavLink
to="/"
className="rounded-sm bg-white border-[1px] border-[#15b4e9] text-[#15b4e9] px-4 py-3 text-xs font-semibold shadow uppercase"
<button
onClick={() => navigate("/", { replace: true })}
className="op-btn op-btn-secondary"
>
Login
</NavLink>
</button>
</div>
</form>
</div>
+199 -140
View File
@@ -11,12 +11,14 @@ import SignersInput from "../components/shared/fields/SignersInput";
import Title from "../components/Title";
import PageNotFound from "./PageNotFound";
import { SaveFileSize } from "../constant/saveFileSize";
import { getFileName, toDataUrl } from "../constant/Utils";
import { checkIsSubscribed, getFileName, toDataUrl } from "../constant/Utils";
import { PDFDocument } from "pdf-lib";
import axios from "axios";
import { isEnableSubscription, submitBtn } from "../constant/const";
import { isEnableSubscription } from "../constant/const";
import ModalUi from "../primitives/ModalUi";
import { Tooltip } from "react-tooltip";
import Upgrade from "../primitives/Upgrade";
import Loader from "../primitives/Loader";
// `Form` render all type of Form on this basis of their provided in path
function Form() {
@@ -48,7 +50,9 @@ const Forms = (props) => {
TimeToCompleteDays: 15,
SendinOrder: "false",
password: "",
file: ""
file: "",
remindOnceInEvery: 5,
autoreminder: false
});
const [fileupload, setFileUpload] = useState("");
const [fileload, setfileload] = useState(false);
@@ -60,6 +64,7 @@ const Forms = (props) => {
const [isPassword, setIsPassword] = useState(false);
const [isDecrypting, setIsDecrypting] = useState(false);
const [isCorrectPass, setIsCorrectPass] = useState(true);
const [isSubscribe, setIsSubscribe] = useState(false);
const handleStrInput = (e) => {
setIsCorrectPass(true);
setFormData({ ...formData, [e.target.name]: e.target.value });
@@ -70,6 +75,17 @@ const Forms = (props) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.title]);
useEffect(() => {
fetchSubscription();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const fetchSubscription = async () => {
if (isEnableSubscription) {
const getIsSubscribe = await checkIsSubscribed();
setIsSubscribe(getIsSubscribe);
}
};
function getFileAsArrayBuffer(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
@@ -383,6 +399,8 @@ const Forms = (props) => {
if (props.title !== "Sign Yourself") {
const isChecked = formData.SendinOrder === "false" ? false : true;
object.set("SendinOrder", isChecked);
object.set("AutomaticReminders", formData.autoreminder);
object.set("RemindOnceInEvery", parseInt(formData.remindOnceInEvery));
}
object.set("URL", fileupload);
object.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
@@ -402,7 +420,6 @@ const Forms = (props) => {
className: "contracts_Users",
objectId: ExtCls[0].objectId
});
const res = await object.save();
if (res) {
setSigners([]);
@@ -427,7 +444,7 @@ const Forms = (props) => {
setIsSubmit(false);
}
} else {
alert("Please wait until the PDF has been uploading.");
alert("Please wait while the document is being uploaded.");
}
};
@@ -457,12 +474,19 @@ const Forms = (props) => {
? "Note to myself"
: "Please review and sign this document",
TimeToCompleteDays: 15,
SendinOrder: "true"
SendinOrder: "true",
password: "",
file: "",
remindOnceInEvery: 5,
autoreminder: false
});
setFileUpload("");
setpercentage(0);
setTimeout(() => setIsReset(false), 50);
};
const handleCancel = () => {
navigate("/dashboard/35KBoSgoAK");
};
const handlePasswordSubmit = async (e) => {
e.preventDefault();
setIsPassword(false);
@@ -536,8 +560,11 @@ const Forms = (props) => {
inputFileRef.current.value = ""; // Set file input value to empty string
}
};
const handleAutoReminder = () => {
setFormData((prev) => ({ ...prev, autoreminder: !formData.autoreminder }));
};
return (
<div className="shadow-md rounded my-2 p-3 bg-[#ffffff] md:border-[1px] md:border-gray-600/50">
<div className="shadow-md rounded-box my-[2px] p-3 bg-base-100 text-base-content">
<Title title={props?.title} />
{isAlert && (
<Alert type={isErr ? "danger" : "success"}>
@@ -547,16 +574,8 @@ const Forms = (props) => {
</Alert>
)}
{isSubmit ? (
<div style={{ height: "300px" }}>
<div
style={{
marginLeft: "45%",
marginTop: "150px",
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
<div className="h-[300px] flex justify-center items-center">
<Loader />
</div>
) : (
<>
@@ -567,29 +586,30 @@ const Forms = (props) => {
>
<form onSubmit={handlePasswordSubmit}>
<div className="px-6 pt-3 pb-2">
<label className="mb-2 text-xs">Password</label>
<label className="mb-2 text-xs text-base-content">
Password
</label>
<input
type="text"
name="password"
value={formData.password}
onChange={(e) => handleStrInput(e)}
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
placeholder="Enter pdf password"
required
/>
{!isCorrectPass ? (
<p className="ml-2 text-[11px] text-red-600">
Please provide correct password
</p>
) : (
<p className="ml-2 text-[11px] text-transparent text-red-600">
.
</p>
)}
<p
className={`${
!isCorrectPass
? "text-red-600"
: "text-transparent pointer-events-none"
} ml-2 text-[11px] `}
>
Please provide correct password
</p>
</div>
<hr />
<div className="px-6 my-3">
<button type="submit" className={submitBtn}>
<div className="px-6 mb-3">
<button type="submit" className="op-btn op-btn-primary">
Submit
</button>
</div>
@@ -605,12 +625,12 @@ const Forms = (props) => {
style={{ width: `${percentage}%` }}
></div>
</div>
<span className="text-black text-sm">{percentage}%</span>
<span className="text-base-content text-sm">{percentage}%</span>
</div>
)}
{isDecrypting && (
<div className="flex items-center gap-x-2">
<span className="text-black text-sm">
<span className="text-base-content text-sm">
Decrypting pdf please wait...
</span>
</div>
@@ -623,16 +643,16 @@ const Forms = (props) => {
<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 : {getFileName(fileupload)}
<div className="flex gap-1 justify-center items-center">
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm w-full h-full text-[13px]">
<div className="break-all cursor-default">
file selected: {getFileName(fileupload)}
</div>
<div
onClick={() => setFileUpload("")}
className="cursor-pointer px-[10px] text-[20px] font-bold bg-white text-red-500"
className="cursor-pointer px-[10px] text-[20px] font-bold text-red-500"
>
<i className="fa-solid fa-xmark"></i>
<i className="fa-light fa-xmark"></i>
</div>
</div>
{process.env.REACT_APP_DROPBOX_API_KEY && (
@@ -643,10 +663,10 @@ const Forms = (props) => {
)}
</div>
) : (
<div className="flex gap-2 justify-center items-center">
<div className="flex gap-1 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"
className="op-file-input op-file-input-bordered op-file-input-sm focus:outline-none hover:border-base-content w-full text-xs"
onChange={(e) => handleFileInput(e)}
ref={inputFileRef}
accept={
@@ -674,21 +694,23 @@ const Forms = (props) => {
</label>
<input
name="Name"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={formData.Name}
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>
{props.title === "New Template" && (
<div className="text-xs mt-2">
<label className="block">Description</label>
<input
name="Description"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={formData.Description}
onChange={(e) => handleStrInput(e)}
/>
</div>
)}
{props.signers && (
<SignersInput
onChange={handleSigners}
@@ -702,7 +724,7 @@ const Forms = (props) => {
</label>
<input
name="Note"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={formData.Note}
onChange={(e) => handleStrInput(e)}
required
@@ -724,7 +746,7 @@ const Forms = (props) => {
<input
type="number"
name="TimeToCompleteDays"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={formData.TimeToCompleteDays}
onChange={(e) => handleStrInput(e)}
required
@@ -732,105 +754,142 @@ const Forms = (props) => {
</div>
)}
{props.title !== "Sign Yourself" && (
<div className="text-xs mt-2">
<label className="block">
Send In Order
<a data-tooltip-id="sendInOrder-tooltip" className="ml-1">
<sup>
<i
className="fa-solid fa-question rounded-full"
style={{
borderColor: "#33bbff",
color: "#33bbff",
fontSize: 13,
borderWidth: 1.5,
padding: "1.5px 4px"
}}
></i>
</sup>
</a>
<Tooltip id="sendInOrder-tooltip" className="z-50">
<div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">Send in Order</p>
<p>
Choose how you want the signing requests to be sent to
the document signers:
</p>
<p className="p-[5px]">
<ol className="list-disc">
<li>
<span className="font-bold">Yes:</span>
<span>
{" "}
Selecting this option will send the signing
request to the first signer initially. Once the
first signer completes their part, the next signer
in the sequence will receive the request. This
process continues until all signers have signed
the document. This method ensures that the
document is signed in a specific order.
</span>
</li>
<li>
<span className="font-bold">No: </span>
<span>
Selecting this option will send the signing links
to all signers simultaneously. Every signer can
sign the document at their convenience, regardless
of whether other signers have completed their
signatures. This method is faster but does not
enforce any signing order among the participants.
</span>
</li>
</ol>
</p>
<>
<div className="text-xs mt-2">
<label className="block">
Send In Order
<a data-tooltip-id="sendInOrder-tooltip" className="ml-1">
<sup>
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
</sup>
</a>
<Tooltip id="sendInOrder-tooltip" className="z-50">
<div className="max-w-[200px] md:max-w-[450px]">
<p className="font-bold">Send in Order</p>
<p>
Choose how you want the signing requests to be sent to
the document signers:
</p>
<p className="p-[5px]">
<ol className="list-disc">
<li>
<span className="font-bold">Yes:</span>
<span>
Selecting this option will send the signing
request to the first signer initially. Once the
first signer completes their part, the next
signer in the sequence will receive the request.
This process continues until all signers have
signed the document. This method ensures that
the document is signed in a specific order.
</span>
</li>
<li>
<span className="font-bold">No: </span>
<span>
Selecting this option will send the signing
links to all signers simultaneously. Every
signer can sign the document at their
convenience, regardless of whether other signers
have completed their signatures. This method is
faster but does not enforce any signing order
among the participants.
</span>
</li>
</ol>
</p>
<p>
Select the option that best suits the needs of your
document processing.
</p>
</div>
</Tooltip>
</label>
<div className="flex items-center gap-2 ml-2 mb-1">
<input
type="radio"
value={"true"}
name="SendinOrder"
checked={formData.SendinOrder === "true"}
className=""
onChange={handleStrInput}
/>
<div className="text-center">Yes</div>
<p>
Select the option that best suits the needs of your
document processing.
</p>
</div>
</Tooltip>
</label>
<div className="flex items-center gap-2 ml-2 mb-1">
<input
type="radio"
value={"true"}
className="op-radio op-radio-xs"
name="SendinOrder"
checked={formData.SendinOrder === "true"}
onChange={handleStrInput}
/>
<div className="text-center">Yes</div>
</div>
<div className="flex items-center gap-2 ml-2 mb-1">
<input
type="radio"
value={"false"}
name="SendinOrder"
className="op-radio op-radio-xs"
checked={formData.SendinOrder === "false"}
onChange={handleStrInput}
/>
<div className="text-center">No</div>
</div>
</div>
<div className="flex items-center gap-2 ml-2 mb-1">
<input
type="radio"
value={"false"}
name="SendinOrder"
checked={formData.SendinOrder === "false"}
onChange={handleStrInput}
/>
<div className="text-center">No</div>
</div>
</div>
{isEnableSubscription && (
<div className="text-xs mt-2">
<span
className={
isSubscribe
? "font-semibold"
: "font-semibold text-gray-300"
}
>
Auto reminder{" "}
{!isSubscribe && isEnableSubscription && <Upgrade />}
</span>
<label
className={`${
isSubscribe
? "cursor-pointer "
: "pointer-events-none opacity-50"
} relative block items-center mb-0`}
>
<input
type="checkbox"
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
checked={formData.autoreminder}
onChange={handleAutoReminder}
/>
</label>
</div>
)}
{formData?.autoreminder === true && (
<div className="text-xs mt-2">
<label className="block">
Remind once in every (Days)
<span className="text-red-500 text-[13px]">*</span>
</label>
<input
type="number"
value={formData.remindOnceInEvery}
name="remindOnceInEvery"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
onChange={handleStrInput}
required
/>
</div>
)}
</>
)}
<div className="flex items-center mt-3 gap-2 text-white">
<div className="flex items-center mt-3 gap-2">
<button
className={`${
isSubmit && "cursor-progress"
} bg-[#1ab6ce] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 focus:outline-none`}
isSubmit ? "cursor-progress" : ""
} op-btn op-btn-primary`}
type="submit"
disabled={isSubmit}
>
Next
</button>
<div
className="cursor-pointer bg-[#188ae2] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 text-center ml-[2px] focus:outline-none"
onClick={() => handleReset()}
className="op-btn op-btn-ghost"
onClick={() => handleCancel()}
>
Reset
Cancel
</div>
</div>
</form>
+140 -165
View File
@@ -1,26 +1,30 @@
import React, { useEffect, useState } from "react";
import Title from "../components/Title";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import Alert from "../primitives/Alert";
import ModalUi from "../primitives/ModalUi";
import { isEnableSubscription, rejectBtn, submitBtn } from "../constant/const";
import { isEnableSubscription } from "../constant/const";
import { checkIsSubscribed, copytoData, openInNewTab } from "../constant/Utils";
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
import Tooltip from "../primitives/Tooltip";
import Loader from "../primitives/Loader";
import SubscribeCard from "../primitives/SubscribeCard";
import Tour from "reactour";
const tourSteps = [
{
selector: '[data-tut="apisubscribe"]',
content: "Upgrade now to generate API token"
}
];
function GenerateToken() {
const navigation = useNavigate();
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [apiToken, SetApiToken] = useState("");
const [isLoader, setIsLoader] = useState(true);
const [copied, setCopied] = useState(false);
const [isGenerate, setIsGenerate] = useState(false);
const [isErr, setIsErr] = useState(false);
const [isModal, setIsModal] = useState(false);
const [isSubscribe, setIsSubscribe] = useState(false);
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
const [isTour, setIsTour] = useState(false);
useEffect(() => {
fetchToken();
// eslint-disable-next-line
@@ -32,7 +36,6 @@ function GenerateToken() {
const getIsSubscribe = await checkIsSubscribed();
setIsSubscribe(getIsSubscribe);
}
const url = parseBaseUrl + "functions/getapitoken";
const headers = {
"Content-Type": "application/json",
@@ -41,9 +44,8 @@ function GenerateToken() {
};
const res = await axios.post(url, {}, { headers: headers });
if (res) {
SetApiToken(res.data.result.result);
SetApiToken(res.data?.result?.result);
}
setIsLoader(false);
} catch (err) {
SetApiToken();
@@ -53,49 +55,43 @@ function GenerateToken() {
};
const handleSubmit = async (e) => {
e.preventDefault();
setIsLoader(true);
setIsModal(false);
try {
const url = parseBaseUrl + "functions/generateapitoken";
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessiontoken: localStorage.getItem("accesstoken")
};
await axios.post(url, {}, { headers: headers }).then((res) => {
if (!isSubscribe && isEnableSubscription) {
setIsTour(true);
} else {
setIsLoader(true);
setIsModal(false);
try {
const url = parseBaseUrl + "functions/generateapitoken";
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessiontoken: localStorage.getItem("accesstoken")
};
const res = await axios.post(url, {}, { headers: headers });
if (res) {
SetApiToken(res.data.result.token);
// localStorage.setItem("apiToken", res.data.result.token);
setIsGenerate(true);
setTimeout(() => {
setIsGenerate(false);
}, 1500);
setIsLoader(false);
setIsAlert({ type: "success", msg: "Token generated successfully." });
} else {
console.error("Error while generating Token");
setIsLoader(false);
setIsErr(true);
setTimeout(() => {
setIsErr(false);
}, 1500);
setIsAlert({ type: "danger", msg: "Something went wrong." });
}
});
} catch (error) {
setIsLoader(false);
setIsErr(true);
setTimeout(() => {
setIsErr(false);
}, 1500);
console.log("err", error);
} catch (error) {
setIsAlert({ type: "danger", msg: "Something went wrong." });
console.log("while generating Token", error);
} finally {
setIsLoader(false);
setTimeout(() => {
setIsAlert({ type: "success", msg: "" });
}, 1500);
}
}
};
const copytoclipboard = (text) => {
copytoData(text);
setCopied(true);
setIsAlert({ type: "success", msg: "Copied" });
setTimeout(() => {
setCopied(false);
setIsAlert({ type: "success", msg: "" });
}, 1500); // Reset copied state after 1.5 seconds
};
const handleModal = () => setIsModal(!isModal);
@@ -103,139 +99,118 @@ function GenerateToken() {
return (
<React.Fragment>
<Title title={"API Token"} />
{isGenerate && (
<Alert type="success">Token generated successfully!</Alert>
{isAlert.msg && (
<Alert type={isAlert.type}>
<div className="ml-3">{isAlert.msg}</div>
</Alert>
)}
{copied && <Alert type="success">Copied</Alert>}
{isErr && <Alert type="danger">Something went wrong!</Alert>}
{isLoader ? (
<div
style={{
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
<div className="flex justify-center items-center h-screen">
<Loader />
</div>
) : (
<div className="bg-white flex flex-col justify-center shadow rounded">
{!isEnableSubscription && <PremiumAlertHeader />}
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
OpenSign API{" "}
<Tooltip
url={
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
}
isSubscribe={true}
/>
</h1>
<ul
className={
isSubscribe || !isEnableSubscription
? "w-full flex flex-col p-2 text-sm "
: "w-full flex flex-col p-2 text-sm opacity-20 pointer-events-none select-none"
}
>
<li
className={`flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
>
<div className="w-[70%] flex-col md:flex-row flex items-center gap-5 ">
<span className="">Api Token:</span>{" "}
<span
id="token"
className=" md:text-end cursor-pointer"
onClick={() => copytoclipboard(apiToken)}
<>
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box mb-3">
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
OpenSign API{" "}
<Tooltip
url={
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
}
isSubscribe={true}
/>
</h1>
<ul className="w-full flex flex-col p-2 text-sm">
<li className="flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2">
<div className="w-full md:w-[70%] flex-col md:flex-row text-xs md:text-[15px] flex items-center gap-x-5">
<span className="ml-1">API Token:</span>{" "}
<span
id="token"
className={`${
isSubscribe
? ""
: "bg-white/20 pointer-events-none select-none"
} md:text-end py-2 md:py-0`}
>
<span
className="cursor-pointer"
onClick={() => copytoclipboard(apiToken)}
>
{apiToken ? apiToken : "_____"}
</span>
<button
className="op-btn op-btn-accent op-btn-outline op-btn-sm ml-2 cursor-pointer"
onClick={() => copytoclipboard(apiToken)}
>
<i className="fa-light fa-copy"></i>
</button>
</span>
</div>
<button
onClick={apiToken ? handleModal : handleSubmit}
className="op-btn op-btn-primary"
>
{apiToken ? apiToken : "_____"}
</span>
</div>
{apiToken ? "Regenerate Token" : "Generate Token"}
</button>
</li>
</ul>
<div className="flex items-center justify-center">
<button
type="button"
onClick={apiToken ? handleModal : handleSubmit}
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base focus:outline-none"
onClick={() =>
openInNewTab(
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
)
}
className="op-btn op-btn-secondary mt-2 mb-3 px-8"
>
{apiToken ? "Regenerate Token" : "Generate Token"}
View Docs
</button>
</li>
</ul>
<div className="flex items-center justify-center ">
<button
type="button"
onClick={() =>
openInNewTab(
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
)
}
className="rounded hover:bg-[#15b4e9] border-[1px] my-2 border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
>
View Docs
</button>
</div>
{!isSubscribe && isEnableSubscription && (
<>
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
Upgrade to PRO Plan
</h1>
<ul className={"w-full flex flex-col p-2 text-sm "}>
<li
className={`flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
>
<div className="w-[70%] flex-col md:flex-row flex items-center gap-3 ">
<span className="">$29.99/month:</span>{" "}
<span id="token" className=" md:text-end cursor-pointer">
Sign 100 docs using API. Only 0.15/docs after that.
</span>
</div>
{!isSubscribe && isEnableSubscription && (
<button
type="button"
onClick={() => navigation("/subscription")}
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
>
Upgrade Now
</button>
)}
</li>
</ul>
</>
)}
<ModalUi
isOpen={isModal}
title={"Regenerate Token"}
handleClose={handleModal}
>
<div className="m-[20px]">
<div className="text-lg font-normal text-black">
Are you sure you want to regenerate token it will expire old
token?
</div>
<hr className="bg-[#ccc] mt-4 " />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={handleSubmit}
className={submitBtn + "ml-[2px]"}
>
Yes
</button>
<button onClick={handleModal} className={rejectBtn}>
No
</button>
</div>
</div>
</ModalUi>
</div>
<ModalUi
isOpen={isModal}
title={apiToken ? "Regenerate Token" : "Generate Token"}
handleClose={handleModal}
>
<div className="m-[20px]">
<div className="text-lg font-normal text-base-content">
Are you sure you want to regenerate token it will expire old
token?
</div>
<hr className="bg-[#ccc] mt-4" />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={handleSubmit}
className="op-btn op-btn-primary ml-[2px]"
>
Yes
</button>
<button
onClick={handleModal}
className="op-btn op-btn-secondary"
>
No
</button>
</div>
</div>
</ModalUi>
</div>
{!isSubscribe && isEnableSubscription && (
<div data-tut="apisubscribe">
<SubscribeCard />
</div>
)}
</>
)}
<Tour
onRequestClose={() => setIsTour(false)}
steps={tourSteps}
isOpen={isTour}
closeWithMask={false}
disableKeyboardNavigation={["esc"]}
scrollOffset={-100}
rounded={5}
/>
</React.Fragment>
);
}
+193 -175
View File
@@ -1,16 +1,16 @@
import React, { useState, useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom";
import "../styles/loginPage.css";
import loader from "../assets/images/loader2.gif";
import axios from "axios";
import { isEnableSubscription, themeColor } from "../constant/const";
import { isEnableSubscription } from "../constant/const";
import { contractUsers, getAppLogo } from "../constant/Utils";
import logo from "../assets/images/logo.png";
import { appInfo } from "../constant/appinfo";
import Parse from "parse";
import Loader from "../primitives/Loader";
function GuestLogin() {
const { id, userMail, contactBookId, base64url } = useParams();
let navigate = useNavigate();
const navigate = useNavigate();
const [email, setEmail] = useState(userMail);
const [OTP, setOTP] = useState("");
const [EnterOTP, setEnterOtp] = useState(false);
@@ -19,18 +19,19 @@ function GuestLogin() {
const [appLogo, setAppLogo] = useState("");
const [documentId, setDocumentId] = useState(id);
const [contactId, setContactId] = useState(contactBookId);
const [sendmail, setSendmail] = useState();
const [contact, setContact] = useState({ name: "", phone: "", email: "" });
useEffect(() => {
handleServerUrl();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
//function generate serverUrl and parseAppId from url and save it in local storage
const handleServerUrl = async () => {
if (isEnableSubscription) {
const applogo = await getAppLogo();
if (applogo) {
setAppLogo(applogo);
const app = await getAppLogo();
if (app?.logo) {
setAppLogo(app?.logo);
} else {
setAppLogo(logo);
}
@@ -41,10 +42,8 @@ function GuestLogin() {
localStorage.clear();
const parseId = appInfo.appId;
const newServer = `${appInfo.baseUrl}/`;
const appName = appInfo.appname;
localStorage.setItem("baseUrl", newServer);
localStorage.setItem("parseAppId", parseId);
localStorage.setItem("_appName", appName);
//this condition is used decode base64 to string and get userEmail,documentId, contactBoookId data.
if (!id) {
//`atob` function is used to decode base64
@@ -52,53 +51,51 @@ function GuestLogin() {
//split url in array from '/'
const checkSplit = decodebase64.split("/");
setDocumentId(checkSplit[0]);
setContact((prev) => ({ ...prev, email: checkSplit[1] }));
setEmail(checkSplit[1]);
setContactId(checkSplit[2]);
const contactId = checkSplit?.[2];
setSendmail(checkSplit[3]);
if (!contactId) {
const params = { email: checkSplit[1], docId: checkSplit[0] };
try {
const linkContactRes = await Parse.Cloud.run(
"linkcontacttodoc",
params
);
// console.log("linkContactRes ", linkContactRes);
setContactId(linkContactRes?.contactId);
} catch (err) {
console.log("Err in link ext contact", err);
}
} else {
setContactId(checkSplit[2]);
}
}
setIsLoading(false);
};
const handleChange = (event) => {
const { value } = event.target;
setOTP(value);
};
//send email OTP function
const SendOtp = async (e) => {
const serverUrl =
localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl");
const parseId =
localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId");
if (serverUrl && localStorage) {
setLoading(true);
e.preventDefault();
setEmail(email);
try {
let url = `${serverUrl}functions/SendOTPMailV1/`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseId
};
let body = {
email: email.toString(),
docId: documentId
};
let Otp = await axios.post(url, body, { headers: headers });
if (Otp) {
setLoading(false);
setEnterOtp(true);
}
} catch (error) {
alert("something went wrong!");
const SendOtp = async () => {
setLoading(true);
setEmail(email);
try {
const params = { email: email.toString(), docId: documentId };
const Otp = await Parse.Cloud.run("SendOTPMailV1", params);
if (Otp) {
setLoading(false);
setEnterOtp(true);
}
} else {
} catch (error) {
alert("something went wrong!");
}
};
const handleSendOTPBtn = async (e) => {
e.preventDefault();
await SendOtp();
};
//verify OTP send on via email
const VerifyOTP = async (e) => {
e.preventDefault();
@@ -127,14 +124,16 @@ function GuestLogin() {
setLoading(false);
} else {
let _user = user.data.result;
await Parse.User.become(_user.sessionToken);
const parseId = localStorage.getItem("parseAppId");
const contractUserDetails = await contractUsers(_user.email);
const contractUserDetails = await contractUsers();
localStorage.setItem("UserInformation", JSON.stringify(_user));
localStorage.setItem(
`Parse/${parseId}/currentUser`,
JSON.stringify(_user)
);
if (contractUserDetails) {
// console.log("contractUserDetails ", contractUserDetails);
if (contractUserDetails && contractUserDetails.length > 0) {
localStorage.setItem(
"Extand_Class",
JSON.stringify(contractUserDetails)
@@ -146,7 +145,13 @@ function GuestLogin() {
//save isGuestSigner true in local to handle login flow header in mobile view
localStorage.setItem("isGuestSigner", true);
setLoading(false);
navigate(`/load/recipientSignPdf/${documentId}/${contactId}`);
if (sendmail === "false") {
navigate(
`/load/recipientSignPdf/${documentId}/${contactId}?sendmail=${sendmail}`
);
} else {
navigate(`/load/recipientSignPdf/${documentId}/${contactId}`);
}
}
} catch (error) {
console.log("err ", error);
@@ -155,156 +160,169 @@ function GuestLogin() {
alert("Please Enter OTP!");
}
};
const handleUserData = async (e) => {
e.preventDefault();
const params = { ...contact, docId: documentId };
try {
setLoading(true);
const linkContactRes = await Parse.Cloud.run("linkcontacttodoc", params);
// console.log("linkContactRes ", linkContactRes);
setContactId(linkContactRes.contactId);
setEnterOtp(true);
await SendOtp();
} catch (err) {
setLoading(false);
alert("something went wron, please try agian later.");
console.log("Err in link ext contact", err);
}
};
const handleInputChange = (e) => {
setContact((prev) => ({ ...prev, [e.target.name]: e.target.value }));
};
return (
<div style={{ padding: "2rem", background: "white" }}>
<div className="p-[2rem]">
{isLoading ? (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
flexDirection: "column"
}}
>
<img
alt="no img"
src={loader}
style={{ width: "80px", height: "80px" }}
/>
<span style={{ fontSize: "13px", color: "gray" }}>
{isLoading.message}
</span>
<div className="flex flex-col justify-center items-center h-[100vh]">
<Loader />
<span className="text-[13px] text-[gray]">{isLoading.message}</span>
</div>
) : (
<div
style={{
margin: "10px",
border: "0.5px solid #c5c7c9",
padding: "30px",
boxShadow: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"
}}
>
<div className="main_head">
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
{appLogo && (
<img
src={appLogo}
className="object-contain h-full"
alt="logo"
/>
)}
</div>
<div className="m-1 md:m-2 p-[30px] text-base-content bg-base-100 op-card shadow-md">
<div className="md:w-[250px] md:h-[66px] inline-block overflow-hidden mt-2 mb-11">
{appLogo && (
<img src={appLogo} className="object-contain" alt="logo" />
)}
</div>
{!EnterOTP ? (
<div className="row">
<div className="col-sm-6 KLO">
<span className="welcomeText">Welcome Back !</span>
<br />
<span className="KNLO">
Verification code is sent to your email
</span>
<div className="card card-box" style={{ borderRadius: "0px" }}>
<div className="card-body">
{contactId ? (
<>
{!EnterOTP ? (
<div className="w-full md:w-[50%] text-base-content">
<h1 className="text-2xl md:text-[30px]">Welcome Back!</h1>
<legend className="text-[12px] text-[#878787] mt-2 mb-1">
Verification code is sent to your email
</legend>
<div className="p-[20px] outline outline-1 outline-slate-300/50 my-2 op-card shadow-md">
<input
type="email"
name="mobile"
value={email}
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full disabled:text-[#5c5c5c] text-xs"
disabled
className="loginInput"
/>
<br />
</div>
<div className="mt-3">
<button
className="op-btn op-btn-primary"
onClick={(e) => handleSendOTPBtn(e)}
disabled={loading}
>
{loading ? "Loading..." : "Get verification code"}
</button>
</div>
</div>
<div className="btnContainer">
{loading ? (
<button
type="button"
style={{
background: themeColor,
color: "white"
}}
className="verifyBtn"
disabled
>
<span
className="spinner-border spinner-border-sm "
role="status"
aria-hidden="true"
></span>
Loading...
</button>
) : (
<button
className="verifyBtn"
style={{
background: themeColor,
color: "white",
marginLeft: "0px !important"
}}
onClick={(e) => SendOtp(e)}
>
Send OTP
</button>
)}
</div>
</div>
</div>
) : (
<div className="row">
<div className="col-sm-6 KLO">
<span className="welcomeText">Welcome Back !</span>
<br />
<span className="KNLO">You will get a OTP via Email</span>
<div className="card card-box">
<div className="card-body">
<label>Enter Verification Code</label>
) : (
<form
className="w-full md:w-[50%] text-base-content"
onSubmit={VerifyOTP}
>
<h1 className="text-2xl md:text-[30px]">Welcome Back!</h1>
<legend className="text-[12px] text-[#878787] mt-2">
You will get a verification code via Email
</legend>
<div className="p-[20px] pt-[15px] outline outline-1 outline-slate-300/50 op-card my-2 shadow-md">
<p className="text-sm">Enter Verification Code</p>
<input
type="number"
className="loginInput"
className="mt-2 op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
name="OTP"
value={OTP}
onChange={handleChange}
onChange={(e) => setOTP(e.target.value)}
/>
<br />
</div>
</div>
<div>
{loading ? (
<div className="mt-2.5">
<button
style={{
background: themeColor,
color: "white"
}}
className="verifyBtn"
type="button"
disabled
className="op-btn op-btn-primary"
type="submit"
disabled={loading}
>
<span
className="spinner-border spinner-border-sm "
role="status"
aria-hidden="true"
></span>
Loading...
{loading ? "Loading..." : "Verify"}
</button>
) : (
<button
type="button"
onClick={(e) => VerifyOTP(e)}
style={{
background: themeColor,
color: "white"
}}
className="verifyBtn"
>
Verify
</button>
)}
</div>
</form>
)}
</>
) : (
<div className="w-full md:w-[50%] text-base-content">
<h1 className="text-2xl md:text-[30px]">Welcome</h1>
<legend className="text-[12px] text-[#878787] mt-2">
Provide your details
</legend>
<form
className="p-[20px] pt-[15px] outline outline-1 outline-slate-300/50 my-2 op-card shadow-md"
onSubmit={handleUserData}
>
<div className="mb-2">
<label
htmlFor="name"
className="block text-xs text-gray-700 font-semibold"
>
Name
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="text"
name="name"
value={contact.name}
onChange={handleInputChange}
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
disabled={loading}
required
/>
</div>
</div>
<div className="mb-2">
<label
htmlFor="email"
className="block text-xs text-gray-700 font-semibold"
>
Email
<span className="text-[red] text-[13px]"> *</span>
</label>
<input
type="email"
name="email"
value={contact.email}
onChange={handleInputChange}
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
required
disabled
/>
</div>
<div className="mt-2.5">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
Phone
</label>
<input
type="text"
name="phone"
value={contact.phone}
onChange={handleInputChange}
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
disabled={loading}
/>
</div>
<div className="mt-2 flex justify-start">
<button
type="submit"
className="op-btn op-btn-primary"
disabled={loading}
>
{loading ? "Loading..." : "Next"}
</button>
</div>
</form>
</div>
)}
</div>
File diff suppressed because it is too large Load Diff
+142 -230
View File
@@ -4,10 +4,10 @@ import "../styles/managesign.css";
import "../styles/signature.css";
import { toDataUrl } from "../constant/Utils";
import Parse from "parse";
import { appInfo } from "../constant/appinfo";
import { SaveFileSize } from "../constant/saveFileSize";
import Alert from "../primitives/Alert";
import Loader from "../primitives/Loader";
const ManageSign = () => {
const appName = appInfo.appname;
const [penColor, setPenColor] = useState("blue");
const [initialPen, setInitialPen] = useState("blue");
const [image, setImage] = useState();
@@ -17,7 +17,7 @@ const ManageSign = () => {
const [isvalue, setIsValue] = useState(false);
const allColor = ["blue", "red", "black"];
const [isLoader, setIsLoader] = useState(true);
const [isSuccess, setIsSuccess] = useState(false);
const [isAlert, setIsAlert] = useState({ type: "success", message: "" });
const [Initials, setInitials] = useState("");
const [isInitials, setIsInitials] = useState(false);
const [id, setId] = useState("");
@@ -37,7 +37,7 @@ const ManageSign = () => {
objectId: User.id
};
try {
const signCls = `${appName}_Signature`;
const signCls = "contracts_Signature";
const signQuery = new Parse.Query(signCls);
signQuery.equalTo("UserId", userId);
const signRes = await signQuery.first();
@@ -172,7 +172,7 @@ const ManageSign = () => {
};
const saveEntry = async (obj) => {
const signCls = `${appName}_Signature`;
const signCls = "contracts_Signature";
const User = Parse.User.current().id;
const userId = { __type: "Pointer", className: "_User", objectId: User };
if (id) {
@@ -185,12 +185,20 @@ const ManageSign = () => {
updateSign.set("UserId", userId);
const res = await updateSign.save();
setIsLoader(false);
setIsSuccess(true);
setIsAlert({
type: "success",
message: "Signature saved successfully."
});
setTimeout(() => setIsAlert({}), 2000);
return res;
} catch (err) {
console.log(err);
setIsLoader(false);
alert(`${err.message}`);
setIsAlert({
type: "danger",
message: `${err.message}`
});
setTimeout(() => setIsAlert({}), 2000);
}
} else {
try {
@@ -201,21 +209,24 @@ const ManageSign = () => {
updateSign.set("UserId", userId);
const res = await updateSign.save();
setIsLoader(false);
setIsSuccess(true);
setIsAlert({
type: "success",
message: "Signature saved successfully."
});
setTimeout(() => setIsAlert({}), 2000);
return res;
} catch (err) {
console.log(err);
setIsLoader(false);
alert(`${err.message}`);
setIsAlert({
type: "success",
message: `${err.message}`
});
setTimeout(() => setIsAlert({}), 2000);
}
}
};
const handleSignatureBtn = () => {
if (imageRef.current) {
imageRef.current.value = "";
}
setImage("");
};
const handleUploadBtn = () => {
imageRef.current.click();
};
@@ -224,213 +235,130 @@ const ManageSign = () => {
setIsValue(true);
};
return (
<div className="relative h-full bg-white flex shadow rounded overflow-auto">
<div className="relative h-full bg-base-100 text-base-content flex shadow-md rounded-box overflow-auto">
{isLoader && (
<div className="absolute bg-black bg-opacity-75 z-50 w-full h-full flex justify-center items-center">
<div
style={{ color: "#3dd3e0" }}
className="loader-37 text-[45px]"
></div>
<div className="absolute bg-black bg-opacity-30 z-50 w-full h-full flex justify-center items-center">
<Loader />
</div>
)}
{isSuccess && (
<div
className="alert alert-success successBox"
role="alert"
onAnimationEnd={() => setIsSuccess(false)}
>
Signature saved successfully!
</div>
)}
<div
className="mainDiv"
style={{
width: "100%",
paddingRight: "10px"
}}
>
<div style={{ margin: 20 }}>
<div
style={{
fontWeight: "700",
fontSize: 15,
color: "#000",
paddingBottom: 8
}}
>
{isAlert?.message && <Alert type={isAlert.type}>{isAlert.message}</Alert>}
<div className="relative w-full">
<div className="ml-[5px] my-[20px] md:m-[20px]">
<div className="text-[20px] font-semibold m-[10px] md:m-0 mb-2">
My Signature
</div>
<div className="signBlock mt-4">
<div>
<div style={{ position: "relative" }}>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
width: "50%",
paddingLeft: 10
}}
>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-around",
alignItems: "center",
gap: 10,
marginBottom: 10
}}
>
<>
<span
onClick={() => handleSignatureBtn()}
className="signature"
>
Signature
</span>
</>
<span
onClick={() => handleUploadBtn()}
className="imgupload"
>
Upload Image
</span>
<input
type="file"
onChange={onImageChange}
className="filetype"
accept="image/*"
ref={imageRef}
hidden
/>
</div>
</div>
<div style={{ position: "relative" }}>
<div>
{image ? (
<div
style={{
position: "relative",
border: "2px solid #888"
}}
className="signatureCanvas"
>
<img
alt="preview image"
src={image}
style={{
width: "100%",
height: "100%",
objectFit: "contain"
}}
/>
</div>
) : (
<SignatureCanvas
ref={canvasRef}
penColor={penColor}
canvasProps={{
width: "456px",
height: "180px",
className: "signatureCanvas"
}}
backgroundColor="rgb(255, 255, 255)"
onEnd={() =>
handleSignatureChange(canvasRef.current.toDataURL())
}
dotSize={1}
<div className="flex flex-col md:flex-row gap-0 md:gap-[12px]">
<div className="relative">
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
Signature
</span>
<input
type="file"
onChange={onImageChange}
className="filetype"
accept="image/*"
ref={imageRef}
hidden
/>
<div className="relative">
<div>
{image ? (
<div className="signatureCanvas relative border-[2px] border-[#888] rounded-box overflow-hidden">
<img
alt="signature"
src={image}
className="w-full h-full object-contain"
/>
)}
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between"
</div>
) : (
<SignatureCanvas
ref={canvasRef}
penColor={penColor}
canvasProps={{
width: "456px",
height: "180px",
className: "signatureCanvas rounded-box"
}}
className="penContainerDefault"
>
<div>
{!image && (
<div
style={{ display: "flex", flexDirection: "row" }}
>
{allColor.map((data, key) => {
return (
<i
style={{
margin: "5px",
color: data,
borderBottom:
key === 0 && penColor === "blue"
? "2px solid blue"
: key === 1 && penColor === "red"
backgroundColor="rgb(255, 255, 255)"
onEnd={() =>
handleSignatureChange(canvasRef.current.toDataURL())
}
dotSize={1}
/>
)}
<div className="penContainerDefault flex flex-row justify-between">
<div>
{!image && (
<div className="flex flex-row">
{allColor.map((data, key) => {
return (
<i
style={{
margin: "5px",
color: data,
borderBottom:
key === 0 && penColor === "blue"
? "2px solid blue"
: key === 1 && penColor === "red"
? "2px solid red"
: key === 2 && penColor === "black"
? "2px solid black"
: "2px solid white"
}}
onClick={() => {
if (key === 0) {
setPenColor("blue");
} else if (key === 1) {
setPenColor("red");
} else if (key === 2) {
setPenColor("black");
}
}}
key={key}
className="fa solid fa-pen-nib"
width={20}
height={20}
></i>
);
})}
</div>
)}
</div>
<div>
<div
type="button"
className="clearbtn cursor-pointer"
onClick={() => handleClear()}
>
Clear
? "2px solid black"
: "2px solid white"
}}
onClick={() => {
if (key === 0) {
setPenColor("blue");
} else if (key === 1) {
setPenColor("red");
} else if (key === 2) {
setPenColor("black");
}
}}
key={key}
className="fa-light fa-pen-nib"
width={20}
height={20}
></i>
);
})}
</div>
)}
</div>
<div className="flex flex-row gap-2 text-sm md:text-base mr-1">
<div
type="button"
className="op-link"
onClick={() => handleUploadBtn()}
>
Upload image
</div>
<div
type="button"
className="op-link"
onClick={() => handleClear()}
>
Clear
</div>
</div>
</div>
{warning && (
<div
className="warning signWarning"
style={{ fontSize: 12 }}
>
<i
className="fas fa-exclamation-circle"
style={{ color: "#fab005", fontSize: 15 }}
></i>{" "}
Please upload signature/Image
</div>
)}
</div>
{warning && (
<span className="customwarning signWarning text-[12px] w-[220px] md:w-[300px]">
<i className="fa-light fa-exclamation-circle text-[#fab005] text-[15px] mr-[4px]"></i>
Please upload signature/Image
</span>
)}
</div>
</div>
<div style={{ position: "relative" }}>
<div style={{ margin: "6px 5px 18px" }}>
<span className="signature">Initials</span>
</div>
<div className="relative">
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
Initials
</span>
<div>
{isInitials ? (
<div
style={{
position: "relative",
border: "2px solid #888"
}}
className="intialSignature"
>
<div className="intialSignature relative border-[1px] border-[#888] rounded-box overflow-hidden">
<img
alt="preview image"
alt="inititals"
src={Initials}
style={{
width: "100%",
@@ -444,7 +372,7 @@ const ManageSign = () => {
ref={initailsRef}
penColor={initialPen}
canvasProps={{
className: "intialSignature"
className: "intialSignature rounded-box"
}}
backgroundColor="rgb(255, 255, 255)"
onEnd={() =>
@@ -453,17 +381,10 @@ const ManageSign = () => {
dotSize={1}
/>
)}
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between"
}}
className="penContainerInitial"
>
<div className="flex flex-row justify-between w-[183px]">
<div>
{!isInitials && (
<div style={{ display: "flex", flexDirection: "row" }}>
<div className="flex flex-row">
{allColor.map((data, key) => {
return (
<i
@@ -474,10 +395,10 @@ const ManageSign = () => {
key === 0 && initialPen === "blue"
? "2px solid blue"
: key === 1 && initialPen === "red"
? "2px solid red"
: key === 2 && initialPen === "black"
? "2px solid black"
: "2px solid white"
? "2px solid red"
: key === 2 && initialPen === "black"
? "2px solid black"
: "2px solid white"
}}
onClick={() => {
if (key === 0) {
@@ -489,7 +410,7 @@ const ManageSign = () => {
}
}}
key={key}
className="fa solid fa-pen-nib"
className="fa-light fa-pen-nib"
width={20}
height={20}
></i>
@@ -501,7 +422,7 @@ const ManageSign = () => {
<div>
<div
type="button"
className="clearbtn cursor-pointer"
className="op-link text-sm md:text-base mr-1"
onClick={() => handleClearInitials()}
>
Clear
@@ -509,20 +430,11 @@ const ManageSign = () => {
</div>
</div>
</div>
{/* {!warning && (
<div className="warning signWarning" style={{ fontSize: 12 }}>
<i
className="fas fa-exclamation-circle"
style={{ color: "#fab005", fontSize: 15 }}
></i>{" "}
Please upload signature/Image
</div>
)} */}
</div>
</div>
<div style={{ paddingTop: 10 }}>
<div className="pt-3 ml-2 md:ml-0">
<button
className="customBtn successBtn"
className="op-btn op-btn-primary"
onClick={(e) => handleSubmit(e)}
>
save
+283 -425
View File
@@ -1,7 +1,6 @@
import React, { useEffect, useState, useRef } from "react";
import "../styles/opensigndrive.css";
import loader from "../assets/images/loader2.gif";
import { themeColor, iconColor } from "../constant/const";
import { iconColor } from "../constant/const";
import { getDrive } from "../constant/Utils";
import { useNavigate } from "react-router-dom";
import Title from "../components/Title";
@@ -10,27 +9,15 @@ import ModalUi from "../primitives/ModalUi";
import TourContentWithBtn from "../primitives/TourContentWithBtn";
import Tour from "reactour";
import axios from "axios";
import Loader from "../primitives/Loader";
const DriveBody = React.lazy(
() => import("../components/opensigndrive/DriveBody")
);
const Loader = () => {
const AppLoader = () => {
return (
<div
style={{
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
<div className="h-[100vh] flex justify-center items-center">
<Loader />
</div>
);
};
@@ -279,12 +266,13 @@ function Opensigndrive() {
setNewFolderName(value);
};
//function for create folder
const handleAddFolder = async () => {
const handleAddFolder = async (e) => {
e.preventDefault();
if (newFolderName) {
setIsFolderLoader(true);
const getParentObjId = folderName[folderName.length - 1];
const parentId = getParentObjId && getParentObjId.objectId;
const foldercls = `${localStorage.getItem("_appName")}_Document`;
const foldercls = "contracts_Document";
const folderPtr = {
__type: "Pointer",
className: foldercls,
@@ -300,6 +288,7 @@ function Opensigndrive() {
const exsitQuery = new Parse.Query(foldercls);
exsitQuery.equalTo("Name", newFolderName);
exsitQuery.equalTo("Type", "Folder");
exsitQuery.notEqualTo("IsArchive", true);
if (parentId) {
exsitQuery.equalTo("Folder", folderPtr);
}
@@ -449,21 +438,10 @@ function Opensigndrive() {
<React.Fragment key={id}>
<span
onClick={() => handleRoute(id, folderData)}
style={{
color: "#a64b4e",
fontWeight: "400",
cursor: "pointer"
}}
className="text-[#a64b4e] font-normal cursor-pointer"
>
{data.name}
<span
style={{
color: "#a64b4e",
fontWeight: "200",
cursor: "pointer",
margin: "0 4px"
}}
>
<span className="text-[#a64b4e] font-extralight cursor-pointer mx-[4px]">
&gt;
</span>
</span>
@@ -487,7 +465,6 @@ function Opensigndrive() {
if (isDontShow) {
const serverUrl = localStorage.getItem("baseUrl");
const appId = localStorage.getItem("parseAppId");
const extUserClass = localStorage.getItem("extended_class");
const json = JSON.parse(localStorage.getItem("Extand_Class"));
const extUserId = json && json.length > 0 && json[0].objectId;
let updatedTourStatus = [];
@@ -505,7 +482,7 @@ function Opensigndrive() {
updatedTourStatus = [{ driveTour: true }];
}
await axios.put(
serverUrl + "classes/" + extUserClass + "/" + extUserId,
serverUrl + "classes/contracts_Users/" + extUserId,
{
TourStatus: updatedTourStatus
},
@@ -519,10 +496,7 @@ function Opensigndrive() {
};
//function to use check tour status of open sign drive
async function checkTourStatus() {
const currentUser = Parse.User.current();
const cloudRes = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
const cloudRes = await Parse.Cloud.run("getUserDetails");
const res = { data: cloudRes.toJSON() };
if (res.data && res.data.TourStatus && res.data.TourStatus.length > 0) {
const tourStatus = res.data.TourStatus;
@@ -544,411 +518,295 @@ function Opensigndrive() {
}
}
return (
<div style={{ backgroundColor: "white" }} className="folderComponent">
<div className="bg-base-100 text-base-content rounded-box w-full shadow-md">
<Title title={"OpenSign™ Drive"} drive={true} />
<div>
<ModalUi
headerColor={"#dc3545"}
isOpen={isAlert.isShow}
title={"Alert"}
handleClose={() => {
setIsAlert({
isShow: false,
alertMessage: ""
});
}}
>
<div style={{ height: "100%", padding: 20 }}>
<p>{isAlert.alertMessage}</p>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginTop: "15px",
marginBottom: "15px"
}}
></div>
<button
onClick={() =>
setIsAlert({
isShow: false,
alertMessage: ""
})
}
type="button"
className="finishBtn cancelBtn"
<ModalUi
isOpen={isAlert.isShow}
title={"Alert"}
handleClose={() => {
setIsAlert({
isShow: false,
alertMessage: ""
});
}}
>
<div className="h-full p-[20px] pb-[15px]">
<p>{isAlert.alertMessage}</p>
<div className="h-[1px] bg-[#9f9f9f] w-full my-[15px]"></div>
<button
onClick={() =>
setIsAlert({
isShow: false,
alertMessage: ""
})
}
type="button"
className="op-btn op-btn-neutral op-btn-sm"
>
Close
</button>
</div>
</ModalUi>
<ModalUi
isOpen={isFolder}
title={"Add New Folder"}
handleClose={oncloseFolder}
>
<div className="h-full p-[20px] pt-[10px] pb-[15px]">
{folderLoader ? (
<div className="h-[200px] flex justify-center items-center">
<Loader />
</div>
) : (
<form
onSubmit={handleAddFolder}
className="flex flex-col text-base-content"
>
Close
</button>
</div>
</ModalUi>
<ModalUi
isOpen={isFolder}
title={"Add New Folder"}
handleClose={oncloseFolder}
>
<div style={{ height: "100%", padding: 20 }}>
{folderLoader ? (
<div
style={{
height: "200px",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center"
}}
>
<img
alt="loader img"
src={loader}
style={{ width: "50px", height: "50px" }}
/>
<span style={{ fontSize: "13px", color: "gray" }}>
Loading...
</span>
<label className="py-[8px] text-[15px] font-[400] mb-0">
Name
<span className="text-[red]">*</span>
</label>
<input
required
className="op-input op-input-bordered op-input-sm"
type="text"
value={newFolderName}
onChange={(e) => handleFolderName(e)}
/>
<span className="text-[red] text-[12px] mt-[6px]">{error}</span>
<div className="w-full h-[1px] bg-[#9f9f9f] my-[15px]"></div>
<div className="flex flex-row">
<button type="submit" className="op-btn op-btn-primary">
Add
</button>
<button
type="button"
className="op-btn op-btn-ghost ml-1"
onClick={oncloseFolder}
>
Close
</button>
</div>
) : (
<form
onSubmit={(e) => {
e.preventDefault();
handleAddFolder();
}}
style={{ display: "flex", flexDirection: "column" }}
>
<label
style={{
margin: "10px 0px 10px 0px",
fontSize: "15px",
fontWeight: "400"
}}
>
Name
<span style={{ color: "red" }}>*</span>
</label>
<input
required
className="form-control inputStyle"
type="text"
value={newFolderName}
onChange={(e) => handleFolderName(e)}
// className="addFolderInput"
/>
<span
style={{ color: "red", fontSize: "12px", marginTop: "6px" }}
>
{error}
</span>
<div
style={{
height: "1px",
backgroundColor: "#9f9f9f",
width: "100%",
marginTop: "15px",
marginBottom: "15px"
}}
></div>
<div style={{ display: "flex", flexDirection: "row" }}>
<button
style={{ background: themeColor }}
type="submit"
className="finishBtn"
>
Add
</button>
<button
type="button"
className="finishBtn cancelBtn"
onClick={oncloseFolder}
>
Close
</button>
</div>
</form>
</form>
)}
</div>
</ModalUi>
{isLoading.isLoad ? (
<div className="flex flex-col justify-center items-center h-[100vh] w-full">
<Loader />
<span className="text-[13px] text-base-content">
{isLoading.message}
</span>
</div>
) : handleError ? (
<div className="flex justify-center items-center h-[100vh] w-full">
<span className="text-[20px] text-base-content">{handleError}</span>
</div>
) : (
<>
<div className="flex flex-row justify-between items-center px-[25px] pt-[20px]">
{tourData && (
<Tour
onRequestClose={closeTour}
steps={tourData}
isOpen={isTour}
closeWithMask={false}
scrollOffset={-100}
rounded={5}
/>
)}
</div>
</ModalUi>
{isLoading.isLoad ? (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
width: "100%",
flexDirection: "column"
}}
>
<img
alt="loader img"
src={loader}
style={{ width: "80px", height: "80px" }}
/>
<span style={{ fontSize: "13px", color: "gray" }}>
{isLoading.message}
</span>
</div>
) : handleError ? (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
width: "100%"
}}
>
<span style={{ fontSize: "20px", color: "gray" }}>
{handleError}
</span>
</div>
) : (
<>
<div className="folderContainer">
{tourData && (
<Tour
onRequestClose={closeTour}
steps={tourData}
isOpen={isTour}
closeWithMask={false}
scrollOffset={-100}
rounded={5}
/>
)}
<div
data-tut="reactourFirst"
onMouseEnter={(e) => handleMouseEnter(e)}
ref={scrollRef}
className="w-full whitespace-nowrap cursor-pointer select-none overflow-x-auto"
>
{handleFolderTab(folderName)}
</div>
<div className="flex flex-row items-center">
<div
data-tut="reactourFirst"
onMouseEnter={(e) => handleMouseEnter(e)}
ref={scrollRef}
style={{
width: "100%"
}}
className="folderPath"
id="folder-menu"
className={
isNewFol ? "dropdown show dropDownStyle" : "dropdown"
}
onClick={() => setIsNewFol(!isNewFol)}
>
{handleFolderTab(folderName)}
</div>
<div className="dropMenuBD">
<div
id="folder-menu"
className={
isNewFol ? "dropdown show dropDownStyle" : "dropdown"
}
onClick={() => setIsNewFol(!isNewFol)}
>
<div className="sort" data-tut="reactourSecond">
<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={() => setIsFolder(true)}
>
<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 className="sort" data-tut="reactourSecond">
<i
className="fa-light fa-plus-square"
aria-hidden="true"
style={{ fontSize: "25px", color: `${iconColor}` }}
></i>
</div>
<div
id="menu-container"
className={isShowSort ? "dropdown show" : "dropdown"}
onClick={() => setIsShowSort(!isShowSort)}
className={isNewFol ? "dropdown-menu show" : "dropdown-menu"}
aria-labelledby="dropdownMenuButton"
aria-expanded={isNewFol ? "true" : "false"}
>
<div
data-tut="reactourThird"
className=" sort "
data-toggle="dropdown"
>
<i
className="fa fa-sort-amount-asc"
aria-hidden="true"
style={{
marginRight: "5px",
fontSize: "14px",
color: `${iconColor}`
}}
></i>
<div className="flex flex-col">
<span
style={{
fontSize: "15px",
color: `${iconColor}`
}}
className="dropdown-item text-[10px] md:text-[13px]"
onClick={() => setIsFolder(true)}
>
{selectedSort}
<i
className="fa-light fa-plus mr-[5px]"
aria-hidden="true"
></i>
Create folder
</span>
<span
className="dropdown-item text-[10px] md:text-[13px]"
onClick={() => navigate("/form/sHAnZphf69")}
>
<i className="fa-light fa-pen-nib mr-[5px]"></i>
Sign Yourself
</span>
<span
className="dropdown-item text-[10px] md:text-[13px]"
onClick={() => navigate("/form/8mZzFxbG1z")}
>
<i className="fa-light fa-file-signature mr-[5px]"></i>
Request Signatures
</span>
</div>
<div
className={
isShowSort ? "dropdown-menu show" : "dropdown-menu"
}
aria-labelledby="dropdownMenuButton"
aria-expanded={isShowSort ? "true" : "false"}
>
{sortingValue.map((value, ind) => {
return (
<span
key={ind}
onClick={() => {
setSelectedSort(value);
sortingData(value, null, pdfData);
}}
className="dropdown-item itemColor"
style={{
paddingLeft: selectedSort !== value && "33px"
}}
>
{selectedSort === value && (
<i
className="fa fa-check"
aria-hidden="true"
style={{ marginRight: "5px" }}
></i>
)}
{value}
</span>
);
})}
<hr className="hrStyle" />
{sortOrder.map((order, ind) => {
return (
<span
key={ind}
onClick={() => {
setSortingOrder(order);
sortingData(null, order, pdfData);
}}
className="dropdown-item itemColor"
style={{
paddingLeft: sortingOrder !== order && "33px"
}}
>
{sortingOrder === order && (
<i
className="fa fa-check"
aria-hidden="true"
style={{ marginRight: "5px" }}
></i>
)}
{order}
</span>
);
})}
</div>
</div>
</div>
<div
id="menu-container"
className={isShowSort ? "dropdown show" : "dropdown"}
onClick={() => setIsShowSort(!isShowSort)}
>
<div
data-tut="reactourThird"
className="sort "
data-toggle="dropdown"
>
<i
className="fa-light fa-sort-amount-asc mr-[5px] text-[14px]"
aria-hidden="true"
style={{ color: `${iconColor}` }}
></i>
<span style={{ fontSize: "15px", color: `${iconColor}` }}>
{selectedSort}
</span>
</div>
<div
className={
isShowSort ? "dropdown-menu show" : "dropdown-menu"
}
aria-labelledby="dropdownMenuButton"
aria-expanded={isShowSort ? "true" : "false"}
>
{sortingValue.map((value, ind) => {
return (
<span
key={ind}
onClick={() => {
setSelectedSort(value);
sortingData(value, null, pdfData);
}}
className="dropdown-item text-[10px] md:text-[13px]"
style={{
paddingLeft: selectedSort !== value && "31px"
}}
>
{selectedSort === value && (
<i
className="fa-light fa-check"
aria-hidden="true"
></i>
)}
<span className="ml-[5px]">{value}</span>
</span>
);
})}
<div>
{isList ? (
<div className="sort" onClick={() => setIsList(!isList)}>
<i
onClick={() => setIsList(!isList)}
className="fa fa-th-large"
style={{ fontSize: "24px", color: `${iconColor}` }}
aria-hidden="true"
></i>
</div>
) : (
<div
data-tut="reactourForth"
className="sort"
<hr className="hrStyle" />
{sortOrder.map((order, ind) => {
return (
<span
key={ind}
onClick={() => {
setSortingOrder(order);
sortingData(null, order, pdfData);
}}
className="dropdown-item text-[10px] md:text-[13px]"
style={{
paddingLeft: sortingOrder !== order && "31px"
}}
>
{sortingOrder === order && (
<i
className="fa-light fa-check"
aria-hidden="true"
></i>
)}
<span className="ml-[5px]">{order}</span>
</span>
);
})}
</div>
</div>
<div>
{isList ? (
<div className="sort" onClick={() => setIsList(!isList)}>
<i
onClick={() => setIsList(!isList)}
>
<i
className="fa fa-list"
aria-hidden="true"
style={{ fontSize: "23px", color: `${iconColor}` }}
></i>
</div>
)}
</div>
className="fa-light fa-th-large"
style={{ fontSize: "24px", color: `${iconColor}` }}
aria-hidden="true"
></i>
</div>
) : (
<div
data-tut="reactourForth"
className="sort"
onClick={() => setIsList(!isList)}
>
<i
className="fa-light fa-list"
aria-hidden="true"
style={{ fontSize: "23px", color: `${iconColor}` }}
></i>
</div>
)}
</div>
</div>
</div>
{pdfData && pdfData.length === 0 ? (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "50vh",
width: "100%"
}}
>
<span style={{ fontWeight: "bold" }}>No Data Found!</span>
</div>
) : (
<div data-tut="reactourFifth">
<React.Suspense fallback={<Loader />}>
<DriveBody
dataTutSixth="reactourSixth"
dataTutSeventh="reactourSeventh"
pdfData={pdfData}
setFolderName={setFolderName}
setIsLoading={setIsLoading}
setDocId={setDocId}
getPdfDocumentList={getPdfDocumentList}
isDocId={docId}
setPdfData={setPdfData}
isList={isList}
setIsAlert={setIsAlert}
setSkip={setSkip}
sortingData={sortingData}
/>
{loading && (
<div style={{ textAlign: "center" }}>Loading...</div>
)}
</React.Suspense>
</div>
)}
</>
)}
</div>
{pdfData && pdfData.length === 0 ? (
<div className="flex justify-center items-center w-full h-[50vh]">
<span className="text-base-content font-bold">
No Data Found!
</span>
</div>
) : (
<div data-tut="reactourFifth">
<React.Suspense fallback={<AppLoader />}>
<DriveBody
dataTutSixth="reactourSixth"
dataTutSeventh="reactourSeventh"
pdfData={pdfData}
setFolderName={setFolderName}
setIsLoading={setIsLoading}
setDocId={setDocId}
getPdfDocumentList={getPdfDocumentList}
isDocId={docId}
setPdfData={setPdfData}
isList={isList}
setIsAlert={setIsAlert}
setSkip={setSkip}
sortingData={sortingData}
/>
{loading && (
<div className="text-center pb-[20px]">Loading...</div>
)}
</React.Suspense>
</div>
)}
</>
)}
</div>
);
}
+3 -5
View File
@@ -4,13 +4,11 @@ import Title from "../components/Title";
const PageNotFound = ({ prefix }) => {
return (
<div className="flex items-center justify-center h-screen w-full bg-white rounded">
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
<Title title={"Page Not Found"} />
<div className="text-center">
<h1 className="text-[60px] lg:text-[120px] font-semibold text-black">
404
</h1>
<p className="text-[30px] lg:text-[50px] text-black">
<h1 className="text-[60px] lg:text-[120px] font-semibold">404</h1>
<p className="text-[30px] lg:text-[50px]">
{prefix ? prefix : "Page"} Not Found
</p>
</div>
File diff suppressed because it is too large Load Diff
+141 -280
View File
@@ -1,5 +1,4 @@
import React, { useState, useEffect } from "react";
import "../styles/pgsignup.css";
import Parse from "parse";
import axios from "axios";
import { useDispatch } from "react-redux";
@@ -8,6 +7,7 @@ import { useNavigate, useLocation } from "react-router-dom";
import { appInfo } from "../constant/appinfo";
import { showTenant } from "../redux/reducers/ShowTenant";
import { fetchAppInfo } from "../redux/reducers/infoReducer";
import Loader from "../primitives/Loader";
const PgSignUp = () => {
const navigate = useNavigate();
@@ -70,6 +70,17 @@ const PgSignUp = () => {
});
if (res) {
localStorage.removeItem("userDetails");
try {
const extUser = await Parse.Cloud.run("getUserDetails");
const userRole = extUser?.get("UserRole");
const _currentRole = userRole;
const _role = _currentRole.replace("contracts_", "");
localStorage.setItem("_user_role", _role);
const extInfo_stringify = JSON.stringify([extUser]);
localStorage.setItem("Extand_Class", extInfo_stringify);
} catch (err) {
console.log("Err in fetching extuser", err);
}
navigate(
"/" + userSettings[0].pageType + "/" + userSettings[0].pageId
);
@@ -107,8 +118,6 @@ const PgSignUp = () => {
}
};
const saveUser = async (obj) => {
// const domain = localStorage.getItem("domain");
// console.log("domain", domain)
try {
const zohoRes = await axios.post(
parseBaseUrl + "functions/zohodetails",
@@ -127,7 +136,9 @@ const PgSignUp = () => {
user.set("username", zohoRes.data.result.email);
user.set("password", obj.password);
user.set("email", zohoRes.data.result.email);
user.set("phone", zohoRes.data.result.phone);
if (zohoRes?.data?.result?.phone) {
user.set("phone", zohoRes.data.result.phone);
}
user.set("name", zohoRes.data.result.name);
const res = await user.signUp();
@@ -140,7 +151,7 @@ const PgSignUp = () => {
company: zohoRes.data.result.company,
name: zohoRes.data.result.name,
email: zohoRes.data.result.email,
phone: zohoRes.data.result.phone,
phone: zohoRes?.data?.result?.phone || "",
role: obj.role
},
subscription: zohoRes.data.result.subscription
@@ -207,8 +218,6 @@ const PgSignUp = () => {
if (res.data) {
let _user = res.data;
localStorage.setItem("UserInformation", JSON.stringify(_user));
localStorage.setItem("userEmail", _user.email);
localStorage.setItem("username", _user.name);
localStorage.setItem("accesstoken", _user.sessionToken);
localStorage.setItem("scriptId", true);
if (_user.ProfilePic) {
@@ -218,296 +227,148 @@ const PgSignUp = () => {
}
// Check extended class user role and tenentId
try {
let userRoles = [];
if (appInfo.settings) {
let userSettings = appInfo.settings;
//Get Current user roles
let url = `${baseUrl}functions/UserGroups`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessionToken: _user.sessionToken
};
let body = {
appname: localStorage.getItem("_appName")
};
await axios
.post(url, JSON.stringify(body), { headers: headers })
.then((roles) => {
if (roles) {
userRoles = roles.data.result;
let _currentRole = "";
if (userRoles.length > 1) {
if (
userRoles[0] ===
`${localStorage.getItem("_appName")}_appeditor`
) {
_currentRole = userRoles[1];
} else {
_currentRole = userRoles[0];
}
} else {
_currentRole = userRoles[0];
}
if (
_currentRole !==
`${localStorage.getItem("_appName")}_appeditor`
) {
userSettings.forEach(async (element) => {
if (element.role === _currentRole) {
let _role = _currentRole.replace(
`${localStorage.getItem("_appName")}_`,
""
);
localStorage.setItem("_user_role", _role);
// Get TenentID from Extendend Class
localStorage.setItem(
"extended_class",
element.extended_class
);
const currentUser = Parse.User.current();
await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
}).then(
(result) => {
const results = [result];
let tenentInfo = [];
if (results) {
let extendedInfo_stringify =
JSON.stringify(results);
localStorage.setItem(
"Extand_Class",
extendedInfo_stringify
);
let extendedInfo = JSON.parse(
extendedInfo_stringify
);
if (extendedInfo.length > 1) {
extendedInfo.forEach((x) => {
if (x.TenantId) {
let obj = {
tenentId: x.TenantId.objectId,
tenentName: x.TenantId.TenantName || ""
};
tenentInfo.push(obj);
}
});
if (tenentInfo.length) {
dispatch(
showTenant(tenentInfo[0].tenentName || "")
);
localStorage.setItem(
"TenantName",
tenentInfo[0].tenentName || ""
);
}
localStorage.setItem("showpopup", true);
localStorage.setItem(
"PageLanding",
element.pageId
);
localStorage.setItem(
"defaultmenuid",
element.menuId
);
localStorage.setItem(
"pageType",
element.pageType
);
setIsLoader(false);
navigate("/", { replace: true });
} else {
extendedInfo.forEach((x) => {
if (x.TenantId) {
let obj = {
tenentId: x.TenantId.objectId,
tenentName: x.TenantId.TenantName || ""
};
localStorage.setItem(
"TenantId",
x.TenantId.objectId
);
tenentInfo.push(obj);
}
});
if (tenentInfo.length) {
dispatch(
showTenant(tenentInfo[0].tenentName || "")
);
localStorage.setItem(
"TenantName",
tenentInfo[0].tenentName || ""
);
}
localStorage.setItem(
"PageLanding",
element.pageId
);
localStorage.setItem(
"defaultmenuid",
element.menuId
);
localStorage.setItem(
"pageType",
element.pageType
);
setIsLoader(false);
alert("Registered user successfully");
const redirectUrl =
location?.state?.from ||
`/${element.pageType}/${element.pageId}`;
// Redirect to the appropriate URL after successful login
navigate(redirectUrl);
}
} else {
alert("Registered user successfully");
localStorage.setItem("PageLanding", element.pageId);
localStorage.setItem(
"defaultmenuid",
element.menuId
);
localStorage.setItem("pageType", element.pageType);
setIsLoader(false);
const redirectUrl =
location?.state?.from ||
`/${element.pageType}/${element.pageId}`;
// Redirect to the appropriate URL after successful login
navigate(redirectUrl);
}
},
(error) => {
setIsLoader(false);
console.error("Error while fetching Follow", error);
}
);
}
});
} else {
setIsLoader(false);
}
} else {
setIsLoader(false);
const userSettings = appInfo.settings;
const extUser = await Parse.Cloud.run("getUserDetails");
if (extUser) {
const IsDisabled = extUser?.get("IsDisabled") || false;
if (!IsDisabled) {
const userRole = extUser?.get("UserRole");
const menu =
userRole && userSettings.find((menu) => menu.role === userRole);
if (menu) {
const _currentRole = userRole;
const _role = _currentRole.replace("contracts_", "");
localStorage.setItem("_user_role", _role);
const extInfo_stringify = JSON.stringify([extUser]);
localStorage.setItem("Extand_Class", extInfo_stringify);
const extInfo = JSON.parse(JSON.stringify(extUser));
localStorage.setItem("userEmail", extInfo?.Email);
localStorage.setItem("username", extInfo?.Name);
if (extInfo?.TenantId) {
const tenant = {
Id: extInfo?.TenantId?.objectId || "",
Name: extInfo?.TenantId?.TenantName || ""
};
localStorage.setItem("TenantId", tenant?.Id);
dispatch(showTenant(tenant?.Name));
localStorage.setItem("TenantName", tenant?.Name);
}
})
.catch((err) => {
console.log("err", err);
localStorage.setItem("PageLanding", menu.pageId);
localStorage.setItem("defaultmenuid", menu.menuId);
localStorage.setItem("pageType", menu.pageType);
setIsLoader(false);
});
alert("Registered user successfully");
const redirectUrl =
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
// Redirect to the appropriate URL after successful login
navigate(redirectUrl);
}
} else {
setIsLoader(false);
}
}
} catch (error) {
setIsLoader(false);
console.log(error);
console.log("Err in fetch extuser", error);
}
}
};
return (
<div className="bg-white">
<div className="w-full h-screen">
<Title title={"Pgsignup page"} />
{isLoader ? (
<div
style={{
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
<div className="flex justify-center items-center h-[100vh]">
<Loader />
</div>
) : (
<form id="signup" className="pgsignup-content" onSubmit={handleSubmit}>
<div className="pgsignup-container">
<h1 className="text-2xl md:text-3xl font-bold">Choose Password</h1>
<hr className="hrt" />
<label htmlFor="password">
<b className="text-[13px]">Password</b>
</label>
<input
type="password"
placeholder="Enter Password"
name="password"
className="inputt"
value={formData.password}
onChange={handlePassowordChange}
required
/>
<label htmlFor="confirmPassword">
<b className="text-[13px]">Confirm Password</b>
</label>
<input
type="password"
placeholder="Confirm Password"
name="confirmPassword"
className="confirmInputt"
style={{
border: validationMessage
? validationMessage === "Passwords match!"
? "2px solid green"
: "2px solid red"
: "2px solid transparent",
outline: "none"
}}
value={formData.confirmPassword}
onChange={handleConFirmPassowordChange}
required
/>
<div
className="icon"
style={{
margin: validationMessage ? "0 2px 0 2px" : "0 2px 22px 2px",
color:
validationMessage === "Passwords match!" ? "green" : "red",
fontSize: 11
}}
>
{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 className="py-10 lg:p-16 flex justify-center">
<form
id="signup"
className="w-[90%] md:w-[55%] bg-base-100 text-base-content op-card shadow-md"
onSubmit={handleSubmit}
>
<div className="p-[16px]">
<h1 className="text-2xl md:text-3xl font-bold">
Choose Password
</h1>
<hr className="border-[1px] border-[#cecece] mb-[5px]" />
<label htmlFor="password">
<b className="text-[13px]">Password</b>
</label>
<input
type="password"
placeholder="Enter Password"
name="password"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={formData.password}
onChange={handlePassowordChange}
required
/>
<label htmlFor="confirmPassword">
<b className="text-[13px]">Confirm Password</b>
</label>
<input
type="password"
placeholder="Confirm Password"
name="confirmPassword"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
style={{
border: validationMessage
? validationMessage === "Passwords match!"
? "1px solid green"
: "1px solid red"
: ""
}}
value={formData.confirmPassword}
onChange={handleConFirmPassowordChange}
required
/>
<div
className={`${
validationMessage === "Passwords match!"
? "text-[green]"
: "text-[red]"
} ml-[13px] text-[11px]`}
>
{validationMessage}
</div>
)}
<div className="clearfix">
<button type="submit" className="signupbtn">
{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>
)}
<button
type="submit"
className="op-btn op-btn-primary w-full mt-[8px]"
>
Submit
</button>
</div>
</div>
</form>
</form>
</div>
)}
</div>
);
File diff suppressed because it is too large Load Diff
+129 -115
View File
@@ -1,9 +1,11 @@
import React, { useState, useEffect } from "react";
import { NavLink, useNavigate } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import checkmark from "../assets/images/checkmark.png";
import plansArr from "../json/plansArr";
import Title from "../components/Title";
import Parse from "parse";
import { openInNewTab } from "../constant/Utils";
import Loader from "../primitives/Loader";
const listItemStyle = {
paddingLeft: "20px", // Add padding to create space for the image
backgroundImage: `url(${checkmark})`, // Set your image as the list style image
@@ -14,14 +16,28 @@ const listItemStyle = {
const PlanSubscriptions = () => {
const navigate = useNavigate();
const [yearlyVisible, setYearlyVisible] = useState(false);
const [yearlyVisible, setYearlyVisible] = useState(true);
const [isLoader, setIsLoader] = useState(true);
const userDetails = JSON.parse(localStorage.getItem("userDetails"));
const name =
userDetails && userDetails.name
? "first_name=" + encodeURIComponent(userDetails.name)
: "";
const extUser =
localStorage.getItem("Extand_Class") &&
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
const user = {
name: extUser?.Name,
email: extUser?.Email,
company: extUser?.Company,
phone: extUser?.Phone
};
const userDetails = JSON.parse(localStorage.getItem("userDetails")) || user;
// console.log("userDetails ", userDetails);
const fullname =
userDetails && userDetails.name ? userDetails.name.split(" ") : "";
const firstname = fullname?.[0]
? "first_name=" + encodeURIComponent(fullname?.[0])
: "";
const lastname = fullname?.[1]
? "&last_name=" + encodeURIComponent(fullname?.[1])
: "";
const name = firstname ? firstname + lastname : "";
const email =
userDetails && userDetails.email
? "&email=" + encodeURIComponent(userDetails.email)
@@ -42,88 +58,70 @@ const PlanSubscriptions = () => {
company +
phone;
useEffect(() => {
// if (localStorage.getItem("accesstoken")) {
setIsLoader(false);
// } else {
// navigate("/", { replace: true });
// }
// eslint-disable-next-line
}, []);
const handleFreePlan = async () => {
setIsLoader(true);
try {
const params = { userId: Parse.User.current().id };
const res = await Parse.Cloud.run("freesubscription", params);
if (res.status === "success" && res.result === "already subscribed!") {
setIsLoader(false);
alert("You have already subscribed to plan!");
} else if (res.status === "success") {
setIsLoader(false);
navigate("/");
} else if (res.status === "error") {
setIsLoader(false);
alert(res.result);
const handleFreePlan = async (item) => {
if (item.url) {
const url = yearlyVisible ? item.yearlyUrl + details : item.url + details;
if (user) {
localStorage.setItem("userDetails", JSON.stringify(user));
}
openInNewTab(url, item?.target);
} else {
setIsLoader(true);
try {
const params = { userId: Parse.User.current().id };
const res = await Parse.Cloud.run("freesubscription", params);
if (res.status === "success" && res.result === "already subscribed!") {
setIsLoader(false);
alert("You have already subscribed to plan!");
} else if (res.status === "success") {
setIsLoader(false);
navigate("/");
} else if (res.status === "error") {
setIsLoader(false);
alert(res.result);
}
} catch (err) {
setIsLoader(false);
console.log("err in free subscribe", err.message);
alert("Somenthing went wrong, please try again later!");
}
} catch (err) {
setIsLoader(false);
console.log("err in free subscribe", err.message);
alert("Somenthing went wrong, please try again later!");
}
};
return (
<>
<Title title={"Subscriptions"} />
{isLoader ? (
<div
style={{
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
<div className="flex items-center justify-center h-screen">
<Loader />
</div>
) : (
<div
style={{
backgroundColor: "white",
overflowY: "auto",
maxHeight: "100%"
}}
>
<div className="overflow-y-auto max-h-full">
<div className="block my-2">
<div className="flex flex-col justify-center items-center w-full">
<div className="mb-6 mt-2 flex flex-row border-[1px] p-2 border-gray-300 rounded text-sm">
<span
<div
role="tablist"
className="op-tabs op-tabs-boxed bg-base-100 my-2 shadow-lg transition-all"
>
<a
onClick={() => setYearlyVisible(false)}
className={`${
!yearlyVisible
? "bg-[#002862] text-white"
: "bg-white text-black"
} px-4 py-1 rounded cursor-pointer`}
role="tab"
className={`${!yearlyVisible ? "op-tab-active" : ""} op-tab`}
>
Monthly
</span>
<span
</a>
<a
onClick={() => setYearlyVisible(true)}
className={`${
yearlyVisible
? "bg-[#002862] text-white"
: "bg-white text-black"
} px-4 py-1 rounded cursor-pointer`}
role="tab"
className={`${yearlyVisible ? "op-tab-active" : ""} op-tab`}
>
Yearly (10% off)
</span>
Yearly (upto 66% off)
</a>
</div>
<ul className="flex flex-col md:flex-row h-full bg-white justify-center">
<ul className="op-card flex flex-col md:flex-row h-full bg-base-100 justify-center shadow-lg">
{plansArr.map((item) => (
<li
className="flex flex-col text-center border-collapse border-[1px] border-gray-300 max-w-[250px]"
@@ -133,19 +131,43 @@ const PlanSubscriptions = () => {
<h3 className="text-[#002862] uppercase">
{item.planName}
</h3>
<div className="w-[150px] h-[150px]">
<div className="w-[120px] h-[120px] overflow-hidden">
<img
className="icon-basic mx-auto"
src="https://js.zohostatic.com/books/zfwidgets/assets/images/plan.png"
alt="freeimg"
className="w-full h-full object-contain"
src={require(`../assets/images/${item?.img}`)}
alt="img"
/>
</div>
<div>
<span className="text-3xl">
{item.currency && <small>{item.currency}</small>}
{yearlyVisible
? item?.yearlyPrice
: item.monthlyPrice}
{yearlyVisible ? (
<>
{item?.yearlyPrice.includes("<") ? (
<div
className="inline-block"
dangerouslySetInnerHTML={{
__html: item?.yearlyPrice
}}
/>
) : (
<span>{item?.yearlyPrice}</span>
)}
</>
) : (
<>
{item?.monthlyPrice.includes("<") ? (
<div
className="inline-block"
dangerouslySetInnerHTML={{
__html: item?.monthlyPrice
}}
/>
) : (
<span>{item?.monthlyPrice}</span>
)}
</>
)}
</span>
<p className="font-semibold pt-2 text-sm">
{yearlyVisible ? "Billed Yearly" : "Billed Monthly"}
@@ -171,59 +193,51 @@ const PlanSubscriptions = () => {
</div>
</div>
</div>
{item.url ? (
<NavLink
to={
item.btnText === "Subscribe"
? yearlyVisible
? item.yearlyUrl + details
: item.url + details
: item.url
}
className="bg-[#002862] w-full text-white py-2 rounded uppercase hover:no-underline hover:text-white cursor-pointer"
target={item.target}
>
{item.btnText}
</NavLink>
) : (
<button
className="bg-[#002862] w-full text-white py-2 rounded uppercase hover:text-white cursor-pointer"
onClick={() => handleFreePlan()}
>
{item.btnText}
</button>
)}
<button
className={`${
item?.btn?.color ? item?.btn?.color : "op-btn-primary"
} w-full text-white py-2 op-btn uppercase hover:text-white cursor-pointer`}
onClick={() => handleFreePlan(item)}
>
{item?.btn?.text}
</button>
</div>
<hr className="w-full bg-gray-300 h-[0.5px]" />
<ul className="mx-1 p-3 text-left break-words text-sm list-none">
{item.benefits.map((subitem, index) => (
<li style={listItemStyle} key={index} className="m-1">
<span style={{ position: "relative" }}>
{subitem}
</span>
</li>
))}
{!yearlyVisible &&
item.benefits.map((subitem, index) => (
<li style={listItemStyle} key={index} className="m-1">
<span className="relative">{subitem}</span>
</li>
))}
{yearlyVisible &&
item?.yearlyBenefits?.map((subitem, index) => (
<li style={listItemStyle} key={index} className="m-1">
<span className="relative">{subitem}</span>
</li>
))}
</ul>
</li>
))}
</ul>
</div>
<div className="text-sm flex justify-center items-center">
<hr className="border-[1px] border-gray-300 w-[20%]" />
<span className="px-2 text-gray-500 cursor-default">or</span>
<hr className="border-[1px] border-gray-300 w-[20%]" />
<div className="text-sm flex justify-center items-center mt-3 mb-2">
<hr className="border-[2px] border-gray-350 w-[20%]" />
<span className="px-2 text-base-content cursor-default">or</span>
<hr className="border-[2px] border-gray-350 w-[20%]" />
</div>
<div className="flex flex-col justify-center w-full items-center">
<div className="flex flex-col justify-center items-center">
<h3 className="text-[#002862] mt-1 mb-2">
Host it yourself for free
</h3>
<NavLink
to={"https://github.com/OpenSignLabs/OpenSign"}
className="bg-[#002862] w-[200px] text-center text-white py-2 rounded uppercase hover:no-underline hover:text-white cursor-pointer"
target={"_blank"}
<div
className="op-btn op-btn-primary w-[200px]"
onClick={() =>
openInNewTab("https://github.com/OpenSignLabs/OpenSign")
}
>
Visit Github
</NavLink>
</div>
</div>
</div>
</div>
+13 -15
View File
@@ -7,6 +7,7 @@ import { useParams } from "react-router-dom";
import Title from "../components/Title";
import PageNotFound from "./PageNotFound";
import TourContentWithBtn from "../primitives/TourContentWithBtn";
import Loader from "../primitives/Loader";
const Report = () => {
const { id } = useParams();
@@ -21,6 +22,7 @@ const Report = () => {
const [form, setForm] = useState("");
const [tourData, setTourData] = useState([]);
const [isDontShow, setIsDontShow] = useState(false);
const [isPublic, setIsPublic] = useState({});
const abortController = new AbortController();
const docPerPage = 10;
@@ -155,6 +157,13 @@ const Report = () => {
? [...prevRecord, ...res.data.result]
: res.data.result
);
const listData = res.data.result;
setIsPublic(
listData.reduce((acc, item) => {
acc[item.objectId] = item?.IsPublic || false;
return acc;
}, {})
);
}
}
setIsLoader(false);
@@ -173,21 +182,8 @@ const Report = () => {
<>
<Title title={reportName} />
{isLoader ? (
<div
style={{
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
<div className="h-[100vh] flex justify-center items-center">
<Loader />
</div>
) : (
<>
@@ -205,6 +201,8 @@ const Report = () => {
report_help={reporthelp}
tourData={tourData}
isDontShow={isDontShow}
setIsPublic={setIsPublic}
isPublic={isPublic}
/>
) : (
<PageNotFound prefix={"Report"} />

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