Compare commits

...
70 Commits
Author SHA1 Message Date
AmolandGitHub a9ccb1a3e5 Update README.md 2025-02-09 00:59:35 +05:30
ZathielandGitHub f3d34b1d2c Merge pull request #1513 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/npm_and_yarn-af93afb32e
build(deps): bump nanoid from 3.3.7 to 3.3.8 in /apps/OpenSign in the npm_and_yarn group
2024-12-14 02:29:22 +01:00
dependabot[bot]andGitHub 3f56aa0860 build(deps): bump nanoid in /apps/OpenSign in the npm_and_yarn group
Bumps the npm_and_yarn group in /apps/OpenSign with 1 update: [nanoid](https://github.com/ai/nanoid).


Updates `nanoid` from 3.3.7 to 3.3.8
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.7...3.3.8)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-12 04:38:43 +00:00
prafull-opensignlabsandGitHub 4eeacbaaf1 Merge pull request #1502 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/npm_and_yarn-86577ad91c
build(deps): bump the npm_and_yarn group in /apps/OpenSign with 2 updates
2024-12-12 10:07:09 +05:30
ZathielandGitHub 096a9e5736 Merge pull request #1505 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/axios-1.7.9
build(deps): bump axios from 1.7.7 to 1.7.9 in /apps/OpenSignServer
2024-12-11 22:07:10 +01:00
ZathielandGitHub 4650660a26 Merge pull request #1507 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/mongoose-8.8.4
build(deps): bump mongoose from 8.8.2 to 8.8.4 in /apps/OpenSignServer
2024-12-11 22:06:25 +01:00
dependabot[bot]andGitHub 9e6309644a build(deps): bump mongoose from 8.8.2 to 8.8.4 in /apps/OpenSignServer
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.8.2 to 8.8.4.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/8.8.2...8.8.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-09 00:54:35 +00:00
dependabot[bot]andGitHub 14477a17ee build(deps): bump axios from 1.7.7 to 1.7.9 in /apps/OpenSignServer
Bumps [axios](https://github.com/axios/axios) from 1.7.7 to 1.7.9.
- [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.7...v1.7.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-09 00:53:46 +00:00
dependabot[bot]andGitHub 7d3d618ff3 build(deps): bump the npm_and_yarn group
Bumps the npm_and_yarn group in /apps/OpenSign with 2 updates: [path-to-regexp](https://github.com/pillarjs/path-to-regexp) and [express](https://github.com/expressjs/express).


Updates `path-to-regexp` from 0.1.10 to 3.3.0
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.10...v3.3.0)

Updates `express` from 4.21.1 to 4.21.2
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.1...4.21.2)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: express
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-05 22:50:29 +00:00
ZathielandGitHub 284cd277ea Merge pull request #1489 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/aws-sdk/s3-request-presigner-3.700.0
build(deps): bump @aws-sdk/s3-request-presigner from 3.691.0 to 3.700.0 in /apps/OpenSignServer
2024-11-26 03:53:06 +01:00
ZathielandGitHub df61d752c8 Merge pull request #1486 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/lottiefiles/dotlottie-react-0.10.0
build(deps): bump @lottiefiles/dotlottie-react from 0.9.3 to 0.10.0 in /apps/OpenSign
2024-11-26 03:52:16 +01:00
dependabot[bot]andGitHub 9def956929 build(deps): bump @aws-sdk/s3-request-presigner in /apps/OpenSignServer
Bumps [@aws-sdk/s3-request-presigner](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/s3-request-presigner) from 3.691.0 to 3.700.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/s3-request-presigner/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.700.0/packages/s3-request-presigner)

---
updated-dependencies:
- dependency-name: "@aws-sdk/s3-request-presigner"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-26 02:50:17 +00:00
ZathielandGitHub 53aa5a26aa Merge pull request #1482 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/mongoose-8.8.2
build(deps): bump mongoose from 8.8.1 to 8.8.2 in /apps/OpenSignServer
2024-11-26 03:50:10 +01:00
ZathielandGitHub 86cb5ccf78 Merge pull request #1483 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/posthog-node-4.2.3
build(deps): bump posthog-node from 4.2.1 to 4.2.3 in /apps/OpenSignServer
2024-11-26 03:49:35 +01:00
ZathielandGitHub c8e91e5205 Merge pull request #1485 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/aws-sdk/client-s3-3.699.0
build(deps): bump @aws-sdk/client-s3 from 3.691.0 to 3.699.0 in /apps/OpenSignServer
2024-11-26 03:48:45 +01:00
dependabot[bot]andGitHub 87cfb643f9 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.9.3 to 0.10.0.
- [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.10.0/packages/react)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-26 02:47:29 +00:00
ZathielandGitHub 2f7bd75608 Merge pull request #1488 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/react-pdf/renderer-4.1.4
build(deps): bump @react-pdf/renderer from 4.0.0 to 4.1.4 in /apps/OpenSign
2024-11-26 03:46:06 +01:00
ZathielandGitHub 930bac71a0 Merge pull request #1464 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/tailwindcss-3.4.15
build(deps-dev): bump tailwindcss from 3.4.14 to 3.4.15 in /apps/OpenSign
2024-11-26 03:45:26 +01:00
dependabot[bot]andGitHub fcad7dc020 build(deps): bump @react-pdf/renderer in /apps/OpenSign
Bumps [@react-pdf/renderer](https://github.com/diegomura/react-pdf/tree/HEAD/packages/renderer) from 4.0.0 to 4.1.4.
- [Release notes](https://github.com/diegomura/react-pdf/releases)
- [Changelog](https://github.com/diegomura/react-pdf/blob/master/packages/renderer/CHANGELOG.md)
- [Commits](https://github.com/diegomura/react-pdf/commits/@react-pdf/renderer@4.1.4/packages/renderer)

---
updated-dependencies:
- dependency-name: "@react-pdf/renderer"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-25 01:04:36 +00:00
dependabot[bot]andGitHub bada731d16 build(deps): bump @aws-sdk/client-s3 in /apps/OpenSignServer
Bumps [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-s3) from 3.691.0 to 3.699.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.699.0/clients/client-s3)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-s3"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-25 00:58:13 +00:00
dependabot[bot]andGitHub fd5e86edf2 build(deps): bump posthog-node in /apps/OpenSignServer
Bumps [posthog-node](https://github.com/PostHog/posthog-js-lite/tree/HEAD/posthog-node) from 4.2.1 to 4.2.3.
- [Release notes](https://github.com/PostHog/posthog-js-lite/releases)
- [Changelog](https://github.com/PostHog/posthog-js-lite/blob/main/posthog-node/CHANGELOG.md)
- [Commits](https://github.com/PostHog/posthog-js-lite/commits/posthog-node-v4.2.3/posthog-node)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-25 00:57:28 +00:00
dependabot[bot]andGitHub 1a886261ef build(deps): bump mongoose from 8.8.1 to 8.8.2 in /apps/OpenSignServer
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.8.1 to 8.8.2.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/8.8.1...8.8.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-25 00:57:21 +00:00
AmolandGitHub 41c3b4746d Update CONTRIBUTING.md 2024-11-22 11:07:44 +05:30
AmolandGitHub f52d013b06 Update LICENSE 2024-11-21 18:36:03 +05:30
AmolandGitHub 0045603cb0 Create LICENSE 2024-11-21 18:35:11 +05:30
nxglabs 4235bc077d refactor: add comment for optional phone field 2024-11-21 17:53:08 +05:30
prafull-opensignlabsandGitHub 58b3cc6ba2 Merge pull request #1481 from OpenSignLabs/feat_status
fix: cannot read undefined objectId in reports
2024-11-21 11:04:02 +05:30
prafull-opensignlabs 97f5d09306 refactor: remove console log 2024-11-21 10:57:36 +05:30
prafull-opensignlabs fa98972b27 fix: cannot read undefined objectId in reports 2024-11-21 10:48:23 +05:30
AmolandGitHub 76848b7e09 Merge pull request #1479 from OpenSignLabs/feat_status
refactor: made phone field optional for signer/contact
2024-11-20 19:45:37 +05:30
prafull-opensignlabs c3faaa65b9 refactor: made phone field optional for signer/contact 2024-11-20 19:39:41 +05:30
AmolandGitHub e819513650 Merge pull request #1478 from OpenSignLabs/feat_status
feat: show status and signers list in need your sign and in-progress report
2024-11-20 19:21:20 +05:30
prafull-opensignlabs dd0e2f0e58 feat: show status and signers list in need your sign and in-progress report 2024-11-20 19:19:43 +05:30
prafull-opensignlabsandGitHub fa08efeac6 Merge pull request #1476 from OpenSignLabs/raktima-patch-12
fix: resolved text widget data embedding issue after sending the document
2024-11-20 16:31:28 +05:30
RaktimaandGitHub f3ba02496c Update PlaceHolderSign.js 2024-11-20 16:13:04 +05:30
RaktimaNXG 5cbbb00f66 fix: resolved text widget data embedding issue after sending the document 2024-11-20 15:34:02 +05:30
AndrewandGitHub 7050df8b4c Merge pull request #1474 from OpenSignLabs/uncompatible_pdf 2024-11-19 22:28:58 +05:30
prafull-opensignlabs 4fb27f4896 refactor: add date format in label for expiry date 2024-11-19 19:18:39 +05:30
AndrewandGitHub 145aa5da97 Merge pull request #1473 from OpenSignLabs/uncompatible_pdf 2024-11-19 18:20:59 +05:30
prafull-opensignlabs 1a455415f1 feat: add extend document expiry date functionality 2024-11-19 18:10:59 +05:30
prafull-opensignlabsandGitHub 44ef1fe825 Merge pull request #1472 from OpenSignLabs/uncompatible_pdf
feat: add column for expiry date in in-progress and expired report
2024-11-19 13:07:52 +05:30
prafull-opensignlabs cb07e376d5 feat: add column for expiry date in in-progress and expired report 2024-11-18 19:28:12 +05:30
AndrewandGitHub 9b472a6b8b Merge pull request #1471 from OpenSignLabs/uncompatible_pdf 2024-11-18 18:23:52 +05:30
prafull-opensignlabs 9840fe9412 fix: notify on signatures not working in public template 2024-11-18 18:22:39 +05:30
prafull-opensignlabsandGitHub d1a99d5211 Merge pull request #1418 from hanicker/patch-1
Specify signatureVersion for AWS S3
2024-11-18 17:28:29 +05:30
prafull-opensignlabsandGitHub 5f7736882b Merge pull request #1470 from OpenSignLabs/uncompatible_pdf
fix: schema mismatch issue while saving preferences
2024-11-18 15:41:39 +05:30
prafull-opensignlabs d8095e077a fix: schema mismatch issue while saving preferences 2024-11-18 13:55:54 +05:30
AndrewandGitHub c8fae00ce5 Merge pull request #1469 from OpenSignLabs/uncompatible_pdf 2024-11-18 12:54:00 +05:30
prafull-opensignlabs 7c6a03a2d2 fix: notify on signature not working in quicksend and publictemplate 2024-11-18 12:52:17 +05:30
dependabot[bot]andGitHub 657ab13a04 build(deps-dev): bump tailwindcss in /apps/OpenSign
Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss) from 3.4.14 to 3.4.15.
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/v3.4.15/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/compare/v3.4.14...v3.4.15)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-18 00:18:58 +00:00
AndrewandGitHub 40c21321dd Merge pull request #1461 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/npm_and_yarn-c3cc913ac2 2024-11-16 23:54:23 +05:30
AndrewandGitHub 476dbb555d Merge pull request #1462 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/npm_and_yarn-c3cc913ac2 2024-11-16 23:54:10 +05:30
dependabot[bot]andGitHub 19b4bfb9ef build(deps): bump cross-spawn
Bumps the npm_and_yarn group in /apps/OpenSign with 1 update: [cross-spawn](https://github.com/moxystudio/node-cross-spawn).


Updates `cross-spawn` from 7.0.3 to 7.0.5
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.5)

---
updated-dependencies:
- dependency-name: cross-spawn
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-16 17:06:34 +00:00
dependabot[bot]andGitHub e9a85162e7 build(deps): bump cross-spawn
Bumps the npm_and_yarn group in /apps/OpenSignServer with 1 update: [cross-spawn](https://github.com/moxystudio/node-cross-spawn).


Updates `cross-spawn` from 7.0.3 to 7.0.5
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.5)

---
updated-dependencies:
- dependency-name: cross-spawn
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-16 17:05:07 +00:00
ZathielandGitHub 960c297995 Merge pull request #1460 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/npm_and_yarn-7503158af6
build(deps): bump @eslint/plugin-kit from 0.2.0 to 0.2.3 in /apps/OpenSign in the npm_and_yarn group
2024-11-16 18:04:55 +01:00
ZathielandGitHub 50e525f448 Merge pull request #1459 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/npm_and_yarn-7503158af6
build(deps): bump @eslint/plugin-kit from 0.2.0 to 0.2.3 in /apps/OpenSignServer in the npm_and_yarn group
2024-11-16 18:03:46 +01:00
dependabot[bot]andGitHub c86f048498 build(deps): bump @eslint/plugin-kit
Bumps the npm_and_yarn group in /apps/OpenSign with 1 update: [@eslint/plugin-kit](https://github.com/eslint/rewrite).


Updates `@eslint/plugin-kit` from 0.2.0 to 0.2.3
- [Release notes](https://github.com/eslint/rewrite/releases)
- [Changelog](https://github.com/eslint/rewrite/blob/main/release-please-config.json)
- [Commits](https://github.com/eslint/rewrite/compare/core-v0.2.0...plugin-kit-v0.2.3)

---
updated-dependencies:
- dependency-name: "@eslint/plugin-kit"
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-15 21:09:03 +00:00
dependabot[bot]andGitHub 39fd2f697f build(deps): bump @eslint/plugin-kit
Bumps the npm_and_yarn group in /apps/OpenSignServer with 1 update: [@eslint/plugin-kit](https://github.com/eslint/rewrite).


Updates `@eslint/plugin-kit` from 0.2.0 to 0.2.3
- [Release notes](https://github.com/eslint/rewrite/releases)
- [Changelog](https://github.com/eslint/rewrite/blob/main/release-please-config.json)
- [Commits](https://github.com/eslint/rewrite/compare/core-v0.2.0...plugin-kit-v0.2.3)

---
updated-dependencies:
- dependency-name: "@eslint/plugin-kit"
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-15 21:08:08 +00:00
prafull-opensignlabsandGitHub 3f2cf3ddf4 Merge pull request #1458 from OpenSignLabs/uncompatible_pdf
feat: send email notification to document owner when signer sign document
2024-11-14 19:26:38 +05:30
prafull-opensignlabs 5a53a70dcf feat: send email notification to document owner when signer sign document 2024-11-14 19:02:16 +05:30
prafull-opensignlabsandGitHub 66323f9347 Merge pull request #1456 from OpenSignLabs/uncompatible_pdf
fix: otp auth must be disable in certificate if OTP verification is off
2024-11-13 16:22:16 +05:30
prafull-opensignlabs c65f17a216 fix: otp auth must be disable in certificate if OTP verfication is off 2024-11-13 16:20:17 +05:30
prafull-opensignlabsandGitHub 9bf93fb231 Merge pull request #1454 from OpenSignLabs/uncompatible_pdf
fix: incompatible pdf error while signing pdf
2024-11-13 14:13:43 +05:30
prafull-opensignlabs f418e02270 fix: uncompatible pdf error while signing pdf 2024-11-13 14:11:11 +05:30
prafull-opensignlabsandGitHub 403254a5c6 Merge pull request #1451 from OpenSignLabs/validation
fix: server get crash in self-hosting
2024-11-13 10:09:14 +05:30
prafull-opensignlabs c893d96ad3 fix: server get crash in self-hosting 2024-11-13 00:33:46 +05:30
AndrewandGitHub 3971118af8 Merge pull request #1449 from OpenSignLabs/validation 2024-11-12 17:04:04 +05:30
prafull-opensignlabs 4db0d93f41 refactor: update news from header 2024-11-12 16:24:50 +05:30
Nicola M.andGitHub 124fbfd798 Update getSignedUrl.js 2024-11-05 12:17:46 +01:00
Nicola M.andGitHub 893e433805 Update uploadFiletoS3.js
set signatureVersion
2024-11-05 12:12:31 +01:00
49 changed files with 3052 additions and 3659 deletions
+2 -2
View File
@@ -77,6 +77,6 @@ Engage with the community on our [Gitter Channel](https://gitter.im/OpenSignLabs
## License
By contributing, you agree that your contributions will be licensed under its [MIT License](LICENSE).
By contributing, you agree that your contributions will be licensed under its [AGPL-V3 License](LICENSE).
---
---
+6 -1
View File
@@ -1,4 +1,9 @@
GNU AFFERO GENERAL PUBLIC LICENSE
* All content that resides under the "apps/OpenSignServer/cloud/customRoute" directory of this repository, if that directory exists, is licensed under the license defined in "apps/OpenSignServer/cloud/customRoute".
* All third party components incorporated into the OpenSign Software are licensed under the original license provided by the owner of the applicable component.
* Content outside of the above mentioned directories or restrictions above is available under the "GNU AFFERO GENERAL PUBLIC LICENSE" as defined below -
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+2
View File
@@ -158,3 +158,5 @@ We would like to thank all our contributors and users for their support and feed
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project is tested with BrowserStack.
+1140 -334
View File
File diff suppressed because it is too large Load Diff
+12 -12
View File
@@ -4,10 +4,10 @@
"private": true,
"dependencies": {
"@formkit/auto-animate": "^0.8.2",
"@lottiefiles/dotlottie-react": "^0.9.3",
"@lottiefiles/dotlottie-react": "^0.10.0",
"@pdf-lib/fontkit": "^1.1.1",
"@radix-ui/themes": "^3.1.4",
"@react-pdf/renderer": "^4.0.0",
"@radix-ui/themes": "^3.1.6",
"@react-pdf/renderer": "^4.1.4",
"@reduxjs/toolkit": "^2.3.0",
"axios": "^1.7.7",
"file-saver": "^2.0.5",
@@ -34,13 +34,13 @@
"react-dom": "^18.2.0",
"react-gtm-module": "^2.0.11",
"react-helmet": "^6.1.0",
"react-i18next": "^15.0.3",
"react-i18next": "^15.1.1",
"react-konva": "^18.2.10",
"react-pdf": "^9.1.1",
"react-quill-new": "^3.3.3",
"react-redux": "^9.1.2",
"react-rnd": "^10.4.13",
"react-router-dom": "^6.27.0",
"react-router-dom": "^6.28.0",
"react-scripts": "5.0.1",
"react-scrollbars-custom": "^4.1.1",
"react-select": "^5.8.3",
@@ -54,7 +54,7 @@
"regex-parser": "^2.3.0",
"serve": "^14.2.4",
"styled-components": "^5.3.0",
"web-vitals": "^4.2.3",
"web-vitals": "^4.2.4",
"ws": "^8.18.0"
},
"scripts": {
@@ -103,20 +103,20 @@
"babel-loader": "^9.2.1",
"clean-webpack-plugin": "^4.0.0",
"commitizen": "^4.3.1",
"concurrently": "^9.0.1",
"concurrently": "^9.1.0",
"css-loader": "^7.1.2",
"daisyui": "^4.12.14",
"dotenv": "^16.4.5",
"dotenv-webpack": "^8.1.0",
"eslint": "^9.13.0",
"eslint": "^9.14.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.37.1",
"eslint-plugin-react": "^7.37.2",
"lint-staged": "^15.2.10",
"mini-css-extract-plugin": "^2.9.1",
"postcss": "^8.4.48",
"mini-css-extract-plugin": "^2.9.2",
"postcss": "^8.4.49",
"prettier": "^3.3.3",
"pretty-quick": "^4.0.0",
"tailwindcss": "^3.4.14",
"tailwindcss": "^3.4.15",
"terser-webpack-plugin": "^5.3.10",
"webpack-cli": "^5.1.4"
},
@@ -1,5 +1,5 @@
{
"header-news": "New feature: Public profiles are now live! Easily create and share public templates",
"header-news": "New feature: Teams plan users can now integrate their own AWS S3 buckets for file storage",
"header-news-btn": "Setup Now",
"create-account": "Create Account",
"login": "Login",
@@ -134,7 +134,8 @@
"option": "Option",
"Embed": "Embed",
"Copy TemplateId":"Copy TemplateId",
"Copy Public URL":"Copy Public URL"
"Copy Public URL":"Copy Public URL",
"extend-expiry-date": "Extend expiry date"
},
"report-heading": {
"Sr.No": "Sr.No",
@@ -155,7 +156,8 @@
"Status": "Status",
"created-date": "Created Date",
"Type": "Type",
"Logs": "Logs"
"Logs": "Logs",
"Expiry-date": "Expiry Date"
},
"report-help": {
"Draft Documents": "These are documents you have started but have not finalized for sending.",
@@ -266,7 +268,8 @@
"make-template-public-alert": "Are you sure you want to make this template public?",
"make-template-private-alert": "Are you sure you want to make this template private? This will remove it from your public profile.",
"public-role": "Public role",
"public-url": "Public profile needed",
"public-url": "Public profile",
"embed-template": "Embed Template",
"public-url-copy": "Heres your public URL: ",
"public-url-copy-mssg":"Copy it or share it with the signer, and you will be able to see all your publicly set templates.",
"add-public-url-alert": "Please complete your OpenSign public profile setup. Once done, youll be able to make templates public. This process only needs to be completed once.",
@@ -512,7 +515,7 @@
"error": "Error",
"invalid-document": "Error: invalid document!",
"document-not-found": "Document not Found!",
"document-signed-alert-1": "You have successfully signed the document. You can download or print a copy of the partially signed document. A copy of the digitally signed document will be sent to the owner over email once it is signed by all signers.",
"document-signed-alert-1": "You have successfully signed the document. You can download or print a copy of the partially signed document. A copy of the digitally signed document & completion certificate will be sent to the owner & all signers over email once it is signed by all signers.",
"encrypted-pdf-not-support": "Currently encrypted pdf files are not supported.",
"document-signed-alert-4": " Congratulations! 🎉 This document has been successfully signed by all participants!",
"document-signed-alert-5": "This document has been signed by all Signers.",
@@ -652,6 +655,7 @@
"angular-npm-mssg-1": "To integrate OpenSign into your Angular project, simply run the following command:",
"quota-mail-info-head":"Monthly request signatures email limit",
"quota-mail-info": "You can send upto 15 signature request emails every month. Upgrade now to send unlimited signing requests directly.",
"quota-mail-reset": "Your signature request email credits will be reset on",
"quota-mail": "You've reached your limit of 15 signature request emails for this month. Upgrade now to continue sending emails directly.",
"quota-mail-tip":"Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.",
"quota-mail-head":"Quota Reached",
@@ -674,14 +678,14 @@
"document-logs":"Document logs",
"server-down": "Unable to connect to the OpenSign server. If you are self-hosting OpenSign, please ensure that all the steps in the documentation have been followed correctly. If you're running OpenSign locally, you might be accessing it through an incorrect port number.",
"admin-exists": "Admin already exists. Please login to the application using admin credentials in order to manage users.",
"enable-tour":"Enable Tour",
"istourenabled-help":{
"enable-tour":"Enable Tour",
"istourenabled-help":{
"p1":"This will enable a guided tour for signers, providing instructions during the signing process.",
"p2":"This will disable the guided tour, ensuring a faster, uninterrupted signing experience.",
"p3":"Tip: If your signers are familiar with OpenSign and frequently use it, you may want to disable the guided tour for a more seamless experience. Choose the option that best fits your document signing needs."
},
"form-title-1":"Document Flow Setting",
"form-title-2":"Security Settings",
"form-title-1":"Document Flow Setting",
"form-title-2":"Security Settings",
"public-tour-message":"The template needs to be public before you can generate a shareable link.",
"add-user-template": "You need to add a role before you can add fields for it.",
"pdf-uncompatible": "This pdf is not compatible with opensign, please contact <support@opensignlabs.com>",
@@ -697,5 +701,13 @@
"l2": "Enter your name and choose from various font styles to create a signature.",
"l3": "Upload an existing digital version of your signature.",
"l4": "Use a pre-set signature style saved under 'My Signature' in your settings."
}
},
"notify-on-signatures": "Notify on signatures",
"notify-on-signatures-help": {
"p1": "The document creator will receive an email notification whenever a signer signs the document.",
"note": "Note: Notification email will not be sent for the last signer, as the document creator will receive a completion email instead."
},
"expiry-date": "Expiry Date",
"expiry-date-updated": "The expiry date has been successfully extended to {{newexpirydate}}",
"expiry-date-error": "Please provide a new expiry date that is later than the current one"
}
@@ -1,5 +1,5 @@
{
"header-news": "Nueva funcionalidad: ¡Los perfiles públicos ahora están disponibles! Crea y comparte plantillas públicas fácilmente",
"header-news": "Nueva característica: los usuarios del plan Teams ahora pueden integrar sus propios depósitos de AWS S3 para el almacenamiento de archivos",
"header-news-btn": "Configurar ahora",
"create-account": "Crear cuenta",
"login": "Iniciar sesión",
@@ -134,7 +134,8 @@
"option": "Opción",
"Embed": "Incrustar",
"Copy TemplateId": "Copiar ID de plantilla",
"Copy Public URL": "Copiar URL pública"
"Copy Public URL": "Copiar URL pública",
"extend-expiry-date": "Ampliar fecha de caducidad"
},
"report-heading": {
"Sr.No": "Nº",
@@ -155,7 +156,8 @@
"Status": "Estado",
"created-date": "Fecha de creación",
"Type": "Tipo",
"Logs": "Registros"
"Logs": "Registros",
"Expiry-date": "Date d'expiration"
},
"report-help": {
"Draft Documents": "Estos son documentos que has iniciado pero no has finalizado para su envío.",
@@ -266,7 +268,8 @@
"make-template-public-alert": "¿En definitiva quieres convertir esta plantilla en pública?",
"make-template-private-alert": "¿En definitiva quieres convertir esta plantilla en privada? Esto lo removerá de tu perfil público.",
"public-role": "Rol público",
"public-url": "Se requiere perfil público",
"public-url": "Perfil publico",
"embed-template": "Insertar plantilla",
"public-url-copy": "Aquí está tu URL pública: ",
"public-url-copy-mssg": "Cópiala o compártela con el firmante y podrás ver todas tus plantillas públicas.",
"add-public-url-alert": "Por favor, completa la configuración de tu perfil público OpenSign. Una vez terminado, podrás crear plantillas públicas. Este proceso solo necesita ser completado una vez.",
@@ -512,7 +515,7 @@
"error": "Error",
"invalid-document": "Error: ¡Documento inválido!",
"document-not-found": "¡Documento no encontrado!",
"document-signed-alert-1": "Has firmado el documento exitosamente. Puedes descargar o imprimir una copia del documento parcialmente firmado. Una copia del documento firmado digitalmente será enviada al propietario mediante correo electrónico una vez haya sido firmado por todos los firmantes.",
"document-signed-alert-1": "Ha firmado exitosamente el documento. Puede descargar o imprimir una copia del documento parcialmente firmado. Se enviará una copia del documento firmado digitalmente y del certificado de finalización al propietario y a todos los firmantes por correo electrónico una vez que todos los firmantes lo hayan firmado.",
"encrypted-pdf-not-support": "Los archivos PDF encriptados no están soportados actualmente.",
"document-signed-alert-4": " ¡Felicitaciones! 🎉 ¡Este documento ha sido firmado exitosamente por todos los participantes!",
"document-signed-alert-5": "Este documento ha sido firmado por todos los firmantes.",
@@ -652,6 +655,7 @@
"angular-npm-mssg-1": "Para integrar OpenSign a tu proyecto Angular, simplemente ejecuta los siguientes comandos:",
"quota-mail-info-head": "Límite mensual de solicitudes de firma por correo",
"quota-mail-info": "Puedes enviar hasta 15 solicitudes de firma por correo cada mes. Mejora ahora para enviar solicitudes de firma sin límite.",
"quota-mail-reset": "Los créditos de tu correo electrónico de solicitud de firma se restablecerán el",
"quota-mail": "Has alcanzado tu límite de 15 solicitudes de firma por correo para este mes. Mejora ahora para continuar enviando correos.",
"quota-mail-tip": "Consejo: Todavía puedes solciitar la firma de <1>documentos ilimitados</1> compartiendo manualmente los enlaces de solicitud de firma.",
"quota-mail-head": "Cuota alcanzada",
@@ -678,24 +682,32 @@
"add-user-template": "Es necesario agregar un rol antes de poder agregarle campos.",
"pdf-uncompatible": "Este pdf no es compatible con opensign, comuníquese con <support@opensignlabs.com>",
"enable-tour": "Habilitar recorrido",
"istourenabled-help":{
"p1": "Esto permitirá realizar una visita guiada para los firmantes, brindando instrucciones durante el proceso de firma.",
"p2": "Esto desactivará la visita guiada, lo que garantizará una experiencia de firma más rápida e ininterrumpida.",
"p3": "Consejo: si sus firmantes están familiarizados con OpenSign y lo utilizan con frecuencia, es posible que desee desactivar la visita guiada para disfrutar de una experiencia más fluida. Elija la opción que mejor se adapte a sus necesidades de firma de documentos"
"istourenabled-help":{
"p1": "Esto permitirá realizar una visita guiada para los firmantes, brindando instrucciones durante el proceso de firma.",
"p2": "Esto desactivará la visita guiada, lo que garantizará una experiencia de firma más rápida e ininterrumpida.",
"p3": "Consejo: si sus firmantes están familiarizados con OpenSign y lo utilizan con frecuencia, es posible que desee desactivar la visita guiada para disfrutar de una experiencia más fluida. Elija la opción que mejor se adapte a sus necesidades de firma de documentos"
},
"form-title-1": "Configuración del flujo de documentos",
"form-title-2": "Configuración de seguridad",
"text-field-tour":"Los campos de tipo 'Texto' deben completarse con anticipación antes de enviar el documento. Si necesita que los firmantes proporcionen información, utilice el campo 'Entrada de texto'",
"attach-signer-tour" :"Debe adjuntar un firmante a cada función. Puede hacerlo haciendo clic en este icono. Una vez que seleccione un Firmante, se adjuntará a todos los campos asociados con ese rol que aparecen en el mismo color.",
"allowed-signature-types": "Tipos de firma permitidos",
"at-least-one-signature-type": "Se debe habilitar al menos un tipo de firma.",
"expect-default-one-signature-type": "Habilite un tipo de firma adicional aparte del predeterminado.",
"add-signer-note": "Nota - Este contacto se agregará a su lista de contactos",
"allowed-signature-types-help": {
"form-title-1": "Configuración del flujo de documentos",
"form-title-2": "Configuración de seguridad",
"text-field-tour":"Los campos de tipo 'Texto' deben completarse con anticipación antes de enviar el documento. Si necesita que los firmantes proporcionen información, utilice el campo 'Entrada de texto'",
"attach-signer-tour" :"Debe adjuntar un firmante a cada función. Puede hacerlo haciendo clic en este icono. Una vez que seleccione un Firmante, se adjuntará a todos los campos asociados con ese rol que aparecen en el mismo color.",
"allowed-signature-types": "Tipos de firma permitidos",
"at-least-one-signature-type": "Se debe habilitar al menos un tipo de firma.",
"expect-default-one-signature-type": "Habilite un tipo de firma adicional aparte del predeterminado.",
"add-signer-note": "Nota - Este contacto se agregará a su lista de contactos",
"allowed-signature-types-help": {
"p1": "Esta preferencia de firma controla qué opciones de firma están disponibles para sus firmantes. Solo los tipos de firma que seleccione aparecerán en el widget de firma cuando se firme un documento. Por ejemplo, si elige sólo la opción 'Draw' en las preferencias, su firmante verá sólo la opción 'Draw' en el widget de firma, mientras que las otras tres opciones no estarán disponibles.",
"l1": "Cree una firma manuscrita directamente en la pantalla usando su dedo o un lápiz.",
"l2": "Ingrese su nombre y elija entre varios estilos de fuente para crear una firma.",
"l3": "Cargue una versión digital existente de su firma.",
"l4": "Utilice un estilo de firma preestablecido guardado en 'Mi firma' en su configuración."
}
},
"notify-on-signatures": "Notificar sobre firmas",
"notify-on-signatures-help": {
"p1": "El creador del documento recibirá una notificación por correo electrónico cada vez que un firmante firme el documento.",
"note": "Nota: No se enviará un correo electrónico de notificación al último firmante, ya que el creador del documento recibirá un correo electrónico de finalización."
},
"expiry-date": "Date d'expiration",
"expiry-date-updated": "La fecha de vencimiento se ha extendido con éxito hasta el {{newexpirydate}}",
"expiry-date-error": "Proporcione una nueva fecha de vencimiento que sea posterior a la actual"
}
@@ -1,5 +1,5 @@
{
"header-news": "Nouvelle fonctionnalité : les profils publics sont désormais en ligne ! Créez et partagez facilement des modèles publics",
"header-news": "Nouvelle fonctionnalité : les utilisateurs du forfait Teams peuvent désormais intégrer leurs propres compartiments AWS S3 pour le stockage de fichiers",
"header-news-btn": "Configurer maintenant",
"create-account": "Créer un compte",
"login": "Se Connecter",
@@ -138,7 +138,8 @@
"Status": "Statut",
"created-date": "Date de création",
"Type": "Saisir",
"Logs": "Journaux"
"Logs": "Journaux",
"Expiry-date": "Fecha de caducidad"
},
"btnLabel": {
"sign": "Signer",
@@ -154,7 +155,8 @@
"option": "Option",
"Embed": "Intégrer",
"Copy TemplateId": "Copier l'ID du modèle",
"Copy Public URL":"Copier l'URL publique"
"Copy Public URL":"Copier l'URL publique",
"extend-expiry-date": "Prolonger la date d'expiration"
},
"report-help": {
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
@@ -265,7 +267,8 @@
"make-template-public-alert": "Êtes-vous sûr de vouloir rendre ce modèle public ?",
"make-template-private-alert": "Êtes-vous sûr de vouloir rendre ce modèle privé ? Cela le supprimera de votre profil public.",
"public-role": "Rôle public",
"public-url": "Profil public requis",
"public-url": "Profil public",
"embed-template": "Intégrer le modèle",
"public-url-copy": "Voici votre URL publique : ",
"public-url-copy-mssg": "copiez-la ou partagez-le avec le signataire et vous pouvoir voir tous vos paramètres publics modèles.",
"add-public-url-alert": "Veuillez terminer la configuration de votre profil public OpenSign. Une fois cela fait, vous pourrez rendre les modèles publics. Ce processus ne doit être effectué quune seule fois.",
@@ -511,7 +514,7 @@
"error": "Erreur",
"invalid-document": "Erreur : document invalide !",
"document-not-found": "Document introuvable !",
"document-signed-alert-1": "Vous avez signé le document avec succès. Vous pouvez télécharger ou imprimer une copie du document partiellement signé. Une copie du document signé numériquement sera envoyée au propriétaire par e-mail une fois qu'il sera signé par tous les signataires.",
"document-signed-alert-1": "Vous avez signé le document avec succès. Vous pouvez télécharger ou imprimer une copie du document partiellement signé. Une copie du document signé numériquement et du certificat d'achèvement sera envoyée au propriétaire et à tous les signataires par e-mail une fois qu'il aura été signé par tous les signataires.",
"encrypted-pdf-not-support": "Les fichiers PDF actuellement cryptés ne sont pas pris en charge. ",
"document-signed-alert-4": "Toutes nos félicitations! 🎉 Ce document a été signé avec succès par tous les participants !",
"document-signed-alert-5": "Ce document a été signé par tous les signataires.",
@@ -651,6 +654,7 @@
"angular-npm-mssg-1" :"Pour intégrer OpenSign dans votre projet Angular, exécutez simplement la commande suivante :",
"quota-mail-info-head":"Limite mensuelle d'e-mails de signatures de demandes",
"quota-mail-info": "Vous pouvez envoyer jusqu'à 15 e-mails de demande de signature chaque mois. Mettez à niveau maintenant pour envoyer directement des demandes de signature illimitées.",
"quota-mail-reset": "Les crédits de votre email de demande de signature seront réinitialisés le",
"quota-mail": "Vous avez atteint votre limite de 15 e-mails de demande de signature pour ce mois. Mettez à niveau maintenant pour continuer à envoyer des e-mails directement.",
"quota-mail-tip-tip":"Astuce : Vous pouvez toujours signer un nombre <1>illimité de documents</1> en partageant manuellement les liens de demande de signature.",
"quota-mail-head":"Quota atteint",
@@ -696,5 +700,13 @@
"l2": "Entrez votre nom et choisissez parmi différents styles de police pour créer une signature.",
"l3": "Téléchargez une version numérique existante de votre signature.",
"l4": "Utilisez un style de signature prédéfini enregistré sous 'Ma signature' dans vos paramètres."
}
},
"notify-on-signatures": "Notifier les signatures",
"notify-on-signatures-help": {
"p1": "Le créateur du document recevra une notification par e-mail chaque fois qu'un signataire signera le document.",
"note": "Remarque : L'e-mail de notification ne sera pas envoyé pour le dernier signataire, car le créateur du document recevra à la place un e-mail de fin."
},
"expiry-date": "Fecha de caducidad",
"expiry-date-updated": "La fecha de vencimiento se ha extendido con éxito hasta el {{newexpirydate}}",
"expiry-date-error": "Veuillez fournir une nouvelle date d'expiration postérieure à la date actuelle"
}
-5
View File
@@ -35,7 +35,6 @@ const GenerateToken = lazy(() => import("./pages/GenerateToken"));
const Webhook = lazy(() => import("./pages/Webhook"));
const AddAdmin = lazy(() => import("./pages/AddAdmin"));
const UpdateExistUserAdmin = lazy(() => import("./pages/UpdateExistUserAdmin"));
const DraftTemplate = lazy(() => import("./pages/DraftTemplate"));
const Preferences = lazy(() => import("./pages/Preferences"));
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
@@ -206,10 +205,6 @@ function App() {
/>
</Route>
<Route path="/sso" element={<SSOVerify />} />
<Route
path="/drafttemplate/:jwttoken"
element={<DraftTemplate />}
/>
<Route path="*" element={<PageNotFound />} />
</Routes>
</BrowserRouter>
@@ -274,6 +274,7 @@ const AddSigner = (props) => {
onChange={(e) => setPhone(e.target.value)}
disabled={addYourself}
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
placeholder={t("phone-optional")}
/>
</div>
<div className="mt-4 flex gap-x-2 justify-start">
+2 -2
View File
@@ -431,13 +431,13 @@ const AddUser = (props) => {
{t("phone")}
{/* <span className="text-[red] text-[13px]"> *</span> */}
</label>
{/* added hint for phone number being optional */}
<input
type="text"
name="phone"
placeholder="optional"
placeholder={t("phone-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>
+24 -3
View File
@@ -6,6 +6,7 @@ import Parse from "parse";
import { useWindowSize } from "../hook/useWindowSize";
import {
checkIsSubscribed,
formatDate,
getAppLogo,
openInNewTab,
saveLanguageInLocal
@@ -33,6 +34,7 @@ const Header = ({ showSidebar, setIsMenu }) => {
);
const [emailUsed, setEmailUsed] = useState(0);
const [isModal, setIsModal] = useState(false);
const [emailResetDate, setEmailResetDate] = useState("");
const [showNotification, setShowNotification] = useState(
(!dismissedVersion || dismissedVersion !== current_notification_version) &&
true
@@ -64,6 +66,14 @@ const Header = ({ showSidebar, setIsMenu }) => {
const extUser = await Parse.Cloud.run("getUserDetails");
const MonthlyFreeEmails = extUser?.get("MonthlyFreeEmails") || 0;
setEmailUsed(MonthlyFreeEmails);
if (extUser) {
const _extUser = JSON.parse(JSON.stringify(extUser));
if (_extUser?.LastEmailCountReset?.iso) {
const resetDate = formatDate(_extUser?.LastEmailCountReset?.iso);
setEmailResetDate(resetDate);
}
localStorage.setItem("Extand_Class", JSON.stringify([_extUser]));
}
} catch (err) {
console.log("err in while fetching monthlyfreeEmails", err);
}
@@ -140,15 +150,22 @@ const Header = ({ showSidebar, setIsMenu }) => {
);
setShowNotification(false);
};
const handleSetupNowNavigation = () => {
const url = isStaging
? "https://staging-console.opensignlabs.com/fileadapter"
: "https://console.opensignlabs.com/fileadapter";
openInNewTab(url);
};
return (
<div>
{isEnableSubscription && showNotification && (
<div className="flex justify-between items-center shadow py-1 bg-[#CAE4FA] p-1">
<div className="flex justify-between items-center shadow py-1 bg-[#CAE4FA] p-1">
<div className="text-center text-[14px] ml-auto">
{t("header-news")}
<span
className="cursor-pointer font-medium underline text-blue-800"
onClick={() => navigate("/profile")}
onClick={() => handleSetupNowNavigation()}
>
{" " + t("header-news-btn") + "."}
</span>
@@ -291,7 +308,11 @@ const Header = ({ showSidebar, setIsMenu }) => {
</div>
</div>
<ModalUi isOpen={isModal}>
<QuotaCard isPaidInfo={true} handlClose={handleMailUsed} />
<QuotaCard
isPaidInfo={true}
handlClose={handleMailUsed}
emailResetDate={emailResetDate}
/>
</ModalUi>
</div>
);
+141 -73
View File
@@ -17,7 +17,11 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => {
IsEnableOTP: template?.IsEnableOTP ? `${template?.IsEnableOTP}` : "false",
IsTourEnabled: template?.IsTourEnabled
? `${template?.IsTourEnabled}`
: "false"
: "false",
NotifyOnSignatures:
template?.NotifyOnSignatures !== undefined
? template?.NotifyOnSignatures
: false
});
const [isSubscribe, setIsSubscribe] = useState(false);
useEffect(() => {
@@ -64,6 +68,11 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => {
AutomaticReminders: !formData.AutomaticReminders
}));
};
// `handleNotifySignChange` is trigger when user change radio of notify on signatures
const handleNotifySignChange = (value) => {
setFormData((obj) => ({ ...obj, NotifyOnSignatures: value }));
};
return (
<div className="max-h-[300px] md:max-h-[400px] overflow-y-scroll p-[10px]">
<div className="text-base-content">
@@ -120,27 +129,29 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => {
</div>
<div className="mb-[0.35rem]">
<label className="text-[13px]">{t("send-in-order")}</label>
<div className="flex items-center gap-[8px] ml-[8px] mb-[5px]">
<input
type="radio"
value={"true"}
className="op-radio op-radio-xs"
name="SendinOrder"
checked={formData.SendinOrder === "true"}
onChange={handleStrInput}
/>
<div className="text-[12px]">{t("yes")}</div>
</div>
<div className="flex items-center gap-[8px] ml-[8px] mb-[5px]">
<input
type="radio"
value={"false"}
name="SendinOrder"
className="op-radio op-radio-xs"
checked={formData.SendinOrder === "false"}
onChange={handleStrInput}
/>
<div className="text-[12px]">{t("no")}</div>
<div className="flex flex-col md:flex-row md:gap-4">
<div className="flex items-center gap-[8px] ml-[8px] mb-[5px]">
<input
type="radio"
value={"true"}
className="op-radio op-radio-xs"
name="SendinOrder"
checked={formData.SendinOrder === "true"}
onChange={handleStrInput}
/>
<div className="text-[12px]">{t("yes")}</div>
</div>
<div className="flex items-center gap-[8px] ml-[8px] mb-[5px]">
<input
type="radio"
value={"false"}
name="SendinOrder"
className="op-radio op-radio-xs"
checked={formData.SendinOrder === "false"}
onChange={handleStrInput}
/>
<div className="text-[12px]">{t("no")}</div>
</div>
</div>
</div>
{isEnableSubscription && (
@@ -156,7 +167,7 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => {
<label
className={`${
isSubscribe
? "cursor-pointer "
? "cursor-pointer"
: "pointer-events-none opacity-50"
} relative block items-center mb-0`}
>
@@ -221,39 +232,40 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => {
</div>
</Tooltip>
</label>
<div
className={`${
isSubscribe ? "" : "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1 `}
>
<input
type="radio"
value={"true"}
className="op-radio op-radio-xs"
name="IsEnableOTP"
checked={formData.IsEnableOTP === "true"}
onChange={handleStrInput}
/>
<div className="text-center">{t("yes")}</div>
</div>
<div
className={`${
isSubscribe ? "" : "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1 `}
>
<input
type="radio"
value={"false"}
name="IsEnableOTP"
className="op-radio op-radio-xs"
checked={formData.IsEnableOTP === "false"}
onChange={handleStrInput}
/>
<div className="text-center">{t("no")}</div>
<div className="flex flex-col md:flex-row md:gap-4">
<div
className={`${
isSubscribe ? "" : "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1`}
>
<input
type="radio"
value={"true"}
className="op-radio op-radio-xs"
name="IsEnableOTP"
checked={formData.IsEnableOTP === "true"}
onChange={handleStrInput}
/>
<div className="text-center">{t("yes")}</div>
</div>
<div
className={`${
isSubscribe ? "" : "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1 `}
>
<input
type="radio"
value={"false"}
name="IsEnableOTP"
className="op-radio op-radio-xs"
checked={formData.IsEnableOTP === "false"}
onChange={handleStrInput}
/>
<div className="text-center">{t("no")}</div>
</div>
</div>
</div>
)}
<div className="text-xs mt-2">
<label className="block">
<span>
@@ -283,27 +295,83 @@ const EditTemplate = ({ template, onSuccess, jwttoken }) => {
</div>
</Tooltip>
</label>
<div className={` flex items-center gap-2 ml-2 mb-1 `}>
<input
type="radio"
value={"true"}
className="op-radio op-radio-xs"
name="IsTourEnabled"
checked={formData.IsTourEnabled === "true"}
onChange={handleStrInput}
/>
<div className="text-center">{t("yes")}</div>
<div className="flex flex-col md:flex-row md:gap-4">
<div className="flex items-center gap-2 ml-2 mb-1">
<input
type="radio"
value={"true"}
className="op-radio op-radio-xs"
name="IsTourEnabled"
checked={formData.IsTourEnabled === "true"}
onChange={handleStrInput}
/>
<div className="text-center">{t("yes")}</div>
</div>
<div className="flex items-center gap-2 ml-2 mb-1">
<input
type="radio"
value={"false"}
name="IsTourEnabled"
className="op-radio op-radio-xs"
checked={formData.IsTourEnabled === "false"}
onChange={handleStrInput}
/>
<div className="text-center">{t("no")}</div>
</div>
</div>
<div className={` flex items-center gap-2 ml-2 mb-1 `}>
<input
type="radio"
value={"false"}
name="IsTourEnabled"
className="op-radio op-radio-xs"
checked={formData.IsTourEnabled === "false"}
onChange={handleStrInput}
/>
<div className="text-center">{t("no")}</div>
</div>
<div className="text-xs mt-3">
<label
className={`${
isSubscribe || !isEnableSubscription ? "" : "text-gray-300"
} block`}
>
{t("notify-on-signatures")}
<a data-tooltip-id="nos-tooltip" className="ml-1">
<sup>
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
</sup>
</a>
{!isSubscribe && isEnableSubscription && <Upgrade />}
<Tooltip id="nos-tooltip" className="z-[999]">
<div className="max-w-[200px] md:max-w-[450px] text-[11px]">
<p className="font-bold">{t("notify-on-signatures")}</p>
<p>{t("notify-on-signatures-help.p1")}</p>
<p>{t("notify-on-signatures-help.note")}</p>
</div>
</Tooltip>
</label>
<div className="flex flex-col md:flex-row md:gap-4">
<div
className={`${
isSubscribe || !isEnableSubscription
? ""
: "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1`}
>
<input
className="mr-[2px] op-radio op-radio-xs"
type="radio"
onChange={() => handleNotifySignChange(true)}
checked={formData.NotifyOnSignatures === true}
/>
<div className="text-center">{t("yes")}</div>
</div>
<div
className={`${
isSubscribe || !isEnableSubscription
? ""
: "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1`}
>
<input
className="mr-[2px] op-radio op-radio-xs"
type="radio"
onChange={() => handleNotifySignChange(false)}
checked={formData.NotifyOnSignatures === false}
/>
<div className="text-center">{t("no")}</div>
</div>
</div>
</div>
<div className="mt-[1rem] flex justify-start">
+10 -12
View File
@@ -18,17 +18,16 @@ function EmbedTab(props) {
{
id: 0,
title: "Installation",
codeString: `
npm install @opensign/react`
codeString: `npm install @opensign/react`
},
{
id: 1,
title: "Usage",
codeString: `
import React from "react";
import React from "react";
import Opensign from "@opensign/react";
export function App() {
export default function App() {
return (
<div className="app">
<Opensign
@@ -40,7 +39,6 @@ export function App() {
);
}
`
}
];
@@ -49,15 +47,14 @@ export function App() {
{
id: 0,
title: "Installation",
codeString: `
npm install @opensign/angular`
codeString: `npm install @opensign/angular`
},
{
id: 1,
title: "Usage",
codeString: `
import { Component } from '@angular/core';
import {OpensignComponent} from "@opensign/angular"
import { OpensignComponent } from "@opensign/angular"
@Component({
selector:'app-root',
@@ -68,17 +65,15 @@ import {OpensignComponent} from "@opensign/angular"
(onLoadError)="handleError($event)"
></opensign>\`,
})
export class AppComponent{
export class AppComponent {
handleLoad() {
console.log("success");
}
handleError(error: string) {
console.log(error);
}
}
`
}
];
@@ -98,6 +93,9 @@ export class AppComponent{
return (
<div className="mt-4 border-t-[1px]">
<h3 className="text-base-content font-bold text-lg pt-[15px] pb-[5px]">
{t("embed-template")}
</h3>
<div className="flex justify-center items-center mt-2">
<div role="tablist" className="op-tabs op-tabs-bordered">
{tabName.map((tabData, ind) => (
@@ -107,7 +105,7 @@ export class AppComponent{
role="tab"
className={`${
activeTab === ind ? "op-tab-active" : ""
} op-tab flex items-center`}
} op-tab flex items-center pb-10 md:pb-0`}
>
<i
className={`${tabData.icon}`}
@@ -7,10 +7,7 @@ const DROPBOX_SCRIPT_ID = "dropboxjs";
export default function DropboxChooser({ children, onSuccess, onCancel }) {
useDropScript(DROPBOX_SDK_URL, {
attrs: {
id: DROPBOX_SCRIPT_ID,
"data-app-key": DROPBOX_APP_KEY
}
attrs: { id: DROPBOX_SCRIPT_ID, "data-app-key": DROPBOX_APP_KEY }
});
const options = useMemo(
+21 -8
View File
@@ -705,6 +705,9 @@ export const createDocument = async (
const SignatureType = Doc?.SignatureType
? { SignatureType: Doc?.SignatureType }
: {};
const NotifyOnSignatures = Doc?.NotifyOnSignatures
? { NotifyOnSignatures: Doc?.NotifyOnSignatures }
: {};
const data = {
Name: Doc.Name,
URL: pdfUrl,
@@ -730,7 +733,8 @@ export const createDocument = async (
IsEnableOTP: Doc?.IsEnableOTP || false,
IsTourEnabled: Doc?.IsTourEnabled || false,
FileAdapterId: Doc?.FileAdapterId || "",
...SignatureType
...SignatureType,
...NotifyOnSignatures
};
try {
@@ -1453,7 +1457,6 @@ export const multiSignEmbed = async (widgets, pdfDoc, signyourself, scale) => {
if (position?.options?.values.length > 0) {
position?.options?.values.forEach((item, ind) => {
const checkboxRandomId = "checkbox" + randomId();
if (
position?.options?.response &&
position?.options?.response?.length > 0
@@ -1505,8 +1508,6 @@ export const multiSignEmbed = async (widgets, pdfDoc, signyourself, scale) => {
});
}
} else if (widgetTypeExist) {
const fontSize = position?.options?.fontSize || 12;
parseInt(fontSize);
let textContent;
if (position?.options?.response) {
textContent = position.options?.response;
@@ -1541,7 +1542,6 @@ export const multiSignEmbed = async (widgets, pdfDoc, signyourself, scale) => {
// Function to break text into lines based on when user go next line on press enter button
const breakTextIntoLines = (textContent, width) => {
const lines = [];
for (const word of textContent.split("\n")) {
const lineWidth = font.widthOfTextAtSize(`${word}`, fontSize);
//checking string length to container width
@@ -1583,7 +1583,6 @@ export const multiSignEmbed = async (widgets, pdfDoc, signyourself, scale) => {
y += 18; // Adjust the line height as needed
}
} else if (position.type === "dropdown") {
const fontsize = parseInt(position?.options?.fontSize) || 12;
const dropdownRandomId = "dropdown" + randomId();
const dropdown = form.createDropdown(dropdownRandomId);
dropdown.addOptions(position?.options?.values);
@@ -1598,10 +1597,10 @@ export const multiSignEmbed = async (widgets, pdfDoc, signyourself, scale) => {
// - `FontSize` is the size you want to set (e.g., 12)
// - `Tf` specifies the font and size
// - `0 g` sets the text color to black
const defaultAppearance = `/Helv ${fontsize} Tf 0 g`;
const defaultAppearance = `/Helv ${fontSize} Tf 0 g`;
// Set the default appearance for the dropdown field
dropdown.acroField.setDefaultAppearance(defaultAppearance);
dropdown.setFontSize(fontsize);
dropdown.setFontSize(fontSize);
const dropdownObj = {
x: xPos(position),
y: yPos(position),
@@ -2597,3 +2596,17 @@ export async function handleSignatureType(tenantSignTypes, signatureType) {
}
return updatedSignatureType;
}
// `formatDate` is used to format date to dd-mmm-yyy
export const formatDate = (date) => {
// Create a Date object
const newDate = new Date(date);
// Format the date
const formattedDate = newDate.toLocaleDateString("en-GB", {
day: "2-digit",
month: "short",
year: "numeric"
});
const format = formattedDate.replaceAll(/ /g, "-");
return format;
};
+24 -21
View File
@@ -2,28 +2,12 @@ import { isEnableSubscription } from "../constant/const";
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 iphead = [
"Sr.No",
"Title",
"Note",
"Folder",
"File",
"Status",
"Signers"
];
const contactbook = ["Sr.No", "Name", "Email", "Phone"];
const head = ["Title", "Note", "Folder", "File", "Owner", "Signers"];
const declineHead = ["Title", "Reason", "Folder", "File", "Owner", "Signers"];
const iphead = ["Title", "Note", "Folder", "File", "Signers"];
const contactbook = ["Name", "Email", "Phone"];
const dashboardReportHead = ["Title", "File", "Owner", "Signers"];
const templateReport = ["Sr.No", "Title", "File", "Owner", "Signers"];
const templateReport = ["Title", "File", "Owner", "Signers"];
const templateSubAction = isEnableSubscription
? [
{
@@ -228,6 +212,25 @@ export default function reportJson(id) {
btnIcon: "fa-light fa-trash",
redirectUrl: "",
action: "delete"
},
{
btnId: "3234",
hoverLabel: "option",
btnColor: "",
textColor: "black",
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
action: "option",
subaction: [
{
btnId: "2199",
btnLabel: "extend-expiry-date",
hoverLabel: "Extend expiry date",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-hourglass-end",
redirectUrl: "",
action: "extendexpiry"
}
]
}
],
helpMsg:
File diff suppressed because it is too large Load Diff
+90 -27
View File
@@ -68,7 +68,8 @@ const Forms = (props) => {
remindOnceInEvery: 5,
autoreminder: false,
IsEnableOTP: "false",
IsTourEnabled: "false"
IsTourEnabled: "false",
NotifyOnSignatures: ""
});
const [fileupload, setFileUpload] = useState("");
const [fileload, setfileload] = useState(false);
@@ -102,21 +103,25 @@ const Forms = (props) => {
if (isEnableSubscription) {
const subscribe = await checkIsSubscribed();
setIsSubscribe(subscribe.isValid);
if (subscribe.isValid && extUserData.NotifyOnSignatures !== undefined) {
setFormData((obj) => ({
...obj,
NotifyOnSignatures: extUserData.NotifyOnSignatures
}));
} else if (subscribe.isValid) {
setFormData((obj) => ({ ...obj, NotifyOnSignatures: true }));
}
} else {
setIsSubscribe(true);
setFormData((obj) => ({ ...obj, NotifyOnSignatures: true }));
}
};
function getFileAsArrayBuffer(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
resolve(e.target.result);
};
reader.onerror = (e) => {
reject(e.target.error);
};
reader.onload = (e) => resolve(e.target.result);
reader.onerror = (e) => reject(e.target.error);
reader.readAsArrayBuffer(file);
});
}
@@ -525,7 +530,6 @@ const Forms = (props) => {
}
}
};
const dropboxCancel = async () => {};
const handleSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
@@ -555,8 +559,14 @@ const Forms = (props) => {
const IsEnableOTP =
formData?.IsEnableOTP === "false" ? false : true;
object.set("IsEnableOTP", IsEnableOTP);
if (isSubscribe && formData.NotifyOnSignatures !== undefined) {
object.set("NotifyOnSignatures", formData.NotifyOnSignatures);
}
} else {
object.set("IsEnableOTP", false);
if (formData.NotifyOnSignatures !== undefined) {
object.set("NotifyOnSignatures", formData.NotifyOnSignatures);
}
}
}
object.set("URL", fileupload);
@@ -639,7 +649,7 @@ const Forms = (props) => {
setIsReset(true);
setSigners([]);
setFolder({ ObjectId: "", Name: "" });
setFormData({
let obj = {
Name: "",
Description: "",
Note:
@@ -654,7 +664,8 @@ const Forms = (props) => {
autoreminder: false,
IsEnableOTP: "false",
IsTourEnabled: "true"
});
};
setFormData(obj);
setFileUpload("");
setpercentage(0);
setTimeout(() => setIsReset(false), 50);
@@ -772,6 +783,12 @@ const Forms = (props) => {
const handleAutoReminder = () => {
setFormData((prev) => ({ ...prev, autoreminder: !formData.autoreminder }));
};
// `handleNotifySignChange` is trigger when user change radio of notify on signatures
const handleNotifySignChange = (value) => {
setFormData((obj) => ({ ...obj, NotifyOnSignatures: value }));
};
return (
<div className="shadow-md rounded-box my-[2px] p-3 bg-base-100 text-base-content">
<Title title={props?.title} />
@@ -865,10 +882,7 @@ const Forms = (props) => {
</div>
</div>
{process.env.REACT_APP_DROPBOX_API_KEY && (
<DropboxChooser
onSuccess={dropboxSuccess}
onCancel={dropboxCancel}
/>
<DropboxChooser onSuccess={dropboxSuccess} />
)}
</div>
) : (
@@ -890,10 +904,7 @@ const Forms = (props) => {
required
/>
{process.env.REACT_APP_DROPBOX_API_KEY && (
<DropboxChooser
onSuccess={dropboxSuccess}
onCancel={dropboxCancel}
/>
<DropboxChooser onSuccess={dropboxSuccess} />
)}
</div>
)}
@@ -1215,7 +1226,7 @@ const Forms = (props) => {
<label
className={`${
isSubscribe
? "cursor-pointer "
? "cursor-pointer"
: "pointer-events-none opacity-50"
} relative block items-center mb-0 mt-1.5`}
>
@@ -1251,7 +1262,7 @@ const Forms = (props) => {
)}
<span className="font-[400] mt-2">{t("form-title-2")}</span>
{isEnableSubscription && (
<div className="text-xs mt-4">
<div className="text-xs mt-3">
<label className="block">
<span className={isSubscribe ? "" : " text-gray-300"}>
{t("isenable-otp")}{" "}
@@ -1262,7 +1273,7 @@ const Forms = (props) => {
<sup>
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
</sup>
</a>{" "}
</a>
{!isSubscribe && isEnableSubscription && (
<Upgrade />
)}
@@ -1340,7 +1351,7 @@ const Forms = (props) => {
<sup>
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
</sup>
</a>{" "}
</a>
</span>
<Tooltip id="istourenabled-tooltip" className="z-[999]">
<div className="max-w-[200px] md:max-w-[450px]">
@@ -1364,7 +1375,7 @@ const Forms = (props) => {
</Tooltip>
</label>
<div className="flex flex-col md:flex-row md:gap-4">
<div className={` flex items-center gap-2 ml-2 mb-1 `}>
<div className="flex items-center gap-2 ml-2 mb-1">
<input
type="radio"
value={"true"}
@@ -1375,7 +1386,7 @@ const Forms = (props) => {
/>
<div className="text-center">{t("yes")}</div>
</div>
<div className={` flex items-center gap-2 ml-2 mb-1 `}>
<div className="flex items-center gap-2 ml-2 mb-1">
<input
type="radio"
value={"false"}
@@ -1388,6 +1399,58 @@ const Forms = (props) => {
</div>
</div>
</div>
<div className="text-xs mt-3">
<label
className={`${
isSubscribe ? "" : "text-gray-300"
} block`}
>
{t("notify-on-signatures")}
<a data-tooltip-id="nos-tooltip" className="ml-1">
<sup>
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
</sup>
</a>
{!isSubscribe && isEnableSubscription && <Upgrade />}
<Tooltip id="nos-tooltip" className="z-[999]">
<div className="max-w-[200px] md:max-w-[450px] text-[11px]">
<p className="font-bold">
{t("notify-on-signatures")}
</p>
<p>{t("notify-on-signatures-help.p1")}</p>
<p>{t("notify-on-signatures-help.note")}</p>
</div>
</Tooltip>
</label>
<div className="flex flex-col md:flex-row md:gap-4">
<div
className={`${
isSubscribe ? "" : "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1`}
>
<input
className="mr-[2px] op-radio op-radio-xs"
type="radio"
onChange={() => handleNotifySignChange(true)}
checked={formData.NotifyOnSignatures === true}
/>
<div className="text-center">{t("yes")}</div>
</div>
<div
className={`${
isSubscribe ? "" : "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1`}
>
<input
className="mr-[2px] op-radio op-radio-xs"
type="radio"
onChange={() => handleNotifySignChange(false)}
checked={formData.NotifyOnSignatures === false}
/>
<div className="text-center">{t("no")}</div>
</div>
</div>
</div>
</div>
)}
</div>
+25 -17
View File
@@ -1,7 +1,7 @@
import React, { useState, useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom";
import axios from "axios";
import { isEnableSubscription } from "../constant/const";
import { emailRegex, isEnableSubscription } from "../constant/const";
import {
contractUsers,
getAppLogo,
@@ -189,23 +189,30 @@ function GuestLogin() {
};
const handleUserData = async (e) => {
e.preventDefault();
const params = { ...contact, docId: documentId };
try {
setLoading(true);
const linkContactRes = await Parse.Cloud.run("linkcontacttodoc", params);
setContactId(linkContactRes.contactId);
const IsEnableOTP = await navigateToDoc(
documentId,
linkContactRes.contactId
);
if (!IsEnableOTP) {
setEnterOtp(true);
await SendOtp();
if (!emailRegex.test(contact.email)) {
alert("Please enter a valid email address.");
} else {
const params = { ...contact, docId: documentId };
try {
setLoading(true);
const linkContactRes = await Parse.Cloud.run(
"linkcontacttodoc",
params
);
setContactId(linkContactRes.contactId);
const IsEnableOTP = await navigateToDoc(
documentId,
linkContactRes.contactId
);
if (!IsEnableOTP) {
setEnterOtp(true);
await SendOtp();
}
} catch (err) {
setLoading(false);
alert(t("something-went-wrong-mssg"));
console.log("Err in link ext contact", err);
}
} catch (err) {
setLoading(false);
alert(t("something-went-wrong-mssg"));
console.log("Err in link ext contact", err);
}
};
const handleInputChange = (e) => {
@@ -348,6 +355,7 @@ function GuestLogin() {
onChange={handleInputChange}
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
disabled={loading}
placeholder={t("phone-optional")}
/>
</div>
<div className="mt-2 flex justify-start">
@@ -59,6 +59,7 @@ import LoaderWithMsg from "../primitives/LoaderWithMsg";
import DownloadPdfZip from "../primitives/DownloadPdfZip";
import Loader from "../primitives/Loader";
import PdfDeclineModal from "../primitives/PdfDeclineModal";
import { serverUrl_fn } from "../constant/appinfo";
function PdfRequestFiles(props) {
const { t } = useTranslation();
@@ -1752,6 +1753,42 @@ function PdfRequestFiles(props) {
</div>
);
};
const handleExpiry = async (expiryDate) => {
setIsUiLoading(true);
const doc = pdfDetails?.[0];
const oldExpiryDate = new Date(doc?.ExpiryDate?.iso);
const newExpiryDate = new Date(expiryDate);
if (newExpiryDate > oldExpiryDate) {
const updateExpiryDate = new Date(expiryDate).toISOString();
const expiryIsoFormat = { iso: updateExpiryDate, __type: "Date" };
try {
const serverUrl = serverUrl_fn();
const url = serverUrl + `/classes/contracts_Document/`;
const body = { ExpiryDate: expiryIsoFormat };
const res = await axios.put(url + doc.objectId, body, {
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
});
if (res.data && res.data.updatedAt) {
setIsExpired(false);
let doc = pdfDetails?.[0];
doc.ExpiryDate = expiryIsoFormat;
setPdfDetails([doc]);
}
} catch (err) {
console.log("err", err);
} finally {
setIsUiLoading(false);
}
} else {
setIsUiLoading(false);
alert(t("expiry-date-error"));
}
};
return (
<DndProvider backend={HTML5Backend}>
<Title title={props.templateId ? "Public Sign" : "Request Sign"} />
@@ -1838,10 +1875,12 @@ function PdfRequestFiles(props) {
{/* this modal is used for show expired alert */}
<PdfDeclineModal
show={isExpired}
doc={pdfDetails?.[0]}
headMsg={t("expired-doc-title")}
bodyMssg={t("expired-on-mssg", { expiredDate })}
isDownloadBtn={true}
handleDownloadBtn={handleDownloadBtn}
handleExpiry={handleExpiry}
/>
{!isEmailVerified && (
<VerifyEmail
+44 -22
View File
@@ -40,7 +40,8 @@ import {
handleRemoveWidgets,
handleRotateWarning,
signatureTypes,
handleSignatureType
handleSignatureType,
formatDate
} from "../constant/Utils";
import RenderPdf from "../components/pdf/RenderPdf";
import { useNavigate } from "react-router-dom";
@@ -155,6 +156,7 @@ function PlaceHolderSign() {
const [planCode, setPlanCode] = useState("");
const [unSignedWidgetId, setUnSignedWidgetId] = useState("");
const [signatureType, setSignatureType] = useState(signatureTypes);
const [emailResetDate, setEmailResetDate] = useState("");
const isMobile = window.innerWidth < 767;
const [, drop] = useDrop({
accept: "BOX",
@@ -269,6 +271,12 @@ function PlaceHolderSign() {
} else {
setPdfArrayBuffer(arrayBuffer);
}
if (documentData[0]?.ExtUserPtr?.LastEmailCountReset?.iso) {
const resetDate = formatDate(
documentData[0]?.ExtUserPtr?.LastEmailCountReset?.iso
);
setEmailResetDate(resetDate);
}
setExtUserId(documentData[0]?.ExtUserPtr?.objectId);
if (isEnableSubscription) {
checkIsSubscribed(documentData[0]?.ExtUserPtr?.Email);
@@ -580,22 +588,33 @@ function PlaceHolderSign() {
}
setSignerPos(updatesignerPos);
} else {
let updatesignerPos;
//if condition when widget type is prefill label text widget
if (dragTypeValue === textWidget) {
const prefileTextWidget = {
signerPtr: {},
signerObjId: "",
blockColor: "#f58f8c",
placeHolder: [placeHolder],
Role: "prefill",
Id: key
};
signerPos.push(prefileTextWidget);
setSignerPos(signerPos);
//check text widgets data (prefill) already exist then and want to add text widget on new page
//create new page entry with old data and update placeholder
if (filterSignerPos) {
const addPrefillData =
filterSignerPos && filterSignerPos?.placeHolder;
addPrefillData.push(placeHolder);
const updatePrefillPos = signerPos.map((x) =>
x.Role === "prefill" ? { ...x, placeHolder: addPrefillData } : x
);
setSignerPos(updatePrefillPos);
} //else condition if user do not have any text widget data
else {
const prefillTextWidget = {
signerPtr: {},
signerObjId: "",
blockColor: "#f58f8c",
placeHolder: [placeHolder],
Role: "prefill",
Id: key
};
setSignerPos((prev) => [...prev, prefillTextWidget]);
}
} else {
//else condition to add placeholder widgets on multiple page first time
updatesignerPos = signerPos.map((x) =>
const updatesignerPos = signerPos.map((x) =>
x.Id === uniqueId && x?.placeHolder
? { ...x, placeHolder: [...x.placeHolder, placeHolder] }
: x.Id === uniqueId
@@ -770,15 +789,17 @@ function PlaceHolderSign() {
signerupdate.push(newUpdatePos[0]);
setSignerPos(signerupdate);
} else {
const updatedData = signerPos.map((item) => {
if (item.Id === Id) {
// Create a copy of the item object and delete the placeHolder field
const updatedItem = { ...item };
delete updatedItem.placeHolder;
return updatedItem;
}
return item;
});
const updatedData = signerPos
.filter((item) => !(item.Id === Id && item.Role === "prefill")) // Remove prefill object
.map((item) => {
if (item.Id === Id && item.Role !== "prefill") {
// Create a copy of the item object and delete the placeHolder field
const updatedItem = { ...item };
delete updatedItem.placeHolder;
return updatedItem;
}
return item;
});
setSignerPos(updatedData);
}
}
@@ -1926,6 +1947,7 @@ function PlaceHolderSign() {
) : mailStatus === "quotareached" ? (
<div className="flex flex-col gap-y-3">
<QuotaCard
emailResetDate={emailResetDate}
handleClose={() => {
setIsSend(false);
setSignerPos([]);
+116 -20
View File
@@ -5,12 +5,15 @@ import { useTranslation } from "react-i18next";
import Loader from "../primitives/Loader";
import Tooltip from "../primitives/Tooltip";
import {
checkIsSubscribed,
getTenantDetails,
handleSignatureType,
signatureTypes
} from "../constant/Utils";
import Parse from "parse";
import { Tooltip as ReactTooltip } from "react-tooltip";
import { isEnableSubscription } from "../constant/const";
import Upgrade from "../primitives/Upgrade";
const Preferences = () => {
const { t } = useTranslation();
const [isalert, setIsAlert] = useState({ type: "success", msg: "" });
@@ -18,11 +21,19 @@ const Preferences = () => {
const [isLoader, setIsLoader] = useState(false);
const [signatureType, setSignatureType] = useState([]);
const [errMsg, setErrMsg] = useState("");
const [isNotifyOnSignatures, setIsNotifyOnSignatures] = useState();
const [isSubscribe, setIsSubscribe] = useState(false);
useEffect(() => {
fetchSignType();
}, []);
const fetchSignType = async () => {
if (isEnableSubscription) {
const subscribe = await checkIsSubscribed();
setIsSubscribe(subscribe.isValid);
} else {
setIsSubscribe(true);
}
setIsTopLoader(true);
try {
const user = JSON.parse(
@@ -36,6 +47,11 @@ const Preferences = () => {
const getUser = await Parse.Cloud.run("getUserDetails");
if (getUser) {
const _getUser = JSON.parse(JSON.stringify(getUser));
const notifyOnSignatures =
_getUser?.NotifyOnSignatures !== undefined
? _getUser?.NotifyOnSignatures
: "";
setIsNotifyOnSignatures(notifyOnSignatures);
if (tenantSignTypes?.length > 0) {
const signatureType = _getUser?.SignatureType || signatureTypes;
const updatedSignatureType = await handleSignatureType(
@@ -69,39 +85,61 @@ const Preferences = () => {
// `handleSave` is used save updated value signature type
const handleSave = async () => {
setIsLoader(true);
const enabledSignTypes = signatureType?.filter((x) => x.enabled);
const isDefaultSignTypeOnly =
enabledSignTypes?.length === 1 && enabledSignTypes[0]?.name === "default";
if (enabledSignTypes.length === 0) {
setIsAlert({
type: "danger",
msg: t("at-least-one-signature-type")
});
} else if (isDefaultSignTypeOnly) {
setIsAlert({
type: "danger",
msg: t("expect-default-one-more-signature-type")
});
} else {
if (signatureType.length > 0 || isNotifyOnSignatures) {
let params = {};
if (signatureType.length > 0) {
const enabledSignTypes = signatureType?.filter((x) => x.enabled);
const isDefaultSignTypeOnly =
enabledSignTypes?.length === 1 &&
enabledSignTypes[0]?.name === "default";
if (enabledSignTypes.length === 0) {
setIsAlert({
type: "danger",
msg: t("at-least-one-signature-type")
});
} else if (isDefaultSignTypeOnly) {
setIsAlert({
type: "danger",
msg: t("expect-default-one-more-signature-type")
});
} else {
params = { ...params, SignatureType: signatureType };
}
}
if (isNotifyOnSignatures) {
params = { ...params, NotifyOnSignatures: isNotifyOnSignatures };
}
try {
const updateRes = await Parse.Cloud.run("updatesignaturetype", {
SignatureType: signatureType
});
const updateRes = await Parse.Cloud.run("updatepreferences", params);
if (updateRes) {
setIsAlert({ type: "success", msg: "Saved successfully." });
let extUser =
localStorage.getItem("Extand_Class") &&
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
if (extUser && extUser?.objectId) {
extUser.NotifyOnSignatures = isNotifyOnSignatures;
const _extUser = JSON.parse(JSON.stringify(extUser));
localStorage.setItem("Extand_Class", JSON.stringify([_extUser]));
}
}
} catch (err) {
console.log("Error updating signature type", err);
setIsAlert({ type: "danger", msg: err.message });
}
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
setIsLoader(false);
}
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
setIsLoader(false);
};
// `handleNotifySignChange` is trigger when user change radio of notify on signatures
const handleNotifySignChange = (value) => {
setIsNotifyOnSignatures(value);
};
return (
<React.Fragment>
<Title title={"API Token"} />
<Title title={t("Preferences")} />
{isalert.msg && <Alert type={isalert.type}>{isalert.msg}</Alert>}
{isTopLoader ? (
<div className="flex justify-center items-center h-screen">
@@ -200,6 +238,64 @@ const Preferences = () => {
</div>
))}
</div>
</div>
<div className="mb-[0.75rem]">
<label
className={`${
isSubscribe ? "" : "text-gray-300"
} text-[14px] mb-[0.7rem] font-medium`}
>
{t("notify-on-signatures")}
<a data-tooltip-id="nos-tooltip" className="ml-1">
<sup>
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
</sup>
</a>
<ReactTooltip id="nos-tooltip" className="z-[999]">
<div className="max-w-[200px] md:max-w-[450px] text-[11px]">
<p className="font-bold">{t("notify-on-signatures")}</p>
<p>{t("notify-on-signatures-help.p1")}</p>
<p>{t("notify-on-signatures-help.note")}</p>
</div>
</ReactTooltip>
{!isSubscribe && isEnableSubscription && <Upgrade />}
</label>
<div className="flex flex-col md:flex-row md:gap-4">
<div
className={`${
isSubscribe ? "" : "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1`}
>
<input
className="mr-[2px] op-radio op-radio-xs"
type="radio"
onChange={() => handleNotifySignChange(true)}
checked={isNotifyOnSignatures === true}
/>
<div className="text-[13px] font-medium cursor-default capitalize">
{t("yes")}
</div>
</div>
<div className="flex flex-col md:flex-row md:gap-4">
<div
className={`${
isSubscribe ? "" : "pointer-events-none opacity-50"
} flex items-center gap-2 ml-2 mb-1`}
>
<input
className="mr-[2px] op-radio op-radio-xs"
type="radio"
onChange={() => handleNotifySignChange(false)}
checked={isNotifyOnSignatures === false}
/>
<div className="text-[13px] font-medium cursor-default capitalize">
{t("no")}
</div>
</div>
</div>
</div>
</div>
<div className="mb-[0.75rem]">
<button
className="op-btn op-btn-primary"
onClick={handleSave}
+44 -40
View File
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import Parse from "parse";
import { appInfo } from "../constant/appinfo";
import { isEnableSubscription } from "../constant/const";
import { emailRegex, isEnableSubscription } from "../constant/const";
import { fetchSubscription } from "../constant/Utils";
import { useDispatch } from "react-redux";
import { showTenant } from "../redux/reducers/ShowTenant";
@@ -88,54 +88,58 @@ const SSOVerify = () => {
// `handleSubmitbtn` is used to create a user in the extended class
const handleSubmitbtn = async (e) => {
e.preventDefault();
setIsLoader(true);
let phone;
if (userDetails?.phone) {
phone = validateInput(userDetails?.phone);
if (!emailRegex.test(userDetails.email)) {
alert("Please enter a valid email address.");
} else {
phone = true;
}
if (userDetails.Destination && userDetails.Company && phone) {
const payload = { sessionToken: localStorage.getItem("accesstoken") };
if (payload && payload.sessionToken) {
const params = {
userDetails: {
name: userDetails.name,
email: userDetails.email,
phone: userDetails?.phone || "",
role: "contracts_User",
company: userDetails.Company,
jobTitle: userDetails.Destination
}
};
try {
const userSignUp = await Parse.Cloud.run("usersignup", params);
if (userSignUp && userSignUp.sessionToken) {
const LocalUserDetails = params.userDetails;
localStorage.setItem(
"userDetails",
JSON.stringify(LocalUserDetails)
);
await thirdpartyLoginfn(userSignUp.sessionToken);
setIsLoader(false);
} else {
alert(userSignUp.message);
setIsLoader(true);
let phone;
if (userDetails?.phone) {
phone = validateInput(userDetails?.phone);
} else {
phone = true;
}
if (userDetails.Destination && userDetails.Company && phone) {
const payload = { sessionToken: localStorage.getItem("accesstoken") };
if (payload && payload.sessionToken) {
const params = {
userDetails: {
name: userDetails.name,
email: userDetails.email,
phone: userDetails?.phone || "",
role: "contracts_User",
company: userDetails.Company,
jobTitle: userDetails.Destination
}
};
try {
const userSignUp = await Parse.Cloud.run("usersignup", params);
if (userSignUp && userSignUp.sessionToken) {
const LocalUserDetails = params.userDetails;
localStorage.setItem(
"userDetails",
JSON.stringify(LocalUserDetails)
);
await thirdpartyLoginfn(userSignUp.sessionToken);
setIsLoader(false);
} else {
alert(userSignUp.message);
setIsLoader(false);
}
} catch (err) {
console.log("error in usersignup", err);
localStorage.removeItem("accesstoken");
alert(t("something-went-wrong-mssg"));
setIsLoader(false);
}
} catch (err) {
console.log("error in usersignup", err);
} else {
localStorage.removeItem("accesstoken");
alert(t("something-went-wrong-mssg"));
alert(t("server-error"));
setIsLoader(false);
}
} else {
localStorage.removeItem("accesstoken");
alert(t("server-error"));
alert(t("filed-required-correctly"));
setIsLoader(false);
}
} else {
alert(t("filed-required-correctly"));
setIsLoader(false);
}
};
// `thirdpartyLoginfn` is used to save necessary parameters locally for the logged-in user
@@ -763,7 +763,11 @@ const TemplatePlaceholder = () => {
IsEnableOTP: pdfDetails[0]?.IsEnableOTP === true ? true : false,
IsTourEnabled: pdfDetails[0]?.IsTourEnabled === true ? true : false,
URL: pdfUrl,
SignatureType: signatureType
SignatureType: signatureType,
NotifyOnSignatures:
pdfDetails[0]?.NotifyOnSignatures !== undefined
? pdfDetails[0]?.NotifyOnSignatures
: false
};
const updateTemplate = new Parse.Object("contracts_Template");
updateTemplate.id = templateId;
@@ -197,6 +197,7 @@ const AddContact = (props) => {
onChange={(e) => setPhone(e.target.value)}
disabled={addYourself}
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
placeholder={t("phone-optional")}
/>
</div>
+222 -90
View File
@@ -14,6 +14,7 @@ import {
checkIsSubscribed,
copytoData,
fetchUrl,
formatDate,
getSignedUrl,
getTenantDetails,
handleSignatureType,
@@ -81,6 +82,7 @@ const ReportTable = (props) => {
const [isEmbed, setIsEmbed] = useState(false);
const [isPublicTour, setIsPublicTour] = useState();
const [signatureType, setSignatureType] = useState([]);
const [expiryDate, setExpiryDate] = useState("");
const Extand_Class = localStorage.getItem("Extand_Class");
const extClass = Extand_Class && JSON.parse(Extand_Class);
const startIndex = (currentPage - 1) * props.docPerPage;
@@ -288,6 +290,10 @@ const ReportTable = (props) => {
updatedSignatureType.length > 0
? { SignatureType: updatedSignatureType }
: {};
const NotifyOnSignatures =
Doc.NotifyOnSignatures !== undefined
? { NotifyOnSignatures: Doc.NotifyOnSignatures }
: {};
let placeholdersArr = [];
if (Doc.Placeholders?.length > 0) {
placeholdersArr = Doc.Placeholders;
@@ -315,7 +321,8 @@ const ReportTable = (props) => {
RemindOnceInEvery: Doc?.RemindOnceInEvery || 5,
IsEnableOTP: Doc?.IsEnableOTP || false,
FileAdapterId: Doc?.FileAdapterId || "",
...SignatureType
...SignatureType,
...NotifyOnSignatures
};
try {
const res = await axios.post(
@@ -428,6 +435,8 @@ const ReportTable = (props) => {
} else {
setIsPublicTour({ [item.objectId]: true });
}
} else if (act.action) {
setIsModal({ [`extendexpiry_${item.objectId}`]: true });
}
};
// Get current list
@@ -658,15 +667,12 @@ const ReportTable = (props) => {
}
const closeTour = async () => {
// console.log("closeTour");
setIsTour(false);
if (props.isDontShow) {
const serverUrl = localStorage.getItem("baseUrl");
const appId = localStorage.getItem("parseAppId");
const json = JSON.parse(localStorage.getItem("Extand_Class"));
const extUserId = json && json.length > 0 && json[0].objectId;
// console.log("extUserId ", extUserId)
let updatedTourStatus = [];
if (tourStatusArr.length > 0) {
updatedTourStatus = [...tourStatusArr];
@@ -684,14 +690,8 @@ const ReportTable = (props) => {
await axios.put(
serverUrl + "classes/contracts_Users/" + extUserId,
{
TourStatus: updatedTourStatus
},
{
headers: {
"X-Parse-Application-Id": appId
}
}
{ TourStatus: updatedTourStatus },
{ headers: { "X-Parse-Application-Id": appId } }
);
}
};
@@ -1205,6 +1205,129 @@ const ReportTable = (props) => {
const closePublicTour = () => {
setIsPublicTour();
};
const handleUpdateExpiry = async (e, item) => {
e.preventDefault();
e.stopPropagation();
if (expiryDate) {
const oldExpiryDate = new Date(item?.ExpiryDate?.iso);
const newExpiryDate = new Date(expiryDate);
if (newExpiryDate > oldExpiryDate) {
setActLoader({ [`${item.objectId}`]: true });
const updateExpiryDate = new Date(expiryDate).toISOString();
const expiryIsoFormat = { iso: updateExpiryDate, __type: "Date" };
try {
const serverUrl = serverUrl_fn();
const cls = "contracts_Document";
const url = serverUrl + `/classes/${cls}/`;
const body = { ExpiryDate: expiryIsoFormat };
const res = await axios.put(url + item.objectId, body, {
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
});
if (res.data && res.data.updatedAt) {
setIsAlert(true);
setAlertMsg({
type: "success",
message: t("expiry-date-updated", {
newexpirydate: new Date(expiryDate)?.toLocaleDateString()
})
});
if (props.ReportName === "Expired Documents") {
const upldatedList = props.List.filter(
(x) => x.objectId !== item.objectId
);
props.setList(upldatedList);
}
}
} catch (err) {
console.log("err", err);
setIsAlert(true);
setAlertMsg({
type: "danger",
message: t("something-went-wrong-mssg")
});
} finally {
setActLoader({});
setExpiryDate();
setTimeout(() => setIsAlert(false), 2000);
setIsModal({});
}
} else {
setIsAlert(true);
setAlertMsg({ type: "danger", message: t("expiry-date-error") });
setTimeout(() => setIsAlert(false), 2000);
}
} else {
setIsAlert(true);
setAlertMsg({ type: "danger", message: t("expiry-date-error") });
setTimeout(() => setIsAlert(false), 2000);
}
};
// `formatStatusRow` is used to format status row
const formatStatusRow = (item) => {
const signers = item?.Placeholders?.map((x, i) => {
const matchSigner = item?.AuditTrail?.find(
(audit) => audit?.UserPtr?.objectId === x.signerObjId
);
if (matchSigner) {
return {
id: i,
Email: matchSigner.UserPtr.Email,
Activity: matchSigner?.Activity?.toUpperCase() || "-",
SignedOn: matchSigner?.SignedOn
? new Date(matchSigner?.SignedOn)?.toUTCString()
: "-",
ViewedOn: matchSigner?.ViewedOn
? new Date(matchSigner?.ViewedOn)?.toUTCString()
: "-"
};
} else {
return {
id: i,
Email: x?.signerPtr?.Email || x?.email,
Activity: "SENT",
SignedOn: "-",
ViewedOn: "-"
};
}
});
return signers?.map((x, i) => (
<div
key={i}
className="text-sm font-medium flex flex-row gap-2 items-center"
>
<button
onClick={() => setIsModal({ [`${item.objectId}_${i}`]: true })}
className={`${
x.Activity === "SIGNED"
? "op-border-primary op-text-primary"
: x.Activity === "VIEWED"
? "border-green-400 text-green-400"
: "border-black text-black"
} focus:outline-none border-2 w-[60px] h-[30px] text-[11px] rounded-full`}
>
{x?.Activity?.toUpperCase() || "-"}
</button>
<div className="py-2 font-bold text-[12px]">{x?.Email || "-"}</div>
{isModal[`${item.objectId}_${i}`] && (
<ModalUi
isOpen
title={t("document-logs")}
handleClose={() => setIsModal({})}
>
<div className="pl-3 first:mt-2 border-t-[1px] border-gray-600 text-[12px] py-2">
<p className="font-bold"> {x?.Email}</p>
<p>Viewed on: {x?.ViewedOn}</p>
<p>Signed on: {x?.SignedOn}</p>
</div>
</ModalUi>
)}
</div>
));
};
return (
<div className="relative">
{Object.keys(actLoader)?.length > 0 && (
@@ -1284,18 +1407,18 @@ const ReportTable = (props) => {
}`}
>
<table className="op-table border-collapse w-full mb-4">
<thead className="text-[14px]">
<thead className="text-[14px] text-center">
<tr className="border-y-[1px]">
{props.heading?.map((item, index) => (
<React.Fragment key={index}>
<th className="px-4 py-2">{t(`report-heading.${item}`)}</th>
<th className="p-2">{t(`report-heading.${item}`)}</th>
</React.Fragment>
))}
{props.ReportName === "Templates" && isEnableSubscription && (
<th className="px-4 py-2">{t("public")}</th>
<th className="p-2">{t("public")}</th>
)}
{props.actions?.length > 0 && (
<th className="px-4 py-2 text-transparent pointer-events-none">
<th className="p-2 text-transparent pointer-events-none">
{t("action")}
</th>
)}
@@ -1308,15 +1431,17 @@ const ReportTable = (props) => {
props.ReportName === "Contactbook" ? (
<tr className="border-y-[1px]" key={index}>
{props.heading.includes("Sr.No") && (
<th className="px-4 py-2">
{startIndex + index + 1}
</th>
<th className="p-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="p-2 text-center">
{item?.Email || "-"}
</td>
<td className="p-2 text-center">
{item?.Phone || "-"}
</td>
<td className="px-3 py-2">
<div className="text-base-content min-w-max flex flex-row gap-x-2 gap-y-1 justify-start items-center">
{props.actions?.length > 0 &&
@@ -1373,34 +1498,39 @@ const ReportTable = (props) => {
key={index}
>
{props.heading.includes("Sr.No") && (
<th className="px-4 py-2">
<th className="px-2 py-2">
{startIndex + index + 1}
</th>
)}
<td className="px-4 py-2 font-semibold min-w-56 max-w-56">
{item?.Name}{" "}
<td className="p-2 min-w-56 max-w-56 flex flex-col">
<div className="font-semibold">{item?.Name}</div>
{item?.ExpiryDate?.iso && (
<div className="text-gray-500">
Expire: {formatDate(item?.ExpiryDate?.iso)}
</div>
)}
</td>
{props?.heading?.includes("Reason") && (
<td className="px-4 py-2">
<td className="p-2 text-center">
{item?.DeclineReason?.length > 25
? item?.DeclineReason?.slice(0, 25) + "..."
: item?.DeclineReason || "-"}
</td>
)}
{props.heading.includes("Note") && (
<td className="px-4 py-2">
{item?.Note?.length > 25
? item?.Note?.slice(0, 25) + "..."
: item?.Note || "-"}
<td className="p-2 text-center">
<p className="truncate w-[100px]">
{item?.Note || "-"}
</p>
</td>
)}
{props.heading.includes("Folder") && (
<td className="px-4 py-2">
<td className="p-2 text-center">
{item?.Folder?.Name ||
t("sidebar.OpenSign™ Drive")}
</td>
)}
<td className="px-4 py-2">
<td className="p-2 text-center">
<button
onClick={() => handleDownload(item)}
className="op-link op-link-primary"
@@ -1409,73 +1539,40 @@ const ReportTable = (props) => {
{item?.URL ? t("download") : "-"}
</button>
</td>
{props.ReportName === "In-progress documents" ? (
<td className="px-4 py-2">
<button
onClick={() =>
item?.AuditTrail?.length > 0 &&
setIsModal({ [item?.objectId]: true })
}
className={`${
item?.AuditTrail?.length
? "border-green-400"
: "cursor-default op-border-primary"
} focus:outline-none w-[60px] border-[2px] text-[12px] rounded-full md:self-center`}
>
{item?.AuditTrail?.length ? "VIEWED" : "SENT"}
</button>
{isModal[item.objectId] && (
<ModalUi
isOpen
title={t("document-logs")}
handleClose={() => setIsModal({})}
>
{item?.AuditTrail?.map((x, i) => (
<div
key={i}
className="pl-3 first:mt-2 text-sm font-medium flex flex-col md:flex-row items-start md:gap-4 border-t-[1px] border-gray-600"
>
<div className="py-2 break-all font-bold md:text-[12px] md:col-span-2 w-full md:w-[210px]">
{x?.UserPtr?.Email || "-"}
</div>
<button className="px-2 cursor-default border-[2px] text-[12px] border-green-400 rounded-full md:self-center">
{x?.Activity?.toUpperCase() || "-"}
</button>
<div className=" text-[12px] py-2">
{x?.Activity === "Signed"
? new Date(x?.SignedOn)?.toUTCString()
: new Date(
x?.ViewedOn
)?.toUTCString() || "-"}
</div>
</div>
))}
</ModalUi>
)}
</td>
) : (
<td className="px-4 py-2">
{props.heading.includes("Owner") && (
<td className="p-2 text-center">
{formatRow(item?.ExtUserPtr)}
</td>
)}
<td className="px-4 py-2">
{!item?.IsSignyourself && item?.Placeholders ? (
<button
onClick={() => handleViewSigners(item)}
className="op-link op-link-primary"
>
{t("view")}
</button>
) : (
"-"
)}
</td>
{props.heading.includes("Signers") &&
["In-progress documents", "Need your sign"].includes(
props.ReportName
) ? (
<td className="px-1 py-2">
{!item?.IsSignyourself && item?.Placeholders && (
<>{formatStatusRow(item)}</>
)}
</td>
) : (
<td className="p-2 text-center">
{!item?.IsSignyourself && item?.Placeholders ? (
<button
onClick={() => handleViewSigners(item)}
className="op-link op-link-primary"
>
{t("view")}
</button>
) : (
"-"
)}
</td>
)}
{props.ReportName === "Templates" &&
isEnableSubscription && (
<td className=" pl-[20px] py-2">
{props.ReportName === "Templates" && (
<div
className="flex flex-row "
className="flex flex-row"
data-tut="IsPublic"
>
<label className="cursor-pointer relative inline-flex items-center mb-0">
@@ -1758,6 +1855,41 @@ const ReportTable = (props) => {
)
)}
</div>
{isModal["extendexpiry_" + item.objectId] && (
<ModalUi
isOpen
title={t("btnLabel.extend-expiry-date")}
reduceWidth={"md:max-w-[450px]"}
handleClose={() => setIsModal({})}
>
<form
className="px-4 py-2 flex flex-col"
onSubmit={(e) => handleUpdateExpiry(e, item)}
>
<label className="mr-2">
{t("expiry-date")} {"(dd-mm-yyyy)"}
</label>
<input
type="date"
className="rounded-full mb-2 bg-base-300 w-full px-4 py-2 text-black border-2 hover:border-spacing-2"
defaultValue={
item?.ExpiryDate?.iso?.split("T")?.[0]
}
onChange={(e) => {
setExpiryDate(e.target.value);
}}
/>
<div className="flex justify-start mb-1">
<button
type="submit"
className="op-btn op-btn-primary"
>
{t("update")}
</button>
</div>
</form>
</ModalUi>
)}
{isShareWith[item.objectId] && (
<div className="op-modal op-modal-open">
<div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative">
+74 -11
View File
@@ -5,6 +5,29 @@ import { useTranslation } from "react-i18next";
function CustomModal(props) {
const { t } = useTranslation();
const [reason, setReason] = useState("");
const [isExtendExpiry, setIsExtendExpiry] = useState(false);
const [expiryDate, setExpiryDate] = useState("");
const localuser = localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
);
const currentUser = JSON.parse(localuser);
const isCreator = props?.doc
? props?.doc?.CreatedBy?.objectId === currentUser?.objectId &&
localStorage.getItem("_user_role") !== "Guest"
: false;
const handleExtendBtn = () => setIsExtendExpiry(!isExtendExpiry);
const handleUpdateExpiry = async (e) => {
e.preventDefault();
e.stopPropagation();
if (expiryDate) {
props.handleExpiry && props.handleExpiry(expiryDate);
} else {
alert(t("expiry-date-error"));
}
};
return (
props.show && (
<dialog className="op-modal op-modal-open absolute z-[448]">
@@ -12,17 +35,29 @@ function CustomModal(props) {
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
{props?.headMsg && props?.headMsg}
</h3>
<div className="p-[10px] px-[20px]">
<p className="text-[15px]">{props.bodyMssg && props.bodyMssg}</p>
</div>
{props.isDownloadBtn && (
<div className="flex justify-start w-full ml-[20px] mb-3 mt-1">
<button
className="op-btn op-btn-primary "
onClick={() => props.handleDownloadBtn()}
>
Download
</button>
{!isExtendExpiry && (
<div className="p-[10px] px-[20px]">
<p className="text-[15px]">{props.bodyMssg && props.bodyMssg}</p>
</div>
)}
{!isExtendExpiry && (
<div className="flex flex-row items-center">
{isCreator && (
<button
className="op-btn op-btn-primary px-6 ml-[20px] mb-3 mt-1"
onClick={() => handleExtendBtn()}
>
Extend
</button>
)}
{props.isDownloadBtn && (
<button
className="op-btn op-btn-primary ml-[10px] mb-3 mt-1"
onClick={() => props.handleDownloadBtn()}
>
Download
</button>
)}
</div>
)}
{props.footerMessage && (
@@ -60,6 +95,34 @@ function CustomModal(props) {
</div>
</>
)}
{isExtendExpiry && (
<form className="mx-3 mb-3" onSubmit={handleUpdateExpiry}>
<label className="ml-2 mt-2">
{t("expiry-date")} {"(dd-mm-yyyy)"}
</label>
<input
type="date"
className="rounded-full bg-base-300 w-full px-4 py-2 text-black border-2 hover:border-spacing-2"
defaultValue={props?.doc?.ExpiryDate?.iso?.split("T")?.[0]}
onChange={(e) => setExpiryDate(e.target.value)}
/>
<div className="flex flex-row items-center mt-2">
<button type="submit" className="op-btn op-btn-primary mr-2">
{t("update")}
</button>
<button
type="button"
className="op-btn op-btn-secondary"
onClick={() => {
setExpiryDate("");
setIsExtendExpiry(false);
}}
>
{t("cancel")}
</button>
</div>
</form>
)}
</div>
</dialog>
)
+17 -2
View File
@@ -2,7 +2,7 @@ import React from "react";
import { Trans, useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
const QuotaCard = ({ isPaidInfo, handlClose }) => {
const QuotaCard = ({ isPaidInfo, handlClose, emailResetDate }) => {
const { t } = useTranslation();
const navigate = useNavigate();
return isPaidInfo ? (
@@ -17,6 +17,11 @@ const QuotaCard = ({ isPaidInfo, handlClose }) => {
<div className="op-card-body">
<h2 className="op-card-title">{t("quota-mail-info-head")}</h2>
<p>{t("quota-mail-info")}</p>
{emailResetDate && (
<p>
{t("quota-mail-reset")} {emailResetDate}
</p>
)}
<p>
<Trans i18nKey={"quota-mail-tip"}>
Tip: You can still sign <strong>unlimited documents</strong> by
@@ -39,7 +44,17 @@ const QuotaCard = ({ isPaidInfo, handlClose }) => {
<div className="op-card op-bg-primary text-primary-content w-full shadow-lg">
<div className="op-card-body">
<p>{t("quota-mail")}</p>
<p>{t("quota-mail-tip")}</p>
{emailResetDate && (
<p>
{t("quota-mail-reset")} {emailResetDate}
</p>
)}
<div>
<Trans i18nKey={"quota-mail-tip"}>
Tip: You can still sign <strong>unlimited documents</strong> by
manually sharing the signing request links.
</Trans>
</div>
<div className="op-card-actions justify-end">
<button
onClick={() => navigate("/subscription")}
@@ -1,5 +1,5 @@
{
"header-news": "New feature: Public profiles are now live! Easily create and share public templates",
"header-news": "New feature: Teams plan users can now integrate their own AWS S3 buckets for file storage",
"header-news-btn": "Setup Now",
"create-account": "Create Account",
"login": "Login",
@@ -134,7 +134,8 @@
"option": "Option",
"Embed": "Embed",
"Copy TemplateId": "Copy TemplateId",
"Copy Public URL": "Copy Public URL"
"Copy Public URL": "Copy Public URL",
"extend-expiry-date": "Extend expiry date"
},
"report-heading": {
"Sr.No": "Sr.No",
@@ -155,7 +156,8 @@
"Status": "Status",
"created-date": "Created Date",
"Type": "Type",
"Logs": "Logs"
"Logs": "Logs",
"Expiry-date": "Expiry Date"
},
"report-help": {
"Draft Documents": "These are documents you have started but have not finalized for sending.",
@@ -266,7 +268,8 @@
"make-template-public-alert": "Are you sure you want to make this template public?",
"make-template-private-alert": "Are you sure you want to make this template private? This will remove it from your public profile.",
"public-role": "Public role",
"public-url": "Public profile needed",
"public-url": "Public profile",
"embed-template": "Embed Template",
"public-url-copy": "Heres your public URL: ",
"public-url-copy-mssg": "Copy it or share it with the signer, and you will be able to see all your publicly set templates.",
"add-public-url-alert": "Please complete your OpenSign public profile setup. Once done, youll be able to make templates public. This process only needs to be completed once.",
@@ -512,7 +515,7 @@
"error": "Error",
"invalid-document": "Error: invalid document!",
"document-not-found": "Document not Found!",
"document-signed-alert-1": "You have successfully signed the document. You can download or print a copy of the partially signed document. A copy of the digitally signed document will be sent to the owner over email once it is signed by all signers.",
"document-signed-alert-1": "You have successfully signed the document. You can download or print a copy of the partially signed document. A copy of the digitally signed document & completion certificate will be sent to the owner & all signers over email once it is signed by all signers.",
"encrypted-pdf-not-support": "Currently encrypted pdf files are not supported.",
"document-signed-alert-4": " Congratulations! 🎉 This document has been successfully signed by all participants!",
"document-signed-alert-5": "This document has been signed by all Signers.",
@@ -652,6 +655,7 @@
"angular-npm-mssg-1": "To integrate OpenSign into your Angular project, simply run the following command:",
"quota-mail-info-head": "Monthly request signatures email limit",
"quota-mail-info": "You can send upto 15 signature request emails every month. Upgrade now to send unlimited signing requests directly.",
"quota-mail-reset": "Your signature request email credits will be reset on",
"quota-mail": "You've reached your limit of 15 signature request emails for this month. Upgrade now to continue sending emails directly.",
"quota-mail-tip": "Tip: You can still sign <1>unlimited documents</1> by manually sharing the signing request links.",
"quota-mail-head": "Quota Reached",
@@ -697,5 +701,13 @@
"l2": "Enter your name and choose from various font styles to create a signature.",
"l3": "Upload an existing digital version of your signature.",
"l4": "Use a pre-set signature style saved under 'My Signature' in your settings."
}
},
"notify-on-signatures": "Notify on signatures",
"notify-on-signatures-help": {
"p1": "The document creator will receive an email notification whenever a signer signs the document.",
"note": "Note: Notification email will not be sent for the last signer, as the document creator will receive a completion email instead."
},
"expiry-date":"Expiry date",
"expiry-date-updated": "The expiry date has been successfully extended to {{newexpirydate}}",
"expiry-date-error": "Please provide a new expiry date that is later than the current one"
}
@@ -1,5 +1,5 @@
{
"header-news": "Nueva funcionalidad: ¡Los perfiles públicos ahora están disponibles! Crea y comparte plantillas públicas fácilmente",
"header-news": "Nueva característica: los usuarios del plan Teams ahora pueden integrar sus propios depósitos de AWS S3 para el almacenamiento de archivos",
"header-news-btn": "Configurar ahora",
"create-account": "Crear cuenta",
"login": "Iniciar sesión",
@@ -134,7 +134,8 @@
"option": "Opción",
"Embed": "Incrustar",
"Copy TemplateId": "Copiar ID de plantilla",
"Copy Public URL": "Copiar URL pública"
"Copy Public URL": "Copiar URL pública",
"Expiry-date": "Date d'expiration"
},
"report-heading": {
"Sr.No": "Nº",
@@ -155,7 +156,8 @@
"Status": "Estado",
"created-date": "Fecha de creación",
"Type": "Tipo",
"Logs": "Registros"
"Logs": "Registros",
"Expiry-date": "Date d'expiration"
},
"report-help": {
"Draft Documents": "Estos son documentos que has iniciado pero no has finalizado para su envío.",
@@ -266,7 +268,8 @@
"make-template-public-alert": "¿En definitiva quieres convertir esta plantilla en pública?",
"make-template-private-alert": "¿En definitiva quieres convertir esta plantilla en privada? Esto lo removerá de tu perfil público.",
"public-role": "Rol público",
"public-url": "Se requiere perfil público",
"public-url": "Perfil publico",
"embed-template": "Insertar plantilla",
"public-url-copy": "Aquí está tu URL pública: ",
"public-url-copy-mssg": "Cópiala o compártela con el firmante y podrás ver todas tus plantillas públicas.",
"add-public-url-alert": "Por favor, completa la configuración de tu perfil público OpenSign. Una vez terminado, podrás crear plantillas públicas. Este proceso solo necesita ser completado una vez.",
@@ -512,7 +515,7 @@
"error": "Error",
"invalid-document": "Error: ¡Documento inválido!",
"document-not-found": "¡Documento no encontrado!",
"document-signed-alert-1": "Has firmado el documento exitosamente. Puedes descargar o imprimir una copia del documento parcialmente firmado. Una copia del documento firmado digitalmente será enviada al propietario mediante correo electrónico una vez haya sido firmado por todos los firmantes.",
"document-signed-alert-1": "Ha firmado exitosamente el documento. Puede descargar o imprimir una copia del documento parcialmente firmado. Se enviará una copia del documento firmado digitalmente y del certificado de finalización al propietario y a todos los firmantes por correo electrónico una vez que todos los firmantes lo hayan firmado.",
"encrypted-pdf-not-support": "Los archivos PDF encriptados no están soportados actualmente.",
"document-signed-alert-4": " ¡Felicitaciones! 🎉 ¡Este documento ha sido firmado exitosamente por todos los participantes!",
"document-signed-alert-5": "Este documento ha sido firmado por todos los firmantes.",
@@ -652,6 +655,7 @@
"angular-npm-mssg-1": "Para integrar OpenSign a tu proyecto Angular, simplemente ejecuta los siguientes comandos:",
"quota-mail-info-head": "Límite mensual de solicitudes de firma por correo",
"quota-mail-info": "Puedes enviar hasta 15 solicitudes de firma por correo cada mes. Mejora ahora para enviar solicitudes de firma sin límite.",
"quota-mail-reset": "Los créditos de tu correo electrónico de solicitud de firma se restablecerán el",
"quota-mail": "Has alcanzado tu límite de 15 solicitudes de firma por correo para este mes. Mejora ahora para continuar enviando correos.",
"quota-mail-tip": "Consejo: Todavía puedes solciitar la firma de <1>documentos ilimitados</1> compartiendo manualmente los enlaces de solicitud de firma.",
"quota-mail-head": "Cuota alcanzada",
@@ -697,5 +701,13 @@
"l2": "Ingrese su nombre y elija entre varios estilos de fuente para crear una firma.",
"l3": "Cargue una versión digital existente de su firma.",
"l4": "Utilice un estilo de firma preestablecido guardado en 'Mi firma' en su configuración."
}
},
"notify-on-signatures": "Notificar sobre firmas",
"notify-on-signatures-help": {
"p1": "El creador del documento recibirá una notificación por correo electrónico cada vez que un firmante firme el documento.",
"note": "Nota: No se enviará un correo electrónico de notificación al último firmante, ya que el creador del documento recibirá un correo electrónico de finalización."
},
"expiry-date": "Date d'expiration",
"expiry-date-updated": "La fecha de vencimiento se ha extendido con éxito hasta el {{newexpirydate}}",
"expiry-date-error": "Proporcione una nueva fecha de vencimiento que sea posterior a la actual"
}
@@ -1,5 +1,5 @@
{
"header-news": "Nouvelle fonctionnalité : les profils publics sont désormais en ligne ! Créez et partagez facilement des modèles publics",
"header-news": "Nouvelle fonctionnalité : les utilisateurs du forfait Teams peuvent désormais intégrer leurs propres compartiments AWS S3 pour le stockage de fichiers",
"header-news-btn": "Configurer maintenant",
"create-account": "Créer un compte",
"login": "Se Connecter",
@@ -138,7 +138,8 @@
"Status": "Statut",
"created-date": "Date de création",
"Type": "Saisir",
"Logs": "Journaux"
"Logs": "Journaux",
"Expiry-date": "Fecha de caducidad"
},
"btnLabel": {
"sign": "Signer",
@@ -154,7 +155,8 @@
"option": "Option",
"Embed": "Intégrer",
"Copy TemplateId": "Copier l'ID du modèle",
"Copy Public URL": "Copier l'URL publique"
"Copy Public URL": "Copier l'URL publique",
"extend-expiry-date": "Prolonger la date d'expiration"
},
"report-help": {
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
@@ -265,7 +267,8 @@
"make-template-public-alert": "Êtes-vous sûr de vouloir rendre ce modèle public ?",
"make-template-private-alert": "Êtes-vous sûr de vouloir rendre ce modèle privé ? Cela le supprimera de votre profil public.",
"public-role": "Rôle public",
"public-url": "Profil public requis",
"public-url": "Profil public",
"embed-template": "Intégrer le modèle",
"public-url-copy": "Voici votre URL publique : ",
"public-url-copy-mssg": "copiez-la ou partagez-le avec le signataire et vous pouvoir voir tous vos paramètres publics modèles.",
"add-public-url-alert": "Veuillez terminer la configuration de votre profil public OpenSign. Une fois cela fait, vous pourrez rendre les modèles publics. Ce processus ne doit être effectué quune seule fois.",
@@ -511,7 +514,7 @@
"error": "Erreur",
"invalid-document": "Erreur : document invalide !",
"document-not-found": "Document introuvable !",
"document-signed-alert-1": "Vous avez signé le document avec succès. Vous pouvez télécharger ou imprimer une copie du document partiellement signé. Une copie du document signé numériquement sera envoyée au propriétaire par e-mail une fois qu'il sera signé par tous les signataires.",
"document-signed-alert-1": "Vous avez signé le document avec succès. Vous pouvez télécharger ou imprimer une copie du document partiellement signé. Une copie du document signé numériquement et du certificat d'achèvement sera envoyée au propriétaire et à tous les signataires par e-mail une fois qu'il aura été signé par tous les signataires.",
"encrypted-pdf-not-support": "Les fichiers PDF actuellement cryptés ne sont pas pris en charge. ",
"document-signed-alert-4": "Toutes nos félicitations! 🎉 Ce document a été signé avec succès par tous les participants !",
"document-signed-alert-5": "Ce document a été signé par tous les signataires.",
@@ -651,6 +654,7 @@
"angular-npm-mssg-1": "Pour intégrer OpenSign dans votre projet Angular, exécutez simplement la commande suivante :",
"quota-mail-info-head": "Limite mensuelle d'e-mails de signatures de demandes",
"quota-mail-info": "Vous pouvez envoyer jusqu'à 15 e-mails de demande de signature chaque mois. Mettez à niveau maintenant pour envoyer directement des demandes de signature illimitées.",
"quota-mail-reset": "Les crédits de votre email de demande de signature seront réinitialisés le",
"quota-mail": "Vous avez atteint votre limite de 15 e-mails de demande de signature pour ce mois. Mettez à niveau maintenant pour continuer à envoyer des e-mails directement.",
"quota-mail-tip-tip": "Astuce : Vous pouvez toujours signer un nombre <1>illimité de documents</1> en partageant manuellement les liens de demande de signature.",
"quota-mail-head": "Quota atteint",
@@ -696,5 +700,13 @@
"l2": "Entrez votre nom et choisissez parmi différents styles de police pour créer une signature.",
"l3": "Téléchargez une version numérique existante de votre signature.",
"l4": "Utilisez un style de signature prédéfini enregistré sous 'Ma signature' dans vos paramètres."
}
},
"notify-on-signatures": "Notifier les signatures",
"notify-on-signatures-help": {
"p1": "Le créateur du document recevra une notification par e-mail chaque fois qu'un signataire signera le document.",
"note": "Remarque : L'e-mail de notification ne sera pas envoyé pour le dernier signataire, car le créateur du document recevra à la place un e-mail de fin."
},
"expiry-date": "Fecha de caducidad",
"expiry-date-updated": "La date d'expiration a été prolongée avec succès jusqu'au {{newexpirydate}}",
"expiry-date-error": "Veuillez fournir une nouvelle date d'expiration postérieure à la date actuelle"
}
@@ -0,0 +1,35 @@
The OpenSign Enterprise license (the “Enterprise License”)
Copyright (c) 2020-2024 Qik Innovations Private Limited.
With regard to the OpenSign Software:
This software and associated documentation files (the "Software") may only be
used in production, if you (and any entity that you represent) have agreed to,
and are in compliance with, the OpenSign Subscription Terms of Service(the “Enterprise Terms”), or other
agreement governing the use of the Software, as agreed by you and OpenSign,
and otherwise have a valid OpenSign Enterprise license for the
correct number of user seats. Subject to the foregoing sentence, you are free to
modify this Software and publish patches to the Software. You agree that OpenSign
and/or its licensors (as applicable) retain all right, title and interest in and
to all such modifications and/or patches, and all such modifications and/or
patches may only be used, copied, modified, displayed, distributed, or otherwise
exploited with a valid OpenSign Enterprise license for the correct
number of user seats. Notwithstanding the foregoing, you may copy and modify
the Software for development and testing purposes, without requiring a
subscription. You agree that OpenSign and/or its licensors (as applicable) retain
all right, title and interest in and to all such modifications. You are not
granted any other rights beyond what is expressly stated herein. Subject to the
foregoing, it is forbidden to copy, merge, publish, distribute, sublicense,
and/or sell the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
For all third party components incorporated into the OpenSign Software, those
components are licensed under the original license provided by the owner of the
applicable component.
@@ -29,7 +29,6 @@ import createFolder from './routes/createFolder.js';
import updateFolder from './routes/updateFolder.js';
import getFolderList from './routes/getFolderList.js';
import deleteFolder from './routes/deleteFolder.js';
import draftTemplate from './routes/draftTemplate.js';
dotenv.config();
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
@@ -74,9 +73,6 @@ app.delete('/document/:document_id', deleteDocument);
// get all types of documents on the basis of doctype
app.get('/documentlist/:doctype', getDocumentList);
// create draft template with file base64
app.post('/drafttemplate', draftTemplate);
// create Template with co-ordinate
app.post('/createtemplate', createTemplatewithCoordinate);
@@ -1,238 +0,0 @@
import axios from 'axios';
import {
color,
customAPIurl,
saveFileUsage,
formatWidgetOptions,
sanitizeFileName,
} from '../../../../Utils.js';
import uploadFileToS3 from '../../../parsefunction/uploadFiletoS3.js';
import jwt from 'jsonwebtoken';
const randomId = () => Math.floor(1000 + Math.random() * 9000);
export default async function draftTemplate(request, response) {
const name = request.body.title;
const note = request.body.note;
const description = request.body.description;
const signers = request.body.signers;
const folderId = request.body.folderId;
const base64File = request.body.file;
const fileData = request.files?.[0] ? request.files[0].buffer : null;
const SendinOrder = request.body.sendInOrder || true;
const isEnableOTP = request.body?.enableOTP === true ? true : false;
const isTourEnabled = request.body?.enableTour || false;
const isPublic = request.body?.isPublic;
const protocol = customAPIurl();
const baseUrl = new URL(process.env.PUBLIC_URL).origin;
try {
const reqToken = request.headers['x-api-token'];
if (!reqToken) {
return response.status(400).json({ error: 'Please Provide API Token' });
}
const tokenQuery = new Parse.Query('appToken');
tokenQuery.equalTo('token', reqToken);
tokenQuery.include('userId');
const token = await tokenQuery.first({ useMasterKey: true });
if (token !== undefined) {
// Valid Token then proceed request
const parseUser = JSON.parse(JSON.stringify(token));
const userPtr = {
__type: 'Pointer',
className: '_User',
objectId: parseUser.userId.objectId,
};
const contractsUser = new Parse.Query('contracts_Users');
contractsUser.equalTo('UserId', userPtr);
contractsUser.include('TenantId');
const extUser = await contractsUser.first({ useMasterKey: true });
const parseExtUser = JSON.parse(JSON.stringify(extUser));
let fileUrl;
if (request.files?.[0]) {
const base64 = fileData?.toString('base64');
const file = new Parse.File(request.files?.[0]?.originalname, {
base64: base64,
});
await file.save({ useMasterKey: true });
fileUrl = file.url();
const buffer = Buffer.from(base64, 'base64');
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
} else {
const filename = sanitizeFileName(`${name}.pdf`);
let adapter = {};
const ActiveFileAdapter = parseExtUser?.TenantId?.ActiveFileAdapter || '';
if (ActiveFileAdapter) {
adapter =
parseExtUser?.TenantId?.FileAdapters?.find(x => (x.id = ActiveFileAdapter)) || {};
}
if (adapter?.id) {
const filedata = Buffer.from(base64File, 'base64');
// `uploadFileToS3` is used to save document in user's file storage
fileUrl = await uploadFileToS3(filedata, filename, 'application/pdf', adapter);
} else {
const file = new Parse.File(filename, { base64: base64File }, 'application/pdf');
await file.save({ useMasterKey: true });
fileUrl = file.url();
}
const buffer = Buffer.from(base64File, 'base64');
saveFileUsage(buffer.length, fileUrl, parseUser.userId.objectId);
}
const extUserPtr = {
__type: 'Pointer',
className: 'contracts_Users',
objectId: extUser.id,
};
const object = new Parse.Object('contracts_Template');
object.set('Name', name);
if (note) {
object.set('Note', note);
}
if (description) {
object.set('Description', description);
}
if (SendinOrder) {
object.set('SendinOrder', SendinOrder);
}
object.set('URL', fileUrl);
object.set('CreatedBy', userPtr);
object.set('ExtUserPtr', extUserPtr);
object.set('IsEnableOTP', isEnableOTP);
object.set('IsTourEnabled', isTourEnabled);
const Public = isPublic !== undefined ? isPublic : false;
if (isPublic !== undefined) {
object.set('IsPublic', Public);
}
let contact = [];
if (signers && signers.length > 0) {
let parseSigners;
if (base64File) {
parseSigners = signers;
} else {
parseSigners = JSON.parse(signers);
}
let createContactUrl = protocol + '/v1/createcontact';
for (const [index, element] of parseSigners.entries()) {
if (element?.name && element?.email) {
const body = {
name: element?.name,
email: element?.email,
phone: element?.phone || '',
};
try {
const res = await axios.post(createContactUrl, body, {
headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
});
// console.log('res ', res.data);
const contactPtr = {
__type: 'Pointer',
className: 'contracts_Contactbook',
objectId: res.data?.objectId,
};
const newObj = { ...element, contactPtr: contactPtr, index: index };
contact.push(newObj);
} catch (err) {
// console.log('err ', err.response);
if (err?.response?.data?.objectId) {
const contactPtr = {
__type: 'Pointer',
className: 'contracts_Contactbook',
objectId: err.response.data?.objectId,
};
const newObj = { ...element, contactPtr: contactPtr, index: index };
contact.push(newObj);
}
}
} else {
const newObj = { ...element, contactPtr: {}, index: index };
contact.push(newObj);
}
}
const updatedSigners = contact?.filter(x => x.contactPtr && x.contactPtr.objectId);
if (updatedSigners && updatedSigners.length > 0) {
object.set(
'Signers',
updatedSigners?.map(x => x.contactPtr)
);
}
let updatePlaceholders = [];
for (const signer of contact) {
const placeHolder = [];
if (signer.widgets?.length > 0) {
for (const widget of signer.widgets) {
const pageNumber = widget.page;
const page = placeHolder.find(page => page.pageNumber === pageNumber);
const options = formatWidgetOptions(widget.type, widget.options);
const widgetData = {
isStamp: widget.type === 'stamp' || widget.type === 'image',
key: randomId(),
isDrag: false,
scale: 1,
isMobile: false,
zIndex: 1,
type: widget.type === 'textbox' ? 'text input' : widget.type,
options: options,
Width: widget.w,
Height: widget.h,
xPosition: widget.x,
yPosition: widget.y,
};
if (page) {
page.pos.push(widgetData);
} else {
placeHolder.push({ pageNumber, pos: [widgetData] });
}
}
}
updatePlaceholders.push({
signerObjId: signer?.contactPtr?.objectId || '',
signerPtr: signer?.contactPtr,
Role: signer.role,
Id: randomId(),
blockColor: color[signer?.index],
placeHolder,
});
}
if (updatePlaceholders?.length > 0) {
object.set('Placeholders', updatePlaceholders);
}
}
if (folderId) {
object.set('Folder', {
__type: 'Pointer',
className: 'contracts_Template',
objectId: folderId,
});
}
if (parseExtUser?.TenantId?.ActiveFileAdapter) {
object.set('FileAdapterId', parseExtUser?.TenantId?.ActiveFileAdapter);
}
const newACL = new Parse.ACL();
newACL.setPublicReadAccess(false);
newACL.setPublicWriteAccess(false);
newACL.setReadAccess(userPtr.objectId, true);
newACL.setWriteAccess(userPtr.objectId, true);
object.setACL(newACL);
const res = await object.save(null, { useMasterKey: true });
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_draft_template',
properties: { response_code: 200 },
});
}
const JwtToken = jwt.sign(
{ user_email: parseUser.userId.email, template_id: res.id },
reqToken
);
return response.json({ objectId: res.id, url: `${baseUrl}/drafttemplate/${JwtToken}` });
} else {
return response.status(405).json({ error: 'Invalid API Token!' });
}
} catch (err) {
console.log('err ', err);
return response.status(400).json({ error: 'Something went wrong, please try again later!' });
}
}
+2
View File
@@ -84,6 +84,7 @@ import updateTourStatus from './parsefunction/updateTourStatus.js';
import saveTemplate from './parsefunction/saveTemplate.js';
import updateToPublicTemplate from './parsefunction/updateToPublicTemplate.js';
import updateSignatureType from './parsefunction/updatesignaturetype.js';
import updatePreferences from './parsefunction/updatePreferences.js';
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
@@ -180,3 +181,4 @@ Parse.Cloud.define('isuserincontactbook', isUserInContactBook);
Parse.Cloud.define('updatetourstatus', updateTourStatus);
Parse.Cloud.define('updatetopublictemplate', updateToPublicTemplate);
Parse.Cloud.define('updatesignaturetype', updateSignatureType);
Parse.Cloud.define('updatepreferences', updatePreferences);
@@ -74,6 +74,9 @@ const createDocumentFromTemplate = async (template, existContact, index) => {
if (template?.SignatureType?.length > 0) {
object.set('SignatureType', template?.SignatureType);
}
if (template?.NotifyOnSignatures) {
object.set('NotifyOnSignatures', template?.NotifyOnSignatures);
}
let signers = template?.Signers || [];
const signerobj = {
__type: 'Pointer',
@@ -252,6 +252,7 @@ async function batchQuery(userId, Documents, Ip, parseConfig) {
IsTourEnabled: x?.IsTourEnabled || false,
FileAdapterId: x?.FileAdapterId || '',
...(x?.SignatureType ? { SignatureType: x?.SignatureType } : {}),
...(x?.NotifyOnSignatures ? { NotifyOnSignatures: x?.NotifyOnSignatures } : {}),
},
};
});
@@ -8,7 +8,7 @@ export default function getPresignedUrl(url, adapter) {
AWS.config.update({ credentials: credentials, region: adapter?.region || process.env.DO_REGION });
const spacesEndpoint = adapter?.endpoint || new AWS.Endpoint(process.env.DO_ENDPOINT);
const s3 = new AWS.S3({ endpoint: spacesEndpoint });
const s3 = new AWS.S3({ endpoint: spacesEndpoint, signatureVersion: "v4" });
// Create a new URL object
const parsedUrl = new URL(url);
@@ -458,17 +458,17 @@ export default async function GenerateCertificate(docDetails) {
});
currentPage.drawText('Viewed on :', {
x: half,
x: half + 55,
y: yPosition2,
size: text,
size: timeText,
font: timesRomanFont,
color: textKeyColor,
});
currentPage.drawText(`${new Date(x.ViewedOn).toUTCString()}`, {
x: half + 75,
x: half + 112,
y: yPosition2,
size: text,
size: timeText,
font: timesRomanFont,
color: textValueColor,
});
@@ -490,17 +490,17 @@ export default async function GenerateCertificate(docDetails) {
});
currentPage.drawText('Signed on :', {
x: half,
y: yPosition3,
size: text,
x: half + 55,
y: yPosition3 + 5,
size: timeText,
font: timesRomanFont,
color: textKeyColor,
});
currentPage.drawText(`${new Date(x.SignedOn).toUTCString()}`, {
x: half + 70,
y: yPosition3,
size: text,
x: half + 108,
y: yPosition3 + 5,
size: timeText,
font: timesRomanFont,
color: textValueColor,
});
@@ -520,22 +520,23 @@ export default async function GenerateCertificate(docDetails) {
font: timesRomanFont,
color: textValueColor,
});
currentPage.drawText('Security level :', {
x: half,
y: yPosition4,
size: text,
font: timesRomanFont,
color: textKeyColor,
});
currentPage.drawText(`Email, OTP Auth`, {
x: half + 90,
y: yPosition4,
size: text,
font: timesRomanFont,
color: textValueColor,
});
if (IsEnableOTP) {
currentPage.drawText('Security level :', {
x: half + 55,
y: yPosition4 + 10,
size: timeText,
font: timesRomanFont,
color: textKeyColor,
});
currentPage.drawText(`Email, OTP Auth`, {
x: half + 125,
y: yPosition4 + 10,
size: timeText,
font: timesRomanFont,
color: textValueColor,
});
}
currentPage.drawText('Signature :', {
x: 30,
y: yPosition5,
@@ -95,6 +95,53 @@ async function updateDoc(docId, url, userId, ipAddress, data, className, sign) {
}
}
// `sendNotifyMail` is used to send notification mail of signer signed the document
async function sendNotifyMail(doc, signUser, mailProvider) {
try {
const auditTrailCount = doc?.AuditTrail?.filter(x => x.Activity === 'Signed')?.length || 0;
const signersCount = doc?.Placeholders?.length;
const remaingsign = signersCount - auditTrailCount;
if (remaingsign > 1 && doc?.NotifyOnSignatures) {
const sender = doc.ExtUserPtr;
const pdfName = doc.Name;
const creatorName = doc.ExtUserPtr.Name;
const creatorEmail = doc.ExtUserPtr.Email;
const signerName = signUser.Name;
const signerEmail = signUser.Email;
const mailLogo = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
const viewDocUrl = `${process.env.PUBLIC_URL}/recipientSignPdf/${doc.objectId}`;
const subject = `Document "${pdfName}" has been signed by ${signerName}`;
const body =
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='box-shadow:rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'>" +
`<div><img src=${mailLogo} height='50' style='padding:20px' /></div><div style='padding:2px;font-family:system-ui;background-color:#47a3ad;'>` +
`<p style='font-size:20px;font-weight:400;color:white;padding-left:20px'>Document signed by ${signerName}</p>` +
`</div><div style='padding:20px;font-family:system-ui;font-size:14px'><p>Dear ${creatorName},</p>` +
`<p>${pdfName} has been signed by ${signerName} "${signerEmail}" successfully</p>` +
`<p><a href=${viewDocUrl} target=_blank>View Document</a></p>` +
`</div></div><div><p>This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender ${creatorEmail} directly. If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>`;
const params = {
extUserId: sender.objectId,
from: 'OpenSign™',
recipient: creatorEmail,
subject: subject,
pdfName: pdfName,
html: body,
mailProvider: mailProvider,
};
await axios.post(serverUrl + '/functions/sendmailv3', params, {
headers: {
'Content-Type': 'application/json',
'X-Parse-Application-Id': APPID,
'X-Parse-Master-Key': masterKEY,
},
});
}
} catch (err) {
console.log('err in sendnotifymail', err);
}
}
// `sendCompletedMail` is used to send copy of completed document mail
async function sendCompletedMail(obj) {
const url = obj.doc?.SignedUrl;
@@ -384,6 +431,7 @@ async function PDF(req) {
isCompleted = true;
}
const randomNumber = Math.floor(Math.random() * 5000);
// below regex is used to replace all word with "_" except A to Z, a to z, numbers
const docName = _resDoc?.Name?.replace(/[^a-zA-Z0-9._-]/g, '_')?.toLowerCase();
const name = `signed_${docName}_${randomNumber}.pdf`;
const filePath = `./exports/${name}`;
@@ -446,6 +494,7 @@ async function PDF(req) {
sign // sign base64
);
sendDoctoWebhook(_resDoc, data.imageUrl, 'signed', signUser);
sendNotifyMail(_resDoc, signUser, mailProvider);
saveFileUsage(pdfSize, data.imageUrl, _resDoc?.CreatedBy?.objectId);
if (updatedDoc && updatedDoc.isCompleted) {
const doc = { ..._resDoc, AuditTrail: updatedDoc.AuditTrail, SignedUrl: data.imageUrl };
@@ -76,6 +76,7 @@ export default function reportJson(id, userId) {
'Placeholders',
'SignedUrl',
'FileAdapterId',
'ExpiryDate',
],
};
// In progess report
@@ -211,6 +212,7 @@ export default function reportJson(id, userId) {
'Placeholders',
'SignedUrl',
'FileAdapterId',
'ExpiryDate',
],
};
// Recently sent for signatures report show on dashboard
@@ -292,6 +294,7 @@ export default function reportJson(id, userId) {
'Placeholders',
'SignedUrl',
'FileAdapterId',
'ExpiryDate',
],
};
// Drafts report show on dashboard
@@ -362,6 +365,8 @@ export default function reportJson(id, userId) {
'SharedWith.Name',
'SendinOrder',
'FileAdapterId',
'SignatureType',
'NotifyOnSignatures',
],
};
default:
@@ -37,7 +37,8 @@ const makeEmail = async (to, from, subject, html, url, pdfName) => {
let Pdf = fs.createWriteStream('test.pdf');
const writeToLocalDisk = () => {
return new Promise((resolve, reject) => {
const isSecure = new URL(url)?.protocol === 'https:';
const isSecure =
new URL(url)?.protocol === 'https:' && new URL(url)?.hostname !== 'localhost';
if (useLocal !== 'true' || isSecure) {
https.get(url, async function (response) {
response.pipe(Pdf);
@@ -33,7 +33,9 @@ async function sendMailProvider(req, plan, monthchange) {
let Pdf = fs.createWriteStream('test.pdf');
const writeToLocalDisk = () => {
return new Promise((resolve, reject) => {
const isSecure = new URL(req.params.url)?.protocol === 'https:';
const isSecure =
new URL(req.params.url)?.protocol === 'https:' &&
new URL(req.params.url)?.hostname !== 'localhost';
if (useLocal !== 'true' || isSecure) {
https.get(req.params.url, async function (response) {
response.pipe(Pdf);
@@ -200,7 +202,9 @@ async function sendcustomsmtp(extRes, req) {
let Pdf = fs.createWriteStream('test.pdf');
const writeToLocalDisk = () => {
return new Promise((resolve, reject) => {
const isSecure = new URL(req.params.url)?.protocol === 'https:';
const isSecure =
new URL(req.params.url)?.protocol === 'https:' &&
new URL(req.params.url)?.hostname !== 'localhost';
if (useLocal !== 'true' || isSecure) {
https.get(req.params.url, async function (response) {
response.pipe(Pdf);
@@ -0,0 +1,58 @@
export default async function updatePreferences(request) {
if (!request?.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
}
const SignatureType = request.params.SignatureType || [];
const NotifyOnSignatures = request.params.NotifyOnSignatures;
if (SignatureType?.length > 0 || NotifyOnSignatures !== undefined) {
try {
const orgQuery = new Parse.Query('contracts_Users');
orgQuery.equalTo('UserId', {
__type: 'Pointer',
className: '_User',
objectId: request.user.id,
});
const resUser = await orgQuery.first({ useMasterKey: true });
if (resUser) {
const newOrg = new Parse.Object('contracts_Users');
newOrg.id = resUser.id;
if (NotifyOnSignatures !== undefined) {
newOrg.set('NotifyOnSignatures', NotifyOnSignatures);
}
if (SignatureType.length > 0) {
const enabledSignTypes = SignatureType?.filter(x => x.enabled);
const isDefaultSignTypeOnly =
enabledSignTypes?.length === 1 && enabledSignTypes[0]?.name === 'default';
if (enabledSignTypes.length === 0) {
throw new Parse.Error(
Parse.Error.INVALID_QUERY,
'At least one signature type should be enabled.'
);
} else if (isDefaultSignTypeOnly) {
throw new Parse.Error(
Parse.Error.INVALID_QUERY,
'At least one signature type other than the default should be enabled.'
);
} else {
newOrg.set('SignatureType', SignatureType);
}
}
const updateUserRes = await newOrg.save(null, { useMasterKey: true });
if (updateUserRes) {
const _updateUserRes = JSON.parse(JSON.stringify(updateUserRes));
return _updateUserRes;
}
} else {
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Premission denied.');
}
} catch (err) {
console.log('err in addorganization', err);
const code = err?.code || 400;
const msg = err?.message || 'Something went wrong.';
throw new Parse.Error(code, msg);
}
} else {
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Please provide parameters.');
}
}
@@ -14,6 +14,7 @@ async function uploadFileToS3(buffer, fileName, mimeType, adapter) {
client = new S3Client({
region: adapter?.region,
credentials: { accessKeyId: adapter?.accessKeyId, secretAccessKey: adapter?.secretAccessKey },
signatureVersion: 'v4'
});
}
const prefixId = crypto.randomBytes(16).toString('hex');
@@ -0,0 +1,35 @@
/**
*
* @param {Parse} Parse
*/
exports.up = async Parse => {
const docSchema = new Parse.Schema('contracts_Document');
docSchema.addBoolean('NotifyOnSignatures');
await docSchema.update();
const templateSchema = new Parse.Schema('contracts_Template');
templateSchema.addBoolean('NotifyOnSignatures');
await templateSchema.update();
const extUserSchema = new Parse.Schema('contracts_Users');
extUserSchema.addBoolean('NotifyOnSignatures');
return extUserSchema.update();
};
/**
*
* @param {Parse} Parse
*/
exports.down = async Parse => {
const docSchema = new Parse.Schema('contracts_Document');
docSchema.deleteField('NotifyOnSignatures');
await docSchema.update();
const templateSchema = new Parse.Schema('contracts_Template');
templateSchema.deleteField('NotifyOnSignatures');
await templateSchema.update();
const extUserSchema = new Parse.Schema('contracts_Users');
docSchema.deleteField('NotifyOnSignatures');
return extUserSchema.update();
};
+634 -722
View File
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -18,16 +18,16 @@
"watch": "nodemon index.js"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.685.0",
"@aws-sdk/s3-request-presigner": "^3.688.0",
"@aws-sdk/client-s3": "^3.699.0",
"@aws-sdk/s3-request-presigner": "^3.700.0",
"@parse/fs-files-adapter": "^3.0.0",
"@parse/s3-files-adapter": "^3.0.0",
"@pdf-lib/fontkit": "^1.1.1",
"@signpdf/placeholder-pdf-lib": "^3.2.4",
"@signpdf/signer-p12": "^3.2.4",
"@signpdf/signpdf": "^3.2.4",
"aws-sdk": "^2.1691.0",
"axios": "^1.7.7",
"aws-sdk": "^2.1692.0",
"axios": "^1.7.9",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.21.1",
@@ -35,7 +35,7 @@
"generate-api-key": "^1.0.2",
"googleapis": "^144.0.0",
"mailgun.js": "^10.2.3",
"mongoose": "^8.8.0",
"mongoose": "^8.8.4",
"multer": "^1.4.5-lts.1",
"multer-s3": "^3.0.1",
"node-forge": "^1.3.1",
@@ -45,7 +45,7 @@
"parse-server": "^7.3.0",
"parse-server-api-mail-adapter": "^4.1.0",
"pdf-lib": "^1.17.1",
"posthog-node": "^4.2.1",
"posthog-node": "^4.2.3",
"ws": "^8.18.0"
},
"type": "module",