Compare commits

..
198 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
182 changed files with 232061 additions and 44131 deletions
+1 -1
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)
+3 -3
View File
@@ -2,7 +2,7 @@ name: ci
on:
push:
branches:
- 'main'
- 'staging'
jobs:
docker:
@@ -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:
-
+24 -19
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.
---
+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"]
};
+3228 -2145
View File
File diff suppressed because it is too large Load Diff
+38 -24
View File
@@ -4,24 +4,24 @@
"private": true,
"dependencies": {
"@formkit/auto-animate": "^0.8.2",
"@lottiefiles/dotlottie-react": "^0.6.4",
"@radix-ui/themes": "^3.0.5",
"@lottiefiles/dotlottie-react": "^0.8.6",
"@radix-ui/themes": "^3.1.1",
"@react-pdf/renderer": "^3.4.4",
"@reduxjs/toolkit": "^2.2.5",
"@reduxjs/toolkit": "^2.2.7",
"axios": "^1.7.2",
"file-saver": "^2.0.5",
"jwt-decode": "^4.0.0",
"moment": "^2.30.1",
"nth-check": "^2.1.1",
"parse": "^5.1.0",
"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-bootstrap": "^2.10.4",
"react-confetti": "^6.1.0",
"react-cookie": "^7.1.4",
"react-datepicker": "^6.9.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",
@@ -30,33 +30,35 @@
"react-gtm-module": "^2.0.11",
"react-helmet": "^6.1.0",
"react-konva": "^18.2.10",
"react-pdf": "^9.0.0",
"react-pdf": "^9.1.0",
"react-quill": "^2.0.0",
"react-redux": "^9.1.2",
"react-rnd": "^10.4.11",
"react-router-dom": "^6.22.3",
"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.4",
"react-tooltip": "^5.28.0",
"react-web-share": "^2.0.2",
"reactour": "^1.19.4",
"redux": "^5.0.1",
"redux-thunk": "^3.1.0",
"regex-parser": "^2.3.0",
"serve": "^14.2.3",
"styled-components": "^4.4.1",
"web-vitals": "^4.0.1",
"ws": "^8.17.1"
"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",
@@ -86,21 +88,33 @@
}
},
"devDependencies": {
"@babel/runtime-corejs2": "^7.24.7",
"@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",
"daisyui": "^4.12.2",
"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": "^5.1.3",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.34.3",
"lint-staged": "^15.2.7",
"postcss": "^8.4.38",
"prettier": "^3.3.2",
"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.4"
"tailwindcss": "^3.4.7",
"terser-webpack-plugin": "^5.3.10",
"webpack-cli": "^5.1.4"
},
"overrides": {
"nth-check": "$nth-check",
"ws":"$ws"
"ws": "$ws"
}
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -11,7 +11,7 @@
<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="/css/fonts.css" />
<link rel="stylesheet" href="https://cdn.opensignlabs.com/fonts.css" />
<title>OpenSign™</title>
</head>
<body>
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+38 -8
View File
@@ -18,6 +18,8 @@ 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"));
@@ -30,6 +32,8 @@ const Opensigndrive = lazy(() => import("./pages/Opensigndrive"));
const ManageSign = lazy(() => import("./pages/Managesign"));
const GenerateToken = lazy(() => import("./pages/GenerateToken"));
const Webhook = lazy(() => import("./pages/Webhook"));
const AddAdmin = lazy(() => import("./pages/AddAdmin"));
const UpdateExistUserAdmin = lazy(() => import("./pages/UpdateExistUserAdmin"));
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
const AppLoader = () => {
@@ -52,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);
@@ -72,7 +74,21 @@ function App() {
<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
@@ -139,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 />}
@@ -164,11 +175,30 @@ 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 />} />
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

-27
View File
@@ -1,6 +1,5 @@
import React, { useState, useEffect } from "react";
import Parse from "parse";
import axios from "axios";
import Loader from "../primitives/Loader";
const AddSigner = (props) => {
@@ -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();
@@ -85,18 +82,6 @@ const AddSigner = (props) => {
}
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",
@@ -140,18 +125,6 @@ const AddSigner = (props) => {
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",
+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;
+224 -104
View File
@@ -1,24 +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;
@@ -33,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")
@@ -60,89 +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("password", email);
if (phone) {
_user.set("phone", 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
@@ -153,55 +186,75 @@ 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 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"
@@ -212,9 +265,9 @@ const AddUser = (props) => {
</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="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
@@ -229,44 +282,111 @@ const AddUser = (props) => {
</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="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 className="text-[red] text-[13px]"> *</span>
{/* <span className="text-[red] text-[13px]"> *</span> */}
</label>
<input
type="text"
id="phone"
value={phone}
onChange={(e) => setPhone(e.target.value)}
required
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>
+26 -13
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,15 +35,17 @@ 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);
}
}
@@ -53,22 +61,16 @@ const Header = ({ showSidebar }) => {
}
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);
@@ -91,7 +93,13 @@ 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="op-navbar bg-base-100 shadow">
<div className="flex-none">
@@ -122,11 +130,16 @@ const Header = ({ showSidebar }) => {
</button>
</div>
)}
{isPro && (
{!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>
@@ -194,7 +207,7 @@ const Header = ({ showSidebar }) => {
</li>
<li
onClick={() => {
window.open("https://console.opensignlabs.com/");
handleConsoleRedirect();
}}
>
<span>
@@ -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);
@@ -186,22 +174,16 @@ 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);
@@ -23,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) {
@@ -94,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();
}
@@ -218,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();
}
@@ -31,7 +31,7 @@ const GetDashboard = (props) => {
<div
className={`${
col?.widget?.bgColor ? col.widget.bgColor : "bg-[#2ed8b6]"
} op-card w-full h-[140px] px-3 pt-4 mb-3 shadow-md"`}
} op-card w-full h-[140px] px-3 pt-4 mb-3 shadow-md`}
data-tut={col.widget.data.tourSection}
>
<Suspense
@@ -70,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: {
@@ -104,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) {
@@ -112,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 &&
@@ -122,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 &&
@@ -170,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: {
@@ -219,7 +217,7 @@ function DriveBody(props) {
updateData = {
Folder: {
__type: "Pointer",
className: `${localStorage.getItem("_appName")}_Document`,
className: "contracts_Document",
objectId: moveFolderId
}
};
@@ -231,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: {
@@ -1,23 +1,19 @@
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
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 &&
@@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react";
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([
@@ -214,55 +213,57 @@ function DropdownWidgetOption(props) {
onClick={handleAddInput}
className="fa-light fa-square-plus text-[25px] ml-[10px] op-text-primary cursor-pointer"
></i>
<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}
onChange={(e) => {
const count = handleSetMinMax(e);
setMinCount(count);
}}
className={`${
props.isSubscribe || !isEnableSubscription
? ""
: "pointer-events-none bg-opacity-50"
} op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs`}
/>
<label
className={`${
!props.isSubscribe ? "text-[gray]" : ""
} text-[13px] font-semibold`}
>
Maximum check
</label>
<input
required
defaultValue={0}
value={maxCount}
onChange={(e) => {
const count = handleSetMinMax(e);
setMaxCount(count);
}}
className={`${
props.isSubscribe || !isEnableSubscription
? ""
: "pointer-events-none bg-opacity-50"
} op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs`}
/>
</>
)}
</div>
{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) && (
<>
@@ -344,15 +345,6 @@ function DropdownWidgetOption(props) {
</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
@@ -1,6 +1,5 @@
import React, { useState, useEffect } from "react";
import { checkIsSubscribed, getFileName } from "../../constant/Utils";
import PremiumAlertHeader from "../../primitives/PremiumAlertHeader";
import Upgrade from "../../primitives/Upgrade";
import { isEnableSubscription } from "../../constant/const";
// import SelectFolder from "../../premitives/SelectFolder";
@@ -134,39 +133,32 @@ const EditTemplate = ({ template, onSuccess }) => {
<div className="text-[12px]">No</div>
</div>
</div>
<div className="text-xs mt-2">
{!isEnableSubscription && (
<PremiumAlertHeader
message={
"Auto reminder is free in beta, this feature will incur a fee later."
{isEnableSubscription && (
<div className="text-xs mt-2">
<span
className={
isSubscribe ? "font-semibold" : "font-semibold text-gray-300"
}
/>
)}
<span
className={
isSubscribe || !isEnableSubscription
? "font-semibold"
: "font-semibold text-gray-300"
}
>
Auto reminder{" "}
{!isSubscribe && isEnableSubscription && <Upgrade />}
</span>
<label
className={`${
isSubscribe || !isEnableSubscription
? "cursor-pointer "
: "pointer-events-none opacity-50"
} relative block items-center mb-0`}
>
<input
checked={formData.AutomaticReminders}
onChange={handleAutoReminder}
type="checkbox"
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white mt-2"
/>
</label>
</div>
>
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">
@@ -1,9 +1,7 @@
import React, { useState } from "react";
import { saveAs } from "file-saver";
import axios from "axios";
import { getBase64FromUrl } from "../../constant/Utils";
import { themeColor } from "../../constant/const";
import printModule from "print-js";
import { handleDownloadPdf, handleToPrint } from "../../constant/Utils";
import { themeColor, emailRegex } from "../../constant/const";
import Loader from "../../primitives/Loader";
import ModalUi from "../../primitives/ModalUi";
@@ -12,17 +10,21 @@ function EmailComponent({
pdfUrl,
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;
@@ -111,56 +113,32 @@ 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 */}
@@ -174,15 +152,19 @@ function EmailComponent({
</span>
</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">
<div></div>
{!isAndroid && (
<button
onClick={handleToPrint}
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>
@@ -191,7 +173,9 @@ function EmailComponent({
)}
<button
className="op-btn op-btn-primary op-btn-sm text-[15px] ml-2"
onClick={() => handleDownloadPdf()}
onClick={() =>
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
}
>
<i className="fa-light fa-download" aria-hidden="true"></i>
Download
@@ -203,72 +187,63 @@ function EmailComponent({
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}
<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)}
>
<span className="text-base-100 text-[13px]">
{data}
</span>
<span
className="text-base-100 text-[13px] font-semibold ml-[7px] cursor-pointer"
onClick={() => removeChip(ind)}
>
<i className="fa-light fa-xmark"></i>
</span>
</div>
);
})}
</div>
{emailList.length <= 9 && (
<input
type="text"
value={emailValue}
className="p-[10px] pb-[20px] rounded w-full text-[15px] bg-transparent outline-none"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
onBlur={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
required
/>
)}
<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="text"
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 the email addresses"
onBlur={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
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={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
onClick={() => emailValue && handleEnterPress("add")}
>
<i className="fa-light fa-plus" aria-hidden="true"></i>
</button>
+39 -59
View File
@@ -7,7 +7,6 @@ import {
} from "../../constant/Utils";
import "../../styles/signature.css";
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
import { useNavigate } from "react-router-dom";
import ModalUi from "../../primitives/ModalUi";
import Loader from "../../primitives/Loader";
@@ -33,21 +32,18 @@ function Header({
isSignYourself,
setIsEmail,
completeBtnTitle,
setIsEditTemplate
setIsEditTemplate,
isPublicTemplate
}) {
const filterPrefill =
signerPos && signerPos?.filter((data) => data.Role !== "prefill");
const isMobile = window.innerWidth < 767;
const navigate = useNavigate();
const [isDownloading, setIsDownloading] = useState("");
const isGuestSigner = localStorage.getItem("isGuestSigner");
//function for show decline alert
const handleDeclinePdfAlert = async () => {
const currentDecline = {
currnt: "Sure",
isDeclined: true
};
const currentDecline = { currnt: "Sure", isDeclined: true };
setIsDecline(currentDecline);
};
@@ -64,7 +60,7 @@ function Header({
}}
>
<div className="flex justify-between items-center py-[5px] px-[10px] ">
<div onClick={() => navigate(-1)}>
<div onClick={() => window.history.go(-2)}>
<i
className="fa-light fa-arrow-left text-base-content"
aria-hidden="true"
@@ -209,7 +205,7 @@ function Header({
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content
className="bg-white shadow-md rounded px-2 py-1"
className="bg-white shadow-md rounded-full px-3 py-2"
sideOffset={5}
>
<DropdownMenu.Item
@@ -275,7 +271,7 @@ function Header({
</button>
)}
<button
onClick={() => navigate(-1)}
onClick={() => window.history.go(-2)}
type="button"
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
>
@@ -298,6 +294,17 @@ function Header({
) : isPdfRequestFiles ? (
alreadySign ? (
<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"
@@ -313,19 +320,6 @@ function Header({
<span className="hidden lg:block">Certificate</span>
</button>
)}
<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>
<button
type="button"
className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow"
@@ -343,7 +337,7 @@ function Header({
) : (
<div className="flex" data-tut="reactourFifth">
<button
onClick={() => navigate(-1)}
onClick={() => window.history.go(-2)}
type="button"
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
>
@@ -364,40 +358,16 @@ function Header({
>
Finish
</button>
<div className="op-dropdown op-dropdown-end">
<div
tabIndex={0}
role="button"
className="op-btn op-btn-info op-btn-sm shadow"
>
<i
className="fa-light fa-ellipsis-v"
aria-hidden="true"
></i>
</div>
<ul
tabIndex={0}
className="op-dropdown-content z-[1] op-menu op-menu-sm p-1 shadow bg-base-100 rounded-box mt-1"
>
<li
onClick={() =>
handleDownloadPdf(
pdfDetails,
pdfUrl,
setIsDownloading
)
}
>
<span className="font-semibold text-[12px]">
<i
className="fa-light fa-arrow-down"
aria-hidden="true"
></i>{" "}
Download
</span>
</li>
</ul>
</div>
<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>
@@ -443,10 +413,20 @@ function Header({
<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="op-btn op-btn-ghost op-btn-sm mr-[3px]"
>
+116 -39
View File
@@ -4,6 +4,7 @@ import PlaceholderBorder from "./PlaceholderBorder";
import { Rnd } from "react-rnd";
import {
defaultWidthHeight,
getContainerScale,
handleCopyNextToWidget,
isTabAndMobile,
onChangeInput,
@@ -234,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 &&
@@ -262,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 (
@@ -291,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();
}
@@ -303,7 +318,9 @@ function Placeholder(props) {
props?.setShowDropdown(true);
} else if (props.pos.type === "checkbox") {
props?.setIsCheckbox(true);
} else if (
}
//condition to handle setting icon for signyour-self flow for all type text widgets
else if (
[
textInputWidget,
textWidget,
@@ -311,19 +328,33 @@ function Placeholder(props) {
"company",
"job title",
"email"
].includes(props.pos.type)
].includes(props.pos.type) &&
props.isSignYourself
) {
props.handleTextSettingModal(true);
} else {
props?.handleNameModal && props?.handleNameModal(true);
}
//condition for only placeholder and template flow
if (props.data && props?.pos?.type !== textWidget) {
props.setSignerObjId(props?.data?.signerObjId);
props.setUniqueId(props?.data?.Id);
} else if (props.data && props.pos.type === textWidget) {
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);
@@ -340,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
@@ -400,6 +440,9 @@ function Placeholder(props) {
<>
{(props.isPlaceholder || props.isSignYourself) && (
<>
{/* condition to add setting icon for signyour-self flow for particular text widgets
and also it have diffrent position
*/}
{[
"checkbox",
textInputWidget,
@@ -426,6 +469,7 @@ 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", "signature"].includes(props.pos.type) &&
@@ -448,7 +492,7 @@ function Placeholder(props) {
></i>
)
)}
{/* condition for usericon for all widgets except text widgets and signyour-self flow */}
{props.pos.type !== textWidget && !props.isSignYourself && (
<i
data-tut="assignSigner"
@@ -457,17 +501,26 @@ function Placeholder(props) {
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"
@@ -483,6 +536,10 @@ 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);
}
}}
onTouchEnd={(e) => {
@@ -491,6 +548,10 @@ 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);
}
}}
>
@@ -532,29 +593,37 @@ function Placeholder(props) {
</div>
</div>
)}
{/* copy icon for all widgets */}
<i
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-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);
}
@@ -566,10 +635,11 @@ function Placeholder(props) {
);
};
const xPos = (pos, signYourself) => {
const getPdfPageWidth = props.pdfOriginalWH.find(
(data) => data.pageNumber === props.pageNumber
const containerScale = getContainerScale(
props.pdfOriginalWH,
props.pageNumber,
props.containerWH
);
const containerScale = props.containerWH.width / getPdfPageWidth?.width;
const resizePos = pos.xPosition;
if (signYourself) {
return resizePos * containerScale * props.scale;
@@ -591,10 +661,11 @@ function Placeholder(props) {
}
};
const yPos = (pos, signYourself) => {
const getPdfPageWidth = props.pdfOriginalWH.find(
(data) => data.pageNumber === props.pageNumber
const containerScale = getContainerScale(
props.pdfOriginalWH,
props.pageNumber,
props.containerWH
);
const containerScale = props.containerWH.width / getPdfPageWidth.width;
const resizePos = pos.yPosition;
if (signYourself) {
@@ -621,13 +692,25 @@ function Placeholder(props) {
}
};
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",
@@ -671,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
@@ -775,7 +853,6 @@ function Placeholder(props) {
)}
{isTabAndMobile ? (
<div
// className="sm:inline-block md:inline-block lg:hidden "
className="flex items-stretch"
style={{
left: xPos(props.pos, props.isSignYourself),
@@ -47,14 +47,11 @@ function PlaceholderBorder(props) {
onTouchEnd={() =>
props.pos.type === textWidget && props?.setDraggingEnabled(true)
}
className="absolute inline-block w-[14px] h-[14px] hover:cursor-sw-resize"
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>
);
@@ -189,9 +189,7 @@ function PlaceholderCopy(props) {
<ModalUi
isOpen={props.isPageCopy}
title={"Copy to all pages"}
handleClose={() => {
props.setIsPageCopy(false);
}}
handleClose={() => handleUniqueId()}
>
<div className="h-full p-[20px] text-base-content">
{copyType.map((data, key) => {
@@ -13,10 +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 bg-base-100 whitespace-pre-wrap";
"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 bg-base-100 text-base-content";
"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("");
@@ -61,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":
@@ -139,8 +140,7 @@ function PlaceholderType(props) {
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
<div
className={`${selectWidgetCls} overflow-hidden`}
style={{ fontSize: calculateFontSize() }}
className={`${selectWidgetCls} text-[12px] overflow-hidden`}
onClick={onClick}
ref={ref}
>
@@ -171,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;
@@ -423,8 +417,11 @@ function PlaceholderType(props) {
) : (
<div
style={{
color: "black",
fontSize: "12px"
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black",
overflow: "hidden"
}}
>
<span>{type}</span>
@@ -433,7 +430,7 @@ function PlaceholderType(props) {
case "dropdown":
return props.data?.signerObjId === props.signerObjId ? (
<select
className={`${selectWidgetCls} text-[12px]`}
className={`${selectWidgetCls} text-[12px] bg-inherit`}
id="myDropdown"
value={selectOption}
onChange={(e) => {
@@ -463,10 +460,7 @@ function PlaceholderType(props) {
})}
</select>
) : (
<div
className={selectWidgetCls}
style={{ fontSize: calculateFontSize() }}
>
<div className="text-[12px] overflow-hidden">
{props.pos?.options?.name ? props.pos.options.name : type}
</div>
);
@@ -522,8 +516,12 @@ function PlaceholderType(props) {
) : (
<div
style={{
color: "black",
fontSize: "12px"
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,8 +560,12 @@ function PlaceholderType(props) {
) : (
<div
style={{
color: "black",
fontSize: "12px"
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>
@@ -602,15 +604,20 @@ function PlaceholderType(props) {
) : (
<div
style={{
color: "black",
fontSize: "12px"
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 }) => (
@@ -667,6 +674,16 @@ 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 ? (
@@ -713,15 +730,20 @@ function PlaceholderType(props) {
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black"
color: props.pos.options?.fontColor || "black",
fontFamily: "Arial, sans-serif"
}}
cols="50"
/>
) : (
<div
style={{
color: "black",
fontSize: "12px"
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>
@@ -780,6 +802,7 @@ function PlaceholderType(props) {
}}
className={textWidgetCls}
style={{
fontFamily: "Arial, sans-serif",
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
@@ -61,15 +61,27 @@ 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 (
<>
@@ -101,7 +113,7 @@ const RecipientList = (props) => {
} flex flex-row rounded-xl px-2 py-[10px] mt-1 mx-1 items-center last:mb-0.5`}
style={{
background:
(!isMobile && isHover === ind) || props.isSelectListId === ind
(!isMobile && isHover === ind) || props.uniqueId === obj.Id
? obj?.blockColor
? obj?.blockColor
: color[ind % color.length]
@@ -10,7 +10,8 @@ function RenderAllPdfPage({
setSignBtnPosition,
pageNumber,
signerPos,
signerObjectId
signerObjectId,
containerWH
}) {
const [signPageNumber, setSignPageNumber] = useState([]);
const [bookmarkColor, setBookmarkColor] = useState("");
@@ -48,7 +49,7 @@ function RenderAllPdfPage({
const timer = setTimeout(updateSize, 100); // match the transition duration
return () => clearTimeout(timer);
}, [isHeader, pageContainer]);
}, [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);
@@ -57,13 +58,12 @@ function RenderAllPdfPage({
<div className="absolute z-20 top-[1px] -right-[13px] -translate-x-1/2 -translate-y-1/2">
<i
style={{ color: bookmarkColor || "red" }}
className="fa-light fa-bookmark"
className="fa-solid fa-bookmark"
></i>
</div>
)
);
};
return (
<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">
+19 -10
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";
@@ -57,7 +58,10 @@ function RenderPdf({
setTempSignerId,
uniqueId,
pdfOriginalWH,
scale
scale,
setIsSelectId,
ispublicTemplate,
handleUserDetails
}) {
const isMobile = window.innerWidth < 767;
//check isGuestSigner is present in local if yes than handle login flow header in mobile view
@@ -65,10 +69,11 @@ function RenderPdf({
// handle signature block width and height according to screen
const posWidth = (pos, signYourself) => {
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
const containerScale = getContainerScale(
pdfOriginalWH,
pageNumber,
containerWH
);
const containerScale = containerWH.width / getPdfPageWidth.width || 1;
const defaultWidth = defaultWidthHeight(pos.type).width;
const posWidth = pos.Width ? pos.Width : defaultWidth;
if (signYourself) {
@@ -94,11 +99,11 @@ function RenderPdf({
}
};
const posHeight = (pos, signYourself) => {
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
const containerScale = getContainerScale(
pdfOriginalWH,
pageNumber,
containerWH
);
const containerScale = containerWH.width / getPdfPageWidth?.width || 1;
const posHeight = pos.Height || defaultWidthHeight(pos.type).height;
if (signYourself) {
return posHeight * scale * containerScale;
@@ -194,6 +199,8 @@ function RenderPdf({
containerWH={containerWH}
pdfOriginalWH={pdfOriginalWH}
pageNumber={pageNumber}
ispublicTemplate={ispublicTemplate}
handleUserDetails={handleUserDetails}
/>
</React.Fragment>
)
@@ -319,6 +326,7 @@ function RenderPdf({
containerWH={containerWH}
pdfOriginalWH={pdfOriginalWH}
pageNumber={pageNumber}
setIsSelectId={setIsSelectId}
/>
</React.Fragment>
);
@@ -428,7 +436,7 @@ function RenderPdf({
>
<div
style={{
width: containerWH.width * scale
width: containerWH?.width && containerWH?.width * scale
}}
ref={drop}
id="container"
@@ -501,6 +509,7 @@ function RenderPdf({
containerWH={containerWH}
pdfOriginalWH={pdfOriginalWH}
pageNumber={pageNumber}
setIsSelectId={setIsSelectId}
/>
</React.Fragment>
);
@@ -570,7 +579,7 @@ function RenderPdf({
{/* this component for render pdf document is in middle of the component */}
<Document
onLoadError={() => {
pdfLoad(false);
setPdfLoad(false);
}}
loading={"Loading Document.."}
onLoadSuccess={pageDetails}
+15 -10
View File
@@ -1,6 +1,5 @@
import React, { useRef, useState, useEffect } from "react";
import SignatureCanvas from "react-signature-canvas";
function SignPad({
isSignPad,
isStamp,
@@ -99,7 +98,12 @@ 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();
@@ -149,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) {
@@ -164,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");
@@ -212,11 +215,11 @@ function SignPad({
: fontSelect
? 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
@@ -226,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);
@@ -299,8 +303,9 @@ function SignPad({
<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 className="op-link-primary op-link">
{widgetType === "image"
<span className="text-base-content font-bold text-lg">
{widgetType === "image" ||
currWidgetsDetails?.type === "image"
? "Upload image"
: "Upload stamp image"}
</span>
@@ -35,7 +35,9 @@ function SignerListComponent(props) {
className="flex w-[30px] h-[30px] rounded-full justify-center items-center mx-1"
>
<span className="text-[12px] text-center font-bold text-black uppercase">
{getFirstLetter(props?.obj?.Name || props?.obj?.Role)}
{getFirstLetter(
props.obj?.Name || props.obj?.email || props.obj?.Role
)}
</span>
</div>
<div className="flex flex-col">
@@ -9,9 +9,7 @@ function TextFontSetting(props) {
isOpen={props.isTextSetting}
reduceWidth={"max-w-[350px]"}
title={"Text field"}
handleClose={() => {
props.setIsTextSetting(false);
}}
handleClose={() => props.setIsTextSetting(false)}
>
<div className="h-full p-[20px]">
<div className="flex items-center">
@@ -19,7 +17,9 @@ function TextFontSetting(props) {
<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
props.fontSize ||
props.currWidgetsDetails?.options?.fontSize ||
"12"
}
onChange={(e) => props.setFontSize(e.target.value)}
>
@@ -35,7 +35,9 @@ function TextFontSetting(props) {
<span>color: </span>
<select
value={
props.fontColor || props.currWidgetsDetails?.options?.fontColor
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"
@@ -37,11 +37,10 @@ function WidgetComponent({
sendInOrder,
isTemplateFlow,
setBlockColor,
blockColor,
setIsAddSigner
setIsAddSigner,
uniqueId
}) {
const [isSignersModal, setIsSignersModal] = useState(false);
const [, dropdown] = useDrag({
type: "BOX",
item: {
@@ -187,7 +186,6 @@ function WidgetComponent({
const isMobile = window.innerWidth < 767;
const scrollContainerRef = useRef(null);
const [widget, setWidget] = useState([]);
const color = [
"#93a3db",
"#e6c3db",
@@ -245,86 +243,66 @@ 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
id="navbar"
className="fixed z-[99] bottom-0 right-0"
style={{ width: window.innerWidth + "px" }}
>
<div className="mx-1">
{isSigners && (
<div
data-tut="recipientArea"
className="py-[10px] flex justify-center items-center op-card"
style={{
background: blockColor
? blockColor
: isSelectListId
<div id="navbar" className="fixed z-[99] bottom-0 right-0 w-full">
{isSigners && (
<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]
}}
onClick={() => handleModal()}
>
<span className="text-[13px] font-bold flex items-center">
{title ? title : "Recipient"}
{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 className="ml-[6px] text-[16px]">
<i className="fa-light fa-angle-down"></i>
</div>
</span>
</div>
)}
</div>
<div className="mx-1">
{handleAddSigner ? (
<div
data-tut="reactourAddbtn"
className="op-btn op-btn-accent w-full my-[2px]"
onClick={() => handleAddSigner()}
>
<i className="fa-light fa-plus"></i>
<span>Add role</span>
</div>
) : (
setIsAddSigner && (
<div
data-tut="addRecipient"
className="op-btn op-btn-accent w-full my-[2px]"
onClick={() => setIsAddSigner(true)}
}}
>
<i className="fa-light fa-plus"></i>
<span>Add recipients</span>
</div>
)
)}
</div>
<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}
@@ -392,6 +370,7 @@ function WidgetComponent({
sendInOrder={sendInOrder}
setSignersData={setSignersData}
setBlockColor={setBlockColor}
uniqueId={uniqueId}
/>
</div>
) : (
@@ -2,11 +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({
@@ -23,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 || "",
@@ -35,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) {
@@ -106,22 +106,10 @@ 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"
: ""
props.defaultdata?.type === textInputWidget ? "pt-0" : ""
} p-[20px] text-base-content`}
>
<div className="mb-[0.75rem] text-[13px]">
@@ -137,67 +125,71 @@ const WidgetNameModal = (props) => {
required
/>
</div>
{(props.defaultdata?.type === textInputWidget ||
props.widgetName === textInputWidget) && (
{props.defaultdata?.type === textInputWidget && (
<>
<div className="mb-[0.75rem]">
<div className="flex items-center gap-1">
<label
htmlFor="textvalidate"
{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]`}
>
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"
: ""
} text-[13px]`}
} flex flex-row gap-[10px] mb-[0.5rem]`}
>
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()}
>
<option
disabled={formdata?.textvalidate}
className="text-[13px]"
<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 className="text-[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="mb-[0.75rem]">
<label htmlFor="name" className="text-[13px]">
Default value
@@ -252,8 +244,7 @@ const WidgetNameModal = (props) => {
})}
</div>
</div>
{(props.defaultdata?.type === textInputWidget ||
props?.widgetName === textInputWidget) && (
{props.defaultdata?.type === textInputWidget && (
<div className="mb-[0.75rem]">
<label htmlFor="hint" className="text-[13px]">
Hint
@@ -266,6 +257,63 @@ const WidgetNameModal = (props) => {
/>
</div>
)}
{[
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
@@ -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>
)}
+81 -19
View File
@@ -4,11 +4,14 @@ import Submenu from "./SubMenu";
import SocialMedia from "./SocialMedia";
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([]);
const [submenuOpen, setSubmenuOpen] = useState(false);
let username = localStorage.getItem("username");
const username = localStorage.getItem("username");
const image = localStorage.getItem("profileImg") || dp;
const tenantname = localStorage.getItem("Extand_Class")
? JSON.parse(localStorage.getItem("Extand_Class"))?.[0]?.Company
@@ -23,29 +26,76 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
const menuItem = async () => {
try {
if (localStorage.getItem("defaultmenuid")) {
const menuId = localStorage.getItem("defaultmenuid") !== "VPh91h0ZHk";
if (menuId) {
setmenuList(sidebarList);
} else {
const addUserForm = {
icon: "fa-light fa-user",
title: "Add User",
target: "_self",
pageType: "form",
description: "",
objectId: "lM0xRnM3iE"
};
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 };
// Insert addUserForm at the second position
newItem.children.splice(1, 0, addUserForm);
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) {
@@ -61,13 +111,19 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
closeSidebar();
setSubmenuOpen({});
};
const handleProfile = () => {
navigate("/profile");
};
return (
<aside
className={`absolute lg:relative bg-base-100 h-screen overflow-y-auto transition-all z-[999] shadow-lg hide-scrollbar
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}
@@ -75,9 +131,15 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
/>
</div>
<div>
<p className="text-[14px] font-bold text-base-content">{username}</p>
<p
className={`text-[12px] text-base-content ${
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" : ""
}`}
>
+189 -102
View File
@@ -1,14 +1,14 @@
import axios from "axios";
import moment from "moment";
import { isEnableSubscription } from "./const";
import React from "react";
import { rgb } from "pdf-lib";
import Parse from "parse";
import { appInfo } from "./appinfo";
import { saveAs } from "file-saver";
import printModule from "print-js";
import { validplan } from "../json/plansArr";
export const fontsizeArr = [7, 8, 9, 10, 11, 12, 13, 14, 15, 18];
export const fontsizeArr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28];
export const fontColorArr = ["red", "black", "blue", "yellow"];
export const isMobile = window.innerWidth < 767;
export const isTabAndMobile = window.innerWidth < 1023;
@@ -63,7 +63,7 @@ export async function fetchSubscription(
return { plan: "", billingDate: "" };
}
}
//function to get subcripition details from Extand user class
//function to get subcripition details from subscription class
export async function checkIsSubscribed() {
try {
const res = await fetchSubscription();
@@ -84,6 +84,28 @@ export async function checkIsSubscribed() {
}
}
//function to get subcripition details from subscription class
export async function checkIsSubscribedTeam() {
try {
const res = await fetchSubscription();
if (res.plan === "freeplan") {
return false;
} else if (res.billingDate) {
const plan = validplan[res.plan] || false;
if (plan && new Date(res.billingDate) > new Date()) {
return true;
} else {
return false;
}
} else {
return false;
}
} catch (err) {
console.log("Err in fetch subscription", err);
return false;
}
}
export const color = [
"#93a3db",
"#e6c3db",
@@ -151,7 +173,7 @@ export const getDrive = async (documentId, skip = 0, limit = 100) => {
}
})
.catch((err) => {
console.log("Err ", err);
console.log("Err in getDrive cloud function", err);
return "Error: Something went wrong!";
});
@@ -165,32 +187,19 @@ export const pdfNewWidthFun = (divRef) => {
};
//`contractUsers` function is used to get contract_User details
export const contractUsers = async (email) => {
const data = {
email: email
};
const userDetails = await axios
.post(`${localStorage.getItem("baseUrl")}functions/getUserDetails`, data, {
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessionToken: localStorage.getItem("accesstoken")
}
})
.then((Listdata) => {
const json = Listdata.data;
let data = [];
if (json && json.result) {
data.push(json.result);
}
return data;
})
.catch((err) => {
console.log("Err ", err);
return "Error: Something went wrong!";
});
return userDetails;
export const contractUsers = async () => {
try {
const userDetails = await Parse.Cloud.run("getUserDetails");
let data = [];
if (userDetails) {
const json = JSON.parse(JSON.stringify(userDetails));
data.push(json);
}
return data;
} catch (err) {
console.log("Err in getUserDetails cloud function", err);
return "Error: Something went wrong!";
}
};
//function for resize image and update width and height for mulitisigners
@@ -326,7 +335,7 @@ export const getDate = () => {
};
export const addWidgetOptions = (type) => {
const defaultOpt = {
name: "",
name: type,
status: "required"
};
switch (type) {
@@ -431,7 +440,7 @@ export const resizeBorderExtraWidth = () => {
return 20;
};
export async function getBase64FromUrl(url) {
export async function getBase64FromUrl(url, autosign) {
const data = await fetch(url);
const blob = await data.blob();
return new Promise((resolve) => {
@@ -439,8 +448,12 @@ export async function getBase64FromUrl(url) {
reader.readAsDataURL(blob);
reader.onloadend = function () {
const pdfBase = this.result;
const suffixbase64 = pdfBase.split(",").pop();
resolve(suffixbase64);
if (autosign) {
resolve(pdfBase);
} else {
const suffixbase64 = pdfBase.split(",").pop();
resolve(suffixbase64);
}
};
});
}
@@ -523,25 +536,22 @@ export const signPdfFun = async (
base64Url,
documentId,
signerObjectId,
setIsAlert,
objectId,
isSubscribed,
activeMailAdapter,
xyPosition
widgets
) => {
let singleSign,
isCustomCompletionMail = false;
let isCustomCompletionMail = false;
try {
//get tenant details
const tenantDetails = await getTenantDetails(objectId);
if (tenantDetails && tenantDetails === "user does not exist!") {
alert("User does not exist");
return { status: "error", message: "User does not exist." };
} else {
if (
tenantDetails?.CompletionBody &&
tenantDetails?.CompletionSubject &&
(!isEnableSubscription || isSubscribed)
isSubscribed
) {
isCustomCompletionMail = true;
}
@@ -550,7 +560,7 @@ export const signPdfFun = async (
// below for loop is used to get first signature of user to send if to signpdf
// for adding it in completion certificate
let getSignature;
for (let item of xyPosition) {
for (let item of widgets) {
if (!getSignature) {
const typeExist = item.pos.some((data) => data?.type);
if (typeExist) {
@@ -569,14 +579,15 @@ export const signPdfFun = async (
base64Sign = await fetchImageBase64(base64Sign);
} catch (e) {
console.log("error", e);
return { status: "error", message: "something went wrong." };
}
}
//change image width and height to 104/44 in png base64
//change image width and height to 100/40 in png base64
const getNewse64 = await changeImageWH(base64Sign);
//remove suffiix of base64
const suffixbase64 = getNewse64 && getNewse64.split(",").pop();
singleSign = {
const params = {
mailProvider: activeMailAdapter,
pdfFile: base64Url,
docId: documentId,
@@ -584,34 +595,25 @@ export const signPdfFun = async (
isCustomCompletionMail: isCustomCompletionMail,
signature: suffixbase64
};
const response = await axios
.post(`${localStorage.getItem("baseUrl")}functions/signPdf`, singleSign, {
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
// sessionToken: localStorage.getItem("accesstoken")
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
})
.then((Listdata) => {
const json = Listdata.data;
const res = json.result;
return res;
})
.catch((err) => {
console.log("Err ", err);
setIsAlert({
isShow: true,
alertMessage: "something went wrong"
});
});
return response;
const resSignPdf = await Parse.Cloud.run("signPdf", params);
if (resSignPdf) {
const signedPdf = JSON.parse(JSON.stringify(resSignPdf));
return signedPdf;
}
} catch (e) {
setIsAlert({
isShow: true,
alertMessage: "something went wrong"
});
console.log("Err in signPdf cloud function ", e.message);
if (e && e?.message?.includes("is encrypted.")) {
return {
status: "error",
message: "Currently encrypted pdf files are not supported."
};
} else if (
e.message === "PKCS#12 MAC could not be verified. Invalid password?"
) {
return { status: "error", message: "PFX file password is invalid." };
} else {
return { status: "error", message: "something went wrong." };
}
}
};
@@ -669,9 +671,7 @@ export const createDocument = async (template, placeholders, signerData) => {
try {
const res = await axios.post(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document`,
`${localStorage.getItem("baseUrl")}classes/contracts_Document`,
data,
{
headers: {
@@ -1213,9 +1213,8 @@ export const changeImageWH = async (base64Image) => {
const ctx = canvas.getContext("2d");
canvas.width = newWidth;
canvas.height = newHeight;
ctx.imageSmoothingEnabled = false;
ctx.drawImage(img, 0, 0, newWidth, newHeight);
const resizedBase64 = canvas.toDataURL("image/png", 1);
const resizedBase64 = canvas.toDataURL("image/png", 1.0);
resolve(resizedBase64);
};
img.onerror = (error) => {
@@ -1224,14 +1223,30 @@ export const changeImageWH = async (base64Image) => {
});
};
//function to calculate font size of text area widgets
const calculateFontSize = (position, containerScale, signyourself) => {
const font = position?.options?.fontSize || 12;
if (!signyourself && position?.isMobile && position?.scale) {
return font / position?.scale / containerScale;
} else {
return font / containerScale;
}
};
//function for embed multiple signature using pdf-lib
export const multiSignEmbed = async (
xyPositionArray,
widgets,
pdfDoc,
signyourself,
scale
scale,
pdfOriginalWH,
containerWH
) => {
for (let item of xyPositionArray) {
for (let item of widgets) {
const containerScale = getContainerScale(
pdfOriginalWH,
item?.pageNumber,
containerWH
);
const typeExist = item.pos.some((data) => data?.type);
let updateItem;
@@ -1391,7 +1406,13 @@ export const multiSignEmbed = async (
}
} else if (widgetTypeExist) {
const font = await pdfDoc.embedFont("Helvetica");
const fontSize = parseInt(position?.options?.fontSize) || 12;
const fontSize = calculateFontSize(
position,
containerScale,
signyourself
);
parseInt(fontSize);
const color = position?.options?.fontColor;
let updateColorInRgb;
if (color === "red") {
@@ -1566,7 +1587,7 @@ export const multiSignEmbed = async (
});
}
const pdfBytes = await pdfDoc.saveAsBase64({ useObjectStreams: false });
// console.log("pdf", pdfBytes);
//console.log("pdf", pdfBytes);
return pdfBytes;
};
@@ -1618,9 +1639,9 @@ export const placeholderHeight = (pos) => {
export const contactBook = async (objectId) => {
const result = await axios
.get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Contactbook?where={"objectId":"${objectId}"}`,
`${localStorage.getItem(
"baseUrl"
)}classes/contracts_Contactbook?where={"objectId":"${objectId}"}`,
{
headers: {
"Content-Type": "application/json",
@@ -1636,7 +1657,7 @@ export const contactBook = async (objectId) => {
})
.catch((err) => {
console.log("Err ", err);
console.log("Err in contracts_Contactbook class ", err);
return "Error: Something went wrong!";
});
return result;
@@ -1668,7 +1689,7 @@ export const contractDocument = async (documentId) => {
}
})
.catch((err) => {
console.log("Err ", err);
console.log("Err in getDocument cloud function ", err);
return "Error: Something went wrong!";
});
@@ -1830,18 +1851,21 @@ export const getFileName = (fileUrl) => {
//fetch tenant app logo from `partners_Tenant` class by domain name
export const getAppLogo = async () => {
const domainName = window.location.host;
try {
const tenantCreditsQuery = new Parse.Query("partners_Tenant");
tenantCreditsQuery.equalTo("Domain", domainName);
const res = await tenantCreditsQuery.first();
if (res) {
const updateRes = JSON.parse(JSON.stringify(res));
return updateRes?.Logo;
if (window.location.host === "app.opensignlabs.com") {
return { logo: appInfo.applogo, user: "exist" };
} else {
const domain = window.location.host;
try {
const tenant = await Parse.Cloud.run("getlogobydomain", {
domain: domain
});
if (tenant) {
return { logo: tenant?.logo, user: tenant?.user };
}
} catch (err) {
console.log("err in getlogo ", err);
return { logo: appInfo.applogo, user: "exist" };
}
} catch (e) {
return null;
}
};
@@ -1929,6 +1953,20 @@ export const handleSendOTP = async (email) => {
alert(error.message);
}
};
export const fetchUrl = async (url, pdfName) => {
try {
const response = await fetch(url);
if (!response.ok) {
alert("something went wrong, please try again later.");
throw new Error("Network response was not ok");
}
const blob = await response.blob();
saveAs(blob, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
} catch (error) {
alert("something went wrong, please try again later.");
console.error("Error downloading the file:", error);
}
};
//handle download signed pdf
export const handleDownloadPdf = async (
pdfDetails,
@@ -1940,18 +1978,18 @@ export const handleDownloadPdf = async (
try {
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
const axiosRes = await axios.post(
`${appInfo.baseUrl}/functions/getsignedurl`,
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
{ url: pdfUrl },
{
headers: {
"content-type": "Application/json",
"X-Parse-Application-Id": appInfo.appId,
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
);
const url = axiosRes.data.result;
saveAs(url, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
await fetchUrl(url, pdfName);
setIsDownloading("");
} catch (err) {
console.log("err in getsignedurl", err);
@@ -1970,13 +2008,15 @@ export const handleToPrint = async (event, pdfUrl, setIsDownloading) => {
setIsDownloading("pdf");
try {
// const url = await Parse.Cloud.run("getsignedurl", { url: pdfUrl });
//`localStorage.getItem("baseUrl")` is also use in public-profile flow for public-sign
//if we give this `appInfo.baseUrl` as a base url then in public-profile it will create base url of it's window.location.origin ex- opensign.me which is not base url
const axiosRes = await axios.post(
`${appInfo.baseUrl}/functions/getsignedurl`,
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
{ url: pdfUrl },
{
headers: {
"content-type": "Application/json",
"X-Parse-Application-Id": appInfo.appId,
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
@@ -2181,3 +2221,50 @@ function getImagePosition(page, image, sizeRatio) {
rotate: page.getRotation()
};
}
//function to use calculate pdf rendering scale in the container
export const getContainerScale = (pdfOriginalWH, pageNumber, containerWH) => {
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
);
const containerScale = containerWH?.width / getPdfPageWidth?.width || 1;
return containerScale;
};
//function to get default signatur eof current user from `contracts_Signature` class
export const getDefaultSignature = async (objectId) => {
try {
const result = await axios.get(
`${localStorage.getItem(
"baseUrl"
)}classes/contracts_Signature?where={"UserId": {"__type": "Pointer","className": "_User", "objectId":"${objectId}"}}`,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
);
const res = result.data?.results;
if (res[0] && res.length > 0) {
const defaultSignature = res[0]?.ImageURL
? await getBase64FromUrl(res[0]?.ImageURL, true)
: "";
const defaultInitial = res[0]?.Initials
? await getBase64FromUrl(res[0]?.Initials, true)
: "";
return {
status: "success",
res: {
defaultSignature: defaultSignature,
defaultInitial: defaultInitial
}
};
}
} catch (err) {
console.log("Error: error in fetch data in contracts_Signature", err);
return {
status: "error"
};
}
};
+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 -1
View File
@@ -3,4 +3,11 @@ export const templateCls = "contracts_Template";
export const documentCls = "contracts_Document";
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";
+101 -61
View File
@@ -1,6 +1,15 @@
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"];
@@ -43,7 +52,7 @@ export default function reportJson(id) {
hoverLabel: "Sign",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-signature",
redirectUrl: "pdfRequestFiles",
redirectUrl: "draftDocument",
action: "redirect"
}
],
@@ -69,7 +78,7 @@ export default function reportJson(id) {
hoverLabel: "View",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-eye",
redirectUrl: "pdfRequestFiles",
redirectUrl: "draftDocument",
action: "redirect"
},
{
@@ -140,7 +149,7 @@ export default function reportJson(id) {
case "UPr2Fm5WY3":
return {
reportName: "Declined Documents",
heading: head,
heading: declineHead,
actions: [
{
btnId: "1458",
@@ -207,7 +216,7 @@ export default function reportJson(id) {
hoverLabel: "View",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-eye",
redirectUrl: "pdfRequestFiles",
redirectUrl: "draftDocument",
action: "redirect"
},
{
@@ -258,7 +267,7 @@ export default function reportJson(id) {
hoverLabel: "Sign",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-signature",
redirectUrl: "pdfRequestFiles",
redirectUrl: "draftDocument",
action: "redirect"
}
]
@@ -306,68 +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: templateReport,
actions: [
{
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"
}
]
}
],
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;
}
+4 -4
View File
@@ -143,17 +143,17 @@ const sidebarList = [
icon: "fa-light fa-key",
title: "API Token",
target: "_self",
pageType: "generatetoken",
pageType: "",
description: "",
objectId: ""
objectId: "generatetoken"
},
{
icon: "fa-light fa-globe",
title: "Webhook",
target: "_self",
pageType: "webhook",
pageType: "",
description: "",
objectId: ""
objectId: "webhook"
}
]
}
+111 -16
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,18 +74,74 @@ const plans = [
"Zapier integration",
"API Access",
"100 API signatures included",
"DocumentId removal from signed docs",
"Custom email templates",
"Auto reminders"
"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",
"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: [
@@ -72,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;
+16 -14
View File
@@ -40,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) {
@@ -67,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
@@ -75,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() {
@@ -109,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);
@@ -171,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)
@@ -193,7 +198,7 @@ const HomeLayout = () => {
// console.log("updatedTourStatus ", updatedTourStatus);
await axios.put(
serverUrl + "classes/" + extUserClass + "/" + extUserId,
serverUrl + "classes/contracts_Users/" + extUserId,
{
TourStatus: updatedTourStatus
},
@@ -207,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;
@@ -241,7 +243,7 @@ const HomeLayout = () => {
const handleLoginBtn = () => {
try {
Parse.User.logOut();
Parse?.User?.logOut();
} catch (err) {
console.log("err ", err);
} finally {
@@ -251,7 +253,7 @@ const HomeLayout = () => {
};
return (
<div>
<div className="sticky top-0 z-[101]">
<div className="sticky top-0 z-[501]">
{!isLoader && <Header showSidebar={showSidebar} />}
</div>
{isUserValid ? (
+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;
+6 -2
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.");
+3 -6
View File
@@ -36,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;
@@ -64,9 +61,9 @@ function ForgotPassword() {
}, []);
const saveLogo = async () => {
if (isEnableSubscription) {
const logo = await getAppLogo();
if (logo) {
setImage(logo);
const app = await getAppLogo();
if (app?.logo) {
setImage(app?.logo);
} else {
setImage(appInfo?.applogo || undefined);
}
+31 -37
View File
@@ -18,7 +18,6 @@ import { isEnableSubscription } from "../constant/const";
import ModalUi from "../primitives/ModalUi";
import { Tooltip } from "react-tooltip";
import Upgrade from "../primitives/Upgrade";
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
import Loader from "../primitives/Loader";
// `Form` render all type of Form on this basis of their provided in path
@@ -644,9 +643,9 @@ 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 op-input op-input-bordered op-input-sm w-full h-full text-x text-[13px]">
<div className="break-all ">
<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
@@ -664,7 +663,7 @@ 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="op-file-input op-file-input-bordered op-file-input-sm focus:outline-none hover:border-base-content w-full text-xs"
@@ -830,39 +829,34 @@ const Forms = (props) => {
<div className="text-center">No</div>
</div>
</div>
<div className="text-xs mt-2">
{!isEnableSubscription && (
<PremiumAlertHeader
message={
"Auto reminder is free in beta, this feature will incur a fee later."
{isEnableSubscription && (
<div className="text-xs mt-2">
<span
className={
isSubscribe
? "font-semibold"
: "font-semibold text-gray-300"
}
/>
)}
<span
className={
isSubscribe || !isEnableSubscription
? "font-semibold"
: "font-semibold text-gray-300"
}
>
Auto reminder{" "}
{!isSubscribe && isEnableSubscription && <Upgrade />}
</span>
<label
className={`${
isSubscribe || !isEnableSubscription
? "cursor-pointer "
: "pointer-events-none opacity-50"
} relative block items-center mb-0`}
>
<input
type="checkbox"
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
checked={formData.autoreminder}
onChange={handleAutoReminder}
/>
</label>
</div>
>
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">
+3 -10
View File
@@ -5,7 +5,6 @@ import Alert from "../primitives/Alert";
import ModalUi from "../primitives/ModalUi";
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";
@@ -45,7 +44,7 @@ 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) {
@@ -112,7 +111,6 @@ function GenerateToken() {
) : (
<>
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box mb-3">
{!isEnableSubscription && <PremiumAlertHeader />}
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
OpenSign API{" "}
<Tooltip
@@ -122,19 +120,14 @@ function GenerateToken() {
isSubscribe={true}
/>
</h1>
<ul
className={"w-full flex flex-col p-2 text-sm"}
// isSubscribe || !isEnableSubscription
// ? "w-full flex flex-col p-2 text-sm "
// : "w-full flex flex-col p-2 text-sm opacity-20 pointer-events-none select-none"
>
<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 || !isEnableSubscription
isSubscribe
? ""
: "bg-white/20 pointer-events-none select-none"
} md:text-end py-2 md:py-0`}
+5 -6
View File
@@ -29,9 +29,9 @@ function GuestLogin() {
//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);
}
@@ -42,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
@@ -126,8 +124,9 @@ 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`,
File diff suppressed because it is too large Load Diff
+3 -5
View File
@@ -4,12 +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();
@@ -39,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();
@@ -174,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) {
@@ -265,7 +263,7 @@ const ManageSign = () => {
<div className="relative">
<div>
{image ? (
<div className="signatureCanvas relative border-[2px] border-[#888] rounded-box">
<div className="signatureCanvas relative border-[2px] border-[#888] rounded-box overflow-hidden">
<img
alt="signature"
src={image}
+3 -7
View File
@@ -272,7 +272,7 @@ function Opensigndrive() {
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,
@@ -465,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 = [];
@@ -483,7 +482,7 @@ function Opensigndrive() {
updatedTourStatus = [{ driveTour: true }];
}
await axios.put(
serverUrl + "classes/" + extUserClass + "/" + extUserId,
serverUrl + "classes/contracts_Users/" + extUserId,
{
TourStatus: updatedTourStatus
},
@@ -497,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;
File diff suppressed because it is too large Load Diff
+49 -183
View File
@@ -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",
@@ -209,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) {
@@ -220,190 +227,49 @@ 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);
}
}
};
+142 -207
View File
@@ -33,7 +33,8 @@ import {
replaceMailVaribles,
copytoData,
fetchSubscription,
convertPdfArrayBuffer
convertPdfArrayBuffer,
getContainerScale
} from "../constant/Utils";
import RenderPdf from "../components/pdf/RenderPdf";
import { useNavigate } from "react-router-dom";
@@ -50,7 +51,6 @@ import Upgrade from "../primitives/Upgrade";
import Alert from "../primitives/Alert";
import Loader from "../primitives/Loader";
import { useSelector } from "react-redux";
import TextFontSetting from "../components/pdf/TextFontSetting";
import PdfZoom from "../components/pdf/PdfZoom";
import LottieWithLoader from "../primitives/DotLottieReact";
@@ -170,16 +170,7 @@ function PlaceHolderSign() {
isDragStamp: !!monitor.isDragging()
})
});
const rowLevel =
localStorage.getItem("rowlevel") &&
JSON.parse(localStorage.getItem("rowlevel"));
const objectId =
rowLevel && rowLevel.id
? rowLevel.id
: rowLevel?.objectId && rowLevel.objectId;
const documentId = docId ? docId : objectId && objectId;
const documentId = docId;
useEffect(() => {
if (documentId) {
getDocumentDetails();
@@ -413,8 +404,7 @@ function PlaceHolderSign() {
};
setIsLoading(loadObj);
}
const currentUserEmail = documentData[0]?.ExtUserPtr?.Email;
const res = await contractUsers(currentUserEmail);
const res = await contractUsers();
if (res === "Error: Something went wrong!") {
const loadObj = {
isLoad: false
@@ -454,7 +444,6 @@ function PlaceHolderSign() {
const addPositionOfSignature = (item, monitor) => {
getSignerPos(item, monitor);
};
// console.log("signerpos", signerPos);
const getSignerPos = (item, monitor) => {
// setSignerObjId("");
// setContractName("");
@@ -463,10 +452,11 @@ function PlaceHolderSign() {
setZIndex(posZIndex);
const signer = signersdata.find((x) => x.Id === uniqueId);
const key = randomId();
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
const containerScale = getContainerScale(
pdfOriginalWH,
pageNumber,
containerWH
);
const containerScale = containerWH?.width / getPdfPageWidth?.width || 1;
let dropData = [];
let placeHolder;
const dragTypeValue = item?.text ? item.text : monitor.type;
@@ -679,17 +669,19 @@ function PlaceHolderSign() {
//function for set and update x and y postion after drag and drop signature tab
const handleStop = (event, dragElement, signerId, key) => {
setFontColor();
setFontSize();
if (!isResize && isDragging) {
const dataNewPlace = addZIndex(signerPos, key, setZIndex);
let updateSignPos = [...signerPos];
updateSignPos.splice(0, updateSignPos.length, ...dataNewPlace);
const signId = signerId ? signerId : uniqueId; //? signerId : signerObjId;
const keyValue = key ? key : dragKey;
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
const containerScale = getContainerScale(
pdfOriginalWH,
pageNumber,
containerWH
);
const containerScale = containerWH.width / getPdfPageWidth?.width;
if (keyValue >= 0) {
let filterSignerPos;
if (signId) {
@@ -751,7 +743,6 @@ function PlaceHolderSign() {
setIsDragging(false);
}, 200);
};
//function for delete signature block
const handleDeleteSign = (key, Id) => {
const updateData = [];
@@ -861,13 +852,14 @@ function PlaceHolderSign() {
const pdfDoc = await PDFDocument.load(existingPdfBytes, {
ignoreEncryption: true
});
const isSignYourSelfFlow = false;
try {
const pdfBytes = await multiSignEmbed(
placeholder,
pdfDoc,
isSignYourSelfFlow,
scale,
pdfOriginalWH,
containerWH
);
@@ -1007,9 +999,9 @@ function PlaceHolderSign() {
}
await axios
.put(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document/${documentId}`,
`${localStorage.getItem(
"baseUrl"
)}classes/contracts_Document/${documentId}`,
data,
{
headers: {
@@ -1145,12 +1137,7 @@ function PlaceHolderSign() {
const senderName = `${pdfDetails?.[0].ExtUserPtr.Name}`;
const documentName = `${pdfDetails?.[0].Name}`;
let replaceVar;
if (
requestBody &&
requestSubject &&
isCustomize &&
(isSubscribe || !isEnableSubscription)
) {
if (requestBody && requestSubject && isCustomize && isSubscribe) {
const replacedRequestBody = requestBody.replace(/"/g, "'");
htmlReqBody =
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
@@ -1218,12 +1205,7 @@ function PlaceHolderSign() {
setMailStatus("success");
try {
let data;
if (
requestBody &&
requestSubject &&
isCustomize &&
(isSubscribe || !isEnableSubscription)
) {
if (requestBody && requestSubject && isCustomize && isSubscribe) {
data = {
RequestBody: htmlReqBody,
RequestSubject: requestSubject,
@@ -1237,9 +1219,9 @@ function PlaceHolderSign() {
await axios
.put(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document/${documentId}`,
`${localStorage.getItem(
"baseUrl"
)}classes/contracts_Document/${documentId}`,
data,
{
headers: {
@@ -1488,13 +1470,19 @@ function PlaceHolderSign() {
hint: defaultdata?.hint || "",
defaultValue: defaultdata?.defaultValue || "",
validation:
(isSubscribe || !isEnableSubscription) && inputype
isSubscribe && inputype
? {
type: inputype,
pattern:
inputype === "regex" ? defaultdata.textvalidate : ""
}
: {}
: {},
fontSize:
fontSize || currWidgetsDetails?.options?.fontSize || "12",
fontColor:
fontColor ||
currWidgetsDetails?.options?.fontColor ||
"black"
}
};
} else {
@@ -1504,7 +1492,13 @@ function PlaceHolderSign() {
...position.options,
name: defaultdata.name,
status: defaultdata.status,
defaultValue: defaultdata.defaultValue
defaultValue: defaultdata.defaultValue,
fontSize:
fontSize || currWidgetsDetails?.options?.fontSize || "12",
fontColor:
fontColor ||
currWidgetsDetails?.options?.fontColor ||
"black"
}
};
}
@@ -1528,6 +1522,8 @@ function PlaceHolderSign() {
}
}
setCurrWidgetsDetails({});
setFontSize();
setFontColor();
handleNameModal();
};
@@ -1537,12 +1533,19 @@ function PlaceHolderSign() {
setShowDropdown(false);
setIsRadio(false);
setIsCheckbox(false);
setIsPageCopy(false);
//condition for text widget type after set all values for text widget
//change setUniqueId which is set in tempsignerId
//because textwidget do not have signer user so for selected signers we have to do
if (currWidgetsDetails.type === textWidget) {
setUniqueId(tempSignerId);
setTempSignerId("");
}
};
//function for update TourStatus
const closeTour = async () => {
setPlaceholderTour(false);
if (isDontShow) {
const extUserClass = localStorage.getItem("extended_class");
let updatedTourStatus = [];
if (tourStatus.length > 0) {
updatedTourStatus = [...tourStatus];
@@ -1561,7 +1564,7 @@ function PlaceHolderSign() {
.put(
`${localStorage.getItem(
"baseUrl"
)}classes/${extUserClass}/${signerUserId}`,
)}classes/contracts_Users/${signerUserId}`,
{
TourStatus: updatedTourStatus
},
@@ -1620,13 +1623,11 @@ function PlaceHolderSign() {
setCurrentId(getCurrentUserDeatils[0].Email);
}
}
setSignersData(updateSigner);
const index = signersdata.findIndex((x) => x.Id === uniqueId);
setIsSelectId(index);
}
};
//function to add new signer in document signers list
const handleAddNewRecipients = (data) => {
const newId = randomId();
@@ -1689,60 +1690,6 @@ function PlaceHolderSign() {
setSignerPos(updatePlaceholderUser);
setIsMailSend(false);
};
const handleSaveFontSize = () => {
const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
if (filterSignerPos.length > 0) {
const getPlaceHolder = filterSignerPos[0].placeHolder;
const getPageNumer = getPlaceHolder.filter(
(data) => data.pageNumber === pageNumber
);
if (getPageNumer.length > 0) {
const getXYdata = getPageNumer[0].pos;
const getPosData = getXYdata;
const addSignPos = getPosData.map((position) => {
if (position.key === signKey) {
return {
...position,
options: {
...position.options,
fontSize: fontSize,
fontColor: fontColor
}
};
}
return position;
});
const newUpdateSignPos = getPlaceHolder.map((obj) => {
if (obj.pageNumber === pageNumber) {
return { ...obj, pos: addSignPos };
}
return obj;
});
const newUpdateSigner = signerPos.map((obj) => {
if (obj.Id === uniqueId) {
return { ...obj, placeHolder: newUpdateSignPos };
}
return obj;
});
setSignerPos(newUpdateSigner);
}
}
setFontSize();
setFontColor();
if (currWidgetsDetails.type === textWidget) {
setUniqueId(tempSignerId);
setTempSignerId("");
}
handleTextSettingModal(false);
};
const handleTextSettingModal = (value) => {
setIsTextSetting(value);
};
return (
<>
<Title title={state?.title ? state.title : "New Document"} />
@@ -1813,7 +1760,6 @@ function PlaceHolderSign() {
: isSendAlert.mssg === "confirm" && "Send Mail"
}
handleClose={() => setIsSendAlert({})}
showHeaderMessage={isSendAlert.mssg === "confirm"}
>
<div className="max-h-96 overflow-y-scroll scroll-hide p-[20px] text-base-content">
{isSendAlert.mssg === "sure" ? (
@@ -1828,86 +1774,69 @@ function PlaceHolderSign() {
) : (
isSendAlert.mssg === "confirm" && (
<>
<>
{!isCustomize && (
<span>
Are you sure you want to send out this
document for signatures?
</span>
)}
{isCustomize &&
(!isEnableSubscription || isSubscribe) && (
<>
<EmailBody
editorRef={editorRef}
requestBody={requestBody}
requestSubject={requestSubject}
handleOnchangeRequest={
handleOnchangeRequest
}
setRequestSubject={setRequestSubject}
/>
<div
className="flex justify-end items-center gap-1 mt-2 op-link op-link-primary"
onClick={() => {
setRequestBody(defaultBody);
setRequestSubject(defaultSubject);
}}
>
<span>Reset to default</span>
</div>
</>
)}
<div
className={
"flex flex-row md:items-center gap-2 md:gap-6 mt-2 "
}
>
<div className="flex flex-row gap-2">
<button
onClick={() => sendEmailToSigners()}
className="op-btn op-btn-primary font-[500] text-sm shadow"
>
Send
</button>
{isCustomize && (
<button
onClick={() => {
setIsCustomize(false);
}}
className="op-btn op-btn-ghost font-[500] text-sm"
>
Close
</button>
)}
{!isCustomize && (
<span>
Are you sure you want to send out this document
for signatures?
</span>
)}
{isCustomize && isSubscribe && (
<>
<EmailBody
editorRef={editorRef}
requestBody={requestBody}
requestSubject={requestSubject}
handleOnchangeRequest={handleOnchangeRequest}
setRequestSubject={setRequestSubject}
/>
<div
className="flex justify-end items-center gap-1 mt-2 op-link op-link-primary"
onClick={() => {
setRequestBody(defaultBody);
setRequestSubject(defaultSubject);
}}
>
<span>Reset to default</span>
</div>
{!isCustomize &&
(isSubscribe || !isEnableSubscription) && (
<span
className="op-link op-link-accent text-sm"
onClick={() => {
setIsCustomize(!isCustomize);
}}
>
Cutomize Email
</span>
)}
{!isSubscribe && isEnableSubscription && (
<div className="mt-2">
<Upgrade
message="Upgrade to customize Email"
newWindow={true}
/>
</div>
</>
)}
<div className="flex flex-row md:items-center gap-2 md:gap-6 mt-2">
<div className="flex flex-row gap-2">
<button
onClick={() => sendEmailToSigners()}
className="op-btn op-btn-primary font-[500] text-sm shadow"
>
Send
</button>
{isCustomize && (
<button
onClick={() => setIsCustomize(false)}
className="op-btn op-btn-ghost font-[500] text-sm"
>
Close
</button>
)}
</div>
</>
{!isCustomize && isSubscribe && (
<span
className="op-link op-link-accent text-sm"
onClick={() => setIsCustomize(!isCustomize)}
>
Cutomize Email
</span>
)}
{!isSubscribe && isEnableSubscription && (
<div className="mt-2">
<Upgrade
message="Upgrade to customize Email"
newWindow={true}
/>
</div>
)}
</div>
</>
)
)}
{isSendAlert.mssg === "confirm" && (
<>
<div className="flex justify-center items-center mt-3">
@@ -1948,29 +1877,37 @@ function PlaceHolderSign() {
{!mailStatus && (
<div className="w-full h-[1px] bg-[#9f9f9f] my-[15px]"></div>
)}
{isCurrUser && (
<div
className={
mailStatus === "success"
? "flex justify-center mt-1"
: ""
}
>
{isCurrUser && (
<button
onClick={() => {
handleRecipientSign();
}}
type="button"
className="op-btn op-btn-primary mr-1"
>
Yes
</button>
)}
<button
onClick={() => {
handleRecipientSign();
setIsSend(false);
setSignerPos([]);
navigate("/report/1MwEuxLEkF");
}}
type="button"
className="op-btn op-btn-primary mr-1"
className="op-btn op-btn-ghost"
>
Yes
{isCurrUser ? "No" : "Close"}
</button>
)}
<button
onClick={() => {
setIsSend(false);
setSignerPos([]);
navigate("/report/1MwEuxLEkF");
}}
type="button"
className="op-btn op-btn-ghost"
>
{isCurrUser ? "No" : "Close"}
</button>
</div>
</div>
</ModalUi>
<ModalUi
@@ -2095,10 +2032,10 @@ function PlaceHolderSign() {
handleNameModal={setIsNameModal}
setTempSignerId={setTempSignerId}
uniqueId={uniqueId}
handleTextSettingModal={handleTextSettingModal}
pdfOriginalWH={pdfOriginalWH}
setScale={setScale}
scale={scale}
setIsSelectId={setIsSelectId}
/>
)}
</div>
@@ -2142,6 +2079,7 @@ function PlaceHolderSign() {
setBlockColor={setBlockColor}
setIsAddSigner={setIsAddSigner}
handleDeleteUser={handleDeleteUser}
uniqueId={uniqueId}
/>
</div>
) : (
@@ -2151,6 +2089,7 @@ function PlaceHolderSign() {
aria-disabled
>
<SignerListPlace
setSignerPos={setSignerPos}
signerPos={signerPos}
signersdata={signersdata}
isSelectListId={isSelectListId}
@@ -2167,6 +2106,7 @@ function PlaceHolderSign() {
setIsAddSigner={setIsAddSigner}
handleDeleteUser={handleDeleteUser}
roleName={roleName}
uniqueId={uniqueId}
// handleAddSigner={handleAddSigner}
/>
<div data-tut="addWidgets">
@@ -2211,17 +2151,6 @@ function PlaceHolderSign() {
</button>
</div>
</ModalUi>
<TextFontSetting
isTextSetting={isTextSetting}
setIsTextSetting={setIsTextSetting}
fontSize={fontSize}
setFontSize={setFontSize}
fontColor={fontColor}
setFontColor={setFontColor}
handleSaveFontSize={handleSaveFontSize}
currWidgetsDetails={currWidgetsDetails}
/>
<LinkUserModal
handleAddUser={handleAddUser}
isAddUser={isAddUser}
@@ -2242,6 +2171,12 @@ function PlaceHolderSign() {
handleClose={handleNameModal}
handleData={handleWidgetdefaultdata}
isSubscribe={isSubscribe}
isTextSetting={isTextSetting}
setIsTextSetting={setIsTextSetting}
fontSize={fontSize}
setFontSize={setFontSize}
fontColor={fontColor}
setFontColor={setFontColor}
/>
</DndProvider>
</>
+89 -63
View File
@@ -1,5 +1,5 @@
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";
@@ -16,7 +16,7 @@ const listItemStyle = {
const PlanSubscriptions = () => {
const navigate = useNavigate();
const [yearlyVisible, setYearlyVisible] = useState(false);
const [yearlyVisible, setYearlyVisible] = useState(true);
const [isLoader, setIsLoader] = useState(true);
const extUser =
localStorage.getItem("Extand_Class") &&
@@ -29,10 +29,15 @@ const PlanSubscriptions = () => {
};
const userDetails = JSON.parse(localStorage.getItem("userDetails")) || user;
// console.log("userDetails ", userDetails);
const name =
userDetails && userDetails.name
? "first_name=" + encodeURIComponent(userDetails.name)
: "";
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)
@@ -53,33 +58,37 @@ 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 (
@@ -109,7 +118,7 @@ const PlanSubscriptions = () => {
role="tab"
className={`${yearlyVisible ? "op-tab-active" : ""} op-tab`}
>
Yearly (10% off)
Yearly (upto 66% off)
</a>
</div>
<ul className="op-card flex flex-col md:flex-row h-full bg-base-100 justify-center shadow-lg">
@@ -122,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"}
@@ -160,36 +193,29 @@ 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 className="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>
))}
+10
View File
@@ -22,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;
@@ -156,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);
@@ -193,6 +201,8 @@ const Report = () => {
report_help={reporthelp}
tourData={tourData}
isDontShow={isDontShow}
setIsPublic={setIsPublic}
isPublic={isPublic}
/>
) : (
<PageNotFound prefix={"Report"} />
+47 -88
View File
@@ -1,7 +1,6 @@
import React, { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import Parse from "parse";
import axios from "axios";
import { appInfo } from "../constant/appinfo";
import { isEnableSubscription } from "../constant/const";
import { fetchSubscription } from "../constant/Utils";
@@ -136,8 +135,6 @@ const SSOVerify = () => {
};
// `thirdpartyLoginfn` is used to save necessary parameters locally for the logged-in user
const thirdpartyLoginfn = async (sessionToken) => {
const baseUrl = localStorage.getItem("baseUrl");
const parseAppId = localStorage.getItem("parseAppId");
try {
const validUser = await Parse.User.become(sessionToken);
if (validUser) {
@@ -151,76 +148,41 @@ const SSOVerify = () => {
}
// Check extended class user role and tenentId
try {
let userRoles = [];
const userSettings = appInfo.settings;
//Get Current user roles
const url = `${baseUrl}functions/UserGroups`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessionToken: _user.sessionToken
};
const body = { appname: appInfo.appname };
const UserGroupsRes = await axios.post(url, JSON.stringify(body), {
headers: headers
});
userRoles = (UserGroupsRes.data && UserGroupsRes.data.result) || [];
if (userRoles) {
let _currentRole = "";
const excludeRoles = ["contracts_Guest", `contracts_appeditor`];
const filteredRole = userRoles.filter(
(x) => !excludeRoles.includes(x)
);
if (filteredRole?.length > 1) {
console.log("user has two roles");
// _currentRole = filteredRole.filter((x) => x === "contracts_User");
} else {
_currentRole = filteredRole?.[0] || "";
}
if (_currentRole) {
const roleSetting = userSettings?.find(
(setting) => setting.role === _currentRole
);
const redirectUrl =
location?.state?.from ||
`/${roleSetting.pageType}/${roleSetting.pageId}`;
const _role = _currentRole.replace(`${appInfo.appname}_`, "");
localStorage.setItem("_user_role", _role);
// Get TenentID from Extendend Class
localStorage.setItem(
"extended_class",
roleSetting.extended_class
);
try {
const extUser = await Parse.Cloud.run("getUserDetails", {
email: _user.email
});
if (extUser) {
const _extUser = JSON.parse(JSON.stringify(extUser));
localStorage.setItem("userEmail", _extUser.Email);
localStorage.setItem("username", _extUser.Name);
localStorage.setItem("scriptId", true);
let tenentInfo = [];
const results = [extUser];
if (results) {
let extendedInfo_stringify = JSON.stringify(results);
localStorage.setItem(
"Extand_Class",
extendedInfo_stringify
);
await Parse.Cloud.run("getUserDetails")
.then(async (extUser) => {
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 redirectUrl =
location?.state?.from ||
`/${menu.pageType}/${menu.pageId}`;
const _role = _currentRole.replace("contracts_", "");
localStorage.setItem("_user_role", _role);
const extUser_stringify = JSON.stringify([extUser]);
localStorage.setItem("Extand_Class", extUser_stringify);
const _extUser = JSON.parse(JSON.stringify(extUser));
localStorage.setItem("userEmail", _extUser.Email);
localStorage.setItem("username", _extUser.Name);
localStorage.setItem("scriptId", true);
if (_extUser.TenantId) {
const obj = {
tenentId: _extUser.TenantId.objectId,
tenentName: _extUser.TenantId.TenantName || ""
const tenant = {
Id: _extUser?.TenantId?.objectId || "",
Name: _extUser?.TenantId?.TenantName || ""
};
localStorage.setItem("TenantId", obj.tenentId);
tenentInfo.push(obj);
dispatch(showTenant(obj.tenentName || ""));
localStorage.setItem("TenantName", obj.tenentName || "");
localStorage.setItem("TenantId", tenant?.Id);
dispatch(showTenant(tenant?.Name));
localStorage.setItem("TenantName", tenant?.Name);
}
localStorage.setItem("PageLanding", roleSetting.pageId);
localStorage.setItem("defaultmenuid", roleSetting.menuId);
localStorage.setItem("pageType", roleSetting.pageType);
localStorage.setItem("PageLanding", menu.pageId);
localStorage.setItem("defaultmenuid", menu.menuId);
localStorage.setItem("pageType", menu.pageType);
if (isEnableSubscription) {
const res = await fetchSubscription();
const plan = res.plan;
@@ -232,35 +194,32 @@ const SSOVerify = () => {
localStorage.removeItem("userDetails");
navigate(redirectUrl);
} else {
navigate(`/subscription`, {
replace: true
});
navigate(`/subscription`, { replace: true });
}
} else {
navigate(`/subscription`, {
replace: true
});
navigate(`/subscription`, { replace: true });
}
} else {
navigate(redirectUrl);
}
}
} else {
alert(
"Error: You don't have access, please contact the admin."
);
setMessage(
"Error: You don't have access, please contact the admin."
);
}
} catch (err) {
alert("user not exist.");
setMessage("Error: User not exist.");
console.log("err in get extUser", err);
}
} else {
alert("Role does not exists.");
setMessage("Error: Role does not exists.");
}
} else {
alert("Role does not exists.");
setMessage("Error: Role does not exists.");
}
})
.catch((error) => {
console.error("Err in fetch extuser", error);
alert("user not exist.");
setMessage("Error: User not exist.");
});
} catch (err) {
console.log("err in usergroups", err);
console.log("err in getuserdetails", err);
}
}
} catch (err) {
+65 -254
View File
@@ -44,14 +44,8 @@ const Signup = () => {
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();
@@ -59,14 +53,8 @@ const Signup = () => {
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);
@@ -194,8 +182,6 @@ const Signup = () => {
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) {
@@ -205,252 +191,81 @@ const Signup = () => {
}
// 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];
const userSettings = appInfo.settings;
await Parse.Cloud.run("getUserDetails")
.then(async (extUser) => {
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);
}
} 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
);
await Parse.Cloud.run("getUserDetails", {
email: email
}).then(
(result) => {
let tenentInfo = [];
const results = [result];
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(
"IncludedApps",
JSON.stringify(tenentInfo)
);
localStorage.setItem(
"PageLanding",
element.pageId
);
localStorage.setItem(
"defaultmenuid",
element.menuId
);
localStorage.setItem(
"pageType",
element.pageType
);
setState({ loading: false });
navigate("/");
} 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
);
setState({ loading: false });
if (isEnableSubscription) {
if (isFreeplan) {
navigate(
`/${element.pageType}/${element.pageId}`
);
} else {
navigate(`/subscription`, { replace: true });
}
} else {
alert("Registered user successfully");
navigate(
`/${element.pageType}/${element.pageId}`
);
}
}
} else {
alert("Registered user successfully");
localStorage.setItem("PageLanding", element.pageId);
localStorage.setItem(
"defaultmenuid",
element.menuId
);
localStorage.setItem("pageType", element.pageType);
setState({ loading: false });
if (isEnableSubscription) {
if (isFreeplan) {
navigate(
`/${element.pageType}/${element.pageId}`
);
} else {
navigate(`/subscription`, { replace: true });
}
} else {
navigate(
`/${element.pageType}/${element.pageId}`
);
}
}
},
(error) => {
setState({
loading: false,
alertType: "danger",
alertMsg:
"You dont have access to this application!"
});
setTimeout(function () {
setState({
loading: false,
alertType: "danger",
alertMsg: ""
});
}, 2000);
localStorage.setItem("accesstoken", null);
console.error("Error while fetching Follow", error);
}
);
localStorage.setItem("PageLanding", menu.pageId);
localStorage.setItem("defaultmenuid", menu.menuId);
localStorage.setItem("pageType", menu.pageType);
setState({ loading: false });
if (isEnableSubscription) {
if (isFreeplan) {
navigate(`/${menu.pageType}/${menu.pageId}`);
} else {
navigate(`/subscription`, { replace: true });
}
});
} else {
alert("Registered user successfully");
navigate(`/${menu.pageType}/${menu.pageId}`);
}
} else {
setState({
loading: false,
alertType: "danger",
alertMsg: "User Role Not Found!"
alertMsg: "Role not found."
});
setTimeout(function () {
setState({
loading: false,
alertType: "danger",
alertMsg: ""
});
setTimeout(() => {
setState({ loading: false, alertMsg: "" });
}, 2000);
}
} else {
setState({
loading: false,
alertType: "danger",
alertMsg: "User Role Not Found!"
alertMsg: "You don't have access, please contact the admin."
});
setTimeout(function () {
setState({
loading: false,
alertType: "danger",
alertMsg: ""
});
setTimeout(() => {
setState({ loading: false, alertMsg: "" });
}, 2000);
}
})
.catch((err) => {
console.log("err", err);
setState({
loading: false,
alertType: "danger",
alertMsg:
"Does not have permissions to access this application!"
});
setTimeout(function () {
setState({
loading: false,
alertType: "danger",
alertMsg: ""
});
}, 2000);
}
})
.catch((error) => {
console.log("error in fetch extuser", error);
setState({
loading: false,
alertType: "danger",
alertMsg: "You don't have access, please contact the admin."
});
}
setTimeout(() => {
setState({ loading: false, alertMsg: "" });
}, 2000);
});
} catch (error) {
// alert(`${error.message}`);
setState({
@@ -458,12 +273,8 @@ const Signup = () => {
alertType: "danger",
alertMsg: `${error.message}`
});
setTimeout(function () {
setState({
loading: false,
alertType: "danger",
alertMsg: ""
});
setTimeout(() => {
setState({ loading: false, alertMsg: "" });
}, 2000);
console.log(error);
}
@@ -477,9 +288,9 @@ const Signup = () => {
const saveLogo = async () => {
if (isEnableSubscription) {
const logo = await getAppLogo();
if (logo) {
setImage(logo);
const app = await getAppLogo();
if (app?.logo) {
setImage(app?.logo);
} else {
setImage(appInfo?.applogo || undefined);
}
@@ -601,9 +412,9 @@ const Signup = () => {
onClick={togglePasswordVisibility}
>
{showPassword ? (
<i className="fa fa-eye-slash" /> // Close eye icon
<i className="fa-light fa-eye-slash" /> // Close eye icon
) : (
<i className="fa fa-eye" /> // Open eye icon
<i className="fa-light fa-eye" /> // Open eye icon
)}
</span>
</div>
+168 -171
View File
@@ -2,7 +2,6 @@ import React, { useState, useRef, useEffect } from "react";
import { PDFDocument } from "pdf-lib";
import "../styles/signature.css";
import Parse from "parse";
import { isEnableSubscription } from "../constant/const";
import Confetti from "react-confetti";
import axios from "axios";
import LoaderWithMsg from "../primitives/LoaderWithMsg";
@@ -33,7 +32,9 @@ import {
textInputWidget,
fetchImageBase64,
changeImageWH,
handleSendOTP
handleSendOTP,
getContainerScale,
getDefaultSignature
} from "../constant/Utils";
import { useParams } from "react-router-dom";
import Tour from "reactour";
@@ -71,8 +72,8 @@ function SignYourSelf() {
const signRef = useRef(null);
const dragRef = useRef(null);
const [dragKey, setDragKey] = useState();
const [fontSize, setFontSize] = useState(11);
const [fontColor, setFontColor] = useState("black");
const [fontSize, setFontSize] = useState();
const [fontColor, setFontColor] = useState();
const [signKey, setSignKey] = useState();
const [imgWH, setImgWH] = useState({});
const [pdfNewWidth, setPdfNewWidth] = useState();
@@ -205,131 +206,91 @@ function SignYourSelf() {
}, [divRef.current, isHeader]);
//function for get document details for perticular signer with signer'object id
const getDocumentDetails = async (showComplete) => {
let isCompleted;
//getting document details
const documentData = await contractDocument(documentId);
try {
let isCompleted;
//getting document details
const documentData = await contractDocument(documentId);
if (documentData && documentData.length > 0) {
setPdfDetails(documentData);
setExtUserId(documentData[0]?.ExtUserPtr?.objectId);
const url = documentData[0] && documentData[0]?.URL;
if (url) {
//convert document url in array buffer format to use embed widgets in pdf using pdf-lib
const arrayBuffer = await convertPdfArrayBuffer(url);
if (arrayBuffer === "Error") {
if (documentData && documentData.length > 0) {
setPdfDetails(documentData);
setExtUserId(documentData[0]?.ExtUserPtr?.objectId);
const url = documentData[0] && documentData[0]?.URL;
if (url) {
//convert document url in array buffer format to use embed widgets in pdf using pdf-lib
const arrayBuffer = await convertPdfArrayBuffer(url);
if (arrayBuffer === "Error") {
setHandleError("Error: Something went wrong!");
} else {
setPdfArrayBuffer(arrayBuffer);
}
} else {
setHandleError("Error: Something went wrong!");
} else {
setPdfArrayBuffer(arrayBuffer);
}
} else {
setHandleError("Error: Something went wrong!");
}
isCompleted = documentData[0].IsCompleted && documentData[0].IsCompleted;
if (isCompleted) {
setIsCelebration(true);
setTimeout(() => {
setIsCelebration(false);
}, 5000);
setIsCompleted(true);
setPdfUrl(documentData[0].SignedUrl);
const alreadySign = {
status: true,
mssg: "Congratulations! 🎉 This document has been successfully signed by you!"
};
if (showComplete) {
setShowAlreadySignDoc(alreadySign);
} else {
setIsUiLoading(false);
setIsSignPad(false);
setIsEmail(true);
setXyPostion([]);
setSignBtnPosition([]);
}
}
} else if (
documentData === "Error: Something went wrong!" ||
(documentData.result && documentData.result.error)
) {
const loadObj = {
isLoad: false
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
} else {
setHandleError("No Data Found!");
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
}
await axios
.get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Signature?where={"UserId": {"__type": "Pointer","className": "_User", "objectId":"${
jsonSender.objectId
}"}}`,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
isCompleted =
documentData[0].IsCompleted && documentData[0].IsCompleted;
if (isCompleted) {
setIsCelebration(true);
setTimeout(() => {
setIsCelebration(false);
}, 5000);
setIsCompleted(true);
setPdfUrl(documentData[0].SignedUrl);
const alreadySign = {
status: true,
mssg: "Congratulations! 🎉 This document has been successfully signed by you!"
};
if (showComplete) {
setShowAlreadySignDoc(alreadySign);
} else {
setIsUiLoading(false);
setIsSignPad(false);
setIsEmail(true);
setXyPostion([]);
setSignBtnPosition([]);
}
}
)
.then((Listdata) => {
const json = Listdata.data;
const res = json.results;
if (res[0] && res.length > 0) {
setDefaultSignImg(res[0].ImageURL);
setMyInitial(res[0]?.Initials);
}
})
.catch((err) => {
console.log("Err ", err);
} else if (
documentData === "Error: Something went wrong!" ||
(documentData.result && documentData.result.error)
) {
const loadObj = {
isLoad: false
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
});
const contractUsersRes = await contractUsers(jsonSender.email);
if (contractUsersRes === "Error: Something went wrong!") {
const loadObj = {
isLoad: false
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
} else if (contractUsersRes[0] && contractUsersRes.length > 0) {
setActiveMailAdapter(contractUsersRes[0]?.active_mail_adapter);
setContractName("_Users");
setSignerUserId(contractUsersRes[0].objectId);
const tourstatuss =
contractUsersRes[0].TourStatus && contractUsersRes[0].TourStatus;
if (tourstatuss && tourstatuss.length > 0 && !isCompleted) {
setTourStatus(tourstatuss);
const checkTourRecipients = tourstatuss.filter(
(data) => data.signyourself
);
if (checkTourRecipients && checkTourRecipients.length > 0) {
setCheckTourStatus(checkTourRecipients[0].signyourself);
}
} else {
setCheckTourStatus(true);
setHandleError("No Data Found!");
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
}
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
} else if (contractUsersRes.length === 0) {
const contractContactBook = await contactBook(jsonSender.objectId);
if (contractContactBook && contractContactBook.length > 0) {
setContractName("_Contactbook");
setSignerUserId(contractContactBook[0].objectId);
const tourstatuss =
contractContactBook[0].TourStatus &&
contractContactBook[0].TourStatus;
//function to get default signatur eof current user from `contracts_Signature` class
const defaultSignRes = await getDefaultSignature(jsonSender.objectId);
console.log("defaultSignRes", defaultSignRes);
if (defaultSignRes?.status === "success") {
setDefaultSignImg(defaultSignRes?.res?.defaultSignature);
setMyInitial(defaultSignRes?.res?.defaultInitial);
} else if (defaultSignRes?.status === "error") {
setHandleError("Error: Something went wrong!");
setIsLoading({
isLoad: false
});
}
const contractUsersRes = await contractUsers();
if (contractUsersRes === "Error: Something went wrong!") {
const loadObj = {
isLoad: false
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
} else if (contractUsersRes[0] && contractUsersRes.length > 0) {
setActiveMailAdapter(contractUsersRes[0]?.active_mail_adapter);
setContractName("_Users");
setSignerUserId(contractUsersRes[0].objectId);
const tourstatuss =
contractUsersRes[0].TourStatus && contractUsersRes[0].TourStatus;
if (tourstatuss && tourstatuss.length > 0 && !isCompleted) {
setTourStatus(tourstatuss);
const checkTourRecipients = tourstatuss.filter(
@@ -341,15 +302,47 @@ function SignYourSelf() {
} else {
setCheckTourStatus(true);
}
} else {
setHandleError("No Data Found!");
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
} else if (contractUsersRes.length === 0) {
const contractContactBook = await contactBook(jsonSender.objectId);
if (contractContactBook && contractContactBook.length > 0) {
setContractName("_Contactbook");
setSignerUserId(contractContactBook[0].objectId);
const tourstatuss =
contractContactBook[0].TourStatus &&
contractContactBook[0].TourStatus;
if (tourstatuss && tourstatuss.length > 0 && !isCompleted) {
setTourStatus(tourstatuss);
const checkTourRecipients = tourstatuss.filter(
(data) => data.signyourself
);
if (checkTourRecipients && checkTourRecipients.length > 0) {
setCheckTourStatus(checkTourRecipients[0].signyourself);
}
} else {
setCheckTourStatus(true);
}
} else {
setHandleError("No Data Found!");
}
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
}
const loadObj = {
} catch (err) {
console.log("Error: error in getDocumentDetails", err);
setHandleError("Error: Something went wrong!");
setIsLoading({
isLoad: false
};
setIsLoading(loadObj);
});
}
};
const getWidgetValue = (type) => {
switch (type) {
case "name":
@@ -443,6 +436,7 @@ function SignYourSelf() {
};
//function for setting position after drop signature button over pdf
const addPositionOfSignature = (item, monitor) => {
setCurrWidgetsDetails({});
const key = randomId();
let dropData = [];
let dropObj = {};
@@ -454,10 +448,11 @@ function SignYourSelf() {
const widgetTypeExist = ["name", "company", "job title", "email"].includes(
dragTypeValue
);
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
const containerScale = getContainerScale(
pdfOriginalWH,
pageNumber,
containerWH
);
const containerScale = containerWH?.width / getPdfPageWidth?.width || 1;
//adding and updating drop position in array when user drop signature button in div
if (item === "onclick") {
const getWidth = widgetTypeExist
@@ -695,7 +690,9 @@ function SignYourSelf() {
xyPostion,
pdfDoc,
isSignYourSelfFlow,
scale
scale,
pdfOriginalWH,
containerWH
);
// console.log("pdf", pdfBytes);
//function for call to embed signature in pdf and get digital signature pdf
@@ -706,15 +703,28 @@ function SignYourSelf() {
setIsUiLoading(false);
if (err && err.message.includes("is encrypted.")) {
setIsAlert({
header: "Error",
isShow: true,
alertMessage: `Currently encrypted pdf files are not supported.`
});
} else {
console.log("err in signing", err);
setIsAlert({
isShow: true,
alertMessage: `Something went wrong.`
});
console.log("err in signing", err.message);
if (
err.message ===
"PKCS#12 MAC could not be verified. Invalid password?"
) {
setIsAlert({
header: "Error",
isShow: true,
alertMessage: `PFX file password is invalid.`
});
} else {
setIsAlert({
header: "Error",
isShow: true,
alertMessage: `Something went wrong.`
});
}
}
}
}
@@ -722,6 +732,7 @@ function SignYourSelf() {
console.log("err in embedselfsign ", err);
setIsUiLoading(false);
setIsAlert({
header: "Error",
isShow: true,
alertMessage: "something went wrong, please try again later."
});
@@ -739,7 +750,7 @@ function SignYourSelf() {
if (
tenantDetails?.CompletionBody &&
tenantDetails?.CompletionSubject &&
(!isEnableSubscription || getIsSubscribe)
getIsSubscribe
) {
isCustomCompletionMail = true;
}
@@ -767,39 +778,24 @@ function SignYourSelf() {
console.log("error", e);
}
}
//change image width and height to 104/44 in png base64
//change image width and height to 100/40 in png base64
const getNewse64 = await changeImageWH(base64Sign);
//remove suffiix of base64
const suffixbase64 = getNewse64 && getNewse64.split(",").pop();
let singleSign = {
const params = {
pdfFile: base64Url,
docId: documentId,
isCustomCompletionMail: isCustomCompletionMail,
mailProvider: activeMailAdapter,
signature: suffixbase64
};
await axios
.post(`${localStorage.getItem("baseUrl")}functions/signPdf`, singleSign, {
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
// sessionToken: localStorage.getItem("accesstoken")
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
})
.then((Listdata) => {
const json = Listdata.data;
setPdfUrl(json.result.data);
if (json.result.data) {
getDocumentDetails(false);
}
})
.catch((err) => {
console.log("axois err ", err);
});
const resSignPdf = await Parse.Cloud.run("signPdf", params);
if (resSignPdf) {
const signedpdf = JSON.parse(JSON.stringify(resSignPdf));
setPdfUrl(signedpdf);
getDocumentDetails(false);
}
};
//function for save x and y position and show signature tab on that position
@@ -809,12 +805,15 @@ function SignYourSelf() {
};
//function for set and update x and y postion after drag and drop signature tab
const handleStop = (event, dragElement) => {
setFontSize();
setFontColor();
if (isDragging && dragElement) {
event.preventDefault();
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
const containerScale = getContainerScale(
pdfOriginalWH,
pageNumber,
containerWH
);
const containerScale = containerWH.width / getPdfPageWidth?.width || 1;
if (dragKey >= 0) {
const filterDropPos = xyPostion.filter(
(data) => data.pageNumber === pageNumber
@@ -1028,9 +1027,9 @@ function SignYourSelf() {
}
await axios
.put(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}${contractName}/${signerUserId}`,
`${localStorage.getItem(
"baseUrl"
)}classes/contracts${contractName}/${signerUserId}`,
{
TourStatus: updatedTourStatus
},
@@ -1134,8 +1133,10 @@ function SignYourSelf() {
...position,
options: {
...position.options,
fontSize: fontSize || currWidgetsDetails?.options?.fontSize,
fontColor: fontColor || currWidgetsDetails?.options?.fontColor
fontSize:
fontSize || currWidgetsDetails?.options?.fontSize || "12",
fontColor:
fontColor || currWidgetsDetails?.options?.fontColor || "black"
}
};
}
@@ -1153,7 +1154,6 @@ function SignYourSelf() {
handleTextSettingModal(false);
}
};
return (
<DndProvider backend={HTML5Backend}>
<Title title={"Self Sign"} />
@@ -1222,16 +1222,13 @@ function SignYourSelf() {
setZoomPercent={setZoomPercent}
zoomPercent={zoomPercent}
/>
<div className=" w-full md:w-[95%] ">
<div className="w-full md:w-[95%]">
<ModalUi
isOpen={isAlert.isShow}
title={isAlert?.header || "Alert"}
handleClose={() => {
setIsAlert({
isShow: false,
alertMessage: ""
});
}}
handleClose={() =>
setIsAlert({ isShow: false, alertMessage: "" })
}
>
<div className="p-[20px] h-full">
<p>{isAlert.alertMessage}</p>
@@ -1306,12 +1303,12 @@ function SignYourSelf() {
isEmail={isEmail}
pdfUrl={pdfUrl}
setIsEmail={setIsEmail}
pdfName={pdfDetails[0] && pdfDetails[0].Name}
setSuccessEmail={setSuccessEmail}
sender={jsonSender}
setIsAlert={setIsAlert}
extUserId={extUserId}
activeMailAdapter={activeMailAdapter}
pdfDetails={pdfDetails}
/>
{/* pdf header which contain funish back button */}
<Header
+465
View File
@@ -0,0 +1,465 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import Alert from "../primitives/Alert";
import Loader from "../primitives/Loader";
import { useLocation } from "react-router-dom";
import Tooltip from "../primitives/Tooltip";
import ModalUi from "../primitives/ModalUi";
import pad from "../assets/images/pad.svg";
import AddTeam from "../components/AddTeam";
import { isEnableSubscription } from "../constant/const";
import { checkIsSubscribedTeam } from "../constant/Utils";
import SubscribeCard from "../primitives/SubscribeCard";
import Title from "../components/Title";
const heading = ["Sr.No", "Name", "Parent Team", "Active"];
const actions = [
{
btnId: "1231",
hoverLabel: "Edit",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-pen",
redirectUrl: "",
action: "edit"
}
];
const TeamList = () => {
const recordperPage = 10;
const [teamList, setTeamList] = useState([]);
const [isLoader, setIsLoader] = useState(false);
const [isModal, setIsModal] = useState(false);
const location = useLocation();
const isDashboard =
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
const [currentPage, setCurrentPage] = useState(1);
const [isActiveModal, setIsActiveModal] = useState({});
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
const [isActLoader, setIsActLoader] = useState({});
const [isSubscribe, setIsSubscribe] = useState(false);
const [isEditModal, setIsEditModal] = useState({});
const [isAdmin, setIsAdmin] = useState(false);
const startIndex = (currentPage - 1) * recordperPage; // user per page
const getPaginationRange = () => {
const totalPageNumbers = 7; // Adjust this value to show more/less page numbers
const pages = [];
const totalPages = Math.ceil(teamList.length / recordperPage);
if (totalPages <= totalPageNumbers) {
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
const leftSiblingIndex = Math.max(currentPage - 1, 1);
const rightSiblingIndex = Math.min(currentPage + 1, totalPages);
const showLeftDots = leftSiblingIndex > 2;
const showRightDots = rightSiblingIndex < totalPages - 2;
const firstPageIndex = 1;
const lastPageIndex = totalPages;
if (!showLeftDots && showRightDots) {
let leftItemCount = 3;
let leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1);
pages.push(...leftRange);
pages.push("...");
pages.push(totalPages);
} else if (showLeftDots && !showRightDots) {
let rightItemCount = 3;
let rightRange = Array.from(
{ length: rightItemCount },
(_, i) => totalPages - rightItemCount + i + 1
);
pages.push(firstPageIndex);
pages.push("...");
pages.push(...rightRange);
} else if (showLeftDots && showRightDots) {
let middleRange = Array.from(
{ length: 3 },
(_, i) => leftSiblingIndex + i
);
pages.push(firstPageIndex);
pages.push("...");
pages.push(...middleRange);
pages.push("...");
pages.push(lastPageIndex);
}
}
return pages;
};
const pageNumbers = getPaginationRange();
useEffect(() => {
fetchTeamList();
}, []);
async function fetchTeamList() {
try {
setIsLoader(true);
if (isEnableSubscription) {
const getIsSubscribe = await checkIsSubscribedTeam();
setIsSubscribe(getIsSubscribe);
}
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
if (extUser) {
const admin =
extUser?.UserRole &&
(extUser?.UserRole === "contracts_Admin" ||
extUser?.UserRole === "contracts_OrgAdmin")
? true
: false;
setIsAdmin(admin);
}
const teams = await Parse.Cloud.run("getteams");
if (teams.length > 0) {
const _teamRes = JSON.parse(JSON.stringify(teams));
setTeamList(_teamRes);
}
} catch (err) {
console.log("Err in fetch teamlist", err);
setIsAlert({ type: "danger", msg: "Something went wrong." });
} finally {
setTimeout(() => {
setIsAlert({ type: "success", msg: "" });
}, 1500);
setIsLoader(false);
}
}
const handleFormModal = () => {
setIsModal(!isModal);
};
// Get current list
const indexOfLastDoc = currentPage * recordperPage;
const indexOfFirstDoc = indexOfLastDoc - recordperPage;
const currentList = teamList?.slice(indexOfFirstDoc, indexOfLastDoc);
const handleClose = () => {
setIsActiveModal({});
setIsEditModal({});
};
// Change page
const paginateFront = () => setCurrentPage(currentPage + 1);
const paginateBack = () => setCurrentPage(currentPage - 1);
const handleActionBtn = (act, item) => {
if (act.action === "edit") {
setIsEditModal({ [item.objectId]: true });
}
};
const handleToggleBtn = (team) => {
setIsActiveModal({ [team.objectId]: true });
};
const handleToggleSubmit = async (team) => {
const index = teamList.findIndex((obj) => obj.objectId === team.objectId);
if (index !== -1) {
setIsActiveModal({});
setIsActLoader({ [team.objectId]: true });
const newArray = [...teamList];
const IsActive = newArray[index].IsActive;
newArray[index] = { ...newArray[index], IsActive: !IsActive };
setTeamList(newArray);
try {
await Parse.Cloud.run("updateteam", {
IsActive: !IsActive === false ? "false" : "true",
TeamId: team.objectId
});
// console.log("teamRes ", teamRes);
setIsAlert({
type: !IsActive === false ? "danger" : "success",
msg: !IsActive === false ? "Team disabled." : "Team enabled."
});
} catch (err) {
setIsAlert({ type: "danger", msg: "something went wrong." });
console.log("err in disable team", err);
} finally {
setIsActLoader({});
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
}
}
};
const handleTeamInfo = (team) => {
setTeamList((prev) => [team, ...prev]);
};
const handleEditChange = (e, team) => {
const index = teamList.findIndex((obj) => obj.objectId === team.objectId);
if (index !== -1) {
const newArray = [...teamList];
newArray[index] = { ...newArray[index], Name: e.target.value };
setTeamList(newArray);
}
};
const updateTeamName = async (e, team) => {
e.preventDefault();
e.stopPropagation();
setIsActLoader({ [team.objectId]: true });
setIsEditModal({});
try {
const data = { Name: team.Name, TeamId: team.objectId };
await Parse.Cloud.run("updateteam", data);
// console.log("updateTeamRes ", updateTeamRes);
setIsAlert({ type: "success", msg: "Team Update successfully." });
} catch (Err) {
console.log("Err in update team name"), Err;
setIsAlert({ type: "danger", msg: "Something went wrong." });
} finally {
setIsActLoader({});
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
}
};
return (
<div className="relative">
<Title title={"Teams"} />
{isLoader && (
<div className="absolute w-full h-[300px] md:h-[400px] flex justify-center items-center z-30 rounded-box">
<Loader />
</div>
)}
{Object.keys(isActLoader)?.length > 0 && (
<div className="absolute w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-30 rounded-box">
<Loader />
</div>
)}
{isSubscribe && isEnableSubscription && !isLoader && (
<>
{isAdmin ? (
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
{isAlert.msg && (
<Alert type={isAlert.type}>
<div className="ml-3">{isAlert.msg}</div>
</Alert>
)}
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
<div className="font-light">
Teams{" "}
<span className="text-xs md:text-[13px] font-normal">
<Tooltip message={"Teams"} />
</span>
</div>
<div
className="cursor-pointer"
onClick={() => handleFormModal()}
>
<i className="fa-light fa-square-plus text-accent text-[40px]"></i>
</div>
</div>
<div className={` overflow-x-auto w-full`}>
<table className="op-table border-collapse w-full">
<thead className="text-[14px]">
<tr className="border-y-[1px]">
{heading?.map((item, index) => (
<React.Fragment key={index}>
<th className="px-4 py-2">{item}</th>
</React.Fragment>
))}
</tr>
</thead>
<tbody className="text-[12px]">
{teamList?.length > 0 && (
<>
{currentList.map((item, index) => (
<tr className="border-y-[1px]" key={index}>
{heading.includes("Sr.No") && (
<th className="px-4 py-2">
{startIndex + index + 1}
</th>
)}
<td className="px-4 py-2 font-semibold">
{item?.Name}
</td>
<td className="px-4 py-2 font-semibold">
{item?.ParentId?.Name || "-"}
</td>
<td className="px-4 py-2 font-semibold">
{item?.Name !== "All Users" && (
<>
<label className="cursor-pointer relative block items-center mb-0">
<input
type="checkbox"
className="op-toggle transition-all op-toggle-secondary"
checked={item?.IsActive}
onChange={() => handleToggleBtn(item)}
/>
</label>
{isActiveModal[item.objectId] && (
<ModalUi
isOpen
title={"Team status"}
handleClose={handleClose}
>
<div className="m-[20px]">
<div className="text-lg font-normal text-black">
Are you sure you want to{" "}
{item?.IsActive
? "disable"
: "enable"}{" "}
this team?
</div>
<hr className="bg-[#ccc] mt-4 " />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={() =>
handleToggleSubmit(item)
}
className="op-btn op-btn-primary"
>
Yes
</button>
<button
onClick={handleClose}
className="op-btn op-btn-secondary"
>
No
</button>
</div>
</div>
</ModalUi>
)}
</>
)}
</td>
<td className="px-3 py-2 text-white flex flex-wrap gap-1">
{item?.Name !== "All Users" && (
<>
{actions?.length > 0 &&
actions.map((act, index) => (
<button
key={index}
onClick={() =>
handleActionBtn(act, item)
}
title={act.hoverLabel}
className={`${
act?.btnColor ? act.btnColor : ""
} op-btn op-btn-sm w-[50px]`}
>
<i className={act.btnIcon}></i>
</button>
))}
{isEditModal[item.objectId] && (
<ModalUi
isOpen
title={"Edit Team"}
handleClose={handleClose}
>
<form
className="m-[20px]"
onSubmit={(e) =>
updateTeamName(e, item)
}
>
<label className="text-xs font-semibold text-base-content ml-1">
Name of Team{" "}
<span className="text-[red] text-[13px]">
*
</span>
</label>
<input
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-base-content w-full text-xs"
value={item.Name}
onChange={(e) =>
handleEditChange(e, item)
}
required
/>
<button
type="submit"
className="op-btn op-btn-primary mt-3"
>
Save
</button>
</form>
</ModalUi>
)}
</>
)}
</td>
</tr>
))}
</>
)}
</tbody>
</table>
</div>
<div className="op-join flex flex-wrap items-center p-2">
{teamList.length > recordperPage && (
<button
onClick={() => paginateBack()}
className="op-join-item op-btn op-btn-sm"
>
Prev
</button>
)}
{pageNumbers.map((x, i) => (
<button
key={i}
onClick={() => setCurrentPage(x)}
disabled={x === "..."}
className={`${
x === currentPage ? "op-btn-active" : ""
} op-join-item op-btn op-btn-sm`}
>
{x}
</button>
))}
{teamList.length > recordperPage && (
<button
onClick={() => paginateFront()}
className="op-join-item op-btn op-btn-sm"
>
Next
</button>
)}
</div>
{teamList?.length <= 0 && (
<div
className={`${
isDashboard ? "h-[317px]" : ""
} flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`}
>
<div className="w-[60px] h-[60px] overflow-hidden">
<img
className="w-full h-full object-contain"
src={pad}
alt="img"
/>
</div>
<div className="text-sm font-semibold">No Data Available</div>
</div>
)}
<ModalUi
title={"Add Team"}
isOpen={isModal}
handleClose={handleFormModal}
>
<AddTeam
setIsAlert={setIsAlert}
handleTeamInfo={handleTeamInfo}
closePopup={handleFormModal}
/>
</ModalUi>
</div>
) : (
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
<div className="text-center">
<h1 className="text-[60px] lg:text-[120px] font-semibold">
404
</h1>
<p className="text-[30px] lg:text-[50px]">Page Not Found</p>
</div>
</div>
)}
</>
)}
{!isSubscribe && isEnableSubscription && !isLoader && (
<div data-tut="apisubscribe">
<SubscribeCard plan={"TEAMS"} price={"20"} />
</div>
)}
</div>
);
};
export default TeamList;
+44 -97
View File
@@ -24,7 +24,8 @@ import {
addWidgetOptions,
textInputWidget,
radioButtonWidget,
fetchSubscription
fetchSubscription,
getContainerScale
} from "../constant/Utils";
import RenderPdf from "../components/pdf/RenderPdf";
import "../styles/AddUser.css";
@@ -38,7 +39,6 @@ import TourContentWithBtn from "../primitives/TourContentWithBtn";
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
import Parse from "parse";
import { useSelector } from "react-redux";
import TextFontSetting from "../components/pdf/TextFontSetting";
import PdfZoom from "../components/pdf/PdfZoom";
const TemplatePlaceholder = () => {
const navigate = useNavigate();
@@ -153,14 +153,6 @@ const TemplatePlaceholder = () => {
const [fontColor, setFontColor] = useState();
const [zoomPercent, setZoomPercent] = useState(0);
const [scale, setScale] = useState(1);
const senderUser =
localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
) &&
localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
);
const jsonSender = JSON.parse(senderUser);
useEffect(() => {
fetchTemplate();
@@ -317,7 +309,7 @@ const TemplatePlaceholder = () => {
setHandleError("Error: Something went wrong!");
}
}
const res = await contractUsers(jsonSender.email);
const res = await contractUsers();
if (res[0] && res.length) {
setSignerUserId(res[0].objectId);
setCurrentEmail(res[0].Email);
@@ -365,10 +357,11 @@ const TemplatePlaceholder = () => {
if (signer) {
const posZIndex = zIndex + 1;
setZIndex(posZIndex);
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
const containerScale = getContainerScale(
pdfOriginalWH,
pageNumber,
containerWH
);
const containerScale = containerWH.width / getPdfPageWidth?.width || 1;
const key = randomId();
let filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
const dragTypeValue = item?.text ? item.text : monitor.type;
@@ -389,7 +382,6 @@ const TemplatePlaceholder = () => {
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
key: key,
scale: containerScale,
// isMobile: isMobile,
zIndex: posZIndex,
type: dragTypeValue,
options: addWidgetOptions(dragTypeValue),
@@ -501,6 +493,8 @@ const TemplatePlaceholder = () => {
setShowDropdown(true);
} else if (dragTypeValue === "checkbox") {
setIsCheckbox(true);
} else if (dragTypeValue === radioButtonWidget) {
setIsRadio(true);
} else if (
[textInputWidget, "name", "company", "job title", "email"].includes(
dragTypeValue
@@ -508,8 +502,6 @@ const TemplatePlaceholder = () => {
) {
setFontSize(12);
setFontColor("black");
} else if (dragTypeValue === radioButtonWidget) {
setIsRadio(true);
}
setCurrWidgetsDetails({});
setWidgetType(dragTypeValue);
@@ -555,16 +547,19 @@ const TemplatePlaceholder = () => {
//function for set and update x and y postion after drag and drop signature tab
const handleStop = (event, dragElement, signerId, key) => {
setFontColor();
setFontSize();
if (!isResize && isDragging) {
const dataNewPlace = addZIndex(signerPos, key, setZIndex);
let updateSignPos = [...signerPos];
updateSignPos.splice(0, updateSignPos.length, ...dataNewPlace);
const signId = signerId; //? signerId : signerObjId;
const keyValue = key ? key : dragKey;
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
const containerScale = getContainerScale(
pdfOriginalWH,
pageNumber,
containerWH
);
const containerScale = containerWH.width / getPdfPageWidth?.width || 1;
if (keyValue >= 0) {
const filterSignerPos = updateSignPos.filter(
(data) => data.Id === signId
@@ -615,7 +610,6 @@ const TemplatePlaceholder = () => {
setIsDragging(false);
}, 200);
};
//function for delete signature block
const handleDeleteSign = (key, Id) => {
const updateData = [];
@@ -851,7 +845,6 @@ const TemplatePlaceholder = () => {
const closeTour = async () => {
setTemplateTour(false);
if (isDontShow) {
const extUserClass = localStorage.getItem("extended_class");
let updatedTourStatus = [];
if (tourStatus.length > 0) {
updatedTourStatus = [...tourStatus];
@@ -870,7 +863,7 @@ const TemplatePlaceholder = () => {
.put(
`${localStorage.getItem(
"baseUrl"
)}classes/${extUserClass}/${signerUserId}`,
)}classes/contracts_Users/${signerUserId}`,
{
TourStatus: updatedTourStatus
},
@@ -1199,13 +1192,19 @@ const TemplatePlaceholder = () => {
hint: defaultdata?.hint || "",
defaultValue: defaultdata?.defaultValue || "",
validation:
(isSubscribe || !isEnableSubscription) && inputype
isSubscribe && inputype
? {
type: inputype,
pattern:
inputype === "regex" ? defaultdata.textvalidate : ""
}
: {}
: {},
fontSize:
fontSize || currWidgetsDetails?.options?.fontSize || "12",
fontColor:
fontColor ||
currWidgetsDetails?.options?.fontColor ||
"black"
}
};
} else {
@@ -1215,7 +1214,13 @@ const TemplatePlaceholder = () => {
...position.options,
name: defaultdata.name,
status: defaultdata.status,
defaultValue: defaultdata.defaultValue
defaultValue: defaultdata.defaultValue,
fontSize:
fontSize || currWidgetsDetails?.options?.fontSize || "12",
fontColor:
fontColor ||
currWidgetsDetails?.options?.fontColor ||
"black"
}
};
}
@@ -1238,6 +1243,8 @@ const TemplatePlaceholder = () => {
setSignerPos(newUpdateSigner);
}
}
setFontSize();
setFontColor();
setCurrWidgetsDetails({});
handleNameModal();
};
@@ -1249,55 +1256,6 @@ const TemplatePlaceholder = () => {
setIsCheckbox(false);
};
const handleSaveFontSize = () => {
const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
if (filterSignerPos.length > 0) {
const getPlaceHolder = filterSignerPos[0].placeHolder;
const getPageNumer = getPlaceHolder.filter(
(data) => data.pageNumber === pageNumber
);
if (getPageNumer.length > 0) {
const getXYdata = getPageNumer[0].pos;
const getPosData = getXYdata;
const addSignPos = getPosData.map((position) => {
if (position.key === signKey) {
return {
...position,
options: {
...position.options,
fontSize: fontSize,
fontColor: fontColor
}
};
}
return position;
});
const newUpdateSignPos = getPlaceHolder.map((obj) => {
if (obj.pageNumber === pageNumber) {
return { ...obj, pos: addSignPos };
}
return obj;
});
const newUpdateSigner = signerPos.map((obj) => {
if (obj.Id === uniqueId) {
return { ...obj, placeHolder: newUpdateSignPos };
}
return obj;
});
setSignerPos(newUpdateSigner);
}
}
setFontSize();
setFontColor();
handleTextSettingModal(false);
};
const handleTextSettingModal = (value) => {
setIsTextSetting(value);
};
return (
<>
<Title title={"Template"} />
@@ -1351,7 +1309,7 @@ const TemplatePlaceholder = () => {
setZoomPercent={setZoomPercent}
zoomPercent={zoomPercent}
/>
<div className=" w-full md:w-[95%] ">
<div className="w-full md:w-[95%]">
{/* this modal is used show alert set placeholder for all signers before send mail */}
<ModalUi
isOpen={isSendAlert}
@@ -1388,9 +1346,7 @@ const TemplatePlaceholder = () => {
{currentEmail.length > 0 && (
<>
<button
onClick={() => {
handleCreateDocModal();
}}
onClick={() => handleCreateDocModal()}
type="button"
className="op-btn op-btn-primary"
>
@@ -1399,6 +1355,7 @@ const TemplatePlaceholder = () => {
<button
onClick={() => {
setIsCreateDocModal(false);
navigate("/report/6TeaPr321t");
}}
type="button"
className="op-btn op-btn-secondary ml-2"
@@ -1412,18 +1369,14 @@ const TemplatePlaceholder = () => {
{isCreateDoc && <LoaderWithMsg isLoading={isLoading} />}
<ModalUi
isOpen={isShowEmail}
title={"signers alert"}
handleClose={() => {
setIsShowEmail(false);
}}
title={"Signers alert"}
handleClose={() => setIsShowEmail(false)}
>
<div className="h-full p-[20px]">
<p>Please select signer for add placeholder!</p>
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
<button
onClick={() => {
setIsShowEmail(false);
}}
onClick={() => setIsShowEmail(false)}
type="button"
className="op-btn op-btn-primary"
>
@@ -1472,7 +1425,6 @@ const TemplatePlaceholder = () => {
allPages={allPages}
pageNumber={pageNumber}
signKey={signKey}
// signerObjId={signerObjId}
Id={uniqueId}
/>
{/* pdf header which contain funish back button */}
@@ -1532,10 +1484,10 @@ const TemplatePlaceholder = () => {
selectWidgetId={selectWidgetId}
setIsCheckbox={setIsCheckbox}
handleNameModal={setIsNameModal}
handleTextSettingModal={handleTextSettingModal}
pdfOriginalWH={pdfOriginalWH}
setScale={setScale}
scale={scale}
setIsSelectId={setIsSelectId}
/>
)}
</div>
@@ -1584,13 +1536,12 @@ const TemplatePlaceholder = () => {
/>
</div>
) : (
<div
className={`w-[23%] bg-[#FFFFFF] min-h-screen overflow-y-auto hide-scrollbar`}
>
<div className={`max-h-screen`}>
<div className="w-[23%] bg-base-100 min-h-screen overflow-y-auto hide-scrollbar">
<div className="max-h-screen">
<SignerListPlace
isMailSend={isMailSend}
signerPos={signerPos}
setSignerPos={setSignerPos}
signersdata={signersdata}
isSelectListId={isSelectListId}
setSignerObjId={setSignerObjId}
@@ -1607,6 +1558,7 @@ const TemplatePlaceholder = () => {
setSignersData={setSignersData}
blockColor={blockColor}
setBlockColor={setBlockColor}
uniqueId={uniqueId}
/>
<div data-tut="addWidgets">
<WidgetComponent
@@ -1632,7 +1584,6 @@ const TemplatePlaceholder = () => {
</div>
</div>
)}
<div data-tut="reactourAddbtn--observe">
<AddRoleModal
isModalRole={isModalRole}
@@ -1669,16 +1620,12 @@ const TemplatePlaceholder = () => {
handleClose={handleNameModal}
handleData={handleWidgetdefaultdata}
isSubscribe={isSubscribe}
/>
<TextFontSetting
isTextSetting={isTextSetting}
setIsTextSetting={setIsTextSetting}
fontSize={fontSize}
setFontSize={setFontSize}
fontColor={fontColor}
setFontColor={setFontColor}
handleSaveFontSize={handleSaveFontSize}
currWidgetsDetails={currWidgetsDetails}
/>
</DndProvider>
</>
@@ -0,0 +1,179 @@
import React, { useEffect, useState } from "react";
import Loader from "../primitives/Loader";
import Parse from "parse";
import { NavLink, useNavigate } from "react-router-dom";
import Alert from "../primitives/Alert";
import Title from "../components/Title";
const UpdateExistUserAdmin = () => {
const navigate = useNavigate();
const [formdata, setFormdata] = useState({ email: "", masterkey: "" });
const [loader, setLoader] = useState(true);
const [errMsg, setErrMsg] = useState("");
const [isSubmitLoading, setIsSubmitLoading] = useState(false);
const [isAlert, setIsAlert] = useState({ type: "danger", msg: "" });
useEffect(() => {
checkIsAdminExist();
}, []);
const checkIsAdminExist = async () => {
try {
const isAdminExist = await Parse.Cloud.run("checkadminexist");
if (isAdminExist !== "not_exist") {
console.log("isAdminExist ", isAdminExist);
setErrMsg("Admin already exists.");
}
} catch (err) {
console.log("Err in checkadminexist", err);
setErrMsg("Something went wrong.");
} finally {
setLoader(false);
}
};
const handleSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
setIsSubmitLoading(true);
try {
const updateUserAsAdmin = await Parse.Cloud.run(
"updateuserasadmin",
formdata
);
// console.log("updateUserAsAdmin ", updateUserAsAdmin);
if (updateUserAsAdmin === "admin_created") {
setIsAlert({ type: "success", msg: "Admin created" });
navigate("/");
}
} catch (err) {
console.log("err in updateuserasadmin", err.code);
if (err.code === 404) {
setIsAlert((prev) => ({ ...prev, msg: "Invalid masterkey" }));
} else if (err.code === 101) {
setIsAlert((prev) => ({ ...prev, msg: "User not found" }));
} else if (err.code === 137) {
setIsAlert((prev) => ({ ...prev, msg: "Admin already exist" }));
} else {
setErrMsg("Something went wrong.");
}
} finally {
setIsSubmitLoading(false);
setTimeout(() => {
setIsAlert(() => ({ type: "danger", msg: "" }));
}, 2000);
}
};
return (
<div className="h-screen flex justify-center">
<Title title={"Add Admin"} />
{isAlert.msg && (
<Alert type={isAlert.type}>
<div className="ml-3">{isAlert.msg}</div>
</Alert>
)}
{loader ? (
<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 overflow-hidden">
{isSubmitLoading && (
<div className="absolute z-40 w-full h-full flex justify-center bg-black/30">
<Loader />
</div>
)}
<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>
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={formdata.email}
onChange={(e) =>
setFormdata((prev) => ({
...prev,
email: e.target.value?.toLowerCase()
}))
}
required
/>
<hr className="my-2 border-none" />
<label>
Master key{" "}
<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={formdata.masterkey}
onChange={(e) =>
setFormdata((prev) => ({
...prev,
masterkey: e.target.value
}))
}
required
/>
{/*
<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={loader}
>
{loader ? "Loading..." : "Next"}
</button>
</div>
</div>
</form>
</div>
)}
</>
)}
</div>
);
};
export default UpdateExistUserAdmin;
+426
View File
@@ -0,0 +1,426 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import Alert from "../primitives/Alert";
import Loader from "../primitives/Loader";
import { useLocation } from "react-router-dom";
import ModalUi from "../primitives/ModalUi";
import pad from "../assets/images/pad.svg";
import Tooltip from "../primitives/Tooltip";
import AddUser from "../components/AddUser";
import SubscribeCard from "../primitives/SubscribeCard";
import { isEnableSubscription } from "../constant/const";
import { checkIsSubscribedTeam } from "../constant/Utils";
import Title from "../components/Title";
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"];
// const actions = [];
const UserList = () => {
const [userList, setUserList] = useState([]);
const [isLoader, setIsLoader] = useState(false);
const [isModal, setIsModal] = useState(false);
const location = useLocation();
const isDashboard =
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
const [currentPage, setCurrentPage] = useState(1);
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
const [isActiveModal, setIsActiveModal] = useState({});
const [isActLoader, setIsActLoader] = useState({});
const [isSubscribe, setIsSubscribe] = useState(false);
const [isAdmin, setIsAdmin] = useState(false);
const recordperPage = 10;
const startIndex = (currentPage - 1) * recordperPage; // user per page
const getPaginationRange = () => {
const totalPageNumbers = 7; // Adjust this value to show more/less page numbers
const pages = [];
const totalPages = Math.ceil(userList.length / recordperPage);
if (totalPages <= totalPageNumbers) {
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
const leftSiblingIndex = Math.max(currentPage - 1, 1);
const rightSiblingIndex = Math.min(currentPage + 1, totalPages);
const showLeftDots = leftSiblingIndex > 2;
const showRightDots = rightSiblingIndex < totalPages - 2;
const firstPageIndex = 1;
const lastPageIndex = totalPages;
if (!showLeftDots && showRightDots) {
let leftItemCount = 3;
let leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1);
pages.push(...leftRange);
pages.push("...");
pages.push(totalPages);
} else if (showLeftDots && !showRightDots) {
let rightItemCount = 3;
let rightRange = Array.from(
{ length: rightItemCount },
(_, i) => totalPages - rightItemCount + i + 1
);
pages.push(firstPageIndex);
pages.push("...");
pages.push(...rightRange);
} else if (showLeftDots && showRightDots) {
let middleRange = Array.from(
{ length: 3 },
(_, i) => leftSiblingIndex + i
);
pages.push(firstPageIndex);
pages.push("...");
pages.push(...middleRange);
pages.push("...");
pages.push(lastPageIndex);
}
}
return pages;
};
const pageNumbers = getPaginationRange();
useEffect(() => {
fetchUserList();
}, []);
async function fetchUserList() {
try {
setIsLoader(true);
if (isEnableSubscription) {
const getIsSubscribe = await checkIsSubscribedTeam();
setIsSubscribe(getIsSubscribe);
} else {
setIsSubscribe(true);
}
const extUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
if (extUser) {
const admin =
extUser?.UserRole &&
(extUser?.UserRole === "contracts_Admin" ||
extUser?.UserRole === "contracts_OrgAdmin")
? true
: false;
setIsAdmin(admin);
}
const res = await Parse.Cloud.run("getuserlistbyorg", {
organizationId: extUser.OrganizationId.objectId
});
const _userRes = JSON.parse(JSON.stringify(res));
setUserList(_userRes);
} catch (err) {
console.log("Err in fetch userlist", err);
setIsAlert({ type: "danger", msg: "Something went wrong." });
} finally {
setTimeout(() => {
setIsAlert({ type: "success", msg: "" });
}, 1500);
setIsLoader(false);
}
}
const handleFormModal = () => {
setIsModal(!isModal);
};
// Change page
const paginateFront = () => setCurrentPage(currentPage + 1);
const paginateBack = () => setCurrentPage(currentPage - 1);
// const handleActionBtn = (act, item) => {
// if (act.action === "delete") {
// setIsDeleteModal({ [item.objectId]: true });
// }
// };
const handleUserData = (userData) => {
setUserList((prev) => [userData, ...prev]);
};
// `formatRow` is used to show data in poper manner like
// if data is of array type then it will join array items with ","
// if data is of object type then it Name values will be show in row
// if no data available it will show hyphen "-"
const formatRow = (row) => {
if (Array.isArray(row)) {
let updateArr = row.map((x) => x.Name);
return updateArr.join(", ");
} else if (typeof row === "object" && row !== null) {
return row?.Name || "-";
} else {
return "-";
}
};
const handleClose = () => {
setIsActiveModal({});
};
const handleToggleSubmit = async (user) => {
const index = userList.findIndex((obj) => obj.objectId === user.objectId);
if (index !== -1) {
setIsActiveModal({});
setIsActLoader({ [user.objectId]: true });
const newArray = [...userList];
const IsDisabled = newArray[index]?.IsDisabled;
newArray[index] = { ...newArray[index], IsDisabled: !IsDisabled };
setUserList(newArray);
try {
const extUser = new Parse.Object("contracts_Users");
extUser.id = user.objectId;
extUser.set("IsDisabled", !IsDisabled);
await extUser.save();
setIsAlert({
type: !IsDisabled === true ? "danger" : "success",
msg: !IsDisabled === true ? "User deactivated." : "User activated."
});
} catch (err) {
setIsAlert({ type: "danger", msg: "something went wrong." });
console.log("err in disable team", err);
} finally {
setIsActLoader({});
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
}
}
};
const handleToggleBtn = (user) => {
setIsActiveModal({ [user.objectId]: true });
};
return (
<div className="relative">
<Title title={isAdmin ? "Users" : "Page not found"} />
{isLoader && (
<div className="absolute w-full h-[300px] md:h-[400px] flex justify-center items-center z-30 rounded-box">
<Loader />
</div>
)}
{Object.keys(isActLoader)?.length > 0 && (
<div className="absolute w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-30 rounded-box">
<Loader />
</div>
)}
{isSubscribe && !isLoader && (
<>
{isAdmin ? (
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
{isAlert.msg && (
<Alert type={isAlert.type}>
<div className="ml-3">{isAlert.msg}</div>
</Alert>
)}
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
<div className="font-light">
Users{" "}
<span className="text-xs md:text-[13px] font-normal">
<Tooltip message={"users from Teams"} />
</span>
</div>
<div
className="cursor-pointer"
onClick={() => handleFormModal()}
>
<i className="fa-light fa-square-plus text-accent text-[40px]"></i>
</div>
</div>
<div className={` overflow-x-auto w-full`}>
<table className="op-table border-collapse w-full">
<thead className="text-[14px]">
<tr className="border-y-[1px]">
{heading?.map((item, index) => (
<th key={index} className="px-4 py-2">
{item}
</th>
))}
</tr>
</thead>
<tbody className="text-[12px]">
{userList?.length > 0 && (
<>
{userList.map((item, index) => (
<tr className="border-y-[1px]" key={index}>
{heading.includes("Sr.No") && (
<th className="px-4 py-2">
{startIndex + index + 1}
</th>
)}
<td className="px-4 py-2 font-semibold">
{item?.Name}{" "}
</td>
<td className="px-4 py-2 ">{item?.Email || "-"}</td>
<td className="px-4 py-2">{item?.Phone || "-"}</td>
<td className="px-4 py-2">
{item?.UserRole?.split("_").pop() || "-"}
</td>
<td className="px-4 py-2">
{formatRow(item.TeamIds)}
</td>
{item.UserRole !== "contracts_Admin" && (
<td className="px-4 py-2 font-semibold">
<label className="cursor-pointer relative block items-center mb-0">
<input
type="checkbox"
className="op-toggle transition-all op-toggle-secondary"
checked={item?.IsDisabled !== true}
onChange={() => handleToggleBtn(item)}
/>
</label>
{isActiveModal[item.objectId] && (
<ModalUi
isOpen
title={"User status"}
handleClose={handleClose}
>
<div className="m-[20px]">
<div className="text-lg font-normal text-black">
Are you sure you want to{" "}
{item?.IsDisabled
? "activate"
: "deactivate"}{" "}
this user?
</div>
<hr className="bg-[#ccc] mt-4 " />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={() =>
handleToggleSubmit(item)
}
className="op-btn op-btn-primary"
>
Yes
</button>
<button
onClick={handleClose}
className="op-btn op-btn-secondary"
>
No
</button>
</div>
</div>
</ModalUi>
)}
</td>
)}
{/* <td className="px-3 py-2 text-white grid grid-cols-2">
{actions?.length > 0 &&
actions.map((act, index) => (
<button
key={index}
onClick={() => handleActionBtn(act, item)}
title={act.hoverLabel}
className={`${
act?.btnColor ? act.btnColor : ""
} op-btn op-btn-sm`}
>
<i className={act.btnIcon}></i>
</button>
))}
{isDeleteModal[item.objectId] && (
<ModalUi
isOpen
title={"Delete User"}
handleClose={handleClose}
>
<div className="m-[20px]">
<div className="text-lg font-normal text-black">
Are you sure you want to delete this user?
</div>
<hr className="bg-[#ccc] mt-4 " />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={() => handleDelete(item)}
className="op-btn op-btn-primary"
>
Yes
</button>
<button
onClick={handleClose}
className="op-btn op-btn-secondary"
>
No
</button>
</div>
</div>
</ModalUi>
)}
</td> */}
</tr>
))}
</>
)}
</tbody>
</table>
</div>
<div className="op-join flex flex-wrap items-center p-2">
{userList.length > recordperPage && (
<button
onClick={() => paginateBack()}
className="op-join-item op-btn op-btn-sm"
>
Prev
</button>
)}
{pageNumbers.map((x, i) => (
<button
key={i}
onClick={() => setCurrentPage(x)}
disabled={x === "..."}
className={`${
x === currentPage ? "op-btn-active" : ""
} op-join-item op-btn op-btn-sm`}
>
{x}
</button>
))}
{userList.length > recordperPage && (
<button
onClick={() => paginateFront()}
className="op-join-item op-btn op-btn-sm"
>
Next
</button>
)}
</div>
{userList?.length <= 0 && (
<div
className={`${
isDashboard ? "h-[317px]" : ""
} flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`}
>
<div className="w-[60px] h-[60px] overflow-hidden">
<img
className="w-full h-full object-contain"
src={pad}
alt="img"
/>
</div>
<div className="text-sm font-semibold">No Data Available</div>
</div>
)}
<ModalUi
title={"Add User"}
isOpen={isModal}
handleClose={handleFormModal}
>
<AddUser
setIsAlert={setIsAlert}
handleUserData={handleUserData}
closePopup={handleFormModal}
/>
</ModalUi>
</div>
) : (
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
<div className="text-center">
<h1 className="text-[60px] lg:text-[120px] font-semibold">
404
</h1>
<p className="text-[30px] lg:text-[50px]">Page Not Found</p>
</div>
</div>
)}
</>
)}
{!isSubscribe && isEnableSubscription && !isLoader && (
<div data-tut="apisubscribe">
<SubscribeCard plan={"TEAMS"} price={"20"} />
</div>
)}
</div>
);
};
export default UserList;
+200 -125
View File
@@ -1,8 +1,4 @@
import React, {
useState,
useEffect
// useRef
} from "react";
import React, { useState, useEffect, useRef } from "react";
import { Navigate, useNavigate } from "react-router-dom";
import Parse from "parse";
import { SaveFileSize } from "../constant/saveFileSize";
@@ -10,10 +6,13 @@ import dp from "../assets/images/dp.png";
import Title from "../components/Title";
import sanitizeFileName from "../primitives/sanitizeFileName";
import axios from "axios";
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
import Tooltip from "../primitives/Tooltip";
import { isEnableSubscription } from "../constant/const";
import { checkIsSubscribed, handleSendOTP } from "../constant/Utils";
import {
checkIsSubscribed,
checkIsSubscribedTeam,
handleSendOTP
} from "../constant/Utils";
import Upgrade from "../primitives/Upgrade";
import ModalUi from "../primitives/ModalUi";
import Loader from "../primitives/Loader";
@@ -32,10 +31,11 @@ function UserProfile() {
const [percentage, setpercentage] = useState(0);
const [isDisableDocId, setIsDisableDocId] = useState(false);
const [isSubscribe, setIsSubscribe] = useState(false);
// const [publicUserName, setPublicUserName] = useState(
// extendUser && extendUser?.[0]?.UserName
// );
// const previousPublicUserName = useRef(publicUserName);
const [isUpgrade, setIsUpgrade] = useState(false);
const [publicUserName, setPublicUserName] = useState(
extendUser && extendUser?.[0]?.UserName
);
const previousPublicUserName = useRef(publicUserName);
const [company, setCompany] = useState(
extendUser && extendUser?.[0]?.Company
);
@@ -46,7 +46,11 @@ function UserProfile() {
const [otp, setOtp] = useState("");
const [otpLoader, setOtpLoader] = useState(false);
const [isEmailVerified, setIsEmailVerified] = useState(false);
// const [userNameError, setUserNameError] = useState("");
const [userNameError, setUserNameError] = useState("");
const [tagLine, setTagLine] = useState(
extendUser && extendUser?.[0]?.Tagline
);
const [isTeam, setIsTeam] = useState(false);
useEffect(() => {
getUserDetail();
}, []);
@@ -58,7 +62,9 @@ function UserProfile() {
const HeaderDocId = jsonSender[0]?.HeaderDocId;
if (isEnableSubscription) {
const getIsSubscribe = await checkIsSubscribed();
const getIsTeam = await checkIsSubscribedTeam();
setIsSubscribe(getIsSubscribe);
setIsTeam(getIsTeam);
}
if (HeaderDocId) {
setIsDisableDocId(HeaderDocId);
@@ -85,31 +91,31 @@ function UserProfile() {
}
};
//function to check public username already exist
// const handleCheckPublicUserName = async () => {
// try {
// const res = await Parse.Cloud.run("getpublicusername", {
// username: publicUserName
// });
// if (res) {
// setIsLoader(false);
// setUserNameError("user name already exist");
// setTimeout(() => {
// setUserNameError("");
// }, 3000);
// return res;
// }
// } catch (e) {
// console.log("error in getpublicusername cloud function");
// }
// };
const handleCheckPublicUserName = async () => {
try {
const res = await Parse.Cloud.run("getpublicusername", {
username: publicUserName
});
if (res) {
setIsLoader(false);
setUserNameError("user name already exist");
setTimeout(() => {
setUserNameError("");
}, 3000);
return res;
}
} catch (e) {
console.log("error in getpublicusername cloud function");
}
};
const handleSubmit = async (e) => {
e.preventDefault();
let phn = Phone,
res = "";
//condition to call cloud function when user change publicUserName
// if (previousPublicUserName.current !== publicUserName) {
// res = await handleCheckPublicUserName();
// }
if (publicUserName && previousPublicUserName.current !== publicUserName) {
res = await handleCheckPublicUserName();
}
if (!res) {
setIsLoader(true);
try {
@@ -155,7 +161,6 @@ function UserProfile() {
// `updateExtUser` is used to update user details in extended class
const updateExtUser = async (obj) => {
const extClass = localStorage.getItem("extended_class");
const extData = JSON.parse(localStorage.getItem("Extand_Class"));
const ExtUserId = extData[0].objectId;
const body = {
@@ -163,12 +168,13 @@ function UserProfile() {
Name: obj.Name,
HeaderDocId: isDisableDocId,
JobTitle: jobTitle,
Company: company
// UserName: publicUserName || ""
Company: company,
UserName: publicUserName || "",
Tagline: tagLine || ""
};
await axios.put(
parseBaseUrl + "classes/" + extClass + "/" + ExtUserId,
parseBaseUrl + "classes/contracts_Users/" + ExtUserId,
body,
{
headers: {
@@ -185,6 +191,7 @@ function UserProfile() {
const json = JSON.parse(JSON.stringify([res]));
const extRes = JSON.stringify(json);
localStorage.setItem("Extand_Class", extRes);
previousPublicUserName.current = publicUserName;
// console.log("updateRes ", updateRes);
};
// file upload function
@@ -278,23 +285,20 @@ function UserProfile() {
alert("OTP sent on you email");
};
//function to handle onchange username and restrict 6-characters username for free users
// const handleOnchangeUserName = (e) => {
// const value = e.target.value;
// if (value.length > 6 && !isSubscribe) {
// setUserNameError("Please upgrade to allow more than 6 characters.");
// setTimeout(() => {
// setUserNameError("");
// }, 2000);
// } else {
// setPublicUserName(e.target.value);
// }
// };
const handleOnchangeUserName = (e) => {
const newValue = e.target.value.replace(/\s+/g, "");
setPublicUserName(newValue);
};
const handleOnchangeTagLine = (e) => {
setTagLine(e.target.value);
};
const handleCancel = () => {
setEditMode(false);
SetName(localStorage.getItem("username"));
SetPhone(UserProfile && UserProfile.phone);
setImage(localStorage.getItem("profileImg"));
// setPublicUserName(extendUser && extendUser?.[0]?.UserName);
setPublicUserName(extendUser && extendUser?.[0]?.UserName);
setCompany(extendUser && extendUser?.[0]?.Company);
setJobTitle(extendUser?.[0]?.JobTitle);
setIsDisableDocId(extendUser?.[0]?.HeaderDocId);
@@ -308,13 +312,11 @@ function UserProfile() {
</div>
) : (
<div className="flex justify-center items-center w-full relative">
{/* {userNameError && (
<div
className={`z-[1000] fixed top-[50%] transform border-[1px] text-sm border-[#f0a8a8] bg-[#f4bebe] text-[#c42121] rounded py-[.75rem] px-[1.25rem]`}
>
{userNameError && (
<div className="z-[1000] fixed top-[50%] transform border-[1px] text-sm border-[#f0a8a8] bg-[#f4bebe] text-[#c42121] rounded py-[.75rem] px-[1.25rem]">
{userNameError}
</div>
)} */}
)}
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box w-[450px]">
<div className="flex flex-col justify-center items-center my-4">
<div className="w-[200px] h-[200px] overflow-hidden rounded-full">
@@ -442,85 +444,126 @@ function UserProfile() {
)}
</span>
</li>
{/* {isEnableSubscription && (
<li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all">
<span className="font-semibold">
Public profile :{" "}
<Tooltip
message={`this is your public URL. Copy or share it
with the signer, and you will be able to see
all your publicly set templates.`}
/>
</span>
<div className="flex text-xs items-center">
<span>opensign-me.vercel.app/</span>
{editmode ? (
<input
onChange={handleOnchangeUserName}
value={publicUserName}
disabled={!editmode}
placeholder="enter user name"
className="op-input op-input-bordered focus:outline-none hover:border-base-content op-input-xs"
{isEnableSubscription && (
<>
<li className="flex md:flex-row flex-col md:justify-between md:items-center border-t-[1px] border-gray-300 py-2 break-all">
<span className="font-semibold flex gap-1">
Public profile :{" "}
<Tooltip
maxWidth="max-w-[250px]"
message={`This is your public URL. Copy or share it with the signer, and you will be able to see all your publicly set templates.`}
/>
) : (
<input
value={extendUser?.[0]?.UserName}
disabled
placeholder="enter user name"
className="op-input op-input-bordered op-input-xs"
</span>
<div className="flex md:flex-row flex-col md:items-center">
<span className="mb-1 md:mb-1">opensign.me/</span>
{editmode ? (
<input
maxLength={40}
style={{
border:
!isSubscribe &&
publicUserName?.length > 0 &&
publicUserName?.length < 9 &&
"solid red"
}}
onChange={handleOnchangeUserName}
value={publicUserName}
disabled={!editmode}
placeholder="enter user name"
className="op-input op-input-bordered focus:outline-none hover:border-base-content op-input-xs"
/>
) : (
<input
value={extendUser?.[0]?.UserName}
disabled
placeholder="enter user name"
className="op-input op-input-bordered op-input-xs"
/>
)}
</div>
</li>
<li className="flex md:flex-row flex-col md:justify-between md:items-center border-t-[1px] border-gray-300 py-2 break-all">
<span className="font-semibold flex gap-1">
Tagline :{" "}
<Tooltip
maxWidth="max-w-[250px]"
message={`This Tagline will appear on your OpenSign public profile for ex. https://opensign.me/alex`}
/>
)}
</span>
<div className="flex md:flex-row flex-col md:items-center">
{editmode ? (
<input
onChange={handleOnchangeTagLine}
value={tagLine}
disabled={!editmode}
placeholder="enter tagline"
className="op-input op-input-bordered focus:outline-none hover:border-base-content op-input-xs"
/>
) : (
<input
value={extendUser?.[0]?.Tagline}
disabled
placeholder="enter tagline"
className="op-input op-input-bordered op-input-xs"
/>
)}
</div>
</li>
</>
)}
{isEnableSubscription && (
<li className="border-y-[1px] border-gray-300 break-all">
<div className="flex justify-between items-center py-2">
<span
className={
isTeam ? "font-semibold" : "font-semibold text-gray-300"
}
>
Disable DocumentId :{" "}
<Tooltip
url={
"https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid"
}
/>
{!isTeam && isEnableSubscription && <Upgrade />}
</span>
<label
className={`${
isTeam
? `${editmode ? "cursor-pointer" : ""}`
: "pointer-events-none opacity-50"
} relative block items-center mb-0`}
>
<input
disabled={isTeam ? false : true}
type="checkbox"
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
checked={isDisableDocId}
onChange={handleDisableDocId}
/>
</label>
</div>
</li>
)} */}
<li className="border-y-[1px] border-gray-300 break-all">
<div className="flex justify-between items-center py-2">
<span
className={
isSubscribe || !isEnableSubscription
? "font-semibold"
: "font-semibold text-gray-300"
}
>
Disable DocumentId :{" "}
<Tooltip
url={
"https://docs.opensignlabs.com/docs/help/Settings/disabledocumentid"
}
/>
{!isSubscribe && isEnableSubscription && <Upgrade />}
</span>
<label
className={`${
isSubscribe || !isEnableSubscription
? `${editmode ? "cursor-pointer" : ""}`
: "pointer-events-none opacity-50"
} relative block items-center mb-0`}
>
<input
disabled={editmode ? false : true}
type="checkbox"
className="op-toggle transition-all checked:[--tglbg:#3368ff] checked:bg-white"
checked={isDisableDocId}
onChange={handleDisableDocId}
/>
</label>
</div>
{!isEnableSubscription && (
<PremiumAlertHeader
message={
"Disable documentId is free in beta, this feature will incur a fee later."
}
/>
)}
</li>
)}
</ul>
<div className="flex justify-center gap-2 pt-2 pb-3 md:pt-3 md:pb-4">
<div
className={`${
!isEnableSubscription ? "border-t-[1px] border-gray-300" : ""
} flex justify-center gap-2 pt-2 pb-3 md:pt-3 md:pb-4`}
>
<button
type="button"
onClick={(e) =>
editmode ? handleSubmit(e) : setEditMode(true)
}
onClick={(e) => {
if (
!isSubscribe &&
publicUserName?.length > 0 &&
publicUserName?.length < 9
) {
setIsUpgrade(true);
} else {
editmode ? handleSubmit(e) : setEditMode(true);
}
}}
className="op-btn op-btn-primary"
>
{editmode ? "Save" : "Edit"}
@@ -577,6 +620,38 @@ function UserProfile() {
)}
</ModalUi>
)}
{isUpgrade && (
<div className="op-modal op-modal-open">
<div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative">
<>
<div
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-primary-content absolute right-2 top-2 z-40"
onClick={() => setIsUpgrade(false)}
>
</div>
<div className="op-card op-bg-primary text-primary-content w-full shadow-lg">
<div className="op-card-body">
<h2 className="op-card-title">Upgrade to Plan</h2>
<p>
To have a username less than 8 character please
subscribe
</p>
<div className="op-card-actions justify-end">
<button
onClick={() => navigate("/subscription")}
className="op-btn op-btn-accent"
>
Upgrade Now
</button>
</div>
</div>
</div>
</>
</div>
</div>
)}
</div>
)}
</React.Fragment>
+1 -5
View File
@@ -6,7 +6,6 @@ import ModalUi from "../primitives/ModalUi";
import { isEnableSubscription } from "../constant/const";
import { checkIsSubscribed, openInNewTab } from "../constant/Utils";
import Parse from "parse";
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
import Tooltip from "../primitives/Tooltip";
import Loader from "../primitives/Loader";
import SubscribeCard from "../primitives/SubscribeCard";
@@ -33,14 +32,12 @@ function Webhook() {
}, []);
const fetchWebhook = async () => {
const email = Parse.User.current().getEmail();
if (isEnableSubscription) {
const getIsSubscribe = await checkIsSubscribed();
setIsSubscribe(getIsSubscribe);
}
const params = { email: email };
try {
const extRes = await Parse.Cloud.run("getUserDetails", params);
const extRes = await Parse.Cloud.run("getUserDetails");
if (extRes) {
setWebhook(extRes.get("Webhook"));
}
@@ -107,7 +104,6 @@ function Webhook() {
) : (
<>
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box mb-3">
{!isEnableSubscription && <PremiumAlertHeader />}
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
OpenSign Webhook{" "}
<Tooltip
@@ -1,6 +1,5 @@
import React, { useState, useEffect } from "react";
import Parse from "parse";
import axios from "axios";
import Loader from "./Loader";
const AddContact = (props) => {
const [name, setName] = useState("");
@@ -9,8 +8,6 @@ const AddContact = (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();
}, []);
@@ -77,18 +74,6 @@ const AddContact = (props) => {
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",
@@ -124,18 +109,6 @@ const AddContact = (props) => {
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",
@@ -30,8 +30,7 @@ const LottieWithLoader = () => {
return (
<div>
{!isLoaded && !hasError && (
<div className="loader">
{" "}
<div className="w-[120px] h-[120px] mx-auto">
<Loader />
</div>
)}
@@ -39,9 +38,8 @@ const LottieWithLoader = () => {
{isLoaded && animationSrc && (
<DotLottieReact
src={animationSrc}
loop
autoplay
style={{ display: "block" }}
className="w-[120px] h-[120px] md:w-[200px] md:h-[200px] mx-auto"
/>
)}
</div>
File diff suppressed because it is too large Load Diff
+1 -11
View File
@@ -1,6 +1,4 @@
import React from "react";
import { isEnableSubscription } from "../constant/const";
import PremiumAlertHeader from "./PremiumAlertHeader";
const ModalUi = ({
children,
@@ -9,8 +7,7 @@ const ModalUi = ({
handleClose,
showHeader = true,
showClose = true,
reduceWidth,
showHeaderMessage
reduceWidth
}) => {
const width = reduceWidth;
return (
@@ -37,13 +34,6 @@ const ModalUi = ({
)}
</>
)}
{!isEnableSubscription && showHeaderMessage && (
<PremiumAlertHeader
message={
"Cutomize Email is free in beta, this feature will incur a fee later."
}
/>
)}
<div>{children}</div>
</div>
</dialog>
@@ -1,4 +1,4 @@
import React from "react";
import React, { useState } from "react";
import "../styles/signature.css";
function CustomModal({
@@ -9,11 +9,12 @@ function CustomModal({
declineDoc,
setIsDecline
}) {
const [reason, setReason] = useState("");
return (
show && (
<dialog className="op-modal op-modal-open absolute z-[998]">
<div className="w-[80%] md:w-[40%] op-modal-box p-0 overflow-y-auto hide-scrollbar text-sm">
<h3 className="text-[#de4337] font-bold text-lg pt-[15px] px-[20px]">
<dialog className="op-modal op-modal-open absolute z-[448]">
<div className="w-[95%] md:w-[60%] lg:w-[40%] op-modal-box p-0 overflow-y-auto hide-scrollbar text-sm">
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
{headMsg && headMsg}
</h3>
<div className="p-[10px] px-[20px]">
@@ -21,19 +22,34 @@ function CustomModal({
</div>
{footerMessage && (
<>
<div className="h-[1px] bg-[#9f9f9f] w-full"></div>
<div className="m-[15px] ">
<div className="mx-3">
<textarea
rows={3}
placeholder="Reason (optional)"
className="px-4 op-textarea op-textarea-bordered focus:outline-none hover:border-base-content w-full text-xs"
value={reason}
onChange={(e) => setReason(e.target.value)}
></textarea>
</div>
{/* <div className="h-[1px] bg-[#9f9f9f] w-full"></div> */}
<div className="m-[15px]">
<button
className="op-btn op-btn-primary mr-2"
className="op-btn op-btn-primary mr-2 px-6"
type="button"
onClick={() => declineDoc()}
onClick={() => {
setReason("");
declineDoc(reason);
}}
>
Yes
</button>
<button
type="button"
className="op-btn op-btn-secondary"
onClick={() => setIsDecline({ isDeclined: false })}
onClick={() => {
setReason("");
setIsDecline({ isDeclined: false });
}}
>
Close
</button>
@@ -1,11 +0,0 @@
import React from "react";
const PremiumAlertHeader = ({ message }) => (
<marquee className="bg-yellow-300 text-black px-2">
{message
? message
: "Currently free in Beta, this feature will incur a fee later."}
</marquee>
);
export default PremiumAlertHeader;
@@ -1,13 +1,16 @@
import React from "react";
import { useNavigate } from "react-router-dom";
const SubscribeCard = () => {
const SubscribeCard = ({ plan, price }) => {
const navigate = useNavigate();
return (
<div className="op-card op-bg-primary text-primary-content w-full shadow-lg">
<div className="op-card-body">
<h2 className="op-card-title">Upgrade to PRO Plan</h2>
<p>$29.99/month: Sign 100 docs using API. Only $0.15/doc after that.</p>
<h2 className="op-card-title">Upgrade to {plan ? plan : "PRO"} Plan</h2>
<p>
${price ? price : "29.99"}/month: Sign 100 docs using API. Only
$0.15/doc after that.
</p>
<div className="op-card-actions justify-end">
<button
onClick={() => navigate("/subscription")}
+2 -2
View File
@@ -1,7 +1,7 @@
import React from "react";
import { Tooltip as ReactTooltip } from "react-tooltip";
import { openInNewTab } from "../constant/Utils";
const Tooltip = ({ id, message, url, iconColor }) =>
const Tooltip = ({ id, message, url, iconColor, maxWidth }) =>
url ? (
<button onClick={() => openInNewTab(url)} className={"text-center"}>
<sup>
@@ -33,7 +33,7 @@ const Tooltip = ({ id, message, url, iconColor }) =>
</a>
<ReactTooltip
id={id ? id : "my-tooltip"}
className="max-w-[200px] z-[200]"
className={`${maxWidth ? maxWidth : "max-w-[200px]"} z-[200]`}
/>
</>
);
+19 -18
View File
@@ -8,26 +8,27 @@ const Validate = () => {
const [isUserValid, setIsUserValid] = useState(true);
useEffect(() => {
(async () => {
try {
const userDetails = JSON.parse(
localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
)
);
// Use the session token to validate the user
const userQuery = new Parse.Query(Parse.User);
const user = await userQuery.get(userDetails?.objectId, {
sessionToken: localStorage.getItem("accesstoken")
});
if (user) {
setIsUserValid(true);
} else {
if (localStorage.getItem("accesstoken")) {
try {
const userDetails = JSON.parse(
localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
)
);
// Use the session token to validate the user
const userQuery = new Parse.Query(Parse.User);
const user = await userQuery.get(userDetails?.objectId, {
sessionToken: localStorage.getItem("accesstoken")
});
if (user) {
setIsUserValid(true);
} else {
setIsUserValid(false);
}
} catch (error) {
// Session token is invalid or there was an error
setIsUserValid(false);
}
} catch (error) {
// Session token is invalid or there was an error
setIsUserValid(false);
}
})();
+27 -17
View File
@@ -4,29 +4,39 @@ import { Outlet } from "react-router-dom";
const ValidateRoute = () => {
useEffect(() => {
(async () => {
try {
// Use the session token to validate the user
const userQuery = new Parse.Query(Parse.User);
const user = await userQuery.get(Parse.User.current().id, {
sessionToken: localStorage.getItem("accesstoken")
});
if (!user) {
if (localStorage.getItem("accesstoken")) {
try {
// Use the session token to validate the user
const userQuery = new Parse.Query(Parse.User);
const user = await userQuery.get(Parse?.User?.current()?.id, {
sessionToken: localStorage.getItem("accesstoken")
});
if (!user) {
handlelogout();
}
} catch (error) {
console.log("err in validate route", error);
handlelogout();
}
} catch (error) {
handlelogout();
}
})();
}, []);
const handlelogout = async () => {
try {
Parse.User.logOut();
localStorage.removeItem("accesstoken");
} catch (err) {
console.log("err ", err);
} finally {
localStorage.removeItem("accesstoken");
}
let appdata = localStorage.getItem("userSettings");
let applogo = localStorage.getItem("appLogo");
let defaultmenuid = localStorage.getItem("defaultmenuid");
let PageLanding = localStorage.getItem("PageLanding");
let baseUrl = localStorage.getItem("baseUrl");
let appid = localStorage.getItem("parseAppId");
localStorage.clear();
localStorage.setItem("appLogo", applogo);
localStorage.setItem("defaultmenuid", defaultmenuid);
localStorage.setItem("PageLanding", PageLanding);
localStorage.setItem("userSettings", appdata);
localStorage.setItem("baseUrl", baseUrl);
localStorage.setItem("parseAppId", appid);
};
return <div>{<Outlet />}</div>;
};
@@ -6,15 +6,11 @@ const infoSlice = createSlice({
initialState: {},
reducers: {
fetchAppInfo: () => {
localStorage.setItem("_appName", appInfo.appname);
localStorage.setItem("_app_objectId", appInfo.objectId);
localStorage.setItem("baseUrl", `${appInfo.baseUrl}/`);
localStorage.setItem("parseAppId", appInfo.appId);
localStorage.setItem("appLogo", appInfo.applogo);
localStorage.setItem("appVersion", appInfo.version);
localStorage.removeItem("userSettings");
localStorage.setItem("userSettings", JSON.stringify(appInfo.settings));
localStorage.setItem("appTitle", appInfo.appTitle);
localStorage.setItem("fev_Icon", appInfo.fev_Icon);
return appInfo;
}
@@ -0,0 +1,53 @@
import React, { useState } from "react";
import Parse from "parse";
import ReactDOM from "react-dom/client";
import PdfRequestFiles from "../pages/PdfRequestFiles";
import { pdfjs } from "react-pdf";
import { Provider } from "react-redux";
import { store } from "../redux/store";
import "../index.css";
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.mjs`;
// Wrapper component to manage props
const PublicScriptFileWrapper = ({ initialProps }) => {
const [props, setProps] = useState(initialProps);
// Make the setProps function globally accessible
window.updatePublicTemplateProps = setProps;
return <PdfRequestFiles {...props} />;
};
const appId = "legadranaxn";
// "opensign";
const serverUrl = "https://app.opensignlabs.com/api/app";
// "https://staging-app.opensignlabs.com/api/app";
localStorage.setItem("baseUrl", `${serverUrl}/`);
localStorage.setItem("parseAppId", appId);
Parse.initialize(appId);
Parse.serverURL = serverUrl;
// Create a new div element and append it to the body
const scriptComponent = document.createElement("div");
scriptComponent.id = "script-component";
document.body.appendChild(scriptComponent);
const link = document.createElement("link");
link.href = "https://cdn.opensignlabs.com/fonts.css";
link.rel = "stylesheet";
document.head.appendChild(link);
//add the Tailwind CSS file
const tailwindCssLink = document.createElement("link");
tailwindCssLink.href =
"https://app.opensignlabs.com/static/js/public-template.bundle.css"; // css bundle file
// "https://staging-app.opensignlabs.com/static/js/public-template.bundle.css"; // css bundle file
tailwindCssLink.rel = "stylesheet";
document.head.appendChild(tailwindCssLink);
// Create a root and render the wrapper component with initial props
const root = ReactDOM.createRoot(document.getElementById("script-component"));
root.render(
<div>
<Provider store={store}>
<PublicScriptFileWrapper initialProps={{ text: "templateId" }} />
</Provider>
</div>
);
+3 -34
View File
@@ -1,6 +1,6 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{js,jsx,ts,tsx}"],
content: ["./src/**/*.{js,jsx,ts,tsx}", "./src/script/PublicTemplate.js"],
theme: {
extend: {}
},
@@ -8,38 +8,7 @@ module.exports = {
daisyui: {
// themes: true,
themes: [
"light",
"dark",
"cupcake",
"bumblebee",
"emerald",
"corporate",
"synthwave",
"retro",
"cyberpunk",
"valentine",
"halloween",
"garden",
"forest",
"aqua",
"lofi",
"pastel",
"fantasy",
"wireframe",
"black",
"luxury",
"dracula",
"cmyk",
"autumn",
"business",
"acid",
"lemonade",
"night",
"coffee",
"winter",
"dim",
"nord",
"sunset",
{
opensigncss: {
primary: "#002864",
@@ -60,8 +29,8 @@ module.exports = {
"success-content": "#f5f5f4",
warning: "#ffbe00",
"warning-content": "#ccd9e8",
error: "#ff0000",
"error-content": "#f3f4f6",
error: "#ffa1a7",
"error-content": "#16090a",
"--rounded-btn": "1.9rem",
"--tab-border": "2px",
"--tab-radius": "0.7rem"
+71
View File
@@ -0,0 +1,71 @@
const path = require("path");
const Dotenv = require("dotenv-webpack");
const { CleanWebpackPlugin } = require("clean-webpack-plugin"); //used to clean directory
const TerserPlugin = require("terser-webpack-plugin"); //used to minify and optimize JavaScript files
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //used to extract css file into separate files
const isProduction = process.env.NODE_ENV;
module.exports = {
mode: isProduction ? "production" : "development",
entry: "./src/script/PublicTemplate.js",
output: {
path: path.resolve(__dirname, "public", "static", "js"),
filename: "public-template.bundle.js",
libraryTarget: "umd",
umdNamedDefine: true,
library: "PublicTemplate",
globalObject: "this"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-react"]
}
}
},
{
test: /\.css$/,
use: [
isProduction ? MiniCssExtractPlugin.loader : "style-loader",
"css-loader",
"postcss-loader"
]
},
{
test: /\.(png|jpe?g|gif|svg)$/i,
use: [
{
loader: "file-loader",
options: {
name: "assets/images/[name].[hash].[ext]"
}
}
]
}
]
},
resolve: {
extensions: [".js", ".jsx"]
},
plugins: [
new Dotenv(),
new CleanWebpackPlugin(),
...(isProduction
? [
new MiniCssExtractPlugin({
filename: "public-template.bundle.css"
})
]
: [])
],
optimization: {
minimize: isProduction ? true : false,
minimizer: [new TerserPlugin()]
},
devtool: isProduction ? "source-map" : "inline-source-map"
};
+1 -1
View File
@@ -1,5 +1,5 @@
# Use an official Node runtime as the base image
FROM node:18
FROM node:20
# Set the working directory inside the container
WORKDIR /usr/src/app
+1 -1
View File
@@ -1,5 +1,5 @@
# Use an official Node runtime as the base image
FROM node:18
FROM node:20
# Set the working directory inside the container
WORKDIR /usr/src/app
+4 -3
View File
@@ -4,8 +4,9 @@ dotenv.config();
const appId = process.env.APP_ID;
const serverUrl = process.env.SERVER_URL;
export const cloudServerUrl = 'http://localhost:8080/app';
export function customAPIurl() {
const url = new URL(process.env.SERVER_URL);
const url = new URL(cloudServerUrl);
return url.pathname === '/api/app' ? url.origin + '/api' : url.origin;
}
@@ -143,13 +144,13 @@ export const updateMailCount = async extUserId => {
await contractUser.save(null, { useMasterKey: true });
} else {
// Create new entry if not found
const ContractsUsers = Parse.Object.extend('contracts_users');
const ContractsUsers = Parse.Object.extend('contracts_Users');
const newContractUser = new ContractsUsers();
newContractUser.set('EmailCount', 1);
await newContractUser.save(null, { useMasterKey: true });
}
} catch (error) {
console.log('Error updating EmailCount in contracts_users: ' + error.message);
console.log('Error updating EmailCount in contracts_Users: ' + error.message);
}
};
@@ -1,4 +1,5 @@
import axios from 'axios';
import { cloudServerUrl } from '../../Utils.js';
// `replaceMailVaribles` is used to replace variables from mail with there actual values
function replaceMailVaribles(subject, body, variables) {
@@ -26,7 +27,7 @@ function replaceMailVaribles(subject, body, variables) {
async function sendMail(doc, signer) {
const subject = `{{sender_name}} has requested you to sign "{{document_title}}"`;
const body = `<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><p>Hi {{receiver_name}},</p><br><p>We hope this email finds you well. {{sender_name}}&nbsp;has requested you to review and sign&nbsp;<b>"{{document_title}}"</b>.</p><p>Your signature is crucial to proceed with the next steps as it signifies your agreement and authorization.</p><br><p>{{signing_url}}</p><br><p>If you have any questions or need further clarification regarding the document or the signing process, please contact the sender.</p><br><p>Thanks</p><p> Team OpenSign™</p><br></body> </html>`;
const url = `${process.env.SERVER_URL}/functions/sendmailv3`;
const url = `${cloudServerUrl}/functions/sendmailv3`;
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': process.env.APP_ID,
@@ -1,6 +1,7 @@
import axios from 'axios';
import { cloudServerUrl } from '../../Utils.js';
const appId = process.env.APP_ID;
const serverUrl = process.env.SERVER_URL;
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
export default async function gooogleauth(request, response) {
const code = request.body.code;
const baseUrl = new URL(process.env.SERVER_URL);
@@ -3,7 +3,7 @@ import multer from 'multer';
import multerS3 from 'multer-s3';
import aws from 'aws-sdk';
import dotenv from 'dotenv';
import { useLocal } from '../../Utils.js';
import { cloudServerUrl, useLocal } from '../../Utils.js';
dotenv.config();
function sanitizeFileName(fileName) {
@@ -49,7 +49,7 @@ async function uploadFile(req, res) {
const DO_SECRET_ACCESS_KEY = process.env.DO_SECRET_ACCESS_KEY;
const DO_SPACE = process.env.DO_SPACE;
const parseBaseUrl = process.env.SERVER_URL;
const parseBaseUrl = cloudServerUrl; //process.env.SERVER_URL;
const parseAppId = process.env.APP_ID;
let fileStorage;
if (useLocal === 'true') {
@@ -1,5 +1,5 @@
import axios from 'axios';
import { customAPIurl, replaceMailVaribles } from '../../../../Utils.js';
import { cloudServerUrl, customAPIurl, replaceMailVaribles } from '../../../../Utils.js';
// `sendDoctoWebhook` is used to send res data of document on webhook
async function sendDoctoWebhook(doc, WebhookUrl, userId) {
@@ -220,7 +220,7 @@ export default async function createDocumentWithTemplate(request, response) {
for (let i = 0; i < contactMail.length; i++) {
try {
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
let url = `${process.env.SERVER_URL}/functions/sendmailv3/`;
let url = `${cloudServerUrl}/functions/sendmailv3/`;
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': process.env.APP_ID,

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