Compare commits

...
305 Commits
Author SHA1 Message Date
AmolandGitHub 4f417ccf0f Merge pull request #452 from OpenSignLabs/fix_filename_form 2024-02-28 18:26:44 +05:30
prafull-opensignlabsandGitHub 780c3f5f6d fix: file name is not visible in form for local development 2024-02-28 18:22:14 +05:30
AmolandGitHub 58cd0495e6 Merge pull request #434 from OpenSignLabs/prafull-opensignlabs-patch-2
Update Dockerhubfile
2024-02-23 16:04:15 +05:30
prafull-opensignlabsandGitHub 6b9b2afbef Update Dockerhubfile 2024-02-23 16:03:48 +05:30
AmolandGitHub c55a8d09a2 Merge pull request #433 from OpenSignLabs/prafull-opensignlabs-patch-11
Update Dockerhubfile
2024-02-23 15:36:27 +05:30
prafull-opensignlabsandGitHub 71b06f92ec Update Dockerhubfile 2024-02-23 15:36:11 +05:30
AmolandGitHub 692ec8ecbf Merge pull request #432 from OpenSignLabs/revert-431-fix_server_route
Revert "fix: mount server app on /api for local development"
2024-02-23 14:31:14 +05:30
AmolandGitHub 523ea7f314 Revert "fix: mount server app on /api for local development" 2024-02-23 14:31:00 +05:30
AmolandGitHub f48444f21d Merge pull request #431 from OpenSignLabs/fix_server_route 2024-02-23 12:37:31 +05:30
prafull-opensignlabs b4c5b3cbe6 fix: mount server app on /api for local development 2024-02-23 12:34:24 +05:30
AndrewandGitHub ed88ae013d Merge pull request #429 from OpenSignLabs/prafull-opensignlabs-patch-9 2024-02-23 11:02:30 +05:30
prafull-opensignlabsandGitHub 564f57b879 Update Dockerfile 2024-02-22 20:19:35 +05:30
prafull-opensignlabsandGitHub a47dc8e767 Update Dockerfile 2024-02-22 20:19:17 +05:30
prafull-opensignlabsandGitHub 41e192acb0 Update Dockerhubfile 2024-02-22 20:18:59 +05:30
prafull-opensignlabsandGitHub ff4fb191b8 Update Dockerhubfile 2024-02-22 20:18:42 +05:30
AndrewandGitHub 2feee80168 Merge pull request #428 from OpenSignLabs/prafull-opensignlabs-patch-9 2024-02-22 20:15:49 +05:30
prafull-opensignlabsandGitHub 59fed8a9cc Update Dockerhubfile 2024-02-22 20:15:02 +05:30
AndrewandGitHub 7cfca0a650 Merge pull request #427 from OpenSignLabs/prafull-opensignlabs-patch-9 2024-02-22 20:12:39 +05:30
prafull-opensignlabsandGitHub 6f1a5fd3a9 Update package.json 2024-02-22 20:11:49 +05:30
prafull-opensignlabsandGitHub cd6869778a Update package.json 2024-02-22 20:11:18 +05:30
AndrewandGitHub 2e8d84430e Merge pull request #426 from OpenSignLabs/prafull-opensignlabs-patch-9 2024-02-22 20:08:32 +05:30
prafull-opensignlabsandGitHub b8f32a6d8d Update Dockerhubfile 2024-02-22 20:08:10 +05:30
prafull-opensignlabsandGitHub 11ab37baf1 Update package.json 2024-02-22 20:05:47 +05:30
AndrewandGitHub 9dbde43a44 Merge pull request #425 from OpenSignLabs/prafull-opensignlabs-patch-8 2024-02-22 19:43:53 +05:30
prafull-opensignlabsandGitHub 2a24d71ee3 Update Dockerhubfile 2024-02-22 19:43:23 +05:30
prafull-opensignlabsandGitHub 134444c20a chore: add build command for docker-hub 2024-02-22 19:40:52 +05:30
AndrewandGitHub 44b87f178e Merge pull request #423 from OpenSignLabs/prafull-opensignlabs-patch-6 2024-02-22 18:49:32 +05:30
AndrewandGitHub 666636d554 Merge pull request #424 from OpenSignLabs/prafull-opensignlabs-patch-7 2024-02-22 18:49:20 +05:30
prafull-opensignlabsandGitHub 5ec9d59382 Update Dockerhubfile 2024-02-22 18:48:36 +05:30
prafull-opensignlabsandGitHub addc7622ab Create Dockerhubfile 2024-02-22 18:46:43 +05:30
prafull-opensignlabsandGitHub 1c7c3a4777 Create Dockerhubfile 2024-02-22 18:44:07 +05:30
prafull-opensignlabsandGitHub 2a46b02487 Update Docker.yml 2024-02-22 18:40:21 +05:30
AndrewandGitHub 5974515362 Merge pull request #422 from OpenSignLabs/prafull-opensignlabs-patch-5 2024-02-22 18:31:43 +05:30
prafull-opensignlabsandGitHub 3fab1d9c6f Update Docker.yml 2024-02-22 18:30:57 +05:30
AndrewandGitHub a283f2ee5d Merge pull request #418 from OpenSignLabs/prafull-opensignlabs-patch-2 2024-02-22 18:25:07 +05:30
AmolandGitHub 934823fad4 Merge pull request #419 from OpenSignLabs/prafull-opensignlabs-patch-2-1 2024-02-22 18:24:43 +05:30
AmolandGitHub 351ed795ca Merge pull request #420 from OpenSignLabs/prafull-opensignlabs-patch-3 2024-02-22 18:24:32 +05:30
prafull-opensignlabsandGitHub a335d02156 Update Docker.yml 2024-02-22 18:23:55 +05:30
prafull-opensignlabsandGitHub 8ad396d3ba Update INSTALLATION.md 2024-02-22 17:36:45 +05:30
prafull-opensignlabsandGitHub 26b54f0c00 Update INSTALLATION.md 2024-02-22 17:32:15 +05:30
prafull-opensignlabsandGitHub de5b58fff6 Update .env.local_dev 2024-02-22 17:27:54 +05:30
prafull-opensignlabsandGitHub b9b329dde4 Merge pull request #388 from OpenSignLabs/dependabot/npm_and_yarn/microfrontends/SignDocuments/react-pdf/renderer-3.3.8
build(deps): bump @react-pdf/renderer from 3.1.12 to 3.3.8 in /microfrontends/SignDocuments
2024-02-22 15:38:30 +05:30
prafull-opensignlabsandGitHub 2581500307 Merge pull request #405 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/mongoose-8.1.3
build(deps): bump mongoose from 7.2.1 to 8.1.3 in /apps/OpenSignServer
2024-02-22 15:36:57 +05:30
prafull-opensignlabsandGitHub ef5c20a9f2 Merge pull request #389 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/lint-staged-15.2.2
build(deps-dev): bump lint-staged from 15.0.1 to 15.2.2 in /apps/OpenSign
2024-02-22 15:33:39 +05:30
AmolandGitHub 01aee7c028 Merge pull request #417 from OpenSignLabs/remove_openai 2024-02-22 15:31:32 +05:30
prafull-opensignlabs 569c7f4b48 refactor: update jwt-decode package 2024-02-22 15:30:33 +05:30
prafull-opensignlabsandGitHub bb849f175c Merge pull request #358 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/babel/runtime-corejs2-7.23.9
build(deps-dev): bump @babel/runtime-corejs2 from 7.23.2 to 7.23.9 in /apps/OpenSign
2024-02-22 15:13:50 +05:30
prafull-opensignlabsandGitHub ede0eea944 Merge pull request #291 from OpenSignLabs/dependabot/npm_and_yarn/microfrontends/SignDocuments/npm_and_yarn-security-group-d4599f4155
chore(deps): bump the npm_and_yarn group group in /microfrontends/SignDocuments with 1 update
2024-02-22 15:12:01 +05:30
prafull-opensignlabsandGitHub 47150cca41 Merge pull request #361 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSignServer/axios-1.6.7
build(deps): bump axios from 1.3.5 to 1.6.7 in /apps/OpenSignServer
2024-02-22 15:08:08 +05:30
dependabot[bot]andGitHub 86df98a6a4 build(deps): bump axios from 1.3.5 to 1.6.7 in /apps/OpenSignServer
Bumps [axios](https://github.com/axios/axios) from 1.3.5 to 1.6.7.
- [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.3.5...v1.6.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-22 09:32:54 +00:00
dependabot[bot]andGitHub 8dd5e90f8b build(deps): bump mongoose from 7.2.1 to 8.1.3 in /apps/OpenSignServer
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.2.1 to 8.1.3.
- [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/7.2.1...8.1.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-22 09:32:40 +00:00
prafull-opensignlabsandGitHub f31023e2ed Merge pull request #415 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/npm_and_yarn-security-group-abd453e921
build(deps): bump the npm_and_yarn group across 3 directories with 9 updates
2024-02-22 15:01:52 +05:30
dependabot[bot]andGitHub 740d2e5a6c build(deps): bump the npm_and_yarn group across 3 directories with 9 updates
Bumps the npm_and_yarn group with 4 updates in the /apps/OpenSign directory: [axios](https://github.com/axios/axios), [parse](https://github.com/parse-community/Parse-SDK-JS), [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) and [follow-redirects](https://github.com/follow-redirects/follow-redirects).
Bumps the npm_and_yarn group with 7 updates in the /apps/OpenSignServer directory:

| Package | From | To |
| --- | --- | --- |
| [axios](https://github.com/axios/axios) | `1.3.5` | `1.6.0` |
| [parse](https://github.com/parse-community/Parse-SDK-JS) | `4.1.0` | `4.3.1` |
| [semver](https://github.com/npm/node-semver) | `5.7.1` | `5.7.2` |
| [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) | `7.21.5` | `7.23.9` |
| [minimist](https://github.com/minimistjs/minimist) | `0.0.8` | `1.2.8` |
| [mongodb-runner](https://github.com/mongodb-js/devtools-shared) | `4.10.0` | `5.5.3` |
| [word-wrap](https://github.com/jonschlinkert/word-wrap) | `1.2.3` | `1.2.5` |
Bumps the npm_and_yarn group with 3 updates in the /microfrontends/SignDocuments directory: [axios](https://github.com/axios/axios), [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) and [follow-redirects](https://github.com/follow-redirects/follow-redirects).


Updates `axios` from 1.5.1 to 1.6.0
- [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.5.1...v1.6.0)

Updates `parse` from 4.2.0 to 4.3.1
- [Release notes](https://github.com/parse-community/Parse-SDK-JS/releases)
- [Changelog](https://github.com/parse-community/Parse-SDK-JS/blob/alpha/CHANGELOG.md)
- [Commits](https://github.com/parse-community/Parse-SDK-JS/compare/4.2.0...4.3.1)

Updates `@babel/traverse` from 7.23.0 to 7.23.9
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.9/packages/babel-traverse)

Updates `crypto-js` from 4.1.1 to 4.2.0
- [Commits](https://github.com/brix/crypto-js/compare/4.1.1...4.2.0)

Updates `follow-redirects` from 1.15.3 to 1.15.5
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.5)

Updates `axios` from 1.3.5 to 1.6.0
- [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.5.1...v1.6.0)

Updates `parse` from 4.1.0 to 4.3.1
- [Release notes](https://github.com/parse-community/Parse-SDK-JS/releases)
- [Changelog](https://github.com/parse-community/Parse-SDK-JS/blob/alpha/CHANGELOG.md)
- [Commits](https://github.com/parse-community/Parse-SDK-JS/compare/4.2.0...4.3.1)

Updates `semver` from 5.7.1 to 5.7.2
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

Updates `@babel/traverse` from 7.21.5 to 7.23.9
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.9/packages/babel-traverse)

Updates `minimist` from 0.0.8 to 1.2.8
- [Changelog](https://github.com/minimistjs/minimist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/minimistjs/minimist/compare/v0.0.8...v1.2.8)

Updates `mongodb-runner` from 4.10.0 to 5.5.3
- [Commits](https://github.com/mongodb-js/devtools-shared/commits/mongodb-runner@5.5.3)

Updates `word-wrap` from 1.2.3 to 1.2.5
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.5)

Updates `axios` from 1.5.1 to 1.6.0
- [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.5.1...v1.6.0)

Updates `@babel/traverse` from 7.23.6 to 7.23.9
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.9/packages/babel-traverse)

Updates `follow-redirects` from 1.15.3 to 1.15.5
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.5)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  dependency-group: npm_and_yarn-security-group
- dependency-name: parse
  dependency-type: direct:production
  dependency-group: npm_and_yarn-security-group
- dependency-name: "@babel/traverse"
  dependency-type: indirect
  dependency-group: npm_and_yarn-security-group
- dependency-name: crypto-js
  dependency-type: indirect
  dependency-group: npm_and_yarn-security-group
- dependency-name: follow-redirects
  dependency-type: indirect
  dependency-group: npm_and_yarn-security-group
- dependency-name: axios
  dependency-type: direct:production
  dependency-group: npm_and_yarn-security-group
- dependency-name: parse
  dependency-type: direct:production
  dependency-group: npm_and_yarn-security-group
- dependency-name: semver
  dependency-type: indirect
  dependency-group: npm_and_yarn-security-group
- dependency-name: "@babel/traverse"
  dependency-type: indirect
  dependency-group: npm_and_yarn-security-group
- dependency-name: minimist
  dependency-type: indirect
  dependency-group: npm_and_yarn-security-group
- dependency-name: mongodb-runner
  dependency-type: direct:development
  dependency-group: npm_and_yarn-security-group
- dependency-name: word-wrap
  dependency-type: indirect
  dependency-group: npm_and_yarn-security-group
- dependency-name: axios
  dependency-type: direct:production
  dependency-group: npm_and_yarn-security-group
- dependency-name: "@babel/traverse"
  dependency-type: indirect
  dependency-group: npm_and_yarn-security-group
- dependency-name: follow-redirects
  dependency-type: indirect
  dependency-group: npm_and_yarn-security-group
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-22 09:07:19 +00:00
AmolandGitHub 20d37e1ac9 Merge pull request #416 from OpenSignLabs/remove_openai 2024-02-22 14:33:04 +05:30
prafull-opensignlabs f3f79ed499 refactor: remove openai pacakge 2024-02-22 14:31:57 +05:30
dependabot[bot]andGitHub c581222022 build(deps-dev): bump lint-staged in /apps/OpenSign
Bumps [lint-staged](https://github.com/okonet/lint-staged) from 15.0.1 to 15.2.2.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/master/CHANGELOG.md)
- [Commits](https://github.com/okonet/lint-staged/compare/v15.0.1...v15.2.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-22 07:42:15 +00:00
prafull-opensignlabsandGitHub a3fd738b46 Merge pull request #390 from OpenSignLabs/dependabot/npm_and_yarn/apps/OpenSign/postcss-8.4.35
build(deps-dev): bump postcss from 8.4.31 to 8.4.35 in /apps/OpenSign
2024-02-22 13:10:46 +05:30
prafull-opensignlabsandGitHub 3f16e973eb Merge pull request #325 from OpenSignLabs/dependabot/npm_and_yarn/microfrontends/SignDocuments/react-pdf-7.7.0
chore(deps): bump react-pdf from 7.4.0 to 7.7.0 in /microfrontends/SignDocuments
2024-02-22 13:09:37 +05:30
dependabot[bot]andGitHub cb1013762f build(deps): bump @react-pdf/renderer in /microfrontends/SignDocuments
Bumps [@react-pdf/renderer](https://github.com/diegomura/react-pdf/tree/HEAD/packages/renderer) from 3.1.12 to 3.3.8.
- [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@3.3.8/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-02-22 07:20:59 +00:00
prafull-opensignlabsandGitHub 74e275c5d0 Merge pull request #266 from OpenSignLabs/dependabot/npm_and_yarn/microfrontends/SignDocuments/parse-4.3.1
chore(deps): bump parse from 4.2.0 to 4.3.1 in /microfrontends/SignDocuments
2024-02-22 12:49:52 +05:30
prafull-opensignlabsandGitHub dbeb513f65 Merge pull request #262 from OpenSignLabs/dependabot/npm_and_yarn/microfrontends/SignDocuments/babel/traverse-7.23.6
chore(deps): bump @babel/traverse from 7.23.0 to 7.23.6 in /microfrontends/SignDocuments
2024-02-22 12:47:26 +05:30
AmolandGitHub 6f4561a38f Merge pull request #410 from OpenSignLabs/prafull-opensignlabs-patch-2 2024-02-22 11:47:47 +05:30
prafull-opensignlabsandGitHub 12507190d8 update view docs url of webhook 2024-02-22 11:47:26 +05:30
AmolandGitHub 85dac65030 Merge pull request #409 from OpenSignLabs/fix_err 2024-02-22 11:02:11 +05:30
prafull-opensignlabsandGitHub 4f1708619e refactor: handle uncaught exception in server 2024-02-21 20:03:46 +05:30
AndrewandGitHub b24086e679 Merge pull request #407 from OpenSignLabs/prafull-opensignlabs-patch-1 2024-02-21 15:23:57 +05:30
AndrewandGitHub 137f371528 Merge pull request #408 from OpenSignLabs/fix_err 2024-02-21 13:30:46 +05:30
prafull-opensignlabs 5707039002 fix: handle uncaught err of file storage and email adapter 2024-02-21 13:28:38 +05:30
prafull-opensignlabsandGitHub a4a0630102 fix: handle multiple dots in pdf file name 2024-02-20 19:56:30 +05:30
AmolandGitHub e7b9f3f121 Merge pull request #403 from OpenSignLabs/api-v1-beta
analytics for get document list updated
2024-02-16 20:14:15 +05:30
prafull-opensignlabs 14b4d10be3 analytics for get document list updated 2024-02-16 20:12:58 +05:30
AmolandGitHub 03750e3145 Merge pull request #401 from OpenSignLabs/api-v1-beta
fix: change doctype in get document list API
2024-02-16 19:55:46 +05:30
prafull-opensignlabs ff4879a984 fix: change doctype in get document list API 2024-02-16 19:54:39 +05:30
AmolandGitHub 7a6a543df5 Merge pull request #399 from OpenSignLabs/api-v1-beta 2024-02-16 16:58:58 +05:30
prafull-opensignlabs edda20940b change title of request signtuares form, change response of document and template response, change subject of mail 2024-02-16 16:27:20 +05:30
AmolandGitHub 35d20bd42c Merge pull request #398 from OpenSignLabs/api-v1-beta
feat: add Send in order to send mail sequentially for signing document
2024-02-15 19:27:18 +05:30
prafull-opensignlabs 97983c423f feat: add send in order in template 2024-02-15 18:37:11 +05:30
prafull-opensignlabs 68050e3a35 feat: add Send in order to send mail sequentially for signing document 2024-02-15 15:43:32 +05:30
prafull-opensignlabs 4f2801d901 refactor: change keyword in mail from opensign to OpenSign™ 2024-02-15 11:06:27 +05:30
AmolandGitHub aaa3dfc304 Merge pull request #397 from OpenSignLabs/api-v1-beta 2024-02-15 10:43:11 +05:30
prafull-opensignlabs 7a9bebe035 fix: document completion mail are not receiving 2024-02-15 10:41:35 +05:30
prafull-opensignlabs 9d15b035c5 fix: webhook api not working 2024-02-14 22:10:57 +05:30
AmolandGitHub 22de053cd3 Merge pull request #396 from OpenSignLabs/api-v1-beta 2024-02-14 19:13:16 +05:30
prafull-opensignlabs 13845adbd5 feat: link changelog url to footer version 2024-02-14 19:05:00 +05:30
AmolandGitHub ef68f2da16 Merge pull request #393 from OpenSignLabs/api-v1-beta 2024-02-14 18:36:15 +05:30
prafull-opensignlabs 9114908521 standarize all modal in frontend 2024-02-14 16:03:12 +05:30
prafull-opensignlabs f565edc655 refactor: change tour message as well as popup from template flow 2024-02-14 12:31:37 +05:30
prafull-opensignlabs b0e26b8ae2 refactor: add analytics code for internal tracking 2024-02-13 20:39:53 +05:30
AmolandGitHub 9e185fa33c Merge pull request #391 from OpenSignLabs/api-v1-beta 2024-02-12 17:21:02 +05:30
prafull-opensignlabs 5142a8c62d fix: create contact not working properly & update 400 error 2024-02-12 17:17:48 +05:30
dependabot[bot]andGitHub db4b5f0452 build(deps-dev): bump postcss from 8.4.31 to 8.4.35 in /apps/OpenSign
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.31 to 8.4.35.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.31...8.4.35)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-12 01:12:11 +00:00
AmolandGitHub 042ad8465e Merge pull request #385 from OpenSignLabs/api-v1-beta 2024-02-09 17:35:36 +05:30
prafull-opensignlabs ebfd9d3af7 fix: get contactlist API not working & response fo APIs to lowercase 2024-02-09 17:13:39 +05:30
AmolandGitHub 861a065849 Merge pull request #384 from OpenSignLabs/api-v1-beta 2024-02-09 15:39:34 +05:30
prafull-opensignlabs 3884909965 fix: get templatelist api is not working 2024-02-09 15:10:21 +05:30
AmolandGitHub bd60f91734 Merge pull request #383 from OpenSignLabs/api-v1-beta 2024-02-08 20:05:11 +05:30
prafull-opensignlabs b58c3fd467 add replacemailvaribles function to change varibale from custom mail 2024-02-08 20:03:15 +05:30
prafull-opensignlabs 9d431af0b9 feat: add send_email, email_subject, email_body for custom mail signing request in createdocument 2024-02-08 20:02:19 +05:30
AmolandGitHub cb1ebc6a72 Merge pull request #382 from OpenSignLabs/api-v1-beta 2024-02-08 15:26:03 +05:30
prafull-opensignlabs a198bce3e2 feat: add viewed document event for webhook 2024-02-08 15:24:34 +05:30
AmolandGitHub e5c50a0dbb Merge pull request #381 from OpenSignLabs/api-v1-beta 2024-02-07 22:05:42 +05:30
prafull-opensignlabs caa1dfaf34 changed callwwebhook 2024-02-07 22:04:40 +05:30
prafull-opensignlabs eb01a0b17d feat:add declined, created event which is send document on webhook 2024-02-07 22:01:32 +05:30
AmolandGitHub 1add575d26 Merge pull request #380 from OpenSignLabs/api-v1-beta 2024-02-07 18:59:36 +05:30
prafull-opensignlabs 1a774bfcfa feat: add Signed event for webhook 2024-02-07 12:52:51 +05:30
prafull-opensignlabs db9ec6bfd5 fix: handle error for small screen in debug pdf page 2024-02-07 12:08:27 +05:30
AmolandGitHub cbcfb8c063 Merge pull request #379 from OpenSignLabs/api-v1-beta 2024-02-05 18:30:02 +05:30
prafull-opensignlabs da846dcbbb fix: issue of request payload entity too large 2024-02-05 18:26:22 +05:30
AmolandGitHub e7280bf017 Merge pull request #374 from OpenSignLabs/api-v1-beta 2024-02-05 13:31:03 +05:30
prafull-opensignlabs 9692f57663 feat: provide widgets in create document from binary and create template from binary 2024-02-05 13:29:36 +05:30
prafull-opensignlabs f0655893eb change response of createdocument API 2024-02-05 11:23:47 +05:30
prafull-opensignlabs f9e59905b7 refactor: generate randomId in createDocument and createTemplate API 2024-02-03 18:55:23 +05:30
prafull-opensignlabs c115c7c757 fix: createdocument & createtemplate api not working properly 2024-02-03 18:51:58 +05:30
AmolandGitHub 4edcf807ad Merge pull request #370 from OpenSignLabs/api-v1-beta 2024-02-03 18:31:09 +05:30
prafull-opensignlabs 416d8c823c refactor: remove unncessary code 2024-02-03 18:29:49 +05:30
prafull-opensignlabs bea158b8f2 refactor: remove unnecessary css 2024-02-03 18:19:59 +05:30
prafull-opensignlabs 39c6560a2d refactor: remove rjsf package & change rjsf forms to normal forms 2024-02-03 18:06:27 +05:30
AmolandGitHub 509b004014 Merge pull request #369 from OpenSignLabs/api-v1-beta 2024-02-02 18:39:27 +05:30
prafull-opensignlabs f1b7e1164b fix: change copy box parameter from array to key value pair 2024-02-02 18:33:21 +05:30
AmolandGitHub 3a2f626cb9 Merge pull request #368 from OpenSignLabs/api-v1-beta 2024-02-02 15:03:20 +05:30
prafull-opensignlabs 7cde6fd73c fix: co-ordinates in debugpdf page is not stick on top 2024-02-02 14:41:45 +05:30
AmolandGitHub 06d6eecaf0 Merge pull request #367 from OpenSignLabs/api-v1-beta 2024-02-02 12:31:16 +05:30
prafull-opensignlabs c9ed29261d fix:remov edit template url from create template 2024-02-02 12:28:30 +05:30
AmolandGitHub f74819f50a Merge pull request #366 from OpenSignLabs/api-v1-beta 2024-02-01 23:07:20 +05:30
prafull-opensignlabs 98c8af5b9c feat: create document and template with coordinate 2024-02-01 20:26:36 +05:30
dependabot[bot]andGitHub ca17f1cfc9 chore(deps): bump react-pdf in /microfrontends/SignDocuments
Bumps [react-pdf](https://github.com/wojtekmaj/react-pdf/tree/HEAD/packages/react-pdf) from 7.4.0 to 7.7.0.
- [Release notes](https://github.com/wojtekmaj/react-pdf/releases)
- [Commits](https://github.com/wojtekmaj/react-pdf/commits/v7.7.0/packages/react-pdf)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 11:04:47 +00:00
AmolandGitHub 74e2582ff9 Merge pull request #364 from OpenSignLabs/api-v1-beta 2024-02-01 16:33:54 +05:30
prafull-opensignlabs 8bbbf9b3d8 feat: add debug pdf page 2024-02-01 16:31:34 +05:30
AmolandGitHub 0a6622159f Merge pull request #363 from OpenSignLabs/api-v1-beta 2024-01-31 14:11:33 +05:30
prafull-opensignlabs 7a5cdefcfa fix: document completion webhook not working in selfsign 2024-01-31 13:48:30 +05:30
AmolandGitHub fa405752da Merge pull request #362 from OpenSignLabs/api-v1-beta 2024-01-29 15:06:48 +05:30
prafull-opensignlabs 2d7571af5a fix: change response of createdocumentwithtemplate API for signing document 2024-01-29 15:04:07 +05:30
dependabot[bot]andGitHub 07a57969ac build(deps-dev): bump @babel/runtime-corejs2 in /apps/OpenSign
Bumps [@babel/runtime-corejs2](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime-corejs2) from 7.23.2 to 7.23.9.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.9/packages/babel-runtime-corejs2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-29 01:09:53 +00:00
AmolandGitHub 01b7b1cab8 Merge pull request #356 from OpenSignLabs/api-v1-beta 2024-01-28 17:33:20 +05:30
prafull-opensignlabs fee3d8f672 fix: createdocument, createtemplate and createdocumentwithtemplate APIs not working 2024-01-28 16:34:08 +05:30
prafull-opensignlabsandGitHub f1628e46fa Merge pull request #355 from OpenSignLabs/api-v1-beta
fix: createdocument from template not working
2024-01-28 10:45:43 +05:30
prafull-opensignlabs 17cb4479cb fix: createdocument from template 2024-01-25 22:49:20 +05:30
AmolandGitHub b52511113b Merge pull request #354 from OpenSignLabs/api-v1-beta 2024-01-25 20:00:53 +05:30
prafull-opensignlabs 95cc15ec4c fix: all API body parameter must be in lowercase 2024-01-25 19:58:16 +05:30
AmolandGitHub 1a4b4655c8 Merge pull request #352 from OpenSignLabs/api-v1-beta 2024-01-25 19:37:41 +05:30
prafull-opensignlabsandGitHub 9fc69ba7e6 Merge branch 'staging' into api-v1-beta 2024-01-25 19:35:20 +05:30
prafull-opensignlabs 8ce31d3d80 fix: get host method in API 2024-01-25 19:16:09 +05:30
AmolandGitHub d097f9a741 Merge pull request #353 from OpenSignLabs/revert-351-api-v1-beta
Revert "fix: all body parameter of API must be in lowercase"
2024-01-25 19:00:13 +05:30
AmolandGitHub 8686a35405 Revert "fix: all body parameter of API must be in lowercase" 2024-01-25 18:59:55 +05:30
prafull-opensignlabs a92d90db4a change body parameter of update API 2024-01-25 18:36:49 +05:30
AmolandGitHub bfa0e0e144 Merge pull request #351 from OpenSignLabs/api-v1-beta 2024-01-25 18:30:26 +05:30
prafull-opensignlabs d3b2e1f24b fix: all body parameter must be in lowercase 2024-01-25 18:04:22 +05:30
AmolandGitHub 61afc35ac8 Merge pull request #349 from OpenSignLabs/api-v1-beta 2024-01-25 11:23:50 +05:30
prafull-opensignlabs 00e9396590 change API doc url in webhook and API token in menu 2024-01-24 23:38:49 +05:30
prafull-opensignlabs bbedb13f3e feat: api for createtemplate using base64 and binary 2024-01-24 23:18:08 +05:30
prafull-opensignlabs 55cfbae8a7 feat: api for createtemplate using base64 and binary 2024-01-24 23:17:44 +05:30
AndrewandGitHub bfa19eec0c Merge pull request #348 from OpenSignLabs/api-v1-beta 2024-01-24 18:14:00 +05:30
prafull-opensignlabs 07851ccde2 feat: add create document api with base64 2024-01-24 18:12:38 +05:30
AndrewandGitHub a13478fa64 Merge pull request #347 from OpenSignLabs/api-v1-beta 2024-01-24 12:07:37 +05:30
prafull-opensignlabs 85a1c10d26 feat: api for webhook crate,Read, update, delete 2024-01-24 12:04:37 +05:30
AndrewandGitHub 6918282e31 Merge pull request #346 from OpenSignLabs/api-v1-beta 2024-01-23 13:31:13 +05:30
prafull-opensignlabs fd778c25e6 fix: add link mail tag 2024-01-23 13:06:56 +05:30
prafull-opensignlabs af344c8ae2 feat: add webhook which will call on document completion event 2024-01-23 12:54:28 +05:30
AndrewandGitHub c505f8cf86 Merge pull request #344 from OpenSignLabs/api-v1-beta 2024-01-22 15:52:37 +05:30
prafull-opensignlabs 52320e0cd9 fix: add regenerate confirmation modal in API token menu 2024-01-22 15:35:38 +05:30
prafull-opensignlabsandGitHub 214db474c2 Merge pull request #338 from OpenSignLabs/api-v1-beta
feat: enable automatic redirect to remembered url after login
2024-01-22 14:21:19 +05:30
prafull-opensignlabsandGitHub 1bffabc94d Merge pull request #343 from OpenSignLabs/staging
sync brancg
2024-01-22 10:15:16 +05:30
prafull-opensignlabs 7c8a5e02f2 add createdocument with template Id 2024-01-22 09:52:44 +05:30
prafull-opensignlabs a49c76c188 replace menu name generate token to API Token 2024-01-22 09:48:29 +05:30
prafull-opensignlabs 34fc3afb1e enable automatic redirect to rememberd url after login 2024-01-19 18:08:35 +05:30
prafull-opensignlabsandGitHub 67479a9c1e Merge pull request #337 from OpenSignLabs/api-v1-beta
fix: change userId type from string to pointer in appToken class and handle stringify array
2024-01-19 10:47:50 +05:30
prafull-opensignlabs 2a8cedca58 change userId type from string to pointer in appToken class and handle stringify array 2024-01-19 00:33:08 +05:30
prafull-opensignlabsandGitHub 57fc4aa06b Merge pull request #336 from OpenSignLabs/api-v1-beta
feat: add docs tab in profile menu
2024-01-18 15:23:59 +05:30
prafull-opensignlabs 39f3f73896 feat: add docs tab in profile menu 2024-01-18 12:15:46 +05:30
prafull-opensignlabsandGitHub 3dc109c3dd Merge pull request #334 from OpenSignLabs/api-v1-beta
fix: create contact not working and handle err
2024-01-17 16:40:52 +05:30
prafull-opensignlabs 83df89c115 fix: create contact not working and handle err 2024-01-17 16:33:59 +05:30
AndrewandGitHub 4070409a59 Update README.md 2024-01-16 20:20:54 +05:30
AmolandGitHub 70963c06b8 Merge pull request #332 from OpenSignLabs/api-v1-beta
feat: Api v1 beta
2024-01-16 18:12:33 +05:30
prafull-opensignlabs a1a84b6928 fix: userId missing in aftersave of doucment and template cls 2024-01-16 18:09:10 +05:30
prafull-opensignlabs eefaf5fe50 feat: add migration script for generate token route 2024-01-16 17:43:42 +05:30
prafull-opensignlabs 9500b2d678 update apis response and add delete document api 2024-01-15 20:22:07 +05:30
prafull-opensignlabs e52c7c97cf remove code from response and add update Document api 2024-01-15 18:15:16 +05:30
prafull-opensignlabs ebdc5ef566 update response of apis 2024-01-15 16:16:03 +05:30
prafull-opensignlabsandGitHub 2afb868edc Merge pull request #322 from OpenSignLabs/staging
sync branch
2024-01-12 20:32:36 +05:30
prafull-opensignlabs a5fe4a345b update response message in delete contact api 2024-01-12 20:31:04 +05:30
prafull-opensignlabs 629bf7f51f update documentlist api 2024-01-12 20:29:40 +05:30
AndrewandGitHub 350854ab6b Merge pull request #321 from OpenSignLabs/fix_submitbtn_template 2024-01-12 19:53:25 +05:30
prafull-opensignlabsandGitHub cc980758fd Update TemplateForm.js 2024-01-12 19:49:51 +05:30
prafull-opensignlabsandGitHub 0f1ce43cc5 Merge pull request #320 from OpenSignLabs/modal-ui
fix: replace title Role to Roles in template creation flow
2024-01-12 19:24:53 +05:30
RaktimaNXG 5e1a9cdc20 "fix: replace title Role to Roles in template creation flow" 2024-01-12 17:25:11 +05:30
prafull-opensignlabsandGitHub 550ce10c92 Merge pull request #318 from OpenSignLabs/modal-ui
fix: modal-ui,replace loading pdf to loading document, onclick placeholder open user details popup
2024-01-12 15:38:11 +05:30
RaktimaandGitHub 6080c59bd7 fix: clear image after upload image on sign pad 2024-01-12 15:23:30 +05:30
RaktimaNXG 273a35d42f fix:resolved on-drag placeholder user-details popup open in edit template flow 2024-01-12 15:03:09 +05:30
RaktimaNXG 2f195fe02e fix: clear image issue after upload image using sign pad 2024-01-12 14:27:33 +05:30
RaktimaNXG 0715ca9d85 fix: on-drag placeholder user-details popup open issue,close button design, remove unnecessary code & npm package 2024-01-12 14:07:53 +05:30
prafull-opensignlabs a8d564d74d update api 2024-01-12 13:24:41 +05:30
prafull-opensignlabs 89ba3e0fa4 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into api-v1-beta 2024-01-11 22:27:09 +05:30
prafull-opensignlabs eebcfe94d9 feat: add update template api and update all apis 2024-01-11 22:19:40 +05:30
prafull-opensignlabs ea9b0370c4 Merge branch 'api-v1-beta' of https://github.com/OpenSignLabs/OpenSign into api-v1-beta 2024-01-11 16:30:18 +05:30
prafull-opensignlabs e264511a6e feat: add limit and skip variables in query & contact creation api 2024-01-11 16:29:26 +05:30
RaktimaNXG 1ec10fbcfc fix: modal-ui,replace loading pdf to loading document, onclick placeholder open user details popup 2024-01-11 14:53:14 +05:30
AmolandGitHub 274620d17b Merge pull request #314 from OpenSignLabs/fix_draft_report
update draft report query
2024-01-10 21:04:52 +05:30
prafull-opensignlabsandGitHub 06db7d2360 update draft report query 2024-01-10 21:04:20 +05:30
AndrewandGitHub 2b3549e4df Merge pull request #313 from OpenSignLabs/opensign-drive 2024-01-10 20:48:52 +05:30
RaktimaNXG d16478792c fix:document name bold,openSign to OpenSign™ in email login flow 2024-01-10 19:49:17 +05:30
prafull-opensignlabsandGitHub 7ba2ef6420 Merge pull request #311 from OpenSignLabs/opensign-drive
feat: implement of document delete and move to folder in opensigndrive
2024-01-10 18:29:32 +05:30
prafull-opensignlabsandGitHub b5d98796b7 update template details on save 2024-01-10 18:28:38 +05:30
RaktimaNXG 97c17cfe84 fix: table view design opensign-drive 2024-01-10 18:19:11 +05:30
RaktimaNXG 4b4e200090 extend expire date from current date 2024-01-10 16:57:22 +05:30
RaktimaNXG 232d38440d add extend days value from timeToCompleteDays filed for expired document 2024-01-10 16:12:39 +05:30
RaktimaNXG 341bd9bef0 fix: draft document redirect issue 2024-01-10 15:27:35 +05:30
RaktimaNXG 2f4d04c722 fix: draft document redirect issue 2024-01-10 15:23:35 +05:30
RaktimaNXG 148ae40e1a extend expire date of expired draft document 2024-01-10 15:11:26 +05:30
prafull-opensignlabs 9cb0ced4f6 add migration script for update menu & add IsArchive field in document cls 2024-01-10 12:21:00 +05:30
RaktimaNXG 9a3b70de43 fix: expired document redirect wrong route in opensign-drive 2024-01-10 11:19:16 +05:30
RaktimaNXG 742b8f7eae fix: move folder on same folder issue 2024-01-10 10:57:22 +05:30
RaktimaNXG abc58941e3 fix: onclick to open folder issuein opensign-drive 2024-01-10 10:44:33 +05:30
RaktimaNXG aac200bfd3 fix: right click move functionality issue opensign-drive 2024-01-09 20:20:56 +05:30
RaktimaNXG 27d3297d61 fix: decline alert header message, add icon for right click menu on opensign-drive,on enter create folder 2024-01-09 20:02:40 +05:30
RaktimaNXG 72431b2c82 fix: redirect wrong route of draft docment issue in openSign-drive 2024-01-09 17:24:27 +05:30
RaktimaNXG 3ca48e5848 fix: folder list display issue in move folder modal,add alert for delete document, change modal css 2024-01-09 14:35:45 +05:30
prafull-opensignlabsandGitHub 14784ec80f added validation to get non archive document in getdrive cloud function 2024-01-09 11:36:22 +05:30
prafull-opensignlabsandGitHub 127741eb27 remove override box css 2024-01-09 11:08:03 +05:30
RaktimaNXG 2ed987fe10 feat: implement document delete and move funationality in openSign-drive 2024-01-08 22:12:23 +05:30
AndrewandGitHub 7aaa1876c8 Merge pull request #308 from OpenSignLabs/need-your-sign 2024-01-06 19:31:30 +05:30
RaktimaNXG 390ffb83a2 fix: user redirect wrong route after send placeholder to signers 2024-01-06 18:41:53 +05:30
prafull-opensignlabsandGitHub d63e51b8cb Merge pull request #307 from OpenSignLabs/need-your-sign
fix: placeholder display issue of all signers after save placeholder and login flow
2024-01-05 18:38:15 +05:30
RaktimaNXG 7bd8d64649 fix: instance signature flow issue after send placeholder 2024-01-05 17:37:57 +05:30
RaktimaNXG f9e6f49ede fix: placeholder display issue of all signers after save placeholder and login flow 2024-01-05 17:00:41 +05:30
AndrewandGitHub b701d2863f Merge pull request #295 from OpenSignLabs/text-input 2024-01-05 15:58:04 +05:30
RaktimaandGitHub cf47093227 Merge branch 'staging' into text-input 2024-01-05 12:07:14 +05:30
RaktimaNXG 81d0aea66c fix: text-input signatureissue 2024-01-04 16:14:23 +05:30
AndrewandGitHub 506ca35be8 Merge pull request #305 from OpenSignLabs/pdflib-sign 2024-01-03 20:46:41 +05:30
RaktimaNXG 1cd6718489 fix: single signature issue, change react tour message, add icon for create new tamplate 2024-01-03 19:47:22 +05:30
RaktimaNXG 153c5db4b5 fix: input signature image height issue and limit 30 character of input text signature 2024-01-03 16:17:32 +05:30
RaktimaNXG ac9367a715 fix: fontstyle after save text signature issue 2024-01-03 13:46:44 +05:30
RaktimaNXG 081dae0b90 fix: font style for first time on save text signature 2024-01-03 13:07:59 +05:30
RaktimaandGitHub e286390aec Merge branch 'staging' into text-input 2024-01-03 12:44:55 +05:30
RaktimaNXG cf88eb2124 fix: font-style issue after save text signature 2024-01-03 12:43:01 +05:30
prafull-opensignlabsandGitHub 3226e4fd85 Merge pull request #304 from OpenSignLabs/feat_template
add hyperlink in completed mail for any query
2024-01-03 11:55:39 +05:30
prafull-opensignlabs cab94eb63d add hyperlink in completed mail for any query 2024-01-03 11:52:11 +05:30
prafull-opensignlabsandGitHub bbd5d6805e Merge pull request #303 from OpenSignLabs/feat_template
bug fix in template flow as well as placeholder is not working in mobile view
2024-01-03 10:14:09 +05:30
prafull-opensignlabs 2904ba3085 bug fix in template flow as well as placeholder is not working in mobile view 2024-01-03 10:03:12 +05:30
RaktimaNXG ee609061ed fix: text input signature font-family for mobile view 2024-01-02 10:03:06 +05:30
prafull-opensignlabsandGitHub 6c98a4e899 Merge pull request #301 from OpenSignLabs/feat_template
add don't show button for tour and minor bug fix
2024-01-01 11:46:01 +05:30
prafull-opensignlabs eef9ee7f3c remove unncessary navigation 2024-01-01 11:00:04 +05:30
prafull-opensignlabs 2cb4575db1 add dont show button for reactour and minor bug fix in template flow 2024-01-01 10:49:37 +05:30
prafull-opensignlabsandGitHub e7bcad80cc Merge pull request #298 from OpenSignLabs/staging
sync fork
2023-12-31 16:05:11 +05:30
AndrewandGitHub 353839a1dc Merge pull request #297 from OpenSignLabs/fix 2023-12-31 16:02:18 +05:30
prafull-opensignlabsandGitHub e6d30744ba Update Pgsignup.js 2023-12-31 16:01:37 +05:30
prafull-opensignlabsandGitHub b67932f448 Merge pull request #296 from OpenSignLabs/staging
sync fork
2023-12-30 20:02:38 +05:30
prafull-opensignlabs c185c42b80 vertically center button in reports, add title for template route and placeholder route 2023-12-30 19:52:36 +05:30
prafull-opensignlabs 4648ace84e fix : minor bug fix in template 2023-12-29 23:00:37 +05:30
prafull-opensignlabs ccdf50dbe0 add validation for delete contact 2023-12-29 16:50:10 +05:30
RaktimaNXG 852a3dc8bb feat: Enable text input signature feature 2023-12-29 16:36:49 +05:30
prafull-opensignlabs d49b7bd201 change query of progress and recent sent for signtuare reports 2023-12-29 12:59:57 +05:30
prafull-opensignlabs 07f2ceed6e add session validation, updated migration script and minor ui changes 2023-12-29 12:31:36 +05:30
prafull-opensignlabsandGitHub 751c7b5787 Merge pull request #294 from OpenSignLabs/feat_template
fix: minor template issues, resize issue in mobile, change recipient list Ui in mobile
2023-12-28 19:38:11 +05:30
prafull-opensignlabs e82384dff8 fix: signyourself flow, add validtion in template flow, change UI recipientlist in mobile view 2023-12-28 19:36:06 +05:30
RaktimaNXG 92d3a85147 fix: placeholder resize issue in mobile view 2023-12-28 17:30:08 +05:30
prafull-opensignlabsandGitHub c5762a0baf Merge pull request #293 from OpenSignLabs/feat_template
fix: minor bug fix in template component
2023-12-28 14:41:12 +05:30
prafull-opensignlabs dc40b04a18 fix: minor bug fix in template compoent 2023-12-28 14:39:52 +05:30
prafull-opensignlabsandGitHub 1cca5a3085 Merge pull request #292 from OpenSignLabs/feat_template
fix: add recipient required validation and dropbox is not visible
2023-12-28 12:33:02 +05:30
prafull-opensignlabs 4fe4ca638c add receipent required validation 2023-12-28 12:29:05 +05:30
prafull-opensignlabs b8c7110c63 resolve issue of receipent in not selected by default and dropbox upload 2023-12-28 12:15:02 +05:30
dependabot[bot]andGitHub 288365b74b chore(deps): bump parse in /microfrontends/SignDocuments
Bumps [parse](https://github.com/parse-community/Parse-SDK-JS) from 4.2.0 to 4.3.1.
- [Release notes](https://github.com/parse-community/Parse-SDK-JS/releases)
- [Changelog](https://github.com/parse-community/Parse-SDK-JS/blob/alpha/CHANGELOG.md)
- [Commits](https://github.com/parse-community/Parse-SDK-JS/compare/4.2.0...4.3.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-27 12:15:31 +00:00
dependabot[bot]andGitHub b57e17c01c chore(deps): bump the npm_and_yarn group group
Bumps the npm_and_yarn group group in /microfrontends/SignDocuments with 1 update: [parse](https://github.com/parse-community/Parse-SDK-JS).


Updates `parse` from 4.2.0 to 4.3.1
- [Release notes](https://github.com/parse-community/Parse-SDK-JS/releases)
- [Changelog](https://github.com/parse-community/Parse-SDK-JS/blob/alpha/CHANGELOG.md)
- [Commits](https://github.com/parse-community/Parse-SDK-JS/compare/4.2.0...4.3.1)

---
updated-dependencies:
- dependency-name: parse
  dependency-type: direct:production
  dependency-group: npm_and_yarn-security-group
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-27 12:15:12 +00:00
prafull-opensignlabsandGitHub 711ab6a556 Merge pull request #290 from OpenSignLabs/feat_template
feat: Introducing Template Creation Functionality: Streamline Document Generation and Sharing
2023-12-27 17:44:07 +05:30
prafull-opensignlabs 7a12f54587 add contactbook form in contactbook report 2023-12-27 17:41:51 +05:30
prafull-opensignlabs 056f4b3e80 remove random words from file upload input to show correct pdf name 2023-12-27 16:31:19 +05:30
prafull-opensignlabs 730a7a4e15 add reactour for template 2023-12-27 16:26:56 +05:30
prafull-opensignlabs a4b4dc885c removed unnecessary assets 2023-12-27 14:17:19 +05:30
prafull-opensignlabs 8562a4bb46 change fetch function 2023-12-27 08:21:49 +05:30
prafull-opensignlabs d3b56432e0 resolve color issue on drag placeholder 2023-12-27 08:11:17 +05:30
prafull-opensignlabs 527c5be42c add attach user icon in mobile view 2023-12-26 23:03:27 +05:30
prafull-opensignlabs 6c1d0c712a resolve delete user not working properly with placholder 2023-12-26 20:04:16 +05:30
prafull-opensignlabs fd0ec5fd31 resolve resize issue for template placeholder 2023-12-26 18:52:53 +05:30
prafull-opensignlabs f5f19c9b52 Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into feat_template 2023-12-26 16:50:21 +05:30
prafull-opensignlabsandGitHub 642ef4f5b7 Merge pull request #286 from OpenSignLabs/placeholder
feat: add copy placeholder feature and change in UI of placeholder
2023-12-26 15:33:22 +05:30
prafull-opensignlabs 66b65e600b add validtion for fetch template 2023-12-26 13:53:54 +05:30
prafull-opensignlabs 01a130ef8c add username in placeholder and validtion for fetch template 2023-12-26 13:52:52 +05:30
prafull-opensignlabs c3bccb5412 show role name in placeholder 2023-12-26 09:27:50 +05:30
prafull-opensignlabsandGitHub b32e6e71f8 Merge pull request #288 from OpenSignLabs/staging
sync fork
2023-12-25 19:05:40 +05:30
RaktimaNXG 3b5875e283 fix: size of the placeholder changed after the signature was uploaded in need-your-sign report 2023-12-22 12:44:38 +05:30
prafull-opensignlabs da42fe97ae add/Choose form to link user and ui changes 2023-12-21 21:40:42 +05:30
AmolandGitHub 56bb7d36eb chore: remove mailgun api key value 2023-12-21 16:32:59 +05:30
AmolandGitHub d86b7345d7 chore: set smtp dummy values 2023-12-21 16:25:15 +05:30
AmolandGitHub c1c17160ff chore: set SMTP_ENABLE to true 2023-12-21 16:21:05 +05:30
RaktimaNXG d400c843e4 fix: modified variable name as required and added comment 2023-12-21 15:14:29 +05:30
prafull-opensignlabs 4e67ab50fe resolve minor ui issues 2023-12-20 23:57:50 +05:30
prafull-opensignlabs 74c9e21d55 resolve minor ui issues 2023-12-20 23:57:02 +05:30
RaktimaNXG fefcdf6ffc feat: placeholder copy all pages feature at same location and change placeholder design 2023-12-20 19:31:59 +05:30
AmolandGitHub 0c14d71fa8 docs: Add openapi spec 2023-12-20 19:02:47 +05:30
prafull-opensignlabs 5170e4eee2 migration script for template class 2023-12-20 17:32:51 +05:30
prafull-opensignlabs 8ebfd781c3 add template report and form , as well as migration code for it 2023-12-20 14:33:41 +05:30
prafull-opensignlabs 4e8988bf57 add template feature 2023-12-19 18:58:28 +05:30
prafull-opensignlabsandGitHub c26734751f Merge pull request #282 from OpenSignLabs/staging
sync fork
2023-12-18 10:57:46 +05:30
prafull-opensignlabs ca6b4e7d82 add createDocument from template functionality 2023-12-16 22:19:12 +05:30
prafull-opensignlabs cb4a94d036 add createDocument from template functionality 2023-12-16 22:19:01 +05:30
prafull-opensignlabsandGitHub 300ddb810f Update LoginFacebook.js 2023-12-16 17:03:35 +05:30
prafull-opensignlabsandGitHub 0b687310fd Update LoginGoogle.js 2023-12-16 17:03:04 +05:30
prafull-opensignlabs 3e741ac2f9 add functionality of add placholder in template 2023-12-15 19:01:05 +05:30
prafull-opensignlabsandGitHub f65b23ca26 Merge pull request #278 from OpenSignLabs/staging
Sync fork
2023-12-15 16:37:32 +05:30
dependabot[bot]andGitHub 92527e5847 chore(deps): bump @babel/traverse in /microfrontends/SignDocuments
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.23.0 to 7.23.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.6/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-15 08:00:41 +00:00
prafull-opensignlabsandGitHub db9b8d2ba1 Merge pull request #261 from OpenSignLabs/staging
sync fork
2023-12-12 19:57:56 +05:30
prafull-opensignlabs 4866447f33 add api for template, createDocument 2023-12-12 19:37:59 +05:30
prafull-opensignlabs 2b345ff840 add new template form 2023-12-12 17:57:11 +05:30
prafull-opensignlabs b47bf437a9 created generateapitoken, getapitoken cloud function & generatetoken route 2023-12-02 21:16:56 +05:30
prafull-opensignlabs c44149050c rename files 2023-12-01 18:34:27 +05:30
prafull-opensignlabs 0576123a77 add api for get, delete contact, getUser & get Documents 2023-12-01 18:04:05 +05:30
169 changed files with 20013 additions and 15447 deletions
+5 -5
View File
@@ -45,14 +45,14 @@ DO_REGION=us-west
USE_LOCAL=TRUE USE_LOCAL=TRUE
# Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) ********************************************************************************************************************* # Email mailgun or set SMTP_ENABLE true to use SMTP config (The app will not initialize if any of these 3 variables are not set) *********************************************************************************************************************
MAILGUN_API_KEY=XXXXX MAILGUN_API_KEY=
MAILGUN_DOMAIN=mail.yourdomain.com MAILGUN_DOMAIN=mail.yourdomain.com
MAILGUN_SENDER=postmaster@mail.yourdomain.com MAILGUN_SENDER=postmaster@mail.yourdomain.com
SMTP_ENABLE= SMTP_ENABLE=
SMTP_HOST= SMTP_HOST=smtp.yourhost.com
SMTP_PORT= SMTP_PORT=443
SMTP_USER_EMAIL= SMTP_USER_EMAIL=mailer@yourdomain.com
SMTP_PASS= SMTP_PASS=password # if your password includes spaces then write password in single quotes ('asdf pasd asdf bgds').
# Base64 encoded PFX or p12 document signing certificate file ********************************************************************************************************************* # Base64 encoded PFX or p12 document signing certificate file *********************************************************************************************************************
+7 -4
View File
@@ -2,7 +2,7 @@ name: ci
on: on:
push: push:
branches: branches:
- 'main' - 'staging'
jobs: jobs:
docker: docker:
@@ -11,9 +11,9 @@ jobs:
matrix: matrix:
include: include:
- image: amolshejole/OpenSign - image: amolshejole/OpenSign
dockerfile: apps/OpenSign/Dockerfile dockerfile: apps/OpenSign/Dockerhubfile
- image: amolshejole/OpenSignServer - image: amolshejole/OpenSignServer
dockerfile: apps/OpenSignServer/Dockerfile dockerfile: apps/OpenSignServer/Dockerhubfile
steps: steps:
- -
name: Checkout name: Checkout
@@ -31,8 +31,11 @@ jobs:
with: with:
images: ${{ matrix.image }} images: ${{ matrix.image }}
- -
name: Debug - List files name: Debug - List files opensign
run: ls -R apps/OpenSign/ # Adjust the path as needed run: ls -R apps/OpenSign/ # Adjust the path as needed
-
name: Debug - List files opensignserver
run: ls -R apps/OpenSignServer/ # Adjust the path as needed
- -
name: Build and push name: Build and push
uses: docker/build-push-action@v4 uses: docker/build-push-action@v4
+16 -136
View File
@@ -1,149 +1,29 @@
# INSTALLATON INSTRUCTIONS # INSTALLATON INSTRUCTIONS HAS A NEW HOME
You can use our app as a cloud version from [OpenSignLabs](https://www.opensignlabs.com) We've updated our installation instructions and moved them to our dedicated documentation portal to provide you with a better experience and updated guidance. Whether you're looking to self-host OpenSign™ or contribute to its development, you can find detailed instructions tailored to your needs at [docs.opensignlabs.com](https://docs.opensignlabs.com).
or follow below instructions to install it on your own infrastructure. ## Self Hosting
- Localhost(Frontend only) If you're interested in self-hosting OpenSign™, our new documentation portal provides comprehensive, step-by-step instructions to help you set up OpenSign™ in your own environment. This section is designed for system administrators and those looking to deploy OpenSign™ within their organization or for personal use.
- Digital Ocean
- Localhost(Docker)
## Localhost(Frontend only) - **Access Self Hosting Instructions:** [Self Hosting Guide](https://docs.opensignlabs.com/docs/category/docker)
This is the easiest way to run the frontend application for development or testing purpose without the hassle of installing backend & DB. All the features including document upload, signing, email notifications will work seamlessly from staging backend. ## Contributors
**Warning:** All data, including user accounts and documents, is stored in the staging backend. This data will be erased every time there is a merge to the main branch. As a result, you may need to recreate user accounts repeatedly. If you find that login attempts are failing, it is likely because the data has been cleared due to a recent merge. For developers and contributors who are looking to build upon or contribute to OpenSign™, we've prepared a separate section that covers the setup, development environment configuration, and guidelines for contributing to the OpenSign™ project.
Below are the steps to follow - - **Access Contributor Instructions:** [Contributors Guide](https://docs.opensignlabs.com/docs/contribute/INSTALLATION)
- [Clone the repository](https://help.github.com/articles/cloning-a-repository/) to your local machine using below command -
```
git clone https://github.com/OpenSignLabs/OpenSign.git
```
- Copy the .env.frontend_dev file to apps/OpenSign/.env using below command(on mac & linux). For windows use COPY command instead.
```
cp .env.frontend_dev apps/OpenSign/.env
```
- CD to /apps/OpenSign directory
- Install NPM packages using
```
npm install
```
- Run the project locally using
```
npm run start
```
You should be able to access the application from http://localhost:3000 after this.
Create an account by signing-up and start contributing.
## Additional Resources
## Digital Ocean Should you need further assistance or have any questions, please feel free to reach out to us through our support channels:
OpenSign application consistes of 3 components - - **Twitter:** [OpenSignHQ on Twitter](https://twitter.com/OpenSignHQ)
- ReactJS frontend - **Facebook:** [OpenSign on Facebook](https://www.facebook.com/profile.php?id=61551030403669)
- NodeJS API - **LinkedIn:** [OpenSign™ on LinkedIn](https://www.linkedin.com/company/opensign%E2%84%A2/)
- MongoDB database - **Discord:** [Join our Discord Community](https://discord.com/invite/opensign)
- **YouTube:** [OpenSignHQ on YouTube](https://www.youtube.com/@opensignhq)
You can install all 3 components on digital ocean using the button below - We are committed to providing you with the support you need to successfully install and use OpenSign™. Visit our website at [www.opensignlabs.com](https://www.opensignlabs.com) for more information about our project and its features.
[![Deploy on DigitalOcean](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/OpenSignLabs/Deploy-OpenSign-to-Digital-Ocean/tree/main&refcode=30db1c901ab0)
## You will need to create an AWS S3 bucket or digital ocean space in order to store your uploaded documents
### AWS S3 -
- Step 1 : Create a S3 bucket
- Login to AWS console
- Navigate to S3 under services
- Hit "Create Bucket" button on upper right corner
- Remove the check from "block all public access" checkbox(we need this in order to provide access to not-logged in users after OTP verification)
- Set bucket versioning and tags as per your requirements
- Hit "Create bucket" button
- Step 2 : Create IAM user and provide access to AWS bucket
- Search for "IAM" on the search bar in AWS console
- On IAM dashboard, click the number of users(count) under IAM resources table
- Hit "create user" button on the upper right corner of the page
- Enter the user name & click next
- Click create policy, search for S3 and provide the Read, Write & list permissions
- Click next and click "Create user"
- Step 3 : Generate Credentials
- Go to IAM/Users in AWS console
- Hit the hyperlink for the user created in the previous step
- Click the "Security credentials" tab
- Scroll down to "Access keys" and hit "Create access key"
- In the next step select "Application running outside AWS"
- Add a description tag if needed & hit "Create access key"
- In the next step you will see "Access key" and "Secret Access key". Copy both the values.
- Set the value of "Access key" to "DO_ACCESS_KEY_ID" environment variable
- Set the value of "Secret Access key" to "DO_SECRET_ACCESS_KEY" environment variable
- Step 3 : Copy bucket credentials
- Visit "Amazon S3 -> Buckets" in aws console
- Click the bucket created in previous steps & visit the properties tab
- Under "Bucket overview" you will find the value of AWS region(for ex. ap-south-1). Set that value to env variable "DO_REGION"
- You can create the value for "DO_ENDPOINT" env variable by appending the region value to amazonaws.com (for ex. s3.ap-south-1.amazonaws.com)
- You can create the value for "DO_BASEURL" by adding the bucketname in front of the endpoint value(for ex. https://bucketname.s3.ap-south-1.amazonaws.com)
Visit below link if you face any issues while following the above instructions -
- https://repost.aws/knowledge-center/create-access-key
## Localhost(Docker)
For local Setup we need to need following prerequisite:
Environment Varaibles:
| Environment Varibale | Value | Description |
| ------------- | ------------- | ------------- |
| CI | false | Set CI to false while running the app locally |
| PUBLIC_URL | http://localhost:3000 | Set it to the URL form where the app home page will be accessed |
| GENERATE_SOURCEMAP | false | Set it to true if you want to generate the Sourcemap for debugging |
| REACT_APP_SERVERURL | http://localhost:8080/app | Set it to the URL from where APIs will be accessible, for local development it should be localhost:3000/api/app (use your local port number instead) |
| REACT_APP_APPID | opensignstgn | A 12 character long random app identifier. The value of this should be same as APP_ID which is a variable used by backend API. |
| APP_ID | opensignstgn | A 12 character long random app identifier. The value of this should be same as REACT_APP_APPID which is a variable used by Frontend React App. |
| appName | open_sign_server | Name of the app. It will be visible in the verification emails sent out. |
| MASTER_KEY | XnAadwKxxByMr | A 12 character long random secret key that allows access to all the data. It is used in Parse dashboard config to view all the data in the database. |
| MONGODB_URI | mongodb://host.docker.internal:27017/OpenSignDB | Mongodb URI to connect to |
| PARSE_MOUNT |/app | Path on which APIs should be mounted. Do not change this. This variable shall be removed & value hardcoded in the source code in coming versions. |
| SERVER_URL | http://127.0.0.1:8080/app | Set it to the URL from where APIs will be accessible to the NodeJS functions, for local development it should be localhost:3000/api/app (use your local port number instead) |
| DO_SPACE | DOSPACENAME | Digital ocean space name or AWS S3 bucket name for uploading documents |
| DO_ENDPOINT | ams3.digitaloceanspaces.com | Digital ocean spaces endpoint or AWS S3 endpoint for uploading documents |
| DO_BASEURL |https://DOSPACENAME.ams3.digitaloceanspaces.com | Digital ocean baseurl or AWS S3 base URL |
| DO_ACCESS_KEY_ID | YOUR_S3_ACCESS_ID | Digital ocean spaces access key ID or AWS s3 Access key ID for uploading the docs |
| DO_SECRET_ACCESS_KEY | YOUR_S3_ACCESS_KEY | Digital ocean spaces secret access key or AWS s3 secret access key for uploading the docs |
| DO_REGION | YOUR_S3_REGION | Digital ocean spaces region or AWS s3 region |
| USE_LOCAL | FALSE | To use local file storage to save file |
| MAILGUN_API_KEY | YOUR_MAILGUNAPI_KEY | Mailgun API Key |
| MAILGUN_DOMAIN | YOUR_MAILGUNAPI_DOMAIN | Mailgun API Domain |
| MAILGUN_SENDER | - | Mailgun Sender Mail ID |
| PFX_BASE64 | - | Base64 encoded PFX or p12 document signing certificate file. You can generate base64 encoded self sign certificate using the passphrase `emudhra` |
# Steps to Generate Self Sign Certificate
```
# execute below command and use passphrase emudhra
openssl genrsa -des3 -out ./cert/local_dev.key 2048
openssl req -key ./cert/local_dev.key -new -x509 -days 365 -out ./cert/local_dev.crt
openssl pkcs12 -inkey ./cert/local_dev.key -in ./cert/local_dev.crt -export -out ./cert/local_dev.pfx
openssl base64 -in ./cert/local_dev.pfx -out ./cert/base64_pfx
```
# CORS Configuration
As document storage is delegated to S3-compatible services that reside in a different host than the OpenSign one, document operations (loading, storing, deleting) are subject to [Cross-Origin Resource Sharing](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) restriction policies; as a consequence, OpenSign app may fail with (browser console) errors like the following:
```
Access to fetch at 'https://foo.nyc3.digitaloceanspaces.com/exported_file_4627_0000-00-00T00%3A45%3A43.344Z.pdf'
from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header
is present on the requested resource. If an opaque response serves your needs, set the request's mode to
'no-cors' to fetch the resource with CORS disabled.
```
In order to address this, your document storage system must be instructed to accept requests from other hosts; below the relevant documentation links:
- [How to Configure CORS on DigitalOcean Spaces](https://docs.digitalocean.com/products/spaces/how-to/configure-cors/)
- [Configuring cross-origin resource sharing on AWS S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/enabling-cors-examples.html)
# Build Local Environment
Command to build project -
- Execute `make build`
Command to run project -
- Execute `make run`
+2 -1
View File
@@ -38,10 +38,11 @@
7. [Acknowledgments](#acknowledgments) 7. [Acknowledgments](#acknowledgments)
--- ---
Please star ⭐ the repo to support us! 😀
### Introduction ### Introduction
Welcome to OpenSign, an open-source document e-signing solution designed to provide a secure, reliable, and free alternative to commercial platforms like DocuSign, PandaDoc, SignNow, Adobe Sign, Smartwaiver, SignRequest, HelloSign & Zoho sign. Developed under the OpenSignLabs organization, our mission is to democratize the e-signing process, making it accessible and straightforward for everyone. Welcome to OpenSign, the premier open-source docusign alternative - document e-signing solution designed to provide a secure, reliable, and free alternative to commercial platforms like DocuSign, PandaDoc, SignNow, Adobe Sign, Smartwaiver, SignRequest, HelloSign & Zoho sign. Developed under the OpenSignLabs organization, our mission is to democratize the e-signing process, making it accessible and straightforward for everyone.
--- ---
+1 -1
View File
@@ -1,5 +1,5 @@
# Use an official Node runtime as the base image # Use an official Node runtime as the base image
FROM node:16 FROM node:18
# Set the working directory inside the container # Set the working directory inside the container
WORKDIR /usr/src/app WORKDIR /usr/src/app
+25
View File
@@ -0,0 +1,25 @@
# Use an official Node runtime as the base image
FROM node:18
# Set the working directory inside the container
WORKDIR /usr/src/app
# Copy package.json and package-lock.json first to leverage Docker cache
COPY apps/OpenSign/package*.json ./
# Install application dependencies
RUN npm install
# Copy the current directory contents into the container
COPY apps/OpenSign/ .
COPY microfrontends/ .
COPY apps/OpenSign/.husky .
# Make port 3000 available to the world outside this container
EXPOSE 3000
# Define environment variables if needed
# ENV NODE_ENV production
# Run the application
CMD ["npm", "start"]
-4
View File
@@ -20,10 +20,6 @@ module.exports = {
"react-router-dom": { "react-router-dom": {
singleton: true, singleton: true,
requiredVersion: dependencies["react-router-dom"] requiredVersion: dependencies["react-router-dom"]
},
"rjsf-conditionals": {
singleton: true,
requiredVersion: dependencies["rjsf-conditionals"]
} }
} }
}; };
+229 -371
View File
@@ -9,18 +9,15 @@
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@reduxjs/toolkit": "^1.9.7", "@reduxjs/toolkit": "^1.9.7",
"@rjsf/core": "^5.13.0", "axios": "^1.6.0",
"@rjsf/utils": "^5.13.0",
"@rjsf/validator-ajv8": "^5.13.0",
"axios": "^1.5.1",
"daisyui": "^3.9.2", "daisyui": "^3.9.2",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"html-react-parser": "^4.2.2", "html-react-parser": "^4.2.2",
"json-rules-engine-simplified": "^0.1.17", "json-rules-engine-simplified": "^0.1.17",
"jwt-decode": "^3.1.2", "jwt-decode": "^4.0.0",
"mf-cra": "^0.0.5", "mf-cra": "^0.0.5",
"moment": "^2.29.4", "moment": "^2.29.4",
"parse": "^4.2.0", "parse": "^4.3.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-bootstrap": "^2.9.0", "react-bootstrap": "^2.9.0",
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
@@ -39,20 +36,19 @@
"reactour": "^1.19.2", "reactour": "^1.19.2",
"redux": "^4.2.1", "redux": "^4.2.1",
"redux-thunk": "^2.4.2", "redux-thunk": "^2.4.2",
"rjsf-conditionals": "github:prafullnavkar-nxg/rjsf-conditionals",
"serve": "^14.2.1", "serve": "^14.2.1",
"styled-components": "^4.4.1", "styled-components": "^4.4.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"devDependencies": { "devDependencies": {
"@babel/runtime-corejs2": "^7.23.2", "@babel/runtime-corejs2": "^7.23.9",
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.16",
"commitizen": "^4.3.0", "commitizen": "^4.3.0",
"eslint": "^8.51.0", "eslint": "^8.51.0",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.33.2", "eslint-plugin-react": "^7.33.2",
"lint-staged": "^15.0.1", "lint-staged": "^15.2.2",
"postcss": "^8.4.31", "postcss": "^8.4.35",
"prettier": "^2.8.0", "prettier": "^2.8.0",
"pretty-quick": "^3.1.3", "pretty-quick": "^3.1.3",
"tailwindcss": "^3.3.3" "tailwindcss": "^3.3.3"
@@ -90,11 +86,11 @@
} }
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
"version": "7.22.13", "version": "7.23.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
"dependencies": { "dependencies": {
"@babel/highlight": "^7.22.13", "@babel/highlight": "^7.23.4",
"chalk": "^2.4.2" "chalk": "^2.4.2"
}, },
"engines": { "engines": {
@@ -180,11 +176,11 @@
} }
}, },
"node_modules/@babel/generator": { "node_modules/@babel/generator": {
"version": "7.23.0", "version": "7.23.6",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz",
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==",
"dependencies": { "dependencies": {
"@babel/types": "^7.23.0", "@babel/types": "^7.23.6",
"@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17", "@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1" "jsesc": "^2.5.1"
@@ -463,9 +459,9 @@
} }
}, },
"node_modules/@babel/helper-string-parser": { "node_modules/@babel/helper-string-parser": {
"version": "7.22.5", "version": "7.23.4",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@@ -513,9 +509,9 @@
} }
}, },
"node_modules/@babel/highlight": { "node_modules/@babel/highlight": {
"version": "7.22.20", "version": "7.23.4",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
"dependencies": { "dependencies": {
"@babel/helper-validator-identifier": "^7.22.20", "@babel/helper-validator-identifier": "^7.22.20",
"chalk": "^2.4.2", "chalk": "^2.4.2",
@@ -526,9 +522,9 @@
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.23.0", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz",
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==",
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
}, },
@@ -1986,9 +1982,9 @@
} }
}, },
"node_modules/@babel/runtime-corejs2": { "node_modules/@babel/runtime-corejs2": {
"version": "7.23.2", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.23.2.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.23.9.tgz",
"integrity": "sha512-lTwRWGcAUBANnxD0A4c5/wKQ0eLhgdAy9kdY2rzTmmliumBQ8u8awykMnaQAnZR3PC47jLRjGoj+hozZqy9Bww==", "integrity": "sha512-lwwDy5QfMkO2rmSz9AvLj6j2kWt5a4ulMi1t21vWQEO0kNCFslHoszat8reU/uigIQSUDF31zraZG/qMkcqAlw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"core-js": "^2.6.12", "core-js": "^2.6.12",
@@ -1999,22 +1995,17 @@
} }
}, },
"node_modules/@babel/runtime-corejs3": { "node_modules/@babel/runtime-corejs3": {
"version": "7.21.0", "version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.21.0.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.23.2.tgz",
"integrity": "sha512-TDD4UJzos3JJtM+tHX+w2Uc+KWj7GV+VKKFdMVd2Rx8sdA19hcc3P3AHFYd5LVOw+pYuSd5lICC3gm52B6Rwxw==", "integrity": "sha512-54cIh74Z1rp4oIjsHjqN+WM4fMyCBYe+LpZ9jWm51CZ1fbH3SkAzQD/3XLoNkjbJ7YEmjobLXyvQrFypRHOrXw==",
"dependencies": { "dependencies": {
"core-js-pure": "^3.25.1", "core-js-pure": "^3.30.2",
"regenerator-runtime": "^0.13.11" "regenerator-runtime": "^0.14.0"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/runtime-corejs3/node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.22.15", "version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
@@ -2029,19 +2020,19 @@
} }
}, },
"node_modules/@babel/traverse": { "node_modules/@babel/traverse": {
"version": "7.23.0", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz",
"integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==", "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.22.13", "@babel/code-frame": "^7.23.5",
"@babel/generator": "^7.23.0", "@babel/generator": "^7.23.6",
"@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0", "@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6", "@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.23.0", "@babel/parser": "^7.23.9",
"@babel/types": "^7.23.0", "@babel/types": "^7.23.9",
"debug": "^4.1.0", "debug": "^4.3.1",
"globals": "^11.1.0" "globals": "^11.1.0"
}, },
"engines": { "engines": {
@@ -2049,11 +2040,11 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.23.0", "version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz",
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==",
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.22.5", "@babel/helper-string-parser": "^7.23.4",
"@babel/helper-validator-identifier": "^7.22.20", "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0" "to-fast-properties": "^2.0.0"
}, },
@@ -3921,85 +3912,6 @@
"react": ">=16.14.0" "react": ">=16.14.0"
} }
}, },
"node_modules/@rjsf/core": {
"version": "5.13.0",
"resolved": "https://registry.npmjs.org/@rjsf/core/-/core-5.13.0.tgz",
"integrity": "sha512-rCpJGR0yPP/ip9LKcr3SmDMkbLx4QIaRA+ag0rcalSw1XLXBSzh53SpfgaB2HN++1xhUvWtIUERRHpWjQp1E7w==",
"dependencies": {
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"markdown-to-jsx": "^7.3.2",
"nanoid": "^3.3.6",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"@rjsf/utils": "^5.12.x",
"react": "^16.14.0 || >=17"
}
},
"node_modules/@rjsf/utils": {
"version": "5.13.0",
"resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.13.0.tgz",
"integrity": "sha512-tG2OuOJUJZ0W7VMZceD0I2SOjfMRRT1tRtG+SKbdNqhtH/gpg40aOMUj9cWgSQnYISEkNZjZq/z7NWln5RxW6A==",
"dependencies": {
"json-schema-merge-allof": "^0.8.1",
"jsonpointer": "^5.0.1",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"react-is": "^18.2.0"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"react": "^16.14.0 || >=17"
}
},
"node_modules/@rjsf/utils/node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/@rjsf/validator-ajv8": {
"version": "5.13.0",
"resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-5.13.0.tgz",
"integrity": "sha512-8j0xLsxJA/k1UADeDYZ2aMVrswvOCEYNC++YchoAgWRHqDiaGAUyRbbk7oxMi6QUXnhnlCIepzNeTclHnSfPXQ==",
"dependencies": {
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"@rjsf/utils": "^5.12.x"
}
},
"node_modules/@rjsf/validator-ajv8/node_modules/ajv": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/@rjsf/validator-ajv8/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
},
"node_modules/@rollup/plugin-babel": { "node_modules/@rollup/plugin-babel": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -5612,9 +5524,9 @@
} }
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "1.5.1", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz",
"integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", "integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==",
"dependencies": { "dependencies": {
"follow-redirects": "^1.15.0", "follow-redirects": "^1.15.0",
"form-data": "^4.0.0", "form-data": "^4.0.0",
@@ -6675,16 +6587,16 @@
} }
}, },
"node_modules/cli-truncate": { "node_modules/cli-truncate": {
"version": "3.1.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz",
"integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"slice-ansi": "^5.0.0", "slice-ansi": "^5.0.0",
"string-width": "^5.0.0" "string-width": "^7.0.0"
}, },
"engines": { "engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0" "node": ">=18"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
@@ -6702,18 +6614,24 @@
"url": "https://github.com/chalk/ansi-regex?sponsor=1" "url": "https://github.com/chalk/ansi-regex?sponsor=1"
} }
}, },
"node_modules/cli-truncate/node_modules/emoji-regex": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz",
"integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==",
"dev": true
},
"node_modules/cli-truncate/node_modules/string-width": { "node_modules/cli-truncate/node_modules/string-width": {
"version": "5.1.2", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"eastasianwidth": "^0.2.0", "emoji-regex": "^10.3.0",
"emoji-regex": "^9.2.2", "get-east-asian-width": "^1.0.0",
"strip-ansi": "^7.0.1" "strip-ansi": "^7.1.0"
}, },
"engines": { "engines": {
"node": ">=12" "node": ">=18"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
@@ -6965,27 +6883,6 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}, },
"node_modules/compute-gcd": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/compute-gcd/-/compute-gcd-1.2.1.tgz",
"integrity": "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==",
"dependencies": {
"validate.io-array": "^1.0.3",
"validate.io-function": "^1.0.2",
"validate.io-integer-array": "^1.0.0"
}
},
"node_modules/compute-lcm": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/compute-lcm/-/compute-lcm-1.1.2.tgz",
"integrity": "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==",
"dependencies": {
"compute-gcd": "^1.2.1",
"validate.io-array": "^1.0.3",
"validate.io-function": "^1.0.2",
"validate.io-integer-array": "^1.0.0"
}
},
"node_modules/concat-map": { "node_modules/concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -7132,9 +7029,9 @@
} }
}, },
"node_modules/crypto-js": { "node_modules/crypto-js": {
"version": "4.1.1", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==", "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
"optional": true "optional": true
}, },
"node_modules/crypto-random-string": { "node_modules/crypto-random-string": {
@@ -7676,14 +7573,6 @@
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
}, },
"node_modules/deepcopy": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/deepcopy/-/deepcopy-2.1.0.tgz",
"integrity": "sha512-8cZeTb1ZKC3bdSCP6XOM1IsTczIO73fdqtwa2B0N15eAz7gmyhQo+mc5gnFuulsgN3vIQYmTgbmQVKalH1dKvQ==",
"dependencies": {
"type-detect": "^4.0.8"
}
},
"node_modules/deepmerge": { "node_modules/deepmerge": {
"version": "4.3.1", "version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
@@ -9505,9 +9394,9 @@
"integrity": "sha512-bHWEmjLsTjGP9gVs7P3Hyl+oY5NlMW8aTSPdTJ+X2GKt6glDctt9fUCLbRV+d/l8NDC40+FxMjp9WlTQXaQALw==" "integrity": "sha512-bHWEmjLsTjGP9gVs7P3Hyl+oY5NlMW8aTSPdTJ+X2GKt6glDctt9fUCLbRV+d/l8NDC40+FxMjp9WlTQXaQALw=="
}, },
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.15.3", "version": "1.15.5",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
"integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@@ -9810,6 +9699,18 @@
"node": "6.* || 8.* || >= 10.*" "node": "6.* || 8.* || >= 10.*"
} }
}, },
"node_modules/get-east-asian-width": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz",
"integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==",
"dev": true,
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/get-intrinsic": { "node_modules/get-intrinsic": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
@@ -10506,12 +10407,9 @@
"integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ=="
}, },
"node_modules/idb-keyval": { "node_modules/idb-keyval": {
"version": "6.2.0", "version": "6.2.1",
"resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.0.tgz", "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
"integrity": "sha512-uw+MIyQn2jl3+hroD7hF8J7PUviBU7BPKWw4f/ISf32D4LoGu98yHjrzWWJDASu9QNrX10tCJqk9YY0ClWm8Ng==", "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
"dependencies": {
"safari-14-idb-fix": "^3.0.0"
}
}, },
"node_modules/identity-obj-proxy": { "node_modules/identity-obj-proxy": {
"version": "3.0.0", "version": "3.0.0",
@@ -13418,27 +13316,6 @@
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
}, },
"node_modules/json-schema-compare": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/json-schema-compare/-/json-schema-compare-0.2.2.tgz",
"integrity": "sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ==",
"dependencies": {
"lodash": "^4.17.4"
}
},
"node_modules/json-schema-merge-allof": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz",
"integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==",
"dependencies": {
"compute-lcm": "^1.1.2",
"json-schema-compare": "^0.2.2",
"lodash": "^4.17.20"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/json-schema-traverse": { "node_modules/json-schema-traverse": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -13516,9 +13393,12 @@
} }
}, },
"node_modules/jwt-decode": { "node_modules/jwt-decode": {
"version": "3.1.2", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
"integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
"engines": {
"node": ">=18"
}
}, },
"node_modules/keyv": { "node_modules/keyv": {
"version": "4.5.4", "version": "4.5.4",
@@ -13608,21 +13488,21 @@
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
}, },
"node_modules/lint-staged": { "node_modules/lint-staged": {
"version": "15.0.1", "version": "15.2.2",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.0.1.tgz", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.2.tgz",
"integrity": "sha512-2IU5OWmCaxch0X0+IBF4/v7sutpB+F3qoXbro43pYjQTOo5wumckjxoxn47pQBqqBsCWrD5HnI2uG/zJA7isew==", "integrity": "sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"chalk": "5.3.0", "chalk": "5.3.0",
"commander": "11.1.0", "commander": "11.1.0",
"debug": "4.3.4", "debug": "4.3.4",
"execa": "8.0.1", "execa": "8.0.1",
"lilconfig": "2.1.0", "lilconfig": "3.0.0",
"listr2": "7.0.1", "listr2": "8.0.1",
"micromatch": "4.0.5", "micromatch": "4.0.5",
"pidtree": "0.6.0", "pidtree": "0.6.0",
"string-argv": "0.3.2", "string-argv": "0.3.2",
"yaml": "2.3.2" "yaml": "2.3.4"
}, },
"bin": { "bin": {
"lint-staged": "bin/lint-staged.js" "lint-staged": "bin/lint-staged.js"
@@ -13711,6 +13591,15 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/lint-staged/node_modules/lilconfig": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz",
"integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==",
"dev": true,
"engines": {
"node": ">=14"
}
},
"node_modules/lint-staged/node_modules/mimic-fn": { "node_modules/lint-staged/node_modules/mimic-fn": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
@@ -13790,29 +13679,29 @@
} }
}, },
"node_modules/lint-staged/node_modules/yaml": { "node_modules/lint-staged/node_modules/yaml": {
"version": "2.3.2", "version": "2.3.4",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz",
"integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==", "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">= 14" "node": ">= 14"
} }
}, },
"node_modules/listr2": { "node_modules/listr2": {
"version": "7.0.1", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/listr2/-/listr2-7.0.1.tgz", "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.1.tgz",
"integrity": "sha512-nz+7hwgbDp8eWNoDgzdl4hA/xDSLrNRzPu1TLgOYs6l5Y+Ma6zVWWy9Oyt9TQFONwKoSPoka3H50D3vD5EuNwg==", "integrity": "sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"cli-truncate": "^3.1.0", "cli-truncate": "^4.0.0",
"colorette": "^2.0.20", "colorette": "^2.0.20",
"eventemitter3": "^5.0.1", "eventemitter3": "^5.0.1",
"log-update": "^5.0.1", "log-update": "^6.0.0",
"rfdc": "^1.3.0", "rfdc": "^1.3.0",
"wrap-ansi": "^8.1.0" "wrap-ansi": "^9.0.0"
}, },
"engines": { "engines": {
"node": ">=16.0.0" "node": ">=18.0.0"
} }
}, },
"node_modules/listr2/node_modules/ansi-regex": { "node_modules/listr2/node_modules/ansi-regex": {
@@ -13839,6 +13728,12 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1" "url": "https://github.com/chalk/ansi-styles?sponsor=1"
} }
}, },
"node_modules/listr2/node_modules/emoji-regex": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz",
"integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==",
"dev": true
},
"node_modules/listr2/node_modules/eventemitter3": { "node_modules/listr2/node_modules/eventemitter3": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
@@ -13846,17 +13741,17 @@
"dev": true "dev": true
}, },
"node_modules/listr2/node_modules/string-width": { "node_modules/listr2/node_modules/string-width": {
"version": "5.1.2", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"eastasianwidth": "^0.2.0", "emoji-regex": "^10.3.0",
"emoji-regex": "^9.2.2", "get-east-asian-width": "^1.0.0",
"strip-ansi": "^7.0.1" "strip-ansi": "^7.1.0"
}, },
"engines": { "engines": {
"node": ">=12" "node": ">=18"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
@@ -13878,17 +13773,17 @@
} }
}, },
"node_modules/listr2/node_modules/wrap-ansi": { "node_modules/listr2/node_modules/wrap-ansi": {
"version": "8.1.0", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"ansi-styles": "^6.1.0", "ansi-styles": "^6.2.1",
"string-width": "^5.0.1", "string-width": "^7.0.0",
"strip-ansi": "^7.0.1" "strip-ansi": "^7.1.0"
}, },
"engines": { "engines": {
"node": ">=12" "node": ">=18"
}, },
"funding": { "funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1" "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
@@ -13934,21 +13829,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
}, },
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"node_modules/lodash.debounce": { "node_modules/lodash.debounce": {
"version": "4.0.8", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
}, },
"node_modules/lodash.isequalwith": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.isequalwith/-/lodash.isequalwith-4.4.0.tgz",
"integrity": "sha512-dcZON0IalGBpRmJBmMkaoV7d3I80R2O+FrzsZyHdNSFrANq/cgDqKQNmAHE8UEj4+QYWwwhkQOVdLHiAopzlsQ=="
},
"node_modules/lodash.isplainobject": { "node_modules/lodash.isplainobject": {
"version": "4.0.6", "version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
@@ -14081,34 +13966,34 @@
} }
}, },
"node_modules/log-update": { "node_modules/log-update": {
"version": "5.0.1", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz",
"integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"ansi-escapes": "^5.0.0", "ansi-escapes": "^6.2.0",
"cli-cursor": "^4.0.0", "cli-cursor": "^4.0.0",
"slice-ansi": "^5.0.0", "slice-ansi": "^7.0.0",
"strip-ansi": "^7.0.1", "strip-ansi": "^7.1.0",
"wrap-ansi": "^8.0.1" "wrap-ansi": "^9.0.0"
}, },
"engines": { "engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0" "node": ">=18"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/log-update/node_modules/ansi-escapes": { "node_modules/log-update/node_modules/ansi-escapes": {
"version": "5.0.0", "version": "6.2.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz",
"integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"type-fest": "^1.0.2" "type-fest": "^3.0.0"
}, },
"engines": { "engines": {
"node": ">=12" "node": ">=14.16"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
@@ -14153,6 +14038,27 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/log-update/node_modules/emoji-regex": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz",
"integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==",
"dev": true
},
"node_modules/log-update/node_modules/is-fullwidth-code-point": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz",
"integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==",
"dev": true,
"dependencies": {
"get-east-asian-width": "^1.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/log-update/node_modules/restore-cursor": { "node_modules/log-update/node_modules/restore-cursor": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
@@ -14169,18 +14075,34 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/log-update/node_modules/string-width": { "node_modules/log-update/node_modules/slice-ansi": {
"version": "5.1.2", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"eastasianwidth": "^0.2.0", "ansi-styles": "^6.2.1",
"emoji-regex": "^9.2.2", "is-fullwidth-code-point": "^5.0.0"
"strip-ansi": "^7.0.1"
}, },
"engines": { "engines": {
"node": ">=12" "node": ">=18"
},
"funding": {
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
"node_modules/log-update/node_modules/string-width": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz",
"integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==",
"dev": true,
"dependencies": {
"emoji-regex": "^10.3.0",
"get-east-asian-width": "^1.0.0",
"strip-ansi": "^7.1.0"
},
"engines": {
"node": ">=18"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
@@ -14202,29 +14124,29 @@
} }
}, },
"node_modules/log-update/node_modules/type-fest": { "node_modules/log-update/node_modules/type-fest": {
"version": "1.4.0", "version": "3.13.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz",
"integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=10" "node": ">=14.16"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/log-update/node_modules/wrap-ansi": { "node_modules/log-update/node_modules/wrap-ansi": {
"version": "8.1.0", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"ansi-styles": "^6.1.0", "ansi-styles": "^6.2.1",
"string-width": "^5.0.1", "string-width": "^7.0.0",
"strip-ansi": "^7.0.1" "strip-ansi": "^7.1.0"
}, },
"engines": { "engines": {
"node": ">=12" "node": ">=18"
}, },
"funding": { "funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1" "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
@@ -14310,17 +14232,6 @@
"tmpl": "1.0.5" "tmpl": "1.0.5"
} }
}, },
"node_modules/markdown-to-jsx": {
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.3.2.tgz",
"integrity": "sha512-B+28F5ucp83aQm+OxNrPkS8z0tMKaeHiy0lHJs3LqCyDQFtWuenaIrkaVTgAm1pf1AU85LXltva86hlaT17i8Q==",
"engines": {
"node": ">= 10"
},
"peerDependencies": {
"react": ">= 0.14.0"
}
},
"node_modules/mdn-data": { "node_modules/mdn-data": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
@@ -14624,9 +14535,9 @@
} }
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.3.6", "version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@@ -15128,14 +15039,14 @@
} }
}, },
"node_modules/parse": { "node_modules/parse": {
"version": "4.2.0", "version": "4.3.1",
"resolved": "https://registry.npmjs.org/parse/-/parse-4.2.0.tgz", "resolved": "https://registry.npmjs.org/parse/-/parse-4.3.1.tgz",
"integrity": "sha512-K8bWs0wM2qRhkSr6N16j8OvsF6Uallrynqng9e+tzR3RdKuB09vaJh48qrf9MbiJ1Ya4JZI7AfEHYF+ywEKs7Q==", "integrity": "sha512-ypLPhMPFsJY+C2MXg6HdrVu6ielsL+kUjcSqh7J01lPC5oBuLh70F9YMQSw51QBocEeMSVgB7eUorFOH+MkVpA==",
"dependencies": { "dependencies": {
"@babel/runtime-corejs3": "7.21.0", "@babel/runtime-corejs3": "7.23.2",
"idb-keyval": "6.2.0", "idb-keyval": "6.2.1",
"react-native-crypto-js": "1.0.0", "react-native-crypto-js": "1.0.0",
"uuid": "9.0.0", "uuid": "9.0.1",
"ws": "8.13.0", "ws": "8.13.0",
"xmlhttprequest": "1.8.0" "xmlhttprequest": "1.8.0"
}, },
@@ -15143,7 +15054,7 @@
"node": ">=14.21.0 <17 || >=18 <20" "node": ">=14.21.0 <17 || >=18 <20"
}, },
"optionalDependencies": { "optionalDependencies": {
"crypto-js": "4.1.1" "crypto-js": "4.2.0"
} }
}, },
"node_modules/parse-json": { "node_modules/parse-json": {
@@ -15173,9 +15084,13 @@
} }
}, },
"node_modules/parse/node_modules/uuid": { "node_modules/parse/node_modules/uuid": {
"version": "9.0.0", "version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"bin": { "bin": {
"uuid": "dist/bin/uuid" "uuid": "dist/bin/uuid"
} }
@@ -15445,9 +15360,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.31", "version": "8.4.35",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@@ -15463,7 +15378,7 @@
} }
], ],
"dependencies": { "dependencies": {
"nanoid": "^3.3.6", "nanoid": "^3.3.7",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
"source-map-js": "^1.0.2" "source-map-js": "^1.0.2"
}, },
@@ -18183,9 +18098,9 @@
} }
}, },
"node_modules/rfdc": { "node_modules/rfdc": {
"version": "1.3.0", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz",
"integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==",
"dev": true "dev": true
}, },
"node_modules/rimraf": { "node_modules/rimraf": {
@@ -18202,26 +18117,6 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/rjsf-conditionals": {
"version": "1.5.0",
"resolved": "git+ssh://git@github.com/prafullnavkar-nxg/rjsf-conditionals.git#439aa44e3ece077b1c8098278f86f454ad7185cf",
"license": "Apache-2.0",
"dependencies": {
"@rjsf/validator-ajv8": "^5.13.0",
"deepcopy": "^2.0.0",
"lodash.isequalwith": "^4.4.0",
"selectn": "^1.1.2"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@rjsf/core": ">=2.0.0",
"core-js": "^2.5.7",
"prop-types": "^15.7.2",
"react": "^18.2.0"
}
},
"node_modules/rollup": { "node_modules/rollup": {
"version": "2.79.1", "version": "2.79.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
@@ -18331,11 +18226,6 @@
"tslib": "^2.1.0" "tslib": "^2.1.0"
} }
}, },
"node_modules/safari-14-idb-fix": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/safari-14-idb-fix/-/safari-14-idb-fix-3.0.0.tgz",
"integrity": "sha512-eBNFLob4PMq8JA1dGyFn6G97q3/WzNtFK4RnzT1fnLq+9RyrGknzYiM/9B12MnKAxuj1IXr7UKYtTNtjyKMBog=="
},
"node_modules/safe-array-concat": { "node_modules/safe-array-concat": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz",
@@ -20423,38 +20313,6 @@
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
}, },
"node_modules/validate.io-array": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz",
"integrity": "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg=="
},
"node_modules/validate.io-function": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz",
"integrity": "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ=="
},
"node_modules/validate.io-integer": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz",
"integrity": "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==",
"dependencies": {
"validate.io-number": "^1.0.3"
}
},
"node_modules/validate.io-integer-array": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz",
"integrity": "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==",
"dependencies": {
"validate.io-array": "^1.0.3",
"validate.io-integer": "^1.0.4"
}
},
"node_modules/validate.io-number": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz",
"integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg=="
},
"node_modules/vary": { "node_modules/vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+8 -10
View File
@@ -4,18 +4,15 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@reduxjs/toolkit": "^1.9.7", "@reduxjs/toolkit": "^1.9.7",
"@rjsf/core": "^5.13.0", "axios": "^1.6.0",
"@rjsf/utils": "^5.13.0",
"@rjsf/validator-ajv8": "^5.13.0",
"axios": "^1.5.1",
"daisyui": "^3.9.2", "daisyui": "^3.9.2",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"html-react-parser": "^4.2.2", "html-react-parser": "^4.2.2",
"json-rules-engine-simplified": "^0.1.17", "json-rules-engine-simplified": "^0.1.17",
"jwt-decode": "^3.1.2", "jwt-decode": "^4.0.0",
"mf-cra": "^0.0.5", "mf-cra": "^0.0.5",
"moment": "^2.29.4", "moment": "^2.29.4",
"parse": "^4.2.0", "parse": "^4.3.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-bootstrap": "^2.9.0", "react-bootstrap": "^2.9.0",
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
@@ -34,7 +31,6 @@
"reactour": "^1.19.2", "reactour": "^1.19.2",
"redux": "^4.2.1", "redux": "^4.2.1",
"redux-thunk": "^2.4.2", "redux-thunk": "^2.4.2",
"rjsf-conditionals": "github:prafullnavkar-nxg/rjsf-conditionals",
"serve": "^14.2.1", "serve": "^14.2.1",
"styled-components": "^4.4.1", "styled-components": "^4.4.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
@@ -45,6 +41,8 @@
"version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt", "version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
"build": "npm run version && rm -rf public/mfbuild && npm run micro && CI=false && mf-cra build", "build": "npm run version && rm -rf public/mfbuild && npm run micro && CI=false && mf-cra build",
"micro": "cd ../../microfrontends/SignDocuments && npm install && npm run build", "micro": "cd ../../microfrontends/SignDocuments && npm install && npm run build",
"docker-build": "npm run version && rm -rf public/mfbuild && npm run docker-micro && CI=false && mf-cra build",
"docker-micro": "cd ./SignDocuments && npm install && npm run docker-build",
"test": "react-scripts test", "test": "react-scripts test",
"eject": "react-scripts eject", "eject": "react-scripts eject",
"release": "standard-version", "release": "standard-version",
@@ -74,14 +72,14 @@
} }
}, },
"devDependencies": { "devDependencies": {
"@babel/runtime-corejs2": "^7.23.2", "@babel/runtime-corejs2": "^7.23.9",
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.16",
"commitizen": "^4.3.0", "commitizen": "^4.3.0",
"eslint": "^8.51.0", "eslint": "^8.51.0",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.33.2", "eslint-plugin-react": "^7.33.2",
"lint-staged": "^15.0.1", "lint-staged": "^15.2.2",
"postcss": "^8.4.31", "postcss": "^8.4.35",
"prettier": "^2.8.0", "prettier": "^2.8.0",
"pretty-quick": "^3.1.3", "pretty-quick": "^3.1.3",
"tailwindcss": "^3.3.3" "tailwindcss": "^3.3.3"
+1 -1
View File
@@ -1 +1 @@
v1.0.5-beta v1.1.1-beta
+25 -75
View File
@@ -7,7 +7,7 @@ import Signup from "./routes/Signup";
import Form from "./routes/Form"; import Form from "./routes/Form";
import Report from "./routes/Report"; import Report from "./routes/Report";
import Dashboard from "./routes/Dashboard"; import Dashboard from "./routes/Dashboard";
import PlanSubscriptions from "./routes/PlanSubscriptions"; import Subscriptions from "./routes/PlanSubscriptions";
import HomeLayout from "./layout/HomeLayout"; import HomeLayout from "./layout/HomeLayout";
import UserProfile from "./routes/UserProfile"; import UserProfile from "./routes/UserProfile";
import PageNotFound from "./routes/PageNotFound"; import PageNotFound from "./routes/PageNotFound";
@@ -15,6 +15,10 @@ import ForgetPassword from "./routes/ForgetPassword";
import ChangePassword from "./routes/ChangePassword"; import ChangePassword from "./routes/ChangePassword";
import ReportMicroapp from "./components/ReportMicroapp"; import ReportMicroapp from "./components/ReportMicroapp";
import LoadMf from "./routes/LoadMf"; import LoadMf from "./routes/LoadMf";
import GenerateToken from "./routes/GenerateToken";
import ValidateRoute from "./primitives/ValidateRoute";
import Webhook from "./routes/Webhook";
import Validate from "./primitives/Validate";
function App() { function App() {
const [isloading, setIsLoading] = useState(true); const [isloading, setIsLoading] = useState(true);
@@ -58,88 +62,34 @@ function App() {
) : ( ) : (
<BrowserRouter> <BrowserRouter>
<Routes> <Routes>
<Route exact path="/" element={<Login />} /> <Route element={<ValidateRoute />}>
<Route exact path="/signup" element={<Signup />} /> <Route exact path="/" element={<Login />} />
<Route exact path="/signup" element={<Signup />} />
</Route>
<Route element={<Validate />}>
<Route exact path="/load/:remoteApp/*" element={<LoadMf />} />
</Route>
<Route exact path="/loadmf/:remoteApp/*" element={<LoadMf />} /> <Route exact path="/loadmf/:remoteApp/*" element={<LoadMf />} />
<Route exact path="/forgetpassword" element={<ForgetPassword />} /> <Route exact path="/forgetpassword" element={<ForgetPassword />} />
{process.env.REACT_APP_ENABLE_SUBSCRIPTION && ( {process.env.REACT_APP_ENABLE_SUBSCRIPTION && (
<> <>
<Route exact path="/pgsignup" element={<Pgsignup />} /> <Route exact path="/pgsignup" element={<Pgsignup />} />
<Route <Route exact path="/subscription" element={<Subscriptions />} />
exact
path="/subscription"
element={<PlanSubscriptions />}
/>
</> </>
)} )}
<Route <Route element={<HomeLayout />}>
exact <Route path="/changepassword" element={<ChangePassword />} />
path="/changepassword" <Route path="/mf/:remoteApp/*" element={<Microapp />} />
element={ <Route path="/asmf/:remoteApp/*" element={<Microapp />} />
<HomeLayout> <Route path="/rpmf/:remoteApp/*" element={<ReportMicroapp />} />
<ChangePassword /> <Route path="/form/:id" element={<Form />} />
</HomeLayout> <Route path="/report/:id" element={<Report />} />
} <Route path="/dashboard/:id" element={<Dashboard />} />
/> <Route path="/profile" element={<UserProfile />} />
<Route <Route path="/generatetoken" element={<GenerateToken />} />
path="/mf/:remoteApp/*" <Route path="/webhook" element={<Webhook />} />
element={ </Route>
<HomeLayout>
<Microapp />
</HomeLayout>
}
/>
<Route
path="/asmf/:remoteApp/*"
element={
<HomeLayout>
<Microapp />
</HomeLayout>
}
/>
<Route
path="/rpmf/:remoteApp/*"
element={
<HomeLayout>
<ReportMicroapp />
</HomeLayout>
}
/>
<Route
path="/form/:id"
element={
<HomeLayout>
<Form />
</HomeLayout>
}
/>
<Route
path="/report/:id"
element={
<HomeLayout>
<Report />
</HomeLayout>
}
/>
<Route
path="/dashboard/:id"
element={
<HomeLayout>
<Dashboard />
</HomeLayout>
}
/>
<Route
path="/profile"
element={
<HomeLayout>
<UserProfile />
</HomeLayout>
}
/>
<Route path="*" element={<PageNotFound />} /> <Route path="*" element={<PageNotFound />} />
{/* <Route exact path="/ForgotPassword" element={<ForgotPassword />} /> */}
</Routes> </Routes>
</BrowserRouter> </BrowserRouter>
)} )}
+283
View File
@@ -0,0 +1,283 @@
import React, { useState } from "react";
import Parse from "parse";
import axios from "axios";
import Title from "./Title";
import Alert from "../primitives/Alert";
const AddUser = (props) => {
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const [email, setEmail] = useState("");
const [isLoader, setIsLoader] = useState(false);
const [isUserExist, setIsUserExist] = useState(false);
const parseBaseUrl = localStorage.getItem("baseUrl");
const parseAppId = localStorage.getItem("parseAppId");
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
const checkUserExist = async () => {
try {
const res = await Parse.Cloud.run("getUserDetails", {
email: email,
userId: Parse.User.current().id
});
if (res) {
return true;
} else {
return false;
}
} catch (err) {
console.log("err", err);
}
};
// Define a function to handle form submission
const handleSubmit = async (e) => {
e.preventDefault();
e.stopPropagation();
setIsLoader(true);
const res = await checkUserExist();
if (res) {
setIsUserExist(true);
setIsLoader(false);
setTimeout(() => {
setIsUserExist(false);
}, 1000);
} else {
try {
const contactQuery = new Parse.Object("contracts_Users");
contactQuery.set("Name", name);
contactQuery.set("Phone", phone);
contactQuery.set("Email", email);
contactQuery.set("UserRole", "contracts_User");
if (localStorage.getItem("TenetId")) {
contactQuery.set("TenantId", {
__type: "Pointer",
className: "partners_Tenant",
objectId: localStorage.getItem("TenetId")
});
}
try {
const _users = Parse.Object.extend("User");
const _user = new _users();
_user.set("name", name);
_user.set("username", email);
_user.set("email", email);
_user.set("phone", phone);
_user.set("password", phone);
const user = await _user.save();
if (user) {
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessionToken: localStorage.getItem("accesstoken")
};
const body = {
appName: localStorage.getItem("_appName"),
roleName: "contracts_User",
userId: user.id
};
await axios.post(roleurl, body, { headers: headers });
const currentUser = Parse.User.current();
contactQuery.set(
"CreatedBy",
Parse.User.createWithoutData(currentUser.id)
);
contactQuery.set("UserId", user);
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(true);
acl.setReadAccess(currentUser.id, true);
acl.setWriteAccess(currentUser.id, true);
contactQuery.setACL(acl);
const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res));
if (props.details) {
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
}
if (props.closePopup) {
props.closePopup();
}
if (props.handleUserData) {
props.handleUserData(parseData);
}
setIsLoader(false);
setName("");
setPhone("");
setEmail("");
}
} catch (err) {
console.log("err ", err);
if (err.code === 202) {
const params = { email: email };
const userRes = await Parse.Cloud.run("getUserId", params);
const roleurl = `${parseBaseUrl}functions/AddUserToRole`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessionToken: localStorage.getItem("accesstoken")
};
const body = {
appName: localStorage.getItem("_appName"),
roleName: "contracts_User",
userId: userRes.id
};
await axios.post(roleurl, body, { headers: headers });
const currentUser = Parse.User.current();
contactQuery.set(
"CreatedBy",
Parse.User.createWithoutData(currentUser.id)
);
contactQuery.set("UserId", {
__type: "Pointer",
className: "_User",
objectId: userRes.id
});
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(true);
acl.setReadAccess(currentUser.id, true);
acl.setWriteAccess(currentUser.id, true);
contactQuery.setACL(acl);
const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res));
if (props.details) {
props.details({
value: parseData[props.valueKey],
label: parseData[props.displayKey]
});
}
if (props.closePopup) {
props.closePopup();
}
if (props.handleUserData) {
props.handleUserData(parseData);
}
setIsLoader(false);
setName("");
setPhone("");
setEmail("");
}
}
} catch (err) {
// console.log("err", err);
setIsLoader(false);
alert("something went wrong!");
}
}
};
// Define a function to handle the "add yourself" checkbox
const handleReset = () => {
setName("");
setPhone("");
setEmail("");
};
return (
<div className="shadow-md rounded my-2 p-3 bg-[#ffffff] md:border-[1px] md:border-gray-600/50">
<Title title={"Add User"} />
{isUserExist && <Alert type="danger">User already exists!</Alert>}
{isLoader && (
<div className="fixed inset-0 flex justify-center items-center bg-black bg-opacity-30 z-50">
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
</div>
)}
<div className="w-full mx-auto">
<form onSubmit={handleSubmit}>
<h1 className="text-[20px] font-semibold mb-4">Add User</h1>
<div className="mb-3">
<label
htmlFor="name"
className="block text-xs text-gray-700 font-semibold"
>
Name
<span style={{ color: "red", fontSize: 13 }}> *</span>
</label>
<input
type="text"
id="name"
value={name}
onChange={(e) => setName(e.target.value)}
required
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
/>
</div>
<div className="mb-3">
<label
htmlFor="email"
className="block text-xs text-gray-700 font-semibold"
>
Email
<span style={{ color: "red", fontSize: 13 }}> *</span>
</label>
<input
type="email"
id="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
/>
</div>
<div className="mb-3">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
>
Phone
<span style={{ color: "red", fontSize: 13 }}> *</span>
</label>
<input
type="text"
id="phone"
value={phone}
onChange={(e) => setPhone(e.target.value)}
required
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
/>
</div>
<div className="flex items-center mt-3 gap-2 text-white">
<button
type="submit"
className="bg-[#1ab6ce] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 focus:outline-none"
>
Submit
</button>
<div
type="button"
onClick={() => handleReset()}
className="bg-[#188ae2] rounded-sm shadow-md text-[13px] font-semibold uppercase text-white py-1.5 px-2.5 text-center ml-[2px] focus:outline-none"
>
Reset
</div>
</div>
</form>
</div>
</div>
);
};
export default AddUser;
@@ -1,6 +1,7 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import Parse from "parse"; import Parse from "parse";
import axios from "axios"; import axios from "axios";
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const";
const AppendFormInForm = (props) => { const AppendFormInForm = (props) => {
const [name, setName] = useState(""); const [name, setName] = useState("");
@@ -46,6 +47,7 @@ const AppendFormInForm = (props) => {
// Define a function to handle form submission // Define a function to handle form submission
const handleSubmit = async (e) => { const handleSubmit = async (e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation();
setIsLoader(true); setIsLoader(true);
Parse.serverURL = parseBaseUrl; Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId); Parse.initialize(parseAppId);
@@ -105,13 +107,18 @@ const AppendFormInForm = (props) => {
const res = await contactQuery.save(); const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res)); const parseData = JSON.parse(JSON.stringify(res));
props.details({ if (props.details) {
value: parseData[props.valueKey], props.details({
label: parseData[props.displayKey] value: parseData[props.valueKey],
}); label: parseData[props.displayKey]
});
}
if (props.closePopup) { if (props.closePopup) {
props.closePopup(); props.closePopup();
} }
if (props.handleUserData) {
props.handleUserData(parseData);
}
setIsLoader(false); setIsLoader(false);
// Reset the form fields // Reset the form fields
@@ -158,13 +165,18 @@ const AppendFormInForm = (props) => {
const res = await contactQuery.save(); const res = await contactQuery.save();
const parseData = JSON.parse(JSON.stringify(res)); const parseData = JSON.parse(JSON.stringify(res));
props.details({ if (props.details) {
value: parseData[props.valueKey], props.details({
label: parseData[props.displayKey] value: parseData[props.valueKey],
}); label: parseData[props.displayKey]
});
}
if (props.closePopup) { if (props.closePopup) {
props.closePopup(); props.closePopup();
} }
if (props.handleUserData) {
props.handleUserData(parseData);
}
setIsLoader(false); setIsLoader(false);
// Reset the form fields // Reset the form fields
setAddYourself(false); setAddYourself(false);
@@ -282,14 +294,16 @@ const AppendFormInForm = (props) => {
<div className="mt-4 flex justify-start"> <div className="mt-4 flex justify-start">
<button <button
type="submit" type="submit"
className="bg-[#1ab6ce] text-sm text-white px-4 py-2 rounded shadow focus:outline-none" style={{ backgroundColor: modalSubmitBtnColor }}
className="mr-2 px-[20px] py-1.5 text-white rounded shadow-md text-center focus:outline-none "
> >
Submit Submit
</button> </button>
<button <button
type="button" type="button"
onClick={() => handleReset()} onClick={() => handleReset()}
className="bg-[#188ae2] text-sm text-white px-4 py-2 rounded ml-2 shadow focus:outline-none" style={{ backgroundColor: modalCancelBtnColor }}
className="px-4 py-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none"
> >
Reset Reset
</button> </button>
+9 -2
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Package from "../../package.json"; import Package from "../../package.json";
import axios from "axios"; import axios from "axios";
import { openInNewTab } from "../constant/Utils";
const Footer = () => { const Footer = () => {
const [showButton, setShowButton] = useState(false); const [showButton, setShowButton] = useState(false);
const [version, setVersion] = useState(""); const [version, setVersion] = useState("");
@@ -37,12 +38,18 @@ const Footer = () => {
}, []); }, []);
const appName = "OpenSign™"; const appName = "OpenSign™";
const openUrl = () => {
openInNewTab(
"https://github.com/OpenSignLabs/OpenSign/releases/tag/" + version
);
};
return ( return (
<> <>
<div className="bg-[#222c3c] text-[#98a6ba] text-center text-[13px] py-3"> <div className="bg-[#222c3c] text-[#98a6ba] text-center text-[13px] py-3">
All Rights Reserved &copy; {new Date().getFullYear()} &nbsp; All Rights Reserved &copy; {new Date().getFullYear()} &nbsp;
{appName} ( version: {version ? version : `${Package.version} `}) <span onClick={openUrl} className="hover:underline cursor-pointer">
{appName} ( version: {version ? version : `${Package.version} `})
</span>
</div> </div>
<button <button
className={`${ className={`${
+7
View File
@@ -4,6 +4,7 @@ import FullScreenButton from "./FullScreenButton";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import Parse from "parse"; import Parse from "parse";
import { useWindowSize } from "../hook/useWindowSize"; import { useWindowSize } from "../hook/useWindowSize";
import { openInNewTab } from "../constant/Utils";
const Header = ({ showSidebar }) => { const Header = ({ showSidebar }) => {
const navigation = useNavigate(); const navigation = useNavigate();
const { width } = useWindowSize(); const { width } = useWindowSize();
@@ -118,6 +119,12 @@ const Header = ({ showSidebar }) => {
<ul> <ul>
<li <li
className="hover:bg-gray-100 rounded-t-lg py-1 px-2 cursor-pointer font-normal" className="hover:bg-gray-100 rounded-t-lg py-1 px-2 cursor-pointer font-normal"
onClick={() => openInNewTab("https://docs.opensignlabs.com")}
>
<i className="fa-solid fa-book"></i> Docs
</li>
<li
className="hover:bg-gray-100 py-1 px-2 cursor-pointer font-normal"
onClick={() => { onClick={() => {
setIsOpen(false); setIsOpen(false);
navigation("/profile"); navigation("/profile");
@@ -86,7 +86,7 @@ const LoginFacebook = ({
email: userDetails.Email, email: userDetails.Email,
// "passsword":userDetails.Phone, // "passsword":userDetails.Phone,
phone: userDetails.Phone, phone: userDetails.Phone,
role: "contracts_Admin", role: "contracts_User",
company: userDetails.Company company: userDetails.Company
} }
}; };
+91 -113
View File
@@ -1,7 +1,9 @@
import React, { useState, useRef } from "react"; import React, { useState, useRef } from "react";
import Parse from "parse"; import Parse from "parse";
import jwtDecode from "jwt-decode"; import { jwtDecode } from "jwt-decode";
import { useScript } from "../hook/useScript"; import { useScript } from "../hook/useScript";
import ModalUi from "../primitives/ModalUi";
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const";
/* /*
* `GoogleSignInBtn`as it's name indicates it render google sign in button * `GoogleSignInBtn`as it's name indicates it render google sign in button
@@ -148,7 +150,7 @@ const GoogleSignInBtn = ({
email: userDetails.Email, email: userDetails.Email,
// "passsword":userDetails.Phone, // "passsword":userDetails.Phone,
phone: userDetails.Phone, phone: userDetails.Phone,
role: "contracts_Admin", role: "contracts_User",
company: userDetails.Company, company: userDetails.Company,
jobTitle: userDetails.Destination jobTitle: userDetails.Destination
} }
@@ -231,118 +233,94 @@ const GoogleSignInBtn = ({
</div> </div>
)} )}
<div ref={googleBtn} className="text-sm"></div> <div ref={googleBtn} className="text-sm"></div>
<ModalUi showClose={false} isOpen={isModal} title="Sign up form">
{isModal && ( <form className="px-4 py-3">
<div <div className="mb-3">
className="modal fade show" <label
id="exampleModal" htmlFor="Phone"
tabIndex="-1" style={{ display: "flex" }}
role="dialog" className="block text-xs text-gray-700 font-semibold"
style={{ display: "block", zIndex: 1 }} >
> Phone <span style={{ fontSize: 13, color: "red" }}>*</span>
<div className="modal-dialog" role="document"> </label>
<div className="modal-content"> <input
<div className="modal-header"> type="tel"
<h5 className="modal-title">Sign up form</h5> className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
<span> id="Phone"
<span></span> value={userDetails.Phone}
</span> onChange={(e) =>
</div> setUserDetails({
<div className="modal-body"> ...userDetails,
<form> Phone: e.target.value
<div className="form-group"> })
<label }
htmlFor="Phone" required
style={{ display: "flex" }} />
className="col-form-label"
>
Phone{" "}
<span style={{ fontSize: 13, color: "red" }}>*</span>
</label>
<input
type="tel"
className="form-control"
id="Phone"
value={userDetails.Phone}
onChange={(e) =>
setUserDetails({
...userDetails,
Phone: e.target.value
})
}
required
/>
</div>
<div className="form-group">
<label
htmlFor="Company"
style={{ display: "flex" }}
className="col-form-label"
>
Company{" "}
<span style={{ fontSize: 13, color: "red" }}>*</span>
</label>
<input
type="text"
className="form-control"
id="Company"
value={userDetails.Company}
onChange={(e) =>
setUserDetails({
...userDetails,
Company: e.target.value
})
}
required
/>
</div>
<div className="form-group">
<label
htmlFor="JobTitle"
style={{ display: "flex" }}
className="col-form-label"
>
Job Title{" "}
<span style={{ fontSize: 13, color: "red" }}>*</span>
</label>
<input
type="text"
className="form-control"
id="JobTitle"
value={userDetails.Destination}
onChange={(e) =>
setUserDetails({
...userDetails,
Destination: e.target.value
})
}
required
/>
</div>
<div>
<button
type="button"
className="bg-[#17a2b8] p-2 text-white rounded"
onClick={() => handleSubmitbtn()}
style={{ marginRight: 10 }}
>
Sign up
</button>
<button
type="button"
className="bg-[#6c757d] p-2 text-white rounded"
onClick={handleCloseModal}
style={{ width: 90 }}
>
Cancel
</button>
</div>
</form>
</div>
</div>
</div> </div>
</div> <div className="mb-3">
)} <label
htmlFor="Company"
style={{ display: "flex" }}
className="block text-xs text-gray-700 font-semibold"
>
Company <span style={{ fontSize: 13, color: "red" }}>*</span>
</label>
<input
type="text"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
id="Company"
value={userDetails.Company}
onChange={(e) =>
setUserDetails({
...userDetails,
Company: e.target.value
})
}
required
/>
</div>
<div className="mb-3">
<label
htmlFor="JobTitle"
style={{ display: "flex" }}
className="block text-xs text-gray-700 font-semibold"
>
Job Title <span style={{ fontSize: 13, color: "red" }}>*</span>
</label>
<input
type="text"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
id="JobTitle"
value={userDetails.Destination}
onChange={(e) =>
setUserDetails({
...userDetails,
Destination: e.target.value
})
}
required
/>
</div>
<div>
<button
type="button"
className="px-3 py-1.5 text-white rounded shadow-md text-center focus:outline-none "
onClick={() => handleSubmitbtn()}
style={{ marginRight: 10, backgroundColor: modalSubmitBtnColor }}
>
Sign up
</button>
<button
type="button"
className="p-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none"
onClick={handleCloseModal}
style={{ width: 90, backgroundColor: modalCancelBtnColor }}
>
Cancel
</button>
</div>
</form>
</ModalUi>
</div> </div>
); );
}; };
@@ -1,391 +0,0 @@
import React, { useState, useEffect } from "react";
import Form from "@rjsf/core";
import validator from "@rjsf/validator-ajv8";
import Parse from "parse";
import "../styles/loader.css";
import LayoutField from "./fields/Rjsf-layout";
import TimeWidget from "./fields/TimeWidget";
import Level1Dropdown from "./fields/Level1Dropdown";
import HiddenField from "./fields/HiddenField";
import MultiSelectField from "./fields/MultiSelectField";
import TreeWidget from "../components/TreeWidget";
import { formJson } from "../json/FormJson";
const TreeEditForm = (props) => {
const widget = {
TimeWidget: TimeWidget
};
const fields = {
layout: LayoutField,
Level1Dropdown: Level1Dropdown,
HiddenField: HiddenField,
MultiSelectField: MultiSelectField,
FolderComponent: TreeWidget
};
const [schema, setschema] = useState({});
const [ui_schema, setui_schema] = useState({});
const [title, settitle] = useState("");
const [schemaState, setschemaState] = useState({});
const [formData, setformData] = useState({});
const [active, setactive] = useState(true);
const [loading, setloading] = useState(false);
const [_validate, set_validate] = useState(null);
const [noValidate, setnoValidate] = useState(false);
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const getForm = async (id) => {
setloading(true);
try {
//get json form data (schema ,uischema)
const results = formJson(id);
try {
let _record = Parse.Object.extend(results.class);
var query1 = new Parse.Query(_record);
await query1.get(props.objectId).then(
(x) => {
try {
if (x) {
let result = x.toJSON();
let new_result = result;
for (let [key, value] of Object.entries(result)) {
if (value["__type"] === "Date") {
let todayTime1 = new Date(value.iso);
var month = String(todayTime1.getMonth() + 1);
var day = String(todayTime1.getDate());
var year = String(todayTime1.getFullYear());
if (month.length < 2) month = "0" + month;
if (day.length < 2) day = "0" + day;
let date1 = year + "-" + month + "-" + day;
let bindVar = date1;
if (!results.jsonSchema.properties[key].format) {
bindVar = todayTime1.toISOString();
}
new_result[key] = bindVar;
}
}
setschemaState(results.jsonSchema);
setformData(new_result);
}
} catch (error) {
//alert(error.message);
setloading(false);
}
},
(error) => {
console.log("err", error);
setloading(false);
}
);
setschema(results.jsonSchema);
setui_schema(results.uiSchema);
set_validate(results.validFunction);
setnoValidate(results.noValidate);
settitle(results.class);
setloading(false);
setactive(true);
} catch (error) {
setloading(false);
}
} catch (e) {
setloading(false);
console.error("Problem", e);
}
};
const wrap = (s) => "{ return " + s + " };";
const dynamicValidate = (formData, errors) => {
try {
let body = atob(_validate);
let res = new Function(wrap(body))
.call(null)
.call(null, formData, errors);
return res;
} catch (error) {
console.log(error);
}
};
const handleSubmit = async ({ formData }) => {
setactive(false);
setloading(true);
let RowData = formData;
RowData &&
Object.entries(RowData).forEach(([key, value]) => {
if (typeof value === "string") {
RowData[key] = value.trim();
}
});
let _scanData = schemaState;
if (_scanData.dependencies) {
Object.keys(_scanData.dependencies).forEach((key) => {
if (_scanData.dependencies[key].oneOf) {
_scanData.dependencies[key].oneOf.forEach((val) => {
Object.keys(val.properties).forEach((k) => {
if (typeof val.properties[k] === "object") {
if (val.properties[k].format === "date") {
if (RowData[k]) {
let newdate = new Date(RowData[k]);
RowData[k] = newdate;
}
}
if (val.properties[k].component === "HtmlEditor") {
if (RowData[k]) {
let newHtml = RowData[k]
.replace(/<p[^>]*>/g, "")
.replace(/<\/p>/g, " ");
RowData[k] = newHtml;
}
}
if (val.properties[k].component === "DateTime") {
if (RowData[k]) {
let newDate11 = new Date(RowData[k]);
RowData[k] = newDate11;
}
}
if (val.properties[k].component === "CurrencyInput") {
if (val.properties[k].currencyColumn) {
RowData[`${val.properties[k].currencyColumn}`] =
val.properties[k].defaultcurrency;
}
}
if (val.properties[k].type === "string") {
if (typeof RowData[k] === "string")
RowData[k] = RowData[k].trim();
}
if (val.properties[k].data !== undefined) {
if (val.properties[k].data.isPointer) {
let pointer = undefined;
if (val.properties[k].data.class) {
if (RowData[k]) {
pointer = {
__type: "Pointer",
className: val.properties[k].data.class,
objectId: RowData[k]
};
}
} else {
if (RowData[k]) {
pointer = {
__type: "Pointer",
className: localStorage.getItem("extended_class"),
objectId: RowData[k]
};
}
}
RowData[k] = pointer;
}
if (val.properties[k].data.FolderTypeValue) {
if (RowData[k]) {
let obj = {
__type: "Pointer",
className: val.properties[k].data.ClassName,
objectId: RowData[k]
};
RowData[k] = obj;
}
}
}
}
});
});
}
});
}
let temp = [];
let _dd = _scanData.properties;
let allowed = [];
if (_dd) {
Object.keys(_dd).forEach(function (k) {
allowed.push(k);
if (RowData[k]) {
let pointer = {
__type: "Pointer",
className: _dd[k].class,
objectId: RowData[k]
};
RowData[k] = pointer;
}
if (_dd[k].format === "date") {
if (RowData[k]) {
let newdate = new Date(RowData[k]);
if (!isNaN(newdate.getTime())) {
RowData[k] = newdate;
}
}
}
if (_dd[k].component === "HtmlEditor") {
if (RowData[k]) {
let newHtml = RowData[k]
.replace(/<p[^>]*>/g, "")
.replace(/<\/p>/g, " ");
RowData[k] = newHtml;
}
}
if (_dd[k].component === "DateTime") {
if (RowData[k]) {
let newdate = new Date(RowData[k]);
if (!isNaN(newdate.getTime())) {
RowData[k] = newdate;
}
}
}
if (_dd[k].format === "date-time") {
let newdate = new Date(RowData[k]);
RowData[k] = newdate;
}
if (_dd[k].component === "CurrencyInput") {
if (_dd[k].currencyColumn) {
RowData[`${_dd[k].currencyColumn}`] = _dd[k].defaultcurrency;
}
}
if (_dd[k].data !== undefined) {
if (_dd[k].data.isPointer) {
let pointer = undefined;
if (typeof RowData[k] === "object") {
if (RowData[k]) {
if (RowData[k].objectId !== "Select") {
let obj = {
__type: "Pointer",
className: RowData[k].className,
objectId: RowData[k].objectId
};
pointer = obj;
}
}
} else if (_dd[k].data.class) {
if (RowData[k]) {
pointer = {
__type: "Pointer",
className: _dd[k].data.class,
objectId: RowData[k]
};
}
} else {
if (RowData[k]) {
pointer = {
__type: "Pointer",
className: localStorage.getItem("extended_class"),
objectId: RowData[k]
};
}
}
RowData[k] = pointer;
}
if (_dd[k].data.FolderTypeValue) {
if (RowData[k]) {
let obj = {
__type: "Pointer",
className: _dd[k].data.ClassName,
objectId: RowData[k]
};
RowData[k] = obj;
}
}
}
if (_dd[k].type === "string") {
if (typeof RowData[k] === "string") RowData[k] = RowData[k].trim();
}
});
}
const filtered = Object.keys(RowData)
.filter((key) => allowed.includes(key))
.reduce((obj, key) => {
obj[key] = RowData[key];
return obj;
}, {});
try {
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
const currentUser = Parse.User.current();
if (temp.length !== 0) {
let userPointer = {
__type: "Pointer",
className: "_User",
objectId: currentUser.id
};
filtered[[temp[0]]] = userPointer;
}
var data = Parse.Object.extend(title);
var query = new Parse.Query(data);
query.get(props.objectId).then(async (object) => {
object.save(filtered).then(
() => {
try {
alert("Record updated successfully");
props.HideView(false);
setloading(false);
setactive(true);
} catch (error) {
console.log("err", error);
}
},
(error) => {
console.log("err", error);
setloading(false);
setactive(true);
}
);
});
} catch (error) {
console.log("err", error);
alert(error.message);
setloading(false);
setactive(true);
}
};
useEffect(() => {
if (props.FormId) {
getForm(props.FormId);
}
// eslint-disable-next-line
}, [props.FormId]);
if (loading) {
return (
<div
className="loader-01"
style={{
marginTop: "50px",
marginLeft: "50%",
color: "rgb(0,28,28)",
fontSize: "35px"
}}
></div>
);
}
return (
<Form
schema={schema}
uiSchema={ui_schema}
formData={formData}
showErrorList={false}
widgets={widget}
fields={fields}
validate={noValidate && dynamicValidate}
onSubmit={handleSubmit}
validator={validator}
>
<div>
{active ? (
<button className="bg-[#1ab6ce] px-3 py-2 rounded text-white text-sm" type="submit">
Update
</button>
) : (
<button className="bg-[#1ab6ce] px-3 py-2 rounded text-white text-sm" type="submit" disabled>
Update
</button>
)}
</div>
</Form>
);
};
export default TreeEditForm;
@@ -1,237 +0,0 @@
import React, { useEffect, useState } from "react";
import Form from "@rjsf/core";
import validator from "@rjsf/validator-ajv8";
import LayoutField from "./fields/Rjsf-layout";
import Level1Dropdown from "./fields/Level1Dropdown";
import HiddenField from "./fields/HiddenField";
import MultiSelectField from "./fields/MultiSelectField";
import "../styles/loader.css";
import "../styles/form.css";
import FileUpload from "./fields/FileUpload";
import parse from "html-react-parser";
import TimeWidget from "./fields/TimeWidget";
import { formJson } from "../json/FormJson";
function TreeFormComponent(props) {
const widget = {
TimeWidget: TimeWidget
};
const fields = {
layout: LayoutField,
FileUpload: FileUpload,
Level1Dropdown: Level1Dropdown,
HiddenField: HiddenField,
MultiSelectField: MultiSelectField
};
const [link, setLink] = useState("");
const [help, setHelp] = useState("");
const toastDescription = "";
const toastColor = "#5cb85c";
const [loading, setLoding] = useState(true);
const [schemaState, setSchemaState] = useState({});
const [formData, setFormData] = useState({});
const [ui_schema, setUi_schema] = useState({});
const active = true;
console.log("new form", props);
const getForm = async (id) => {
setLoding(true);
try {
// get json from data(jsonschema, uischema)
const results = formJson(id);
// console.log("result", results);
if (results) {
let parentObject = {},
childObject = {};
const resultjson = results;
for (let [key, value] of Object.entries(
resultjson.jsonSchema.properties
)) {
if (key === props.ParentField) {
if (props.ParentValue[key]) {
parentObject = { [key]: props.ParentValue[key] };
}
} else {
if (props.ParentValue && typeof props.ParentValue === "object") {
Object.entries(props.ParentValue).forEach(([k, value]) => {
if (k === key) {
let newO = { [k]: value };
parentObject = { ...parentObject, ...newO };
}
});
}
}
if (props.ChildField) {
Object.entries(props.ChildField).forEach(([k, value]) => {
if (k === key) {
let newO = { [k]: value };
childObject = { ...childObject, ...newO };
}
});
}
if (typeof value === "object") {
for (let [k, v] of Object.entries(value)) {
if (k === "format" && v === "date") {
let today = new Date();
let date =
today.getFullYear() +
"-" +
("0" + (today.getMonth() + 1)).slice(-2) +
"-" +
("0" + today.getDate()).slice(-2);
value.default = date;
}
}
}
}
if (props.ParentField) {
setFormData({ ...parentObject, ...childObject });
}
let txt, link;
if (resultjson.help) {
if (resultjson.help.htmlbody) {
txt = resultjson.help.htmlbody;
}
if (resultjson.help.link) {
link = resultjson.help.link;
}
}
setHelp(txt);
setLink(link);
props.ClassName(resultjson.class);
props.SchemaState(resultjson.jsonSchema);
setSchemaState(resultjson.jsonSchema);
setUi_schema(resultjson.uiSchema);
setLoding(false);
} else {
alert("form not found");
setLoding(false);
}
} catch (e) {
console.error("Problem", e);
setLoding(false);
}
};
useEffect(() => {
if (!props.IsEdit) {
getForm(props.Id);
}
// console.log("props tree", props);
// eslint-disable-next-line
}, []);
let formView = (
<React.Fragment>
<Form
schema={schemaState}
uiSchema={ui_schema}
showErrorList={false}
widgets={widget}
fields={fields}
formData={formData}
onSubmit={props.handleSubmit}
validator={validator}
>
{active ? (
<button className="btn btn-info submiBtn" type="submit">
{props.IsEdit ? "update folder" : "create folder"}
</button>
) : (
<button className="btn btn-info submiBtn " type="submit" disabled>
submitting...
</button>
)}
</Form>
</React.Fragment>
);
if (loading) {
formView = (
<div style={{ height: "300px" }}>
<div
style={{
marginLeft: "45%",
marginTop: "150px",
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
</div>
);
}
return (
<React.Fragment>
<div className="row">
<div className="col-md-12">
<div className="card">
<div className="card-body no-padding height-9">
{help ? (
<div className="dropdown" style={{ marginTop: "-30px" }}>
<i
className="far fa-question-circle dropdown-toggle hovereffect"
aria-hidden="true"
id="dropdownMenuButton"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
style={{
fontSize: "18px",
color: "purple",
cursor: "pointer !important",
position: "relative",
top: "40px",
left: "98%"
}}
></i>
<div
className="dropdown-menu"
aria-labelledby="dropdownMenuButton"
style={{
marginleft: "-121px",
margintop: "-14px",
position: "absolute",
padding: "10px",
width: "300px",
top: "102px!important"
}}
>
{parse(`
${help}
`)}
<br />
{link ? (
<a
onClick={(e) => {
e.preventDefault();
window.location.href = link;
}}
target="_blank"
className="btn btn-xs btn-primary"
>
Read more..
</a>
) : null}
</div>
</div>
) : null}
<div style={{ fontSize: "13px" }}>{formView}</div>
</div>
</div>
</div>
</div>
<div id="snackbar" style={{ backgroundColor: toastColor }}>
{toastDescription}
</div>
</React.Fragment>
);
}
export default TreeFormComponent;
-895
View File
@@ -1,895 +0,0 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import LabelField from "./fields/LabelField";
import Parse from "parse";
import axios from "axios";
import "../styles/spinner.css";
import TreeFormComponent from "./TreeFormComponent";
import TreeEditForm from "./TreeEditForm";
import "../styles/modal.css";
import Modal from "react-modal";
const TreeWidget = (props) => {
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [isAddField, setIsAddField] = useState(false);
const [folderList, setFolderList] = useState([]);
const [tabList, setTabList] = useState([]);
const [appId, setAppId] = useState(undefined);
const [selectedFolder, setSelectedFolder] = useState(undefined);
const [loader, setLoader] = useState(false);
const [className, setClassName] = useState("");
const [schemaState, setSchemaState] = useState({});
const [TabURL, setTabURL] = useState("");
const [editable, setEditable] = useState(false);
const [editId, setEditId] = useState("");
const [defaultState, setDefaultState] = useState(false);
const [isShowModal, setIsShowModal] = useState(false);
const selectFolderHandle = async () => {
setIsShowModal(true);
setIsAddField(false);
setDefaultState(false);
setFolderList([]);
setLoader(true);
if (tabList.length > 0) {
let len = tabList.length - 1;
selectedItemList(tabList[len]);
} else {
try {
var test;
if (props.schema.parent) {
try {
if (props.parent[props.schema.parent]) {
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
const currentUser = Parse.User.current();
let res;
if (localStorage.getItem("Extand_Class")) {
let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0];
} else {
res = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
if (res) res = res.toJSON();
}
if (res) {
let json = res;
setAppId(json.AppId);
}
// eslint-disable-next-line
let reg = /(\#.*?\#)/gi;
let str = props.schema.data.Query;
if (str.includes("#")) {
test = str.replace(reg, props.parent[props.schema.parent]);
} else {
test = str;
}
} else {
if (props.child[props.schema.parent]) {
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
const currentUser = Parse.User.current();
let res;
if (localStorage.getItem("Extand_Class")) {
let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0];
} else {
res = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
if (res) res = res.toJSON();
}
if (res) {
let json = res;
setAppId(json.AppId);
}
// eslint-disable-next-line
let reg = /(\#.*?\#)/gi;
let str = props.schema.data.Query;
if (str.includes("#")) {
test = str.replace(reg, props.child[props.schema.parent]);
} else {
test = str;
}
} else {
alert(`Please select ${props.schema.parent}`);
setLoader(false);
return;
}
}
} catch (error) {
console.log("error ", error);
}
} else {
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
const currentUser = Parse.User.current();
// eslint-disable-next-line
let reg = /(\#.*?\#)/gi;
let str = props.schema.data.Query;
let res;
if (localStorage.getItem("Extand_Class")) {
let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0];
} else {
// emp = Parse.Object.extend(localStorage.getItem("extended_class"));
// q = new Parse.Query(emp);
// q.equalTo("UserId", currentUser);
// res = await q.first();
// if (res) res = res.toJSON();
const currentUser = Parse.User.current();
res = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
if (res) res = res.toJSON();
}
if (res) {
let json = res;
setAppId(json.AppId);
}
if (str.includes("#")) {
if (res) {
let json = res.toJSON();
let output = str.match(reg);
if (output.length === 1) {
output = output.join();
output = output.substring(1, output.length - 1);
output = output.split(".");
if (output.length === 1) {
let out = output[0];
if (json[out]) {
if (typeof json[out] === "object") {
test = str.replace(reg, JSON.stringify(json[out]));
} else {
test = str.replace(reg, json[out]);
}
} else {
test = str.replace(reg, currentUser.id);
}
} else if (output.length === 2) {
let out1 = json[output[0]][output[1]];
if (out1) {
test = str.replace(reg, out1);
}
}
}
}
} else {
test = str;
}
}
let url = `${parseBaseUrl}classes/${props.schema.data.ClassName}?${test}`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
};
await axios
.get(url, { headers: headers })
.then((res) => {
if (res) {
setFolderList(res.data.results);
setLoader(false);
}
})
.catch((err) => {
setLoader(false);
console.log(err);
});
} catch (error) {
setLoader(false);
}
}
};
const selectedItemList = async (folder) => {
setLoader(true);
setFolderList([]);
try {
let url = `${parseBaseUrl}classes/${props.schema.data.ClassName}?where={"${props.schema.data.ParentFolderField}":{"__type":"Pointer","className":"${props.schema.data.ClassName}","objectId":"${folder.objectId}"}}`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
};
await axios.get(url, { headers: headers }).then((result) => {
if (result) {
setFolderList(result.data.results);
setLoader(false);
}
});
} catch (error) {
setLoader(false);
}
};
const removeTabListItem = async (e, i) => {
e.preventDefault();
setEditable(false);
setLoader(true);
setFolderList([]);
let list = tabList.filter((itm, j) => {
if (j <= i) {
return itm;
}
});
setTabList(list);
setIsAddField(false);
try {
let _len = list.length - 1;
let url = `${parseBaseUrl}classes/${props.schema.data.ClassName}?where={"${props.schema.data.ParentFolderField}":{"__type":"Pointer","className":"${props.schema.data.ClassName}","objectId":"${list[_len].objectId}"}}`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
};
await axios.get(url, { headers: headers }).then((result) => {
if (result) {
setFolderList(result.data.results);
setLoader(false);
}
setLoader(false);
});
} catch (error) {
setLoader(false);
}
};
const onDeleteFolder = async (e) => {
e.preventDefault();
if (folderList.length > 0) {
alert(
"Folder should not delete. To delete first delete sub items in it."
);
} else if (window.confirm(`Are you sure you want to delete this record`)) {
try {
setLoader(true);
let len = tabList.length - 1;
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
var deleted = Parse.Object.extend(props.schema.data.ClassName);
var query = new Parse.Query(deleted);
await query.get(tabList[len].objectId).then(
(del) => {
del.destroy().then(
(y) => {
if (y) {
setLoader(false);
let list = tabList.filter((itm, j) => {
if (j !== len) return itm;
});
setTabList(list);
if (list.length > 0) {
let len = list.length - 1;
selectedItemList(list[len]);
} else {
selectFolderHandle();
}
alert("Folder deleted successfully.");
}
},
(error) => {
alert(error.message);
setLoader(false);
}
);
},
(error) => {
console.log("error ", error);
// The object was not retrieved successfully.
setLoader(false);
}
);
} catch (error) {
setLoader(false);
console.log(error);
}
}
};
const onSubmitResult = async (e) => {
setIsShowModal(false);
e.preventDefault();
//console.log("tabList ", tabList);
if (tabList.length > 0) {
try {
let len = tabList.length - 1;
setSelectedFolder({
Topic: tabList[len][`${props.schema.data.FolderNameField}`],
description: tabList[len][`${props.schema.data.FolderDescription}`]
});
props.onChange(tabList[len]["objectId"]);
let url = "Folders";
tabList.forEach((t) => {
url = url + " / " + t[`${props.schema.data.FolderNameField}`];
});
setTabURL(url);
setIsAddField(false);
if (!props.formData) {
setTabList([]);
}
} catch (error) {
setIsAddField(false);
alert(error.message);
}
} else {
setIsAddField(false);
}
};
const editFolderDisplay = async (formData) => {
try {
let objectId = formData.objectId;
let className = formData.className;
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
const fldr = Parse.Object.extend(className);
let query = new Parse.Query(fldr);
query.equalTo("objectId", objectId);
const result = await query.first();
let resultJson = result.toJSON();
let CustomTabList = [];
if (resultJson) {
CustomTabList.push(resultJson);
if (resultJson[`${props.schema.data.ParentFolderField}`]) {
let tabsRes = resultJson[`${props.schema.data.ParentFolderField}`];
let looping = false;
do {
let fldttr = Parse.Object.extend(tabsRes.className);
let query2 = new Parse.Query(fldttr);
query2.equalTo("objectId", tabsRes.objectId);
let custome_res = await query2.first();
if (custome_res) {
let tabsData = custome_res.toJSON();
CustomTabList.push(tabsData);
if (tabsData[`${props.schema.data.ParentFolderField}`]) {
tabsRes = tabsData[`${props.schema.data.ParentFolderField}`];
looping = true;
} else {
looping = false;
}
}
} while (looping);
}
let url = "Folders";
CustomTabList.length > 0 &&
CustomTabList.reverse().forEach(
(t) => (url = url + " / " + t[props.schema.data.FolderNameField])
);
setTabURL(url);
setSelectedFolder({
Topic: resultJson[`${props.schema.data.FolderNameField}`],
description: resultJson[`${props.schema.data.FolderDescription}`]
});
setTabList(CustomTabList);
props.onChange(resultJson.objectId);
}
} catch (error) {
console.log(error);
}
};
const handleSubmit = async ({ formData }) => {
setLoader(true);
try {
let RowData = formData;
let _scanData = schemaState;
Object.keys(_scanData).forEach(function (key) {
let _dd = _scanData[key];
Object.keys(_dd).forEach(function (k) {
if (_dd[k].component === "AutoSuggest" && _dd[k].isPointer) {
let pointer = {
__type: "Pointer",
className: _dd[k].class,
objectId: RowData[k]
};
RowData[k] = pointer;
}
if (_dd[k].format === "date") {
let newdate = new Date(RowData[k]);
RowData[k] = newdate;
}
if (_dd[k].component === "DateTime") {
let newDate11;
if (!RowData[k]) {
newDate11 = new Date();
} else {
newDate11 = new Date(RowData[k]);
}
RowData[k] = newDate11;
}
if (_dd[k].component === "CurrencyInput") {
if (_dd[k].currencyColumn) {
RowData[`${_dd[k].currencyColumn}`] = _dd[k].defaultcurrency;
}
}
if (_dd[k].data !== undefined) {
if (_dd[k].data.isPointer) {
let pointer = {};
if (RowData[k] && RowData[k] !== "Select") {
if (_dd[k].data.class) {
if (RowData[k]) {
pointer = {
__type: "Pointer",
className: _dd[k].data.class,
objectId: RowData[k]
};
}
} else {
pointer = {
__type: "Pointer",
className: localStorage.getItem("extended_class"),
objectId: RowData[k]
};
}
RowData[k] = pointer;
}
}
if (_dd[k].data.FolderTypeValue) {
let obj = {
__type: "Pointer",
className: _dd[k].data.ClassName,
objectId: RowData[k]
};
RowData[k] = obj;
}
}
if (_dd[k].type === "string") {
let d = RowData[k];
if (typeof d === "string") {
RowData[k] = d.trim();
}
}
});
});
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
var forms = Parse.Object.extend(className);
var folder = new forms();
folder.set(
props.schema.data.FolderNameField,
formData[props.schema.data.FolderNameField]
);
if (props.schema.data.FolderDescription) {
folder.set(
props.schema.data.FolderDescription,
formData[props.schema.data.FolderDescription]
);
}
folder.set("AppId", appId);
folder.set(
props.schema.data.FolderTypeField,
props.schema.data.FolderTypeValue
);
const currentUser = Parse.User.current();
folder.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
if (tabList.length > 0) {
let len = tabList.length - 1;
folder.set(props.schema.data.ParentFolderField, {
__type: "Pointer",
className: props.schema.data.ClassName,
objectId: tabList[len]["objectId"]
});
}
folder.save(RowData).then(
(result) => {
RowData = {};
if (result) {
setIsAddField(false);
setLoader(false);
if (tabList.length > 0) {
let len = tabList.length - 1;
selectedItemList(tabList[len]);
} else {
selectFolderHandle();
}
}
},
(error) => {
console.log("error ", error);
setLoader(false);
}
);
} catch (error) {
setLoader(false);
}
};
useEffect(() => {
if (props.formData) {
editFolderDisplay(props.formData);
}
// eslint-disable-next-line
}, [props.formData]);
useEffect(() => {
if (defaultState) {
selectFolderHandle();
}
// eslint-disable-next-line
}, [defaultState]);
const customStyles = {
content: {
top: "50%",
left: "50%",
right: "auto",
bottom: "auto",
marginRight: "-50%",
transform: "translate(-50%, -50%)",
backgroundColor: "white",
padding: 0
},
overlay: {
width: "100%",
backgroundColor: "rgba(0, 0, 0, 0.75)",
zIndex: 50
}
};
return (
<React.Fragment>
<LabelField
Title={props.schema.title}
Name={props.name}
Required={props.required}
HelpBody={props.schema.helpbody}
HelpLink={props.schema.helplink}
/>
<br />
<div className="block max-w-sm bg-white border border-gray-200 shadow hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700">
<div
style={{
display: "flex",
color: "black",
fontWeight: "bold",
fontSize: "13px",
padding: "2%",
alignItems: "center"
}}
>
<div style={{ width: "20%" }}>
<div
className="pull-left"
title="Select Folder"
style={{
color: "#33bbff",
margin: "auto",
padding: "10px 10px",
textAlign: "center"
}}
>
<i
className="far fa-folder-open"
style={{ fontSize: "40px" }}
aria-hidden="true"
></i>
</div>
</div>
<div style={{ margin: "0px 10px 0 20px", width: "80%" }}>
<div>
{selectedFolder && selectedFolder.Topic
? selectedFolder.Topic
: "Root"}
<i
className="fa fa-pencil"
title="Select Folder"
style={{ fontSize: 17, cursor: "pointer", marginLeft: 12 }}
onClick={selectFolderHandle}
></i>
{selectedFolder && (
<a
className="pull-right"
onClick={() => {
setSelectedFolder(undefined);
setTabURL(undefined);
props.onChange(undefined);
}}
>
<i
className="fa fa-times-circle-o"
aria-hidden="true"
style={{ fontSize: 17 }}
></i>
</a>
)}
</div>
{TabURL && (
<div
style={{ fontSize: "10px", color: "gray", fontWeight: "bold" }}
>
({TabURL})
</div>
)}
</div>
</div>
</div>
{/* save document in folder and add new folder modal */}
<Modal
isOpen={isShowModal}
onRequestClose={() => setIsShowModal(false)}
shouldCloseOnOverlayClick={false}
contentLabel="Modal"
style={customStyles}
>
<div className="w-full min-w-[300px] md:min-w-[500px]">
{/* header */}
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
backgroundColor: "rgba(203, 200, 200, 0.09)"
}}
>
<div style={{ padding: "10px" }}>
<h4 className=" text-black">Select Folder</h4>
</div>
<div style={{ padding: "10px" }}>
<button
className="btn btn-sm pull-right"
data-dismiss="modal"
title="Select Folder"
style={{
width: "auto",
backgroundColor: "white",
border: "1px solid gray",
boxshadow: "rgba(100, 100, 111, 0.2) 0px 7px 29px 0px"
}}
onClick={(e) => {
e.preventDefault();
setIsAddField(false);
setFolderList([]);
setEditable(false);
if (!props.formData) {
setTabList([]);
}
setIsShowModal(false);
}}
>
<span aria-hidden="true">&times;</span>
</button>
</div>
</div>
<hr />
{/* body */}
<div className="p-3 space-y-6">
<div
style={{
color: "#ac4848",
cursor: "pointer",
fontSize: "14px",
fontWeight: "500"
}}
>
<a
onClick={() => {
setTabList([]);
setIsAddField(false);
setDefaultState(true);
setEditable(false);
}}
>
Folders
</a>
{" / "}
{tabList &&
tabList.map((tab, i) => (
<React.Fragment key={`${tab.objectId}-${i}`}>
<a
title={tab[`${props.schema.data.FolderNameField}`]}
onClick={(e) => removeTabListItem(e, i)}
>
{tab[`${props.schema.data.FolderNameField}`]}
</a>
{" / "}
</React.Fragment>
))}
<hr />
</div>
{/* {editable && (
<TreeEditForm
FormId={props.schema.data.FormId}
objectId={editId}
HideView={(cl) => {
setEditable(cl);
selectFolderHandle();
}}
/>
)} */}
{isAddField && !loader && !editable && (
<TreeFormComponent
Id={props.schema.data.FormId}
handleSubmit={handleSubmit}
ParentField={props.schema.parent && props.schema.parent}
ParentValue={props.schema.parent && props.parent}
ChildField={props.child && props.child}
ClassName={(cls) => setClassName(cls)}
SchemaState={(cls) => setSchemaState(cls)}
/>
)}
{loader && (
<div
className="loader-01"
style={{
marginTop: "50px",
marginLeft: "50%",
color: "rgb(0,28,28)",
fontSize: "35px"
}}
></div>
)}
{!isAddField && !editable && (
<div
style={{
maxHeight: "280px",
overflowY: "auto",
marginTop: "5px"
}}
>
<ul>
{folderList &&
folderList.map(
(fldr) =>
fldr[props.schema.data.FolderTypeField] ===
props.schema.data.FolderTypeValue && (
<li
key={`${fldr.objectId}`}
style={{
listStyle: "none",
padding: "10px 20px",
textTransform: "capitalize",
fontWeight: 300,
border: "1px solid gray",
borderRadius: "1px",
marginTop: "8px",
transition: "all 0.75s ease",
WebkitTransition: "all 0.5s ease",
MozTransition: "all 0.5s ease",
MsTransition: "all 0.5s ease",
OTransition: "all 0.5 ease",
display: "flex",
alignItems: "center",
justifyContent: "space-between"
}}
>
<div
style={{
display: "flex",
alignItems: "center"
}}
>
<i
className={"fa fa-folder"}
style={{
fontSize: "1.4rem",
color: "skyblue"
}}
aria-hidden="true"
></i>
<a
style={{
fontWeight: "bold",
fontSize: "12px",
marginLeft: "4px",
cursor: "pointer"
}}
onClick={() => {
setTabList((tabs) => tabs.concat(fldr));
selectedItemList(fldr);
}}
>
{fldr[`${props.schema.data.FolderNameField}`]}
</a>
</div>
{/* {fldr[props.schema.data.FolderTypeField] ===
props.schema.data.FolderTypeValue && (
<a
className="float-right"
onClick={() => {
setEditable(true);
setEditId(fldr.objectId);
}}
>
<i
className={"fa fa-pencil"}
title={"Edit Folder"}
style={{
fontSize: "0.9rem",
color: "purple",
cursor: "pointer"
}}
aria-hidden="true"
></i>
</a>
)} */}
</li>
)
)}
</ul>
</div>
)}
</div>
{/* footer */}
<div className="flex items-center p-3 space-x-2 border-t border-gray-200 rounded-b dark:border-gray-600 justify-between">
<button
className="btn btn-sm float-left createFolder"
title="Create New Folder"
onClick={(e) => {
e.preventDefault();
setIsAddField(true);
}}
>
{" "}
<i
className="fa fa-plus"
style={{ fontSize: "1.5rem" }}
aria-hidden="true"
></i>
</button>
{!isAddField && !editable && (
<div className="flex">
{tabList.length > 0 && (
<button
className="btn btn-sm float-right deleteFolder"
title="Delete Folder"
onClick={onDeleteFolder}
>
{" "}
<i
className="fa fa-trash"
style={{ fontSize: "1rem" }}
aria-hidden="true"
></i>
</button>
)}
<button
className="btn btn-sm float-right saveFolder"
title="Save Here"
onClick={onSubmitResult}
>
{" "}
{/* <i
className="fa fa-floppy-o"
style={{ fontSize: "2rem" }}
aria-hidden="true"
></i> */}
<i
className="fas fa-save"
aria-hidden="true"
style={{ fontSize: "20px" }}
></i>
</button>
</div>
)}
</div>
</div>
</Modal>
</React.Fragment>
);
};
const mapStateToProps = (state) => {
return {
parent: state.Level1_Dropdown,
child: state.Level2_Dropdown
};
};
export default connect(mapStateToProps)(TreeWidget);
@@ -0,0 +1,147 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import Alert from "../../primitives/Alert";
const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
const folderPtr = {
__type: "Pointer",
className: folderCls,
objectId: parentFolderId
};
const [name, setName] = useState("");
const [folderList, setFolderList] = useState([]);
const [isAlert, setIsAlert] = useState(false);
const [selectedParent, setSelectedParent] = useState();
const [alert, setAlert] = useState({ type: "info", message: "" });
useEffect(() => {
fetchFolder();
// eslint-disable-next-line
}, []);
const fetchFolder = async () => {
try {
const FolderQuery = new Parse.Query(folderCls);
if (parentFolderId) {
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
} else {
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
}
const res = await FolderQuery.find();
if (res) {
const result = JSON.parse(JSON.stringify(res));
if (result) {
setFolderList(result);
}
}
} catch (error) {
console.log("Err ", error);
}
};
const handleCreateFolder = async (event) => {
event.preventDefault();
if (name) {
const currentUser = Parse.User.current();
const exsitQuery = new Parse.Query(folderCls);
exsitQuery.equalTo("Name", name);
exsitQuery.equalTo("Type", "Folder");
if (parentFolderId) {
exsitQuery.equalTo("Folder", folderPtr);
}
const templExist = await exsitQuery.first();
if (templExist) {
setAlert({ type: "dange", message: "Folder already exist!" });
setIsAlert(true);
setTimeout(() => {
setIsAlert(false);
}, 1000);
} else {
const template = new Parse.Object(folderCls);
template.set("Name", name);
template.set("Type", "Folder");
if (selectedParent) {
template.set("Folder", {
__type: "Pointer",
className: folderCls,
objectId: selectedParent
});
} else if (parentFolderId) {
template.set("Folder", folderPtr);
}
template.set("CreatedBy", Parse.User.createWithoutData(currentUser.id));
const res = await template.save();
if (res) {
setAlert({
type: "success",
message: "Folder created successfully!"
});
setIsAlert(true);
setTimeout(() => {
setIsAlert(false);
}, 1000);
if (onSuccess) {
onSuccess(res);
}
}
}
} else {
setAlert({ type: "info", message: "Please fill folder name" });
setIsAlert(true);
setTimeout(() => {
setIsAlert(false);
}, 1000);
}
};
const handleOptions = (e) => {
setSelectedParent(e.target.value);
};
return (
<div>
{isAlert && <Alert type={alert.type}>{alert.message}</Alert>}
<div id="createFolder">
<h1 className="text-base font-semibold">Create Folder</h1>
<div className="text-xs mt-2">
<label className="block">
Name<span className="text-red-500 text-[13px]">*</span>
</label>
<input
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
</div>
<div className="text-xs mt-2">
<label className="block">Parent Folder</label>
<select
value={selectedParent}
onChange={handleOptions}
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
>
<option>select</option>
{folderList.length > 0 &&
folderList.map((x) => (
<option key={x.objectId} value={x.objectId}>
{x.Name}
</option>
))}
</select>
</div>
<div>
<button
onClick={handleCreateFolder}
className="flex items-center rounded p-2 bg-[#32a3ac] text-white mt-3"
>
<i className="fa-solid fa-plus mr-1"></i>
<span>Create</span>
</button>
</div>
</div>
</div>
);
};
export default CreateFolder;
@@ -41,7 +41,8 @@ export default function DropboxChooser({ children, onSuccess, onCancel }) {
[onSuccess, onCancel] [onSuccess, onCancel]
); );
const handleChoose = useCallback(() => { const handleChoose = useCallback((e) => {
e.preventDefault()
if (window.Dropbox) { if (window.Dropbox) {
window.Dropbox.choose(options); window.Dropbox.choose(options);
} }
@@ -1,308 +0,0 @@
import React, { useState, useEffect } from "react";
import { SaveFileSize } from "../../constant/saveFileSize";
import Parse from "parse";
import sanitizeFileName from "../../primitives/sanitizeFileName";
import DropboxChooser from "./DropboxChoose";
const FileUpload = (props) => {
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [_fileupload, setFileUpload] = useState("");
const [fileload, setfileload] = useState(false);
const [Message] = useState(false);
const [percentage, setpercentage] = useState(0);
const REQUIRED_FIELD_SYMBOL = "*";
useEffect(() => {
if (!props.formData) {
setFileUpload([]);
props.onChange(undefined);
}
// eslint-disable-next-line
}, [props.formData]);
const onChange = (e) => {
try {
let files = e.target.files;
if (typeof files[0] !== "undefined") {
if (props.schema.filetypes && props.schema.filetypes.length > 0) {
var fileName = files[0].name;
var fileNameExt = fileName
.substr(fileName.lastIndexOf(".") + 1)
.toLowerCase();
let Extensions = props.schema.filetypes.map((x) => x.toLowerCase());
let arr = Extensions.filter((x) => x === fileNameExt);
if (arr.length > 0) {
console.log("multiple type");
} else {
alert(
"Only these file types are accepted : " + Extensions.join(", ")
);
}
}
if (props.schema.maxfilesizeKB && props.schema.maxfilesizeKB !== "") {
// console.log(Math.round(files[0].size / 1024));
if (
Math.round(Number(files[0].size) / 1024) >=
props.schema.maxfilesizeKB
) {
alert(
`The selected file size is too large. Please select a file less than ${Math.round(
props.schema.maxfilesizeKB / 1024
)} MB`
);
return;
}
}
handleFileUpload(files[0]);
} else {
alert("Please select file.");
return false;
}
} catch (error) {
alert(error.message);
return false;
}
};
const handleFileUpload = async (file) => {
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
setfileload(true);
const size = file.size;
const fileName = file.name;
const name = sanitizeFileName(fileName);
const pdfFile = file;
const parseFile = new Parse.File(name, pdfFile);
try {
const response = await parseFile.save({
progress: (progressValue, loaded, total, { type }) => {
if (type === "upload" && progressValue !== null) {
const percentCompleted = Math.round((loaded * 100) / total);
// console.log("percentCompleted ", percentCompleted);
setpercentage(percentCompleted);
}
}
});
setFileUpload(response.url());
props.onChange(response.url());
setfileload(false);
// The response object will contain information about the uploaded file
// console.log("File uploaded:", response);
// You can access the URL of the uploaded file using response.url()
// console.log("File URL:", response.url());
if (response.url()) {
SaveFileSize(size, response.url());
return response.url();
}
} catch (error) {
setfileload(false);
setpercentage(0);
console.error("Error uploading file:", error);
}
};
const dropboxSuccess = async (files) => {
// console.log("file ", files);
setfileload(true);
const file = files[0];
const url = file.link;
const size = file.bytes;
const mb = Math.round(file.bytes / Math.pow(1024, 2));
if (mb > 10) {
setTimeout(() => {
alert(
`The selected file size is too large. Please select a file less than 10 MB`
);
}, 500);
return;
} else {
const name = sanitizeFileName(file.name);
const parseFile = new Parse.File(name, { uri: url });
try {
const response = await parseFile.save({
progress: (progressValue, loaded, total, { type }) => {
if (type === "upload" && progressValue !== null) {
const percentCompleted = Math.round((loaded * 100) / total);
// console.log("percentCompleted ", percentCompleted);
setpercentage(percentCompleted);
}
}
});
// console.log("response.url() ", response.url());
setFileUpload(response.url());
props.onChange(response.url());
setfileload(false);
if (response.url()) {
SaveFileSize(size, response.url());
return response.url();
}
} catch (error) {
setfileload(false);
setpercentage(0);
console.error("Error uploading file:", error);
}
}
};
const dropboxCancel = async () => {
console.log("cancel clicked ");
};
let fileView =
props.formData &&
props.schema.uploadtype === "s3viajw" ? null : props.formData &&
props.formData ? (
<React.Fragment>
<a
href={props.formData}
title={props.formData}
style={{ paddingBottom: "10px", color: "blue" }}
>
Download
</a>
</React.Fragment>
) : fileload === false ? null : (
<React.Fragment>
<a
href={_fileupload}
title={_fileupload}
style={{ paddingBottom: "10px" }}
>
Download
</a>
<br />
</React.Fragment>
);
return (
<React.Fragment>
<div style={{ display: "inline-block" }}>
<label htmlFor={props.name}>
{props.schema.title}
{props.required && (
<span className="required">{REQUIRED_FIELD_SYMBOL}</span>
)}
{fileload ? (
<div className="flex items-center gap-x-2">
<div className="h-2 rounded-full w-[200px] md:w-[400px] bg-gray-200">
<div
className="h-2 rounded-full bg-blue-500"
style={{ width: `${percentage}%` }}
></div>
</div>
<span className="text-black text-sm">{percentage}%</span>
</div>
) : (
Message && (
<span style={{ fontSize: "9px", marginLeft: "4px" }}>
Processing will take 5-10 mins....
</span>
)
)}
{props.schema.helpbody ? (
<div className="dropdown pull-right">
<i
className="far fa-question-circle dropdown-toggle hovereffect"
aria-hidden="true"
id="dropdownMenuButton"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
style={{
fontSize: "12px",
color: "purple",
cursor: "pointer !important",
position: "relative",
bottom: "0px",
left: "0px",
paddingBottom: "4px",
paddingLeft: "4px"
}}
></i>
<div
className="dropdown-menu"
aria-labelledby="dropdownMenuButton"
style={{
marginleft: "-121px",
margintop: "-14px",
position: "absolute",
padding: "10px",
top: "102px!important"
}}
>
<br />
{props.schema.helplink ? (
<a
href={props.schema.helplink}
target="_blank"
rel="noreferrer"
className="btn btn-xs btn-primary"
>
Read more..
</a>
) : null}
</div>
</div>
) : null}
<span style={{ marginLeft: "10px" }}>{fileView}</span>
</label>
</div>
<>
{props.formData ? (
<div className="flex gap-2 justify-center items-center">
<div className="flex justify-between items-center px-2 py-[3px] w-full font-bold rounded border-[1px] border-[#ccc] text-gray-500 bg-white text-[13px]">
<div className="break-all">
file selected : {props.formData.split("/")[3]}
</div>
<div
onClick={() => {
console.log("clicked");
setFileUpload([]);
props.onChange(undefined);
}}
className="cursor-pointer px-[10px] text-[20px] font-bold bg-white text-red-500"
>
<i className="fa-solid fa-xmark"></i>
</div>
</div>
<DropboxChooser
onSuccess={dropboxSuccess}
onCancel={dropboxCancel}
/>
</div>
) : (
<div className="flex gap-2 justify-center items-center">
<input
type="file"
id="hashfile"
style={{
border: "1px solid #ccc",
color: "gray",
backgroundColor: "white",
padding: "5px 10px",
borderRadius: "4px",
fontSize: "13px",
width: "100%",
fontWeight: "bold"
}}
accept="application/pdf,application/vnd.ms-excel"
onChange={onChange}
/>
<DropboxChooser
onSuccess={dropboxSuccess}
onCancel={dropboxCancel}
/>
</div>
)}
</>
</React.Fragment>
);
};
export default FileUpload;
@@ -1,98 +0,0 @@
import React, { Component } from "react";
import Parse from "parse";
// import axios from "axios";
export class HiddenField extends Component {
state = {
baseUrl: localStorage.getItem("baseUrl"),
parseAppId: localStorage.getItem("parseAppId"),
_fields: ""
};
loadData = async () => {
if (this.props.schema.default) {
this.setState({ _fields: this.props.schema.default });
} else {
try {
Parse.serverURL = this.state.baseUrl;
Parse.initialize(this.state.parseAppId);
let currentUser = await Parse.User.current();
if (localStorage.getItem("Extand_Class")) {
let _rdata = JSON.parse(localStorage.getItem("Extand_Class"));
let custome_Filed = "";
let splitArray = this.props.schema.data.valueKey.split(".");
if (splitArray.length > 1) {
custome_Filed = _rdata[0][splitArray[0]][splitArray[1]];
} else {
let _Filed = _rdata[0][splitArray[0]];
if (typeof _Filed === "object") {
custome_Filed = {
__type: "Pointer",
className: _Filed["className"],
objectId: _Filed["objectId"]
};
} else {
custome_Filed = _rdata[0][splitArray[0]];
}
}
this.setState({ _fields: custome_Filed });
} else {
if (currentUser) {
// let url = `${this.state.baseUrl}classes/${localStorage.getItem(
// "extended_class"
// )}?where={"UserId":{"__type":"Pointer","className":"_User","objectId":"${
// currentUser.id
// }"}}&keys=${this.props.schema.data.valueKey}`;
// const headers = {
// "Content-Type": "application/json",
// "X-Parse-Application-Id": this.state.parseAppId
// };
// await axios.get(url, { headers: headers }).then((res) => {
// let custome_Filed = "";
// let _rdata = res.data.results;
// let splitArray = this.props.schema.data.valueKey.split(".");
// if (splitArray.length > 1) {
// custome_Filed = _rdata[0][splitArray[0]][splitArray[1]];
// } else {
// console.log(_rdata[0][splitArray[0]]);
// custome_Filed = _rdata[0][splitArray[0]];
// }
// this.setState({ _fields: custome_Filed });
// });
const res = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
let custome_Filed = "";
const result = res.toJSON();
let _rdata = [result];
let splitArray = this.props.schema.data.valueKey.split(".");
if (splitArray.length > 1) {
custome_Filed = _rdata[0][splitArray[0]][splitArray[1]];
} else {
console.log(_rdata[0][splitArray[0]]);
custome_Filed = _rdata[0][splitArray[0]];
}
this.setState({ _fields: custome_Filed });
}
}
} catch (error) {
console.log("err", error);
}
}
};
componentDidMount() {
this.loadData();
}
render() {
return (
<input
type="hidden"
value={this.state._fields}
onChange={this.props.onChange(this.state._fields)}
/>
);
}
}
export default HiddenField;
@@ -1,70 +0,0 @@
import React from "react";
import parse from "html-react-parser";
import PropTypes from "prop-types";
const LabelField = (props) => {
const { Title, Name, Required, HelpBody, HelpLink } = props;
const REQUIRED_FIELD_SYMBOL = "*";
return (
<div style={{ display: "inline-block" }}>
<label htmlFor={Name}>
{Title}
{Required && <span className="required">{REQUIRED_FIELD_SYMBOL}</span>}
{HelpBody ? (
<div className="dropdown pull-right">
<i
className="far fa-question-circle dropdown-toggle hovereffect pull-right"
aria-hidden="true"
id="dropdownMenuButton"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
style={{
fontSize: "12px",
color: "purple",
cursor: "pointer !important",
position: "relative",
bottom: "0px",
left: "0px",
paddingBottom: "4px",
paddingLeft: "4px"
}}
></i>
<div
className="dropdown-menu"
aria-labelledby="dropdownMenuButton"
style={{
marginleft: "-121px",
margintop: "-14px",
position: "absolute",
padding: "10px",
top: "102px!important"
}}
>
{parse(`
${HelpBody}
`)}
<br />
{HelpLink ? (
<a
href={HelpLink}
target="_blank"
rel="noreferrer"
className="btn btn-xs btn-primary"
>
Read more..
</a>
) : null}
</div>
</div>
) : null}
</label>
</div>
);
};
LabelField.propTypes = {
Name: PropTypes.string.isRequired,
Title: PropTypes.string.isRequired
};
export default LabelField;
@@ -1,482 +0,0 @@
import React, { useEffect, useState } from "react";
import { connect } from "react-redux";
import { onChangeLevel1Dropdown } from "../../redux/actions/index";
import axios from "axios";
import Parse from "parse";
import parse from "html-react-parser";
const Level1Dropdown = (props) => {
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [Level1_DD, setLevel1_DD] = useState([]);
const [toastColor] = useState("#d9534f");
const [toastDescription, setToastDescription] = useState("");
const [active, setActive] = useState(false);
const getParams = (offset) => {
const params = {
skip: offset
};
return params;
};
const Level1DropdownData = async () => {
try {
if (
props.formData &&
props.uiSchema["ui:disabled"] &&
props.formData !== "Select"
) {
let url = `${parseBaseUrl}classes/${props.schema.data.class}/${props.formData}`;
if (typeof props.formData === "object") {
url = `${parseBaseUrl}classes/${props.schema.data.class}/${props.formData.objectId}`;
}
let headers1 = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
};
let data = [];
let response = [];
await axios.get(url, { headers: headers1 }).then((res) => {
if (res) {
data.push(res.data);
}
});
if (data.length > 0) {
let temp = [];
data.forEach((x) => {
let opt = "";
if (Array.isArray(x[props.schema.data.valueKey])) {
x[props.schema.data.valueKey].forEach((tt) => {
if (typeof tt === "object") {
opt = {
objectId: tt[props.schema.data.displayKey],
option: tt[props.schema.data.displayKey]
};
} else {
opt = {
objectId: tt,
option: tt
};
}
temp.push(opt);
});
} else if (props.schema.data.isPointer) {
if (props.schema.data.valueKey.includes(".")) {
let newArr = props.schema.data.valueKey.split(".");
if (newArr.length === 2) {
opt = {
objectId: x[newArr[0]][newArr[1]],
option: x[props.schema.data.displayKey]
};
} else {
opt = {
objectId: x[newArr[0]],
option: x[props.schema.data.displayKey]
};
}
} else {
opt = {
objectId: x[props.schema.data.valueKey],
option: x[props.schema.data.displayKey]
};
}
temp.push(opt);
} else {
opt = {
objectId: x[props.schema.data.valueKey],
option: x[props.schema.data.displayKey]
};
temp.push(opt);
}
});
response = temp;
setLevel1_DD(response);
setActive(false);
if (response.length === 1) {
props.onChangeLevel1Dropdown(response[0].objectId, props.name);
props.onChange(response[0].objectId);
} else if (response.length === 0) {
props.onChangeLevel1Dropdown("", props.name);
props.onChange("");
}
}
} else {
let response = [];
setActive(true);
Parse.serverURL = parseBaseUrl;
Parse.initialize(parseAppId);
const currentUser = Parse.User.current();
// eslint-disable-next-line
var reg = /(\#.*?\#)/gi;
let str = props.schema.data.query;
var test;
if (str.includes("#")) {
let res;
if (localStorage.getItem("Extand_Class")) {
let data = JSON.parse(localStorage.getItem("Extand_Class"));
res = data[0];
} else {
const currentUser = Parse.User.current();
res = await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email")
});
if (res) res = res.toJSON();
}
if (res) {
let json = res;
let output = str.match(reg);
if (output.length === 1) {
output = output.join();
output = output.substring(1, output.length - 1);
output = output.split(".");
if (output.length === 1) {
let out = output[0];
if (json[out]) {
if (typeof json[out] === "object") {
test = str.replace(reg, JSON.stringify(json[out]));
} else {
test = str.replace(reg, json[out]);
}
} else {
test = str.replace(reg, currentUser.id);
}
} else if (output.length === 2) {
let out1 = json[output[0]][output[1]];
if (out1) {
test = str.replace(reg, out1);
}
}
} else if (output.length === 2) {
let output1 = output[0];
output1 = output1.substring(1, output1.length - 1);
output1 = output1.split(".");
if (output1.length === 1) {
let out = output1[0];
if (json[out]) {
if (typeof json[out] === "object") {
str = str.replace(output[0], JSON.stringify(json[out]));
} else {
str = str.replace(output[0], json[out]);
}
} else {
str = str.replace(output[0], currentUser.id);
}
} else if (output1.length === 2) {
let out1 = json[output1[0]][output1[1]];
if (out1) {
str = str.replace(output[0], out1);
}
}
let output2 = output[1];
output2 = output2.substring(1, output2.length - 1);
output2 = output2.split(".");
if (output2.length === 1) {
let out = output2[0];
if (json[out]) {
if (typeof json[out] === "object") {
str = str.replace(output[1], JSON.stringify(json[out]));
} else {
str = str.replace(output[1], json[out]);
}
} else {
str = str.replace(output[1], currentUser.id);
}
} else if (output2.length === 2) {
let out1 = json[output2[0]][output2[1]];
if (out1) {
str = str.replace(output[1], out1);
}
}
test = str;
}
} else {
setToastDescription(
`User not found in ${localStorage.getItem("extended_class")}`
);
setActive(false);
var x = document.getElementById("Level_1");
x.className = "show";
setTimeout(function () {
x.className = x.className.replace("show", "");
}, 5000);
return;
}
} else {
test = str;
}
let url = `${parseBaseUrl}classes/${props.schema.data.class}?${test}`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
};
let fetchCount = 0;
let offset = 0;
let data = [];
/* eslint-disable no-constant-condition */
while (true) {
const params = getParams(offset);
await axios
.get(url, { params: params, headers: headers })
.then((response) => {
fetchCount = response.data.results.length;
offset += response.data.results.length;
if (fetchCount > 0) {
response.data.results.forEach((x) => {
data.push(x);
});
}
})
.catch((err) => {
console.error("Problem", err.response);
setToastDescription(err.response.data.message);
setActive(false);
var x = document.getElementById("Level_1");
x.className = "show";
setTimeout(function () {
x.className = x.className.replace("show", "");
}, 5000);
});
if (fetchCount === 0 || fetchCount < 100) {
break;
}
}
if (data.length > 0) {
let temp = [];
data.forEach((x) => {
let opt = "";
if (Array.isArray(x[props.schema.data.valueKey])) {
x[props.schema.data.valueKey].forEach((tt) => {
if (typeof tt === "object") {
if (props.schema.data.isPointer) {
opt = {
objectId: tt["objectId"],
option: tt[props.schema.data.displayKey]
};
} else {
opt = {
objectId: tt[props.schema.data.displayKey],
option: tt[props.schema.data.displayKey]
};
}
} else {
opt = {
objectId: tt,
option: tt
};
}
temp.push(opt);
});
} else if (props.schema.data.isPointer) {
if (props.schema.data.valueKey.includes(".")) {
let newArr = props.schema.data.valueKey.split(".");
if (newArr.length === 2) {
let _dis = props.schema.data.displayKey.split(".");
if (_dis.length === 2) {
opt = {
objectId: x[newArr[0]][newArr[1]],
option: x[_dis[0]][_dis[1]]
};
} else {
opt = {
objectId: x[newArr[0]][newArr[1]],
option: x[props.schema.data.displayKey]
};
}
} else {
opt = {
objectId: x[newArr[0]],
option: x[props.schema.data.displayKey]
};
}
} else {
opt = {
objectId: x[props.schema.data.valueKey],
option: x[props.schema.data.displayKey]
};
}
temp.push(opt);
} else {
opt = {
objectId: x[props.schema.data.valueKey],
option: x[props.schema.data.displayKey]
};
temp.push(opt);
}
});
response = temp;
setLevel1_DD(response);
setActive(false);
if (!props.formData) {
props.onChangeLevel1Dropdown("", props.name);
}
if (response.length === 1) {
props.onChangeLevel1Dropdown(response[0].objectId, props.name);
props.onChange(response[0].objectId);
} else if (response.length === 0) {
props.onChangeLevel1Dropdown("", props.name);
props.onChange("");
}
} else {
setActive(false);
}
}
} catch (e) {
try {
setToastDescription(e.message);
setActive(false);
x = document.getElementById("Level_1");
x.className = "show";
setTimeout(function () {
x.className = x.className.replace("show", "");
}, 5000);
} catch (error) {
console.log("Err", error);
}
}
};
useEffect(() => {
Level1DropdownData();
// eslint-disable-next-line
}, []);
useEffect(() => {
if (props.formData && props.formData[`objectId`]) {
props.onChangeLevel1Dropdown(props.formData.objectId, props.name);
} else if (props.formData) {
props.onChangeLevel1Dropdown(props.formData, props.name);
}
// eslint-disable-next-line
}, [props.formData]);
const selectDefault = () => {
props.onChange(Level1_DD[0].objectId);
props.onChangeLevel1Dropdown(Level1_DD[0].objectId, props.name);
};
const REQUIRED_FIELD_SYMBOL = "*";
return (
<React.Fragment>
<div style={{ display: "inline-block" }}>
<label htmlFor={props.name}>
{props.schema.title}
{props.required && (
<span className="required">{REQUIRED_FIELD_SYMBOL}</span>
)}
{props.schema.data.helpbody ? (
<div className="dropdown pull-right">
<i
className="far fa-question-circle dropdown-toggle hovereffect pull-right"
aria-hidden="true"
id="dropdownMenuButton"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
style={{
fontSize: "12px",
color: "purple",
cursor: "pointer !important",
position: "relative",
bottom: "0px",
left: "0px",
paddingBottom: "4px",
paddingLeft: "4px"
}}
></i>
<div
className="dropdown-menu"
aria-labelledby="dropdownMenuButton"
style={{
marginleft: "-121px",
margintop: "-14px",
position: "absolute",
padding: "10px",
top: "102px!important"
}}
>
{parse(`
${props.schema.data.helpbody}
`)}
<br />
{props.schema.data.helplink ? (
<a
href={props.schema.data.helplink}
target="_blank"
rel="noreferrer"
className="btn btn-xs btn-primary"
>
Read more..
</a>
) : null}
</div>
</div>
) : null}
</label>
</div>
{Level1_DD && (
<select
className="form-control"
name={props.name}
value={props.value}
required={props.required}
disabled={props.uiSchema["ui:disabled"]}
onChange={(e) => {
if (!e.target.value) {
if (props.schema.data.isPointer) {
localStorage.setItem("Level1", undefined);
props.onChangeLevel1Dropdown(undefined, props.name);
return props.onChange(undefined);
} else {
localStorage.setItem("Level1", e.target.value);
props.onChangeLevel1Dropdown(e.target.value, props.name);
return props.onChange(e.target.value);
}
} else {
localStorage.setItem("Level1", e.target.value);
props.onChangeLevel1Dropdown(e.target.value, props.name);
return props.onChange(e.target.value);
}
}}
readOnly={props.uiSchema["ui:disabled"] ? true : false}
defaultValue={Level1_DD.length === 1 && selectDefault}
>
<option value="">{!active ? "Select" : "loading..."}</option>
{Level1_DD &&
Level1_DD.map((x, i) => (
<React.Fragment key={i}>
{props.formData && props.formData.objectId ? (
props.formData.objectId === x.objectId ? (
<option value={x.objectId} selected>
{x.option}
</option>
) : (
<option value={x.objectId}>{x.option}</option>
)
) : props.formData && props.formData === x.objectId ? (
<option value={x.objectId} selected>
{x.option}
</option>
) : (
<option value={x.objectId}>{x.option}</option>
)}
</React.Fragment>
))}
</select>
)}
<div id="Level_1" style={{ backgroundColor: toastColor }}>
{toastDescription}
</div>
</React.Fragment>
);
};
export default connect(null, { onChangeLevel1Dropdown })(Level1Dropdown);
@@ -1,709 +0,0 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import Select from "react-select";
import axios from "axios";
import LabelField from "./LabelField";
import ReactDragListView from "react-drag-listview";
import AppendFormInForm from "../AppendFormInForm";
import Modal from "react-modal";
function arrayMove(array, from, to) {
array = array.slice();
array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]);
return array;
}
/**
* react-sortable-hoc is depcreated not usable from react 18.x.x
* need to replace it with @dnd-kit
* code changes required
*/
const MultiSelectField = (props) => {
Modal.setAppElement("body");
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [state, setState] = useState(undefined);
// const [editFormData, setEditFormData] = useState([]);
const [selected, setSelected] = React.useState([]);
const [isModal, setIsModel] = useState(false);
const onChange = (selectedOptions) => setSelected(selectedOptions);
const [modalIsOpen, setModalIsOpen] = useState(false);
const onSortEnd = ({ oldIndex, newIndex }) => {
const newValue = arrayMove(selected, oldIndex, newIndex);
setSelected(newValue);
};
// console.log("props",props)
const GetSelectListData = async () => {
try {
let response = [];
let str = props.schema.data.query;
let _query;
/* eslint-disable no-useless-escape */
let reg = /(\#.*?\#)/gi;
let extclass =
localStorage.getItem("Extand_Class") &&
JSON.parse(localStorage.getItem("Extand_Class"));
let extRow = extclass.length && extclass[0];
if (str.includes("#")) {
let output = str.match(reg);
output = output.join();
output = output.substring(1, output.length - 1);
output = output.split(".");
if (output.length === 2) {
let out1 = extRow[output[0]][output[1]];
_query = str.replace(reg, out1 && out1);
} else {
let out1 = extRow[output[0]];
_query = str.replace(reg, out1 && out1);
}
} else {
_query = str;
}
let url = `${parseBaseUrl}classes/${props.schema.data.class}?${_query}`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
};
await axios.get(url, { headers: headers }).then((res) => {
let temp = [];
let formArray = [];
let _selected = [];
if (props.schema.uiLayout === "MultiDropdownList") {
if (props.formData) {
props.formData.forEach((x) => {
if (typeof x === "object") {
formArray.push(x.objectId);
} else {
formArray.push(x);
}
});
}
res.data.results.forEach((x) => {
let obj = {};
if (formArray.includes(x[props.schema.data.valueKey])) {
obj = {
name: x[props.schema.data.displayKey],
value: x[props.schema.data.valueKey],
isChecked: true
};
} else {
if (props.schema.selectAll) {
obj = {
name: x[props.schema.data.displayKey],
value: x[props.schema.data.valueKey],
isChecked: true
};
} else {
obj = {
name: x[props.schema.data.displayKey],
value: x[props.schema.data.valueKey],
isChecked: false
};
}
}
temp.push(obj);
});
response = temp;
if (props.formData) {
let checkData = [];
response.forEach((x) => {
if (x.isChecked) {
checkData.push(x.value);
}
});
setSelected(checkData);
}
setState({ [`${props.name}_DD`]: response });
} else {
res.data.results.forEach((x) => {
let obj = {};
if (props.formData) {
props.formData.forEach((x) => {
if (typeof x === "object") {
formArray.push(x.objectId);
} else {
formArray.push(x);
}
});
}
obj = {
label: x[props.schema.data.displayKey],
value: x[props.schema.data.valueKey]
};
if (formArray.includes(x[props.schema.data.valueKey])) {
_selected.push(obj);
}
if (props.schema.selectAll) {
_selected.push(obj);
}
temp.push(obj);
});
response = temp;
setState({ [`${props.name}_DD`]: response });
setSelected(_selected);
}
});
} catch (error) {
console.log("err", error);
}
};
const handleCheckChieldElement = (event) => {
let SelectLists = state[`${props.name}_DD`];
let List = [];
SelectLists.forEach((select) => {
if (select.value === event.target.value) {
select.isChecked = event.target.checked;
}
if (select.isChecked) {
List.push(select.value);
}
});
setSelected(List);
setState({ [`${props.name}_DD`]: SelectLists });
};
// const Level1CheckList = async (id) => {
// try {
// let response = [];
// // eslint-disable-next-line
// let reg = /(\#.*?\#)/gi;
// let _query = props.schema.data.query;
// let output = _query.match(reg);
// if (output.length === 2) {
// let res;
// if (localStorage.getItem("Extand_Class")) {
// let data = JSON.parse(localStorage.getItem("Extand_Class"));
// res = data[0];
// }
// output = output.filter((x) => x !== "#queryString#");
// if (output.length === 1) {
// _query = _query.replace("#queryString#", id);
// output = output.join();
// output = output.substring(1, output.length - 1);
// output = output.split(".");
// if (output.length > 0) {
// _query = _query.replace(reg, res[output[0]][output[1]]);
// } else {
// _query = _query.replace(reg, res[output[0]]);
// }
// }
// } else {
// _query = props.schema.data.query.replace(reg, id);
// }
// let url = `${parseBaseUrl}classes/${props.schema.data.class}?${_query}`;
// const headers = {
// "Content-Type": "application/json",
// "X-Parse-Application-Id": parseAppId,
// "X-Parse-Session-Token": localStorage.getItem("accesstoken")
// };
// await axios.get(url, { headers: headers }).then(async (res) => {
// let temp = [];
// let formArray = [];
// let _selected = [];
// if (editFormData.length > 0) {
// editFormData.forEach((x) => {
// if (typeof x === "object") {
// formArray.push(x.objectId);
// } else {
// formArray.push(x);
// }
// });
// } else if (
// props.schema.selectedData &&
// Object.keys(props.schema.selectedData).length !== 0 &&
// props.schema.selectedData.constructor === Object
// ) {
// try {
// let selectedDataQuery = props.schema.selectedData.query.replace(
// reg,
// id
// );
// let selectedDataUrl = `${parseBaseUrl}classes/${props.schema.selectedData.class}?${selectedDataQuery}`;
// await axios.get(selectedDataUrl, { headers }).then((sltres) => {
// let sltData = sltres.data.results;
// sltData.forEach((x) => {
// if (props.schema.selectedData.valueKey.includes(".")) {
// let sltArr = props.schema.selectedData.valueKey.split(".");
// if (Array.isArray(x[sltArr[0]])) {
// x[sltArr[0]].forEach((l) => {
// formArray.push(l[sltArr[1]]);
// });
// } else {
// formArray.push(x[sltArr[0][sltArr[1]]]);
// }
// } else {
// formArray.push(x[props.schema.selectedData.valueKey]);
// }
// });
// });
// } catch (error) {}
// }
// res.data.results.forEach((x) => {
// let obj = {};
// if (props.schema.data.valueKey.includes(".")) {
// let newArr = props.schema.data.valueKey.split(".");
// if (Array.isArray(x[newArr[0]])) {
// if (props.schema.data.displayKey.includes(".")) {
// let _dis = props.schema.data.displayKey.split(".");
// x[newArr[0]].forEach((l) => {
// if (formArray.includes(l[newArr[1]])) {
// obj = {
// label: l[_dis[1]],
// value: l[newArr[1]],
// isChecked: true
// };
// _selected.push(obj);
// } else {
// if (props.schema.selectAll) {
// obj = {
// label: l[_dis[1]],
// value: l[newArr[1]],
// isChecked: true
// };
// _selected.push(obj);
// } else {
// obj = {
// label: l[_dis[1]],
// value: l[newArr[1]],
// isChecked: false
// };
// }
// }
// temp.push(obj);
// });
// } else {
// x[newArr[0]].forEach((l) => {
// if (formArray.includes(l[newArr[1]])) {
// obj = {
// label: x[props.schema.data.displayKey],
// value: l[newArr[1]],
// isChecked: true
// };
// _selected.push(obj);
// } else {
// if (props.schema.selectAll) {
// obj = {
// label: x[props.schema.data.displayKey],
// value: l[newArr[1]],
// isChecked: true
// };
// _selected.push(obj);
// } else {
// obj = {
// label: x[props.schema.data.displayKey],
// value: l[newArr[1]],
// isChecked: false
// };
// }
// }
// temp.push(obj);
// });
// }
// } else {
// if (props.schema.data.displayKey.includes(".")) {
// let disArr = props.schema.data.displayKey.split(".");
// if (formArray.includes(x[newArr[0]][newArr[1]])) {
// obj = {
// label: x[disArr[0]][disArr[1]],
// value: x[newArr[0]][newArr[1]],
// isChecked: true
// };
// _selected.push(obj);
// } else {
// if (props.schema.selectAll) {
// obj = {
// label: x[disArr[0]][disArr[1]],
// value: x[newArr[0]][newArr[1]],
// isChecked: true
// };
// _selected.push(obj);
// } else {
// obj = {
// label: x[disArr[0]][disArr[1]],
// value: x[newArr[0]][newArr[1]],
// isChecked: false
// };
// }
// }
// } else {
// if (formArray.includes(x[newArr[0]][newArr[1]])) {
// obj = {
// label: x[props.schema.data.displayKey],
// value: x[newArr[0]][newArr[1]],
// isChecked: true
// };
// _selected.push(obj);
// } else {
// if (props.schema.selectAll) {
// obj = {
// label: x[props.schema.data.displayKey],
// value: x[newArr[0]][newArr[1]],
// isChecked: true
// };
// _selected.push(obj);
// } else {
// obj = {
// label: x[props.schema.data.displayKey],
// value: x[newArr[0]][newArr[1]],
// isChecked: false
// };
// }
// }
// }
// }
// } else {
// if (Array.isArray(x[props.schema.data.valueKey])) {
// x[props.schema.data.valueKey].forEach((t) => {
// if (formArray.includes(t)) {
// obj = {
// label: t,
// value: t,
// isChecked: true
// };
// _selected.push(obj);
// } else {
// if (props.schema.selectAll) {
// obj = {
// label: t,
// value: t,
// isChecked: true
// };
// _selected.push(obj);
// } else {
// obj = {
// label: t,
// value: t,
// isChecked: false
// };
// }
// }
// temp.push(obj);
// });
// } else if (formArray.includes(x[props.schema.data.valueKey])) {
// obj = {
// label: x[props.schema.data.displayKey],
// value: x[props.schema.data.valueKey],
// isChecked: true
// };
// _selected.push(obj);
// } else {
// if (props.schema.selectAll) {
// obj = {
// label: x[props.schema.data.displayKey],
// value: x[props.schema.data.valueKey],
// isChecked: true
// };
// _selected.push(obj);
// } else {
// obj = {
// label: x[props.schema.data.displayKey],
// value: x[props.schema.data.valueKey],
// isChecked: false
// };
// }
// }
// temp.push(obj);
// }
// });
// response = temp;
// if (props.schema.uiLayout === "MultiDropdownList") {
// if (editFormData) {
// let checkData = [];
// response.forEach((x) => {
// if (x.isChecked) {
// checkData.push(x.value);
// }
// });
// setSelected(checkData);
// }
// setState({ [`${props.name}_DD`]: response });
// } else {
// setState({ [`${props.name}_DD`]: response });
// setSelected(_selected);
// }
// });
// } catch (error) {}
// };
const dragProps = {
onDragEnd(fromIndex, toIndex) {
const data = [...state[`${props.name}_DD`]];
const item = data.splice(fromIndex, 1)[0];
data.splice(toIndex, 0, item);
let NewList = [];
data.forEach((x) => {
if (x.isChecked) {
NewList.push(x.value);
}
});
setState({ [`${props.name}_DD`]: data });
setSelected(NewList);
},
nodeSelector: "li",
handleSelector: "a"
};
useEffect(() => {
if (!props.schema.parent) GetSelectListData();
// eslint-disable-next-line
}, []);
useEffect(() => {
if (props.schema.uiLayout === "MultiDropdownList") {
props.onChange(selected);
} else {
if (selected && selected.length) {
let newData = [];
selected.forEach((x) => {
newData.push(x.value);
});
props.onChange(newData);
}
}
// eslint-disable-next-line
}, [selected]);
// useState(() => {
// if (props.formData) {
// if (props.formData === "Select") {
// } else {
// setEditFormData(props.formData);
// }
// }
// // eslint-disable-next-line
// }, [props.formData]);
const handleModalCloseClick = () => {
setIsModel(false);
setModalIsOpen(false);
};
const openModal = () => {
setModalIsOpen(true);
};
// `handleNewDetails` is used to set just save from quick form to selected option in dropdown
const handleNewDetails = (data) => {
setState({ [`${props.name}_DD`]: [...state[`${props.name}_DD`], data] });
if (selected.length > 0) {
setSelected([...selected, data]);
} else {
setSelected([data]);
}
};
if (props.schema.uiLayout === "MultiDropdownList") {
return (
<React.Fragment>
<LabelField
Title={props.schema.title}
Name={props.name}
Required={props.required}
HelpBody={props.schema.helpbody}
HelpLink={props.schema.helplink}
/>
<ReactDragListView {...dragProps}>
<ul
style={{
listStyleType: "square",
listStylePosition: "outside",
maxHeight: "250px",
overflow: "auto",
paddingTop: "10px",
paddingBottom: "10px",
border: "0px solid #b3b3b3",
borderRadius: "5px"
}}
>
{state && state[`${props.name}_DD`].length > 0 ? (
state[`${props.name}_DD`].map((x, i) => {
return (
<li key={i} className="multiSelectList">
<input
key={x.value}
onClick={handleCheckChieldElement}
type="checkbox"
checked={x.isChecked}
style={{ marginTop: "7px" }}
value={x.value}
disabled={props.disabled}
/>{" "}
<span style={{ marginTop: "7px" }}>{x.name}</span>
{props.schema.isSortable && !props.disabled && (
<a
onClick={(e) => e.preventDefault()}
className="pull-right"
title="Sort List"
style={{ textDecoration: "none" }}
>
<i
className="fa fa-bars"
style={{
fontSize: "30px",
color: "skyblue",
paddingTop: "11px"
}}
></i>
</a>
)}
</li>
);
})
) : (
<li className="multiSelectList">No Record Found</li>
)}
</ul>
</ReactDragListView>
</React.Fragment>
);
}
return (
<React.Fragment>
<LabelField
Title={props.schema.title}
Name={props.name}
Required={props.required}
HelpBody={props.schema.helpbody}
HelpLink={props.schema.helplink}
/>
<div style={{ display: "flex", gap: 5 }}>
<div style={{ flexWrap: "wrap", width: "100%" }}>
<Select
onSortEnd={onSortEnd}
distance={4}
isMulti
options={(state && state[`${props.name}_DD`]) || []}
value={selected}
onChange={onChange}
closeMenuOnSelect={false}
/>
</div>
{props.schema.data.quickAddFormId && (
<div
onClick={() => {
setIsModel(true);
openModal();
}}
style={{
cursor: "pointer",
borderRadius: 4,
border: "1px solid #ccc",
minHeight: 38,
minWidth: 48,
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
<i className="fas fa-plus"></i>
</div>
)}
{/* {props.schema.data.quickAddFormId && (
<div
className="modal fade"
id={"multiSelectModal" + props.schema.data.quickAddFormId}
tabIndex="-1"
role="dialog"
aria-labelledby="exampleModalLabel"
aria-hidden="true"
>
<div className="modal-dialog modal-lg" role="document">
<div className="modal-content">
<div className="modal-header">
<button
type="button"
className="close"
data-dismiss="modal"
aria-label="Close"
onClick={handleModalCloseClick}
>
<i className="fa fa-times-circle" aria-hidden="true"></i>
</button>
</div>
<div className="modal-body">
{isModal && (
<AppendFormInForm
id={props.schema.data.quickAddFormId}
valueKey={props.schema.data.valueKey}
displayKey={props.schema.data.displayKey}
details={handleNewDetails}
closePopup={handleModalCloseClick}
/>
)}
</div>
</div>
</div>
</div>
)} */}
<Modal
isOpen={modalIsOpen}
onRequestClose={handleModalCloseClick}
shouldCloseOnOverlayClick={false}
contentLabel="Modal"
style={{
content: {
top: "50%",
left: "50%",
right: "auto",
bottom: "auto",
transform: "translate(-50%, -50%)",
padding: 0
},
overlay: {
width: "100%",
backgroundColor: "rgba(0, 0, 0, 0.75)",
zIndex: 50
}
}}
>
<div className="min-w-full md:min-w-[500px]">
<div
type="button"
className="flex justify-between items-center p-3 border-b-[1px] border-gray-300"
>
<div className=" text-black text-xl font-semibold pl-3">
Add Signer
</div>
<button onClick={handleModalCloseClick}>
<i
style={{ fontSize: 25 }}
className="fa fa-times-circle"
aria-hidden="true"
></i>
</button>
</div>
{isModal && (
<AppendFormInForm
id={props.schema.data.quickAddFormId}
valueKey={props.schema.data.valueKey}
displayKey={props.schema.data.displayKey}
details={handleNewDetails}
closePopup={handleModalCloseClick}
/>
)}
</div>
</Modal>
</div>
</React.Fragment>
);
};
const mapStateToProps = (state) => {
return {
Level1_Dropdown: state.Level1_Dropdown,
Level2_Dropdown: state.Level2_Dropdown,
Level3_Dropdown: state.Level3_Dropdown
};
};
export default connect(mapStateToProps, null)(MultiSelectField);
@@ -1,92 +0,0 @@
import React from "react";
import ObjectField from "@rjsf/core/lib/components/fields/ObjectField";
import validator from "@rjsf/validator-ajv8";
import { Col } from "react-bootstrap";
import { retrieveSchema } from "@rjsf/utils";
class GridField extends ObjectField {
state = {};
render() {
const {
uiSchema,
errorSchema,
idSchema,
disabled,
readonly,
onBlur,
formData
} = this.props;
const { fields, rootSchema } = this.props.registry;
const { SchemaField } = fields;
const schema = retrieveSchema(validator, this.props.schema, rootSchema);
const title = schema.title === undefined ? "" : schema.title;
const description =
schema && schema.description === undefined ? "" : schema.description;
// console.log('this.props.schema ', this.props.schema)
// console.log("schema ", schema);
const layout = uiSchema["ui:layout"];
return (
<fieldset>
{title ? <h4>{title}</h4> : null}
{description ? <h6>{description}</h6> : null}
{layout.map((row, index) => {
return (
<div className="row" key={index}>
{Object.keys(row).map((name, index) => {
const { doShow, ...rowProps } = row[name];
let style = {};
if (doShow && !doShow({ formData })) {
style = { display: "none" };
}
if (schema.properties[name]) {
return (
<Col {...rowProps} key={index} style={style}>
<SchemaField
name={name}
required={this.isRequired(name)}
schema={schema.properties[name]}
uiSchema={uiSchema[name]}
errorSchema={errorSchema[name]}
idSchema={idSchema[name]}
formData={formData[name]}
onChange={this.onPropertyChange(name)}
onBlur={onBlur}
registry={this.props.registry}
disabled={disabled}
readonly={readonly}
/>
</Col>
);
} else {
const { render, ...rowProps } = row[name];
let UIComponent = () => null;
if (render) {
UIComponent = render;
}
return (
<Col {...rowProps} key={index} style={style}>
<UIComponent
name={name}
formData={formData}
errorSchema={errorSchema}
uiSchema={uiSchema}
schema={schema}
registry={this.props.registry}
/>
</Col>
);
}
})}
</div>
);
})}
</fieldset>
);
}
}
export default GridField;
@@ -0,0 +1,261 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import CreateFolder from "./CreateFolder";
import ModalUi from "../../primitives/ModalUi";
const SelectFolder = ({ required, onSuccess, folderCls }) => {
const [isOpen, SetIsOpen] = useState(false);
const [clickFolder, setClickFolder] = useState("");
const [selectFolder, setSelectedFolder] = useState({});
const [folderList, setFolderList] = useState([]);
const [tabList, setTabList] = useState([]);
const [isLoader, setIsLoader] = useState(false);
const [folderPath, setFolderPath] = useState("");
const [isAdd, setIsAdd] = useState(false);
useEffect(() => {
if (isOpen) {
setIsAdd(false);
setClickFolder({});
setFolderList([]);
setTabList([]);
fetchFolder();
}
// eslint-disable-next-line
}, [isOpen]);
const fetchFolder = async (folderPtr) => {
setIsLoader(true);
try {
const FolderQuery = new Parse.Query(folderCls);
if (folderPtr) {
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
} else {
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
}
const res = await FolderQuery.find();
if (res) {
const result = JSON.parse(JSON.stringify(res));
if (result) {
setFolderList(result);
setIsLoader(false);
}
setIsLoader(false);
}
} catch (error) {
setIsLoader(false);
}
};
const handleSelect = (item) => {
setFolderList([]);
setClickFolder({ ObjectId: item.objectId, Name: item.Name });
if (tabList.length > 0) {
const tab = tabList.some((x) => x.objectId === item.objectId);
if (!tab) {
setTabList((tabs) => [...tabs, item]);
const folderPtr = {
__type: "Pointer",
className: folderCls,
objectId: item.objectId
};
fetchFolder(folderPtr);
}
} else {
setTabList((tabs) => [...tabs, item]);
const folderPtr = {
__type: "Pointer",
className: folderCls,
objectId: item.objectId
};
fetchFolder(folderPtr);
}
};
const handleSubmit = () => {
let url = "Root";
tabList.forEach((t) => {
url = url + " / " + t.Name;
});
setFolderPath(url);
setSelectedFolder(clickFolder);
if (onSuccess) {
onSuccess(clickFolder);
}
SetIsOpen(false);
};
const handleCancel = () => {
SetIsOpen(false);
setClickFolder({});
setFolderList([]);
setTabList([]);
};
const removeTabListItem = async (e, i) => {
e.preventDefault();
// setEditable(false);
if (!isAdd) {
setIsLoader(true);
let folderPtr;
if (i) {
setFolderList([]);
let list = tabList.filter((itm, j) => {
if (j <= i) {
return itm;
}
});
let _len = list.length - 1;
folderPtr = {
__type: "Pointer",
className: folderCls,
objectId: list[_len].objectId
};
setTabList(list);
} else {
setClickFolder({});
setSelectedFolder({});
setFolderList([]);
setTabList([]);
}
fetchFolder(folderPtr);
}
};
const handleCreate = () => {
setIsAdd(!isAdd);
};
const handleAddFolder = () => {
setFolderList([]);
if (clickFolder && clickFolder.ObjectId) {
fetchFolder({
__type: "Pointer",
className: folderCls,
objectId: clickFolder.ObjectId
});
} else {
fetchFolder();
}
handleCreate();
};
return (
<div className="text-xs mt-2 ">
<div>
<label className="block">
Select Folder
{required && <span className="text-red-500 text-[13px]">*</span>}
</label>
</div>
<div className="rounded px-[20px] py-[20px] bg-white border border-gray-200 shadow flex max-w-sm gap-8 items-center">
<div>
<i
className="far fa-folder-open text-[40px] text-[#33bbff]"
style={{ fontSize: "40px" }}
aria-hidden="true"
></i>
</div>
<div className="font-semibold ">
<div className="flex items-center gap-2">
<p>
{selectFolder && selectFolder.Name ? selectFolder.Name : "Root"}
</p>
<div className="text-black text-sm" onClick={() => SetIsOpen(true)}>
<i
className="fa fa-pencil"
title="Select Folder"
aria-hidden="true"
></i>
</div>
</div>
<p className="text-[10px] text-gray-400">
{selectFolder && selectFolder.Name ? `(${folderPath})` : ""}
</p>
</div>
</div>
<ModalUi
title={"Select Folder"}
isOpen={isOpen}
handleClose={handleCancel}
>
<div className="w-full min-w-[300px] md:min-w-[500px] px-3">
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
<span
className="cursor-pointer"
title="Root"
onClick={(e) => removeTabListItem(e)}
>
Root /{" "}
</span>
{tabList &&
tabList.map((tab, i) => (
<React.Fragment key={`${tab.objectId}-${i}`}>
<span
className="cursor-pointer"
title={tab.Name}
onClick={(e) => removeTabListItem(e, i)}
>
{tab.Name}
</span>
{" / "}
</React.Fragment>
))}
<hr />
</div>
<div className="mt-2 mb-3">
{!isAdd &&
folderList.length > 0 &&
folderList.map((folder) => (
<div
key={folder.Name}
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer"
onClick={() => handleSelect(folder)}
>
<div className="flex items-center gap-2">
<i
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
aria-hidden="true"
></i>
<span className="font-semibold">{folder.Name}</span>
</div>
</div>
))}
{isAdd && (
<CreateFolder
parentFolderId={clickFolder && clickFolder.ObjectId}
folderCls={folderCls}
onSuccess={handleAddFolder}
/>
)}
{isLoader && (
<div className="flex justify-center">
<i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i>
</div>
)}
</div>
</div>
<hr />
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
<div
className="text-[30px] cursor-pointer text-[#32a3ac]"
title="Save Here"
onClick={handleCreate}
>
{isAdd ? (
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
) : (
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
)}
</div>
<div
className="text-[30px] cursor-pointer"
title="Save Here"
onClick={handleSubmit}
>
<i className="fas fa-save" aria-hidden="true"></i>
</div>
</div>
</ModalUi>
</div>
);
};
export default SelectFolder;
@@ -0,0 +1,189 @@
import React, { useState, useEffect } from "react";
import Select from "react-select";
import AppendFormInForm from "../AppendFormInForm";
import Modal from "react-modal";
import Parse from "parse";
function arrayMove(array, from, to) {
array = array.slice();
array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0]);
return array;
}
/**
* react-sortable-hoc is depcreated not usable from react 18.x.x
* need to replace it with @dnd-kit
* code changes required
*/
const SignersInput = (props) => {
Modal.setAppElement("body");
const [state, setState] = useState(undefined);
// const [editFormData, setEditFormData] = useState([]);
const [selected, setSelected] = React.useState([]);
const [isModal, setIsModel] = useState(false);
const onChange = (selectedOptions) => setSelected(selectedOptions);
const [modalIsOpen, setModalIsOpen] = useState(false);
const onSortEnd = ({ oldIndex, newIndex }) => {
const newValue = arrayMove(selected, oldIndex, newIndex);
setSelected(newValue);
};
const GetSelectListData = async () => {
try {
const currentUser = Parse.User.current();
const contactbook = new Parse.Query("contracts_Contactbook");
contactbook.equalTo(
"CreatedBy",
Parse.User.createWithoutData(currentUser.id)
);
contactbook.notEqualTo("IsDeleted", true);
const contactRes = await contactbook.find();
if (contactRes) {
const res = JSON.parse(JSON.stringify(contactRes));
let list = [];
// let _selected = [];
res.forEach((x) => {
let obj = {
label: x.Name,
value: x.objectId,
isChecked: true
};
list.push(obj);
});
setState(list);
}
} catch (error) {
console.log("err", error);
}
};
useEffect(() => {
GetSelectListData();
}, []);
useEffect(() => {
if (selected && selected.length) {
let newData = [];
selected.forEach((x) => {
newData.push(x.value);
});
if (props.onChange) {
props.onChange(newData);
}
}
// eslint-disable-next-line
}, [selected]);
const handleModalCloseClick = () => {
setIsModel(false);
setModalIsOpen(false);
};
const openModal = () => {
setModalIsOpen(true);
};
// `handleNewDetails` is used to set just save from quick form to selected option in dropdown
const handleNewDetails = (data) => {
setState([...state, data]);
if (selected.length > 0) {
setSelected([...selected, data]);
} else {
setSelected([data]);
}
};
return (
<div className="text-xs mt-2 ">
<label className="block">
Signers
{props.required && <span className="text-red-500 text-[13px]">*</span>}
</label>
<div style={{ display: "flex", gap: 5 }}>
<div style={{ flexWrap: "wrap", width: "100%" }}>
<Select
onSortEnd={onSortEnd}
distance={4}
isMulti
options={state || []}
value={selected}
onChange={onChange}
closeMenuOnSelect={false}
required={props.required}
/>
</div>
<div
onClick={() => {
setIsModel(true);
openModal();
}}
style={{
cursor: "pointer",
borderRadius: 4,
border: "1px solid #ccc",
minHeight: 38,
minWidth: 48,
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
<i className="fas fa-plus"></i>
</div>
<Modal
isOpen={modalIsOpen}
onRequestClose={handleModalCloseClick}
shouldCloseOnOverlayClick={false}
id="modal1"
contentLabel="Modal"
style={{
content: {
top: "50%",
left: "50%",
right: "auto",
bottom: "auto",
transform: "translate(-50%, -50%)",
border: "1px transparent",
padding: 0
},
overlay: {
width: "100%",
backgroundColor: "rgba(0, 0, 0, 0.75)",
zIndex: 50
}
}}
>
<div className="min-w-full md:min-w-[500px]">
<div
className="flex justify-between rounded-t items-center py-[10px] px-[20px] text-white"
style={{ background: "#32a3ac" }}
>
<div className="text-[1.2rem] font-normal">Add Signer</div>
<button
onClick={handleModalCloseClick}
className="text-[1.5rem] cursor-pointer focus:outline-none"
>
&times;
</button>
</div>
{isModal && (
<AppendFormInForm
valueKey={"objectId"}
displayKey={"Name"}
details={handleNewDetails}
closePopup={handleModalCloseClick}
/>
)}
</div>
</Modal>
</div>
</div>
);
};
export default SignersInput;
@@ -1,26 +0,0 @@
import React from "react";
import PropTypes from "prop-types";
function TimeWidget(props) {
const {
onChange,
registry: {
widgets: { BaseInput }
}
} = props;
return (
<BaseInput
type="time"
{...props}
onChange={(value) => onChange(value || undefined)}
/>
);
}
if (process.env.NODE_ENV !== "production") {
TimeWidget.propTypes = {
value: PropTypes.string
};
}
export default TimeWidget;
+3
View File
@@ -0,0 +1,3 @@
export const openInNewTab = (url) => {
window.open(url, "_blank", "noopener,noreferrer");
};
+9
View File
@@ -0,0 +1,9 @@
export const contactCls = "contracts_Contactbook";
export const templateCls = "contracts_Template";
export const documentCls = "contracts_Document";
export const rejectBtn =
"bg-[#ffffff] rounded-sm shadow-md text-[12px] font-semibold uppercase text-black py-1.5 px-4 focus:outline-none text-center border-[1px] border-[#b4b4b4]";
export const submitBtn =
"bg-[#32a3ac] rounded-sm shadow-md text-[12px] font-semibold uppercase text-white py-1.5 px-4 focus:outline-none text-center";
export const modalSubmitBtnColor = "#17a2b8";
export const modalCancelBtnColor = "white";
+11
View File
@@ -5,3 +5,14 @@
body{ body{
background-color: white; background-color: white;
} }
/* Custom CSS to hide scrollbar */
.hide-scrollbar::-webkit-scrollbar {
display: none;
}
.hide-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
+22 -580
View File
@@ -1,584 +1,26 @@
import Parse from "parse"; import { documentCls, templateCls } from "../constant/const";
export const formJson = (id) => { export const formJson = {
let formData;
//json form for signYourself //json form for signYourself
if (id === "sHAnZphf69") { sHAnZphf69: {
formData = { title: "Sign Yourself",
jsonSchema: { redirectRoute: "signaturePdf",
title: "Sign Yourself", msgVar: "Document",
description: "", Cls: documentCls
type: "object", },
required: ["URL", "Name"],
properties: {
URL: {
type: "string",
title: "Select Document",
filetypes: [],
maxfilesizeKB: "10000",
uploadtype: "regular",
helpbody: "",
helplink: ""
},
Name: {
type: "string",
title: "Title",
maxLength: 50
},
Description: {
type: "string",
title: "Description",
maxLength: 500
},
Folder: {
title: "Folder",
parent: null,
data: {
ClassName: "contracts_Document",
FolderNameField: "Name",
FolderTypeField: "Type",
FolderTypeValue: "Folder",
FolderDescription: "Description",
ParentFolderField: "Folder",
FormId: "YjIB7W7Xs6",
Query: 'where={"Folder":{"$exists":false},"Type":"Folder"}'
}
},
ExtUserPtr: {
data: {
valueKey: "objectId",
isPointer: true
}
}
}
},
uiSchema: {
URL: {
"ui:field": "FileUpload"
},
Description: {
"ui:widget": "textarea",
"ui:options": {
rows: 2
}
},
Note: {
"ui:widget": "textarea",
"ui:options": {
rows: 2
}
},
Folder: {
"ui:field": "FolderComponent"
},
ExtUserPtr: {
"ui:field": "HiddenField"
}
},
userSchema: {},
rules: null,
noValidate: false,
liveValidate: false,
isRegisterForm: false,
help: { htmlbody: "" },
description: "",
class: "contracts_Document",
buttons: {
add: {
resetText: "Reset",
submitText: "Submit"
},
edit: { submitText: "Update", cancelText: "Cancel" }
},
formACL: {
"#currentUser#": { read: true, write: true },
"*": { read: true, write: true }
},
redirect_id:
"remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/signaturePdf",
success_message: "Success!",
success_redirect: "Microapp",
validFunction:
"ZnVuY3Rpb24gdmFsaWRhdGUoZm9ybURhdGEsIGVycm9ycykgeyBpZiAoZm9ybURhdGEucGFzczEgIT09IGZvcm1EYXRhLnBhc3MyKSB7IGVycm9ycy5wYXNzMi5hZGRFcnJvcignUGFzc3dvcmRzIGRvbid0IG1hdGNoJyk7IH0gcmV0dXJuIGVycm9yczsgfQ=="
};
return formData; //json form for request signatures
} "8mZzFxbG1z": {
//json form for request signature title: "Request Signatures",
else if (id === "8mZzFxbG1z") { msgVar: "Document",
const user = Parse.User.current(); redirectRoute: "placeHolderSign",
const userPtr = JSON.stringify({ Cls: documentCls,
__type: "Pointer", signers: true
className: "_User", },
objectId: user.id //json form for template
}); template: {
formData = { title: "New Template",
jsonSchema: { redirectRoute: "template",
title: "New Document", msgVar: "Template",
description: "", Cls: templateCls
type: "object",
required: ["URL", "Name", "Note", "TimeToCompleteDays", "Signers"],
properties: {
URL: {
type: "string",
title: "Select Document",
filetypes: [],
maxfilesizeKB: "5000",
uploadtype: "regular",
helpbody: "",
helplink: ""
},
Name: {
type: "string",
title: "Title",
maxLength: 100
},
Description: {
type: "string",
title: "Description",
maxLength: 500
},
Signers: {
type: "array",
title: "Signers",
isSortable: false,
selectAll: false,
selectedData: null,
data: {
class: "contracts_Contactbook",
displayKey: "Name",
valueKey: "objectId",
query: `where={"CreatedBy":${userPtr},"IsDeleted":{"$ne":true}}&keys=Name`,
isPointer: true,
helpbody: "",
helplink: "",
quickAddFormId: "qUGywSWd8e"
}
},
Note: {
type: "string",
title: "Note",
default: "Please review and sign this document",
maxLength: 500
},
Folder: {
title: "Folder",
data: {
ClassName: "contracts_Document",
FolderNameField: "Name",
FolderTypeField: "Type",
FolderTypeValue: "Folder",
FolderDescription: "Description",
ParentFolderField: "Folder",
FormId: "YjIB7W7Xs6",
Query: 'where={"Folder":{"$exists":false},"Type":"Folder"}'
}
},
TimeToCompleteDays: {
type: "number",
title: "Time To Complete (Days)",
default: 15,
maxLength: 5000
},
ExtUserPtr: {
data: {
valueKey: "objectId",
isPointer: true
}
}
}
},
uiSchema: {
URL: {
"ui:field": "FileUpload"
},
Description: {
"ui:widget": "textarea",
"ui:options": {
rows: 2
}
},
Note: {
"ui:widget": "textarea",
"ui:options": {
rows: 2
}
},
Signers: {
"ui:field": "MultiSelectField"
},
Folder: {
"ui:field": "FolderComponent"
},
TimeToCompleteDays: {
"ui:placeholder": "No. of days",
"ui:widget": "updown"
},
ExtUserPtr: {
"ui:field": "HiddenField"
}
},
userSchema: {},
rules: null,
noValidate: false,
liveValidate: false,
isRegisterForm: false,
help: { htmlbody: "" },
description: "",
class: "contracts_Document",
buttons: {
add: {
resetText: "Reset",
submitText: "Submit"
},
edit: { submitText: "Update", cancelText: "Cancel" }
},
formACL: {
"#currentUser#": { read: true, write: true },
"*": { read: true, write: true }
},
redirect_id:
"remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/placeHolderSign",
success_message: "Success!",
success_redirect: "Microapp",
validFunction:
"ZnVuY3Rpb24gdmFsaWRhdGUoZm9ybURhdGEsIGVycm9ycykgeyBpZiAoZm9ybURhdGEucGFzczEgIT09IGZvcm1EYXRhLnBhc3MyKSB7IGVycm9ycy5wYXNzMi5hZGRFcnJvcignUGFzc3dvcmRzIGRvbid0IG1hdGNoJyk7IH0gcmV0dXJuIGVycm9yczsgfQ=="
};
return formData;
}
//json form for create new folder
else if (id === "YjIB7W7Xs6") {
formData = {
jsonSchema: {
title: "New Folder",
description: "",
type: "object",
required: ["Name"],
properties: {
Name: {
type: "string",
title: "Name",
maxLength: 50
},
Type: {
type: "string",
data: {
valueKey: "Type",
isPointer: false
},
default: "Folder"
},
Folder: {
title: "Parent Folder",
data: {
class: "contracts_Document",
displayKey: "Name",
valueKey: "objectId",
query: 'where={"Type":"Folder"}&keys=Name',
isPointer: true,
savePointerClass: "",
helpbody: "",
helplink: ""
}
}
}
},
uiSchema: {
Type: {
"ui:field": "HiddenField"
},
Folder: {
"ui:field": "Level1Dropdown"
}
},
userSchema: {},
rules: null,
noValidate: false,
liveValidate: false,
isRegisterForm: false,
help: { htmlbody: "" },
description: "",
class: "contracts_Document",
buttons: {
add: {
resetText: "Reset",
submitText: "Submit"
},
edit: { submitText: "Update", cancelText: "Cancel" }
},
formACL: {
"#currentUser#": { read: true, write: true },
"*": { read: true, write: true }
},
redirect_id: "",
success_message: "Success!",
success_redirect: "",
validFunction:
"ZnVuY3Rpb24gdmFsaWRhdGUoZm9ybURhdGEsIGVycm9ycykgeyBpZiAoZm9ybURhdGEucGFzczEgIT09IGZvcm1EYXRhLnBhc3MyKSB7IGVycm9ycy5wYXNzMi5hZGRFcnJvcignUGFzc3dvcmRzIGRvbid0IG1hdGNoJyk7IH0gcmV0dXJuIGVycm9yczsgfQ=="
};
return formData;
}
//json form for add signers
else if (id === "fICciRuUcB") {
formData = {
jsonSchema: {
title: "Add Signer",
description: "",
type: "object",
required: ["Name", "Email", "Phone", "Company"],
properties: {
Name: {
type: "string",
title: "Name",
maxLength: 50
},
Email: {
type: "string",
title: "Email",
maxLength: 50
},
Phone: {
type: "string",
title: "Phone",
maxLength: 50
},
Company: {
type: "string",
title: "Company",
maxLength: 50
},
JobTitle: {
type: "string",
title: "JobTitle",
maxLength: 50
},
IsContactEntry: {
type: "boolean",
data: {
valueKey: "IsContactEntry",
isPointer: false
},
default: true
}
}
},
uiSchema: {
Email: {
"ui:widget": "email"
},
IsContactEntry: {
"ui:field": "HiddenField"
}
},
userSchema: {
email: "$Email",
name: "$Name",
password: "$Phone",
phone: "$Phone",
role: "contracts_User",
username: "$Email"
},
rules: null,
noValidate: false,
liveValidate: false,
isRegisterForm: true,
help: {},
description: "",
class: "contracts_Users",
buttons: {
add: {
resetText: "Reset",
submitText: "Submit"
},
edit: { submitText: "Update", cancelText: "Cancel" }
},
formACL: {
"#currentUser#": { read: true, write: true },
"*": { read: true, write: true }
},
redirect_id: "",
success_message: "Success!",
success_redirect: "",
validFunction:
"ZnVuY3Rpb24gdmFsaWRhdGUoZm9ybURhdGEsIGVycm9ycykgeyBpZiAoZm9ybURhdGEucGFzczEgIT09IGZvcm1EYXRhLnBhc3MyKSB7IGVycm9ycy5wYXNzMi5hZGRFcnJvcignUGFzc3dvcmRzIGRvbid0IG1hdGNoJyk7IH0gcmV0dXJuIGVycm9yczsgfQ=="
};
return formData;
}
//json form for add users
else if (id === "lM0xRnM3iE") {
formData = {
jsonSchema: {
title: "Add User",
description: "",
type: "object",
required: ["Name", "Email", "Phone", "JobTitle"],
properties: {
Name: {
type: "string",
title: "Name",
maxLength: 50
},
Email: {
type: "string",
title: "Email",
maxLength: 50
},
Phone: {
type: "string",
title: "Phone",
maxLength: 50
},
JobTitle: {
type: "string",
title: "Job Title",
maxLength: 50
},
Company: {
type: "string",
title: "Company",
maxLength: 50
}
}
},
uiSchema: {
Email: {
"ui:widget": "email"
},
Phone: {
"ui:options": {
inputType: "tel"
}
}
},
userSchema: {
email: "$Email",
name: "$Name",
password: "$Phone",
phone: "$Phone",
role: "contracts_User",
username: "$Email"
},
rules: null,
noValidate: false,
liveValidate: false,
isRegisterForm: true,
help: {},
description: "",
class: "contracts_Users",
buttons: {
add: {
resetText: "Reset",
submitText: "Submit"
},
edit: { submitText: "Update", cancelText: "Cancel" }
},
formACL: {
"#currentUser#": { read: true, write: true },
"*": { read: true, write: true }
},
redirect_id: "",
success_message: "Success!",
success_redirect: "",
validFunction:
"ZnVuY3Rpb24gdmFsaWRhdGUoZm9ybURhdGEsIGVycm9ycykgeyBpZiAoZm9ybURhdGEucGFzczEgIT09IGZvcm1EYXRhLnBhc3MyKSB7IGVycm9ycy5wYXNzMi5hZGRFcnJvcignUGFzc3dvcmRzIGRvbid0IG1hdGNoJyk7IH0gcmV0dXJuIGVycm9yczsgfQ=="
};
return formData;
} else if (id === "qUGywSWd8e") {
formData = {
jsonSchema: {
title: "Add Contact",
description: "",
type: "object",
required: ["Name", "Email", "Phone"],
properties: {
Name: {
type: "string",
title: "Name",
maxLength: 50
},
Email: {
type: "string",
title: "Email",
maxLength: 50
},
Phone: {
type: "string",
title: "Phone",
maxLength: 50
}
}
},
uiSchema: {
Email: {
"ui:widget": "email"
},
Phone: {
"ui:options": {
inputType: "tel"
}
}
},
userSchema: {
name: "$Name",
username: "$Email",
email: "$Email",
password: "$Phone",
phone: "$Phone",
role: "contracts_Guest"
},
restrict_form_entry: {
enable_captcha: false,
allow_one_entry_per_ip_address: false,
allow_one_entry_per_user: false,
enable_geo_fence: false
},
restrict_form_access: {
entryCount: ""
},
help: {},
email_template: {
from: "",
to: "",
subject: "",
message: ""
},
buttons: {
add: {
submitText: "Submit",
resetText: "Reset"
},
edit: {
submitText: "Update",
cancelText: "Cancel"
}
},
appId: {
__type: "Pointer",
className: "w_appinfo",
objectId: "aIPmIvMzGM"
},
formACL: {
"*": {
read: true,
write: true
},
"#currentUser#": {
read: true,
write: true
}
},
class: "contracts_Contactbook",
description: "",
success_message: "Success!",
form_permission: "private",
success_redirect: "",
redirect_id: "",
isRegisterForm: true,
liveValidate: false,
noValidate: false,
validFunction:
"ZnVuY3Rpb24gdmFsaWRhdGUoZm9ybURhdGEsIGVycm9ycykgeyBpZiAoZm9ybURhdGEucGFzczEgIT09IGZvcm1EYXRhLnBhc3MyKSB7IGVycm9ycy5wYXNzMi5hZGRFcnJvcignUGFzc3dvcmRzIGRvbid0IG1hdGNoJyk7IH0gcmV0dXJuIGVycm9yczsgfQ=="
};
return formData;
} }
}; };
+32 -5
View File
@@ -1,7 +1,9 @@
export default function reportJson(id) { export default function reportJson(id) {
// console.log("json ", json); // console.log("json ", json);
const head = ["Sr.No", "Name", "Note", "Folder", "File", "Owner", "Signers"]; const head = ["Sr.No", "Title", "Note", "Folder", "File", "Owner", "Signers"];
const contactbook = ["Sr.No", "Name", "Email", "Phone"]; const contactbook = ["Sr.No", "Title", "Email", "Phone"];
const dashboardReportHead = ["Title", "File", "Owner", "Signers"];
switch (id) { switch (id) {
// draft documents report // draft documents report
case "ByHuevtCFY": case "ByHuevtCFY":
@@ -103,7 +105,7 @@ export default function reportJson(id) {
case "d9k3UfYHBc": case "d9k3UfYHBc":
return { return {
reportName: "Recently sent for signatures", reportName: "Recently sent for signatures",
heading: head, heading: dashboardReportHead,
actions: [ actions: [
{ {
btnLabel: "View", btnLabel: "View",
@@ -119,7 +121,7 @@ export default function reportJson(id) {
case "5Go51Q7T8r": case "5Go51Q7T8r":
return { return {
reportName: "Recent signature requests", reportName: "Recent signature requests",
heading: head, heading: dashboardReportHead,
actions: [ actions: [
{ {
btnLabel: "Sign", btnLabel: "Sign",
@@ -135,7 +137,7 @@ export default function reportJson(id) {
case "kC5mfynCi4": case "kC5mfynCi4":
return { return {
reportName: "Drafts", reportName: "Drafts",
heading: head, heading: ["Title", "Note", "Folder", "File", "Owner", "Signers"],
actions: [ actions: [
{ {
btnLabel: "sign", btnLabel: "sign",
@@ -159,6 +161,31 @@ export default function reportJson(id) {
textColor: "white", textColor: "white",
btnIcon: "fa-solid fa-trash" btnIcon: "fa-solid fa-trash"
} }
],
form: "ContactBook"
};
// template report
case "6TeaPr321t":
return {
reportName: "Templates",
heading: head,
actions: [
{
btnLabel: "Use",
btnColor: "#4bd396",
textColor: "white",
btnIcon: "fa fa-plus",
redirectUrl:
"remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/placeHolderSign"
},
{
btnLabel: "Edit",
btnColor: "#00c9d5",
textColor: "white",
btnIcon: "fa fa-plus",
redirectUrl:
"remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/template"
}
] ]
}; };
default: default:
+2 -2
View File
@@ -27,13 +27,13 @@
"planName": "THANKS PLAN", "planName": "THANKS PLAN",
"currency": "$", "currency": "$",
"price": "29.99", "price": "29.99",
"subtitle": "Use code 'FREEBETA' to get this for free(First 1000 users)", "subtitle": "Use code <span style='background-color: yellow;'>'FREEBETA'</span> to get this for free(First 1000 users)",
"btnText": "Subscribe", "btnText": "Subscribe",
"url": "https://subscriptions.zoho.in/subscribe/ef798486e6a0a11ea65f2bae8f2af901dbadf3175d495584fd25b9af5d2f2b9e/thanks", "url": "https://subscriptions.zoho.in/subscribe/ef798486e6a0a11ea65f2bae8f2af901dbadf3175d495584fd25b9af5d2f2b9e/thanks",
"target": "_self", "target": "_self",
"benefits": [ "benefits": [
"Sign Unlimited Documents", "Sign Unlimited Documents",
"Unlimited Secure Doc Storage with OpenSignDrive", "Unlimited Secure Doc Storage with OpenSignDrive",
"Unlimited Guest Signers", "Unlimited Guest Signers",
"Unlimited completion certificates", "Unlimited completion certificates",
"Unique Code(OTP) verification for guest signers", "Unique Code(OTP) verification for guest signers",
+97 -24
View File
@@ -7,10 +7,37 @@ import Tour from "reactour";
import axios from "axios"; import axios from "axios";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import Parse from "parse"; import Parse from "parse";
const HomeLayout = ({ children }) => { import ModalUi from "../primitives/ModalUi";
import { useNavigate, useLocation, Outlet } from "react-router-dom";
const HomeLayout = () => {
const navigate = useNavigate();
const location = useLocation();
const { width } = useWindowSize(); const { width } = useWindowSize();
const [isOpen, setIsOpen] = useState(true); const [isOpen, setIsOpen] = useState(true);
const arr = useSelector((state) => state.TourSteps); const arr = useSelector((state) => state.TourSteps);
const [isUserValid, setIsUserValid] = useState(true);
const [isLoader, setIsLoader] = useState(true);
useEffect(() => {
(async () => {
try {
// Use the session token to validate the user
const userQuery = new Parse.Query(Parse.User);
const user = await userQuery.get(Parse.User.current().id, {
sessionToken: localStorage.getItem("accesstoken")
});
if (user) {
setIsUserValid(true);
setIsLoader(false);
} else {
setIsUserValid(false);
}
} catch (error) {
// Session token is invalid or there was an error
setIsUserValid(false);
}
})();
}, []);
// reactour state // reactour state
const [isCloseBtn, setIsCloseBtn] = useState(true); const [isCloseBtn, setIsCloseBtn] = useState(true);
@@ -19,7 +46,7 @@ const HomeLayout = ({ children }) => {
const [tourConfigs, setTourConfigs] = useState([]); const [tourConfigs, setTourConfigs] = useState([]);
const showSidebar = () => { const showSidebar = () => {
setIsOpen(value => !value); setIsOpen((value) => !value);
}; };
useEffect(() => { useEffect(() => {
if (width && width <= 768) { if (width && width <= 768) {
@@ -28,9 +55,7 @@ const HomeLayout = ({ children }) => {
}, [width]); }, [width]);
useEffect(() => { useEffect(() => {
if (localStorage.getItem("domain") === "sign" && arr && arr.length > 0) { if (
handleDynamicSteps();
} else if (
localStorage.getItem("domain") === "contracts" && localStorage.getItem("domain") === "contracts" &&
arr && arr &&
arr.length > 0 arr.length > 0
@@ -153,32 +178,80 @@ const HomeLayout = ({ children }) => {
setIsOpen(false); setIsOpen(false);
} }
}; };
const handleLoginBtn = () => {
try {
Parse.User.logOut();
} catch (err) {
console.log("err ", err);
} finally {
localStorage.removeItem("accesstoken");
navigate("/", { replace: true, state: { from: location } });
}
};
return ( return (
<div> <div>
<div className="sticky top-0 z-50"> <div className="sticky top-0 z-50">
<Header showSidebar={showSidebar} /> <Header showSidebar={showSidebar} />
</div> </div>
<div className="flex md:flex-row flex-col z-50"> {isUserValid ? (
<Sidebar isOpen={isOpen} closeSidebar={closeSidebar} /> <>
{isLoader ? (
<div
style={{
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
</div>
) : (
<>
<div className="flex md:flex-row flex-col z-50">
<Sidebar isOpen={isOpen} closeSidebar={closeSidebar} />
<div className="relative h-screen flex flex-col justify-between w-full overflow-y-auto"> <div className="relative h-screen flex flex-col justify-between w-full overflow-y-auto">
<div className="bg-[#eef1f5] p-3">{children}</div> <div className="bg-[#eef1f5] p-3">{<Outlet />}</div>
<div className="z-30"> <div className="z-30">
<Footer /> <Footer />
</div>
</div>
</div>
<Tour
onRequestClose={closeTour}
steps={tourConfigs}
isOpen={isTour}
closeWithMask={false}
disableKeyboardNavigation={["esc"]}
// disableInteraction={true}
scrollOffset={-100}
rounded={5}
showCloseButton={isCloseBtn}
/>
</>
)}
</>
) : (
<ModalUi title={"Session Expired"} isOpen={true} showClose={false}>
<div className="flex flex-col justify-center items-center py-4 md:py-5 gap-5">
<p className="text-xl font-normal">Your session has expired.</p>
<button
onClick={handleLoginBtn}
className="text-base px-3 py-1.5 rounded shadow-md text-white bg-[#1ab6ce]"
>
Login
</button>
</div> </div>
</div> </ModalUi>
</div> )}
<Tour
onRequestClose={closeTour}
steps={tourConfigs}
isOpen={isTour}
closeWithMask={false}
disableKeyboardNavigation={["esc"]}
// disableInteraction={true}
scrollOffset={-100}
rounded={5}
showCloseButton={isCloseBtn}
/>
</div> </div>
); );
}; };
+30
View File
@@ -0,0 +1,30 @@
import React from "react";
const Alert = ({ children, type }) => {
const textcolor = type ? theme(type) : theme();
function theme(color) {
switch (color) {
case "success":
return "border-[#c3e6cb] bg-[#d4edda] text-[#155724]";
case "info":
return "border-[#adcdeb] bg-[#c1daf0] text-[#153756]";
case "danger":
return "border-[#f0a8a8] bg-[#f4bebe] text-[#c42121]";
default:
return "border-[#d6d6d6] bg-[#d9d9d9] text-[#575757]";
}
}
return (
<>
{children && (
<div
className={`z-40 fixed top-20 left-1/2 transform -translate-x-1/2 border-[1px] text-sm ${textcolor} rounded py-[.75rem] px-[1.25rem] `}
>
{children}
</div>
)}
</>
);
};
export default Alert;
+261 -44
View File
@@ -3,6 +3,9 @@ import pad from "../assets/images/pad.svg";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import axios from "axios"; import axios from "axios";
import "../styles/report.css"; import "../styles/report.css";
import ModalUi from "./ModalUi";
import AppendFormInForm from "../components/AppendFormInForm";
import { modalSubmitBtnColor, modalCancelBtnColor } from "../constant/const";
const ReportTable = ({ const ReportTable = ({
ReportName, ReportName,
List, List,
@@ -11,13 +14,19 @@ const ReportTable = ({
heading, heading,
setIsNextRecord, setIsNextRecord,
isMoreDocs, isMoreDocs,
docPerPage docPerPage,
form
}) => { }) => {
const navigate = useNavigate(); const navigate = useNavigate();
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [actLoader, setActLoader] = useState({}); const [actLoader, setActLoader] = useState({});
const [isAlert, setIsAlert] = useState(false); const [isAlert, setIsAlert] = useState(false);
const [isErr, setIsErr] = useState(false); const [isErr, setIsErr] = useState(false);
const [isDocErr, setIsDocErr] = useState(false);
const [isContactform, setIsContactform] = useState(false);
const [isDeleteModal, setIsDeleteModal] = useState({});
const startIndex = (currentPage - 1) * docPerPage;
// For loop is used to calculate page numbers visible below table // For loop is used to calculate page numbers visible below table
// Initialize pageNumbers using useMemo to avoid unnecessary re-creation // Initialize pageNumbers using useMemo to avoid unnecessary re-creation
const pageNumbers = useMemo(() => { const pageNumbers = useMemo(() => {
@@ -55,39 +64,128 @@ const ReportTable = ({
}, [isMoreDocs, pageNumbers, currentPage, setIsNextRecord]); }, [isMoreDocs, pageNumbers, currentPage, setIsNextRecord]);
// `handlemicroapp` is used to open microapp // `handlemicroapp` is used to open microapp
const handlemicroapp = (item, url) => { const handlemicroapp = async (item, url, btnLabel) => {
localStorage.removeItem("rowlevel"); if (ReportName === "Templates") {
navigate("/rpmf/" + url); if (btnLabel === "Edit") {
localStorage.setItem("rowlevel", JSON.stringify(item)); navigate(`/asmf/${url}/${item.objectId}`);
} else {
setActLoader({ [`${item.objectId}_${btnLabel}`]: true });
try {
const params = {
templateId: item.objectId
};
const templateDeatils = await axios.post(
`${localStorage.getItem("baseUrl")}functions/getTemplate`,
params,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessionToken: localStorage.getItem("accesstoken")
}
}
);
// console.log("templateDeatils.data ", templateDeatils.data);
const templateData =
templateDeatils.data && templateDeatils.data.result;
if (!templateData.error) {
const Doc = templateData;
let signers = [];
if (Doc.Signers?.length > 0) {
Doc.Signers?.forEach((x) => {
if (x.objectId) {
const obj = {
__type: "Pointer",
className: "contracts_Contactbook",
objectId: x.objectId
};
signers.push(obj);
}
});
}
let placeholdersArr = [];
if (Doc.Placeholders?.length > 0) {
placeholdersArr = Doc.Placeholders;
const data = {
Name: Doc.Name,
URL: Doc.URL,
SignedUrl: Doc.SignedUrl,
Description: Doc.Description,
Note: Doc.Note,
Placeholders: placeholdersArr,
ExtUserPtr: {
__type: "Pointer",
className: "contracts_Users",
objectId: Doc.ExtUserPtr.objectId
},
CreatedBy: {
__type: "Pointer",
className: "_User",
objectId: Doc.CreatedBy.objectId
},
Signers: signers
};
try {
const res = await axios.post(
`${localStorage.getItem(
"baseUrl"
)}classes/${localStorage.getItem("_appName")}_Document`,
data,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id":
localStorage.getItem("parseAppId"),
"X-Parse-Session-Token":
localStorage.getItem("accesstoken")
}
}
);
// console.log("Res ", res.data);
if (res.data && res.data.objectId) {
setActLoader({});
setIsAlert(true);
navigate(`/asmf/${url}/${res.data.objectId}`, {
state: { title: "Use Template" }
});
}
} catch (err) {
console.log("Err", err);
setIsAlert(true);
setIsErr(true);
setActLoader({});
}
} else {
setIsDocErr(true);
setActLoader({});
}
} else {
setIsAlert(true);
setIsErr(true);
setActLoader({});
}
} catch (err) {
console.log("err", err);
setIsAlert(true);
setIsErr(true);
setActLoader({});
}
}
} else {
localStorage.removeItem("rowlevel");
navigate("/rpmf/" + url);
localStorage.setItem("rowlevel", JSON.stringify(item));
}
// localStorage.setItem("rowlevelMicro"); // localStorage.setItem("rowlevelMicro");
}; };
const handlebtn = async (item) => { const handlebtn = async (item) => {
if (ReportName === "Contactbook") { if (ReportName === "Contactbook") {
setActLoader({ [item.objectId]: true }); setIsDeleteModal({ [item.objectId]: true });
try {
const url =
process.env.REACT_APP_SERVERURL + "/classes/contracts_Contactbook/";
const body = { IsDeleted: true };
const res = await axios.put(url + item.objectId, body, {
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("AppID12"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
});
// console.log("Res ", res.data);
if (res.data && res.data.updatedAt) {
setActLoader({});
setIsAlert(true);
const upldatedList = List.filter((x) => x.objectId !== item.objectId);
setList(upldatedList);
}
} catch (err) {
console.log("err", err);
setIsAlert(true);
setIsErr(true);
setActLoader({});
}
} }
}; };
@@ -101,6 +199,44 @@ const ReportTable = ({
const paginateFront = () => setCurrentPage(currentPage + 1); const paginateFront = () => setCurrentPage(currentPage + 1);
const paginateBack = () => setCurrentPage(currentPage - 1); const paginateBack = () => setCurrentPage(currentPage - 1);
const handleContactFormModal = () => {
setIsContactform(!isContactform);
};
const handleUserData = (data) => {
setList((prevData) => [data, ...prevData]);
};
const handleDelete = async (item) => {
setIsDeleteModal({});
setActLoader({ [item.objectId]: true });
try {
const url =
process.env.REACT_APP_SERVERURL + "/classes/contracts_Contactbook/";
const body = { IsDeleted: true };
const res = await axios.put(url + item.objectId, body, {
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("AppID12"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
});
// console.log("Res ", res.data);
if (res.data && res.data.updatedAt) {
setActLoader({});
setIsAlert(true);
const upldatedList = List.filter((x) => x.objectId !== item.objectId);
setList(upldatedList);
}
} catch (err) {
console.log("err", err);
setIsAlert(true);
setIsErr(true);
setActLoader({});
}
};
const handleCloseDeleteModal = () => setIsDeleteModal({});
return ( return (
<div className="p-2 overflow-x-scroll w-full bg-white rounded-md"> <div className="p-2 overflow-x-scroll w-full bg-white rounded-md">
{isAlert && ( {isAlert && (
@@ -115,7 +251,23 @@ const ReportTable = ({
</div> </div>
)} )}
<h2 className="text-[23px] font-light my-2">{ReportName}</h2> <div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
<div className="font-light">{ReportName}</div>
{ReportName === "Templates" && (
<i
onClick={() => navigate("/form/template")}
className="fa-solid fa-square-plus text-sky-400 text-[25px]"
></i>
)}
{form && (
<div
className="cursor-pointer"
onClick={() => handleContactFormModal()}
>
<i className="fa-solid fa-square-plus text-sky-400 text-[25px]"></i>
</div>
)}
</div>
<table className="table-auto w-full border-collapse"> <table className="table-auto w-full border-collapse">
<thead className="text-[14px]"> <thead className="text-[14px]">
<tr className="border-y-[1px]"> <tr className="border-y-[1px]">
@@ -135,11 +287,13 @@ const ReportTable = ({
{currentLists.map((item, index) => {currentLists.map((item, index) =>
ReportName === "Contactbook" ? ( ReportName === "Contactbook" ? (
<tr className="border-y-[1px]" key={index}> <tr className="border-y-[1px]" key={index}>
<td className="px-4 py-2">{index + 1}</td> {heading.includes("Sr.No") && (
<td className="px-4 py-2">{startIndex + index + 1}</td>
)}
<td className="px-4 py-2 font-semibold">{item?.Name} </td> <td className="px-4 py-2 font-semibold">{item?.Name} </td>
<td className="px-4 py-2">{item?.Email || "-"}</td> <td className="px-4 py-2">{item?.Email || "-"}</td>
<td className="px-4 py-2">{item?.Phone || "-"}</td> <td className="px-4 py-2">{item?.Phone || "-"}</td>
<td className="px-4 py-2 flex flex-col justify-center items-center gap-2 text-white"> <td className="px-3 py-2 text-white">
{actions?.length > 0 && {actions?.length > 0 &&
actions.map((act, index) => ( actions.map((act, index) => (
<button <button
@@ -149,7 +303,7 @@ const ReportTable = ({
? handlemicroapp(item, act.redirectUrl) ? handlemicroapp(item, act.redirectUrl)
: handlebtn(item) : handlebtn(item)
} }
className={`flex justify-center items-center gap-1 px-2 py-1 rounded shadow`} className={`mb-1 flex justify-center items-center gap-1 px-2 py-1 rounded shadow`}
style={{ style={{
backgroundColor: act.btnColor backgroundColor: act.btnColor
? act.btnColor ? act.btnColor
@@ -175,16 +329,54 @@ const ReportTable = ({
)} )}
</button> </button>
))} ))}
{isDeleteModal[item.objectId] && (
<ModalUi
isOpen
title={"Delete Contact"}
handleClose={handleCloseDeleteModal}
>
<div className="m-[20px]">
<div className="text-lg font-normal text-black">
Are you sure you want to delete this contact?
</div>
<hr className="bg-[#ccc] mt-4 " />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={() => handleDelete(item)}
className="px-4 py-1.5 text-white rounded shadow-md text-center focus:outline-none "
style={{ backgroundColor: modalSubmitBtnColor }}
>
Yes
</button>
<button
onClick={handleCloseDeleteModal}
className="px-4 py-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none"
style={{ backgroundColor: modalCancelBtnColor }}
>
No
</button>
</div>
</div>
</ModalUi>
)}
</td> </td>
</tr> </tr>
) : ( ) : (
<tr className="border-y-[1px]" key={index}> <tr className="border-y-[1px]" key={index}>
<td className="px-4 py-2">{index + 1}</td> {heading.includes("Sr.No") && (
<td className="px-4 py-2 font-semibold">{item?.Name} </td> <td className="px-4 py-2">{startIndex + index + 1}</td>
<td className="px-4 py-2">{item?.Note || "-"}</td> )}
<td className="px-4 py-2"> <td className="px-4 py-2 font-semibold w-56">
{item?.Folder?.Name || "OpenSignDrive"} {item?.Name}{" "}
</td> </td>
{heading.includes("Note") && (
<td className="px-4 py-2">{item?.Note || "-"}</td>
)}
{heading.includes("Folder") && (
<td className="px-4 py-2">
{item?.Folder?.Name || "OpenSign™ Drive"}
</td>
)}
<td className="px-4 py-2"> <td className="px-4 py-2">
<a <a
target="_blank" target="_blank"
@@ -202,17 +394,21 @@ const ReportTable = ({
<td className="px-4 py-2"> <td className="px-4 py-2">
{item?.Signers ? formatRow(item?.Signers) : "-"} {item?.Signers ? formatRow(item?.Signers) : "-"}
</td> </td>
<td className="px-4 py-2 flex flex-col justify-center items-center gap-2 text-white"> <td className="px-3 py-2 text-white">
{actions?.length > 0 && {actions?.length > 0 &&
actions.map((act, index) => ( actions.map((act, index) => (
<button <button
key={index} key={index}
onClick={() => onClick={() =>
act?.redirectUrl act?.redirectUrl
? handlemicroapp(item, act.redirectUrl) ? handlemicroapp(
item,
act.redirectUrl,
act.btnLabel
)
: handlebtn(item) : handlebtn(item)
} }
className={`flex justify-center items-center w-full gap-1 px-2 py-1 rounded shadow`} className={`mb-1 flex justify-center items-center gap-1 px-2 py-1 rounded shadow`}
style={{ style={{
backgroundColor: act.btnColor backgroundColor: act.btnColor
? act.btnColor ? act.btnColor
@@ -224,7 +420,9 @@ const ReportTable = ({
{act?.btnIcon && ( {act?.btnIcon && (
<i <i
className={ className={
actLoader[item.objectId] actLoader[
`${item.objectId}_${act.btnLabel}`
]
? "fa-solid fa-spinner fa-spin-pulse" ? "fa-solid fa-spinner fa-spin-pulse"
: act.btnIcon : act.btnIcon
} }
@@ -235,7 +433,6 @@ const ReportTable = ({
{act?.btnLabel ? act.btnLabel : "view"} {act?.btnLabel ? act.btnLabel : "view"}
</span> </span>
</button> </button>
// )
))} ))}
</td> </td>
</tr> </tr>
@@ -293,6 +490,26 @@ const ReportTable = ({
<div className="text-sm font-semibold">No Data Available</div> <div className="text-sm font-semibold">No Data Available</div>
</div> </div>
)} )}
<ModalUi
title={"Add Contact"}
isOpen={isContactform}
handleClose={handleContactFormModal}
>
<AppendFormInForm
handleUserData={handleUserData}
closePopup={handleContactFormModal}
/>
</ModalUi>
<ModalUi
headColor={"#dc3545"}
isOpen={isDocErr}
title={"Receipent required"}
handleClose={() => setIsDocErr(false)}
>
<div style={{ height: "100%", padding: 20 }}>
<p>Please add receipent in template!</p>
</div>
</ModalUi>
</div> </div>
); );
}; };
+28
View File
@@ -0,0 +1,28 @@
import React, { useState } from "react";
const Modal = ({ children, Title }) => {
const [isOpen, SetIsOpen] = useState(false);
return (
<>
{children && (
<div
className={`fixed top-20 left-1/2 transform -translate-x-1/2 border-[1px] text-sm bg-white rounded `}
>
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem] ">
<div className="font-semibold text-xl text-black">{Title}</div>
<div
onClick={() => SetIsOpen()}
className="px-2 py-1 bg-gray-400 rounded cursor-pointer"
>
<i className="fa-solid fa-xmark"></i>
</div>
</div>
<hr />
{isOpen && <div>{children}</div>}
</div>
)}
</>
);
};
export default Modal;
+40
View File
@@ -0,0 +1,40 @@
import React from "react";
const ModalUi = ({
children,
title,
isOpen,
headColor,
handleClose,
showHeader = true,
showClose = true
}) => {
return (
<>
{isOpen && (
<div className="fixed z-[999] top-0 left-0 w-[100%] h-[100%] bg-black bg-opacity-[75%]">
<div className="fixed z-[1000] top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-sm bg-white rounded shadow-md max-h-90 min-w-[90%] md:min-w-[500px] overflow-y-auto hide-scrollbar">
{showHeader && (
<div
className="flex justify-between rounded-t items-center py-[15px] px-[20px] text-white"
style={{ background: headColor ? headColor : "#32a3ac" }}
>
<div className="text-[1.2rem] font-normal">{title}</div>
{showClose && (
<div
className="text-[1.5rem] cursor-pointer"
onClick={() => handleClose && handleClose()}
>
&times;
</div>
)}
</div>
)}
<div>{children}</div>
</div>
</div>
)}
</>
);
};
export default ModalUi;
+57
View File
@@ -0,0 +1,57 @@
import React, { useState, useEffect } from "react";
import Parse from "parse";
import { Outlet, useNavigate, useLocation } from "react-router-dom";
import ModalUi from "./ModalUi";
const Validate = () => {
const navigate = useNavigate();
const location = useLocation();
const [isUserValid, setIsUserValid] = useState(true);
useEffect(() => {
(async () => {
try {
// Use the session token to validate the user
const userQuery = new Parse.Query(Parse.User);
const user = await userQuery.get(Parse.User.current().id, {
sessionToken: localStorage.getItem("accesstoken")
});
if (user) {
setIsUserValid(true);
} else {
setIsUserValid(false);
}
} catch (error) {
// Session token is invalid or there was an error
setIsUserValid(false);
}
})();
}, []);
const handleLoginBtn = () => {
try {
Parse.User.logOut();
} catch (err) {
console.log("err ", err);
} finally {
localStorage.removeItem("accesstoken");
navigate("/", { replace: true, state: { from: location } });
}
};
return isUserValid ? (
<div>
<Outlet />
</div>
) : (
<ModalUi title={"Session Expired"} isOpen={true} showClose={false}>
<div className="flex flex-col justify-center items-center py-4 md:py-5 gap-5">
<p className="text-xl font-normal">Your session has expired.</p>
<button
onClick={handleLoginBtn}
className="text-base px-3 py-1.5 rounded shadow-md text-white bg-[#1ab6ce]"
>
Login
</button>
</div>
</ModalUi>
);
};
export default Validate;
@@ -0,0 +1,34 @@
import React, { useEffect } from "react";
import Parse from "parse";
import { Outlet } from "react-router-dom";
const ValidateRoute = () => {
useEffect(() => {
(async () => {
try {
// Use the session token to validate the user
const userQuery = new Parse.Query(Parse.User);
const user = await userQuery.get(Parse.User.current().id, {
sessionToken: localStorage.getItem("accesstoken")
});
if (!user) {
handlelogout();
}
} catch (error) {
handlelogout();
}
})();
}, []);
const handlelogout = async () => {
try {
Parse.User.logOut();
localStorage.removeItem("accesstoken");
} catch (err) {
console.log("err ", err);
} finally {
localStorage.removeItem("accesstoken");
}
};
return <div>{<Outlet />}</div>;
};
export default ValidateRoute;
@@ -1,5 +1,7 @@
function sanitizeFileName(fileName) { function sanitizeFileName(fileName) {
// Remove spaces and invalid characters // Remove spaces and invalid characters
return fileName.replace(/[^a-zA-Z0-9._-]/g, ""); const file = fileName.replace(/[^a-zA-Z0-9._-]/g, "");
const removedot = file.replace(/\.(?=.*\.)/g, "");
return removedot.replace(/[^a-zA-Z0-9._-]/g, "");
} }
export default sanitizeFileName; export default sanitizeFileName;
+1 -87
View File
@@ -124,8 +124,7 @@ export const login = (username, password) => async (dispatch) => {
const currentUser = Parse.User.current(); const currentUser = Parse.User.current();
await Parse.Cloud.run("getUserDetails", { await Parse.Cloud.run("getUserDetails", {
email: currentUser.get("email") email: currentUser.get("email")
}) }).then(
.then(
(results) => { (results) => {
let userinfo = results.toJSON(); let userinfo = results.toJSON();
if (userinfo.TenantId) { if (userinfo.TenantId) {
@@ -215,95 +214,10 @@ export const fetchRoleEnum = (name) => async (dispatch) => {
dispatch({ type: "FETCH_ROLE", payload: response }); dispatch({ type: "FETCH_ROLE", payload: response });
}; };
export const setEnableCart = (val) => async (dispatch) => {
dispatch({
type: "ENABLE_CART",
payload: val
});
};
export const setCartUpdateData = (val) => async (dispatch) => {
dispatch({
type: "UPDATE_CART",
payload: val
});
};
export const addItemsToCart = (val) => async (dispatch) => {
dispatch({
type: "ADD_CART",
payload: val
});
};
export const clearCartData = () => async (dispatch) => {
dispatch({
type: "CLEAR_CART",
payload: []
});
};
export const SaveMultipleCart = (val) => async (dispatch) => {
dispatch({
type: "MULTI_CART",
payload: val
});
};
export const removeFromCart = (val) => async (dispatch) => {
dispatch({
type: "REMOVE_CART",
payload: val
});
};
export const onChangeLevel1Dropdown = (id, name) => async (dispatch) => {
localStorage.setItem(`_dd${name}`, id);
let _data = { [name]: `${id}` };
dispatch({ type: "Level1_Dropdown", payload: _data });
};
export const onChangeLevel2Dropdown = (id, name) => async (dispatch) => {
localStorage.setItem(`_dd${name}`, id);
let _data = { [name]: `${id}` };
dispatch({ type: "Level2_Dropdown", payload: _data });
};
export const onChangeLevel3Dropdown = (id, name) => async (dispatch) => {
localStorage.setItem(`_dd${name}`, id);
let _data = { [name]: `${id}` };
dispatch({ type: "Level3_Dropdown", payload: _data });
};
export const removeState = () => async (dispatch) => {
dispatch({ type: "REMOVE_STATE", payload: {} });
};
export const removeLevel2State = () => async (dispatch) => {
dispatch({ type: "removeLevel2", payload: {} });
};
export const removeLevel3State = () => async (dispatch) => {
dispatch({ type: "removeLevel3", payload: {} });
};
export const showTenantName = (name) => async (dispatch) => { export const showTenantName = (name) => async (dispatch) => {
dispatch({ type: "SHOW_TENANT", payload: name || null }); dispatch({ type: "SHOW_TENANT", payload: name || null });
}; };
export const saveDependantDDValue = (id, value) => async (dispatch) => {
let _data = { [`${id}_dd`]: value };
dispatch({ type: "SAVE_DEPENDANTDD", payload: _data });
};
export const removeDependantDDValue = (id, value) => async (dispatch) => {
let _data = { [`${id}_dd`]: value };
dispatch({ type: "REMOVE_DEPENDANTDD", payload: _data });
};
export const remove_AlldependantDD = () => async (dispatch) => {
dispatch({ type: "REMOVE_ALLDEPENDANTDD", payload: {} });
};
export const save_tourSteps = (steps) => async (dispatch) => { export const save_tourSteps = (steps) => async (dispatch) => {
dispatch({ type: "SAVE_TOURSTEPS", payload: steps }); dispatch({ type: "SAVE_TOURSTEPS", payload: steps });
}; };
+1 -1
View File
@@ -24,7 +24,7 @@ const Dashboard = (props) => {
getDashboard(localStorage.getItem("PageLanding")); getDashboard(localStorage.getItem("PageLanding"));
} }
} else { } else {
navigate("/", { replace: true }); navigate("/", { replace: true, state: { from: location } });
} }
// eslint-disable-next-line // eslint-disable-next-line
}, [id]); }, [id]);
+26 -4
View File
@@ -4,13 +4,15 @@ import { fetchAppInfo, forgetPassword } from "../redux/actions";
import Title from "../components/Title"; import Title from "../components/Title";
import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
import login_img from "../assets/images/login_img.svg"; import login_img from "../assets/images/login_img.svg";
import Parse from "parse";
import Alert from "../primitives/Alert";
function ForgotPassword(props) { function ForgotPassword(props) {
const [state, setState] = useState({ const [state, setState] = useState({
email: "", email: "",
password: "", password: "",
hideNav: "" hideNav: ""
}); });
const [sentStatus, setSentStatus] = useState("");
const handleChange = (event) => { const handleChange = (event) => {
const { name, value } = event.target; const { name, value } = event.target;
setState({ ...state, [name]: value }); setState({ ...state, [name]: value });
@@ -23,7 +25,7 @@ function ForgotPassword(props) {
} }
}; };
const handleSubmit = (event) => { const handleSubmit = async (event) => {
event.preventDefault(); event.preventDefault();
localStorage.setItem("appLogo", props.appInfo.applogo); localStorage.setItem("appLogo", props.appInfo.applogo);
localStorage.setItem("appName", props.appInfo.appname); localStorage.setItem("appName", props.appInfo.appname);
@@ -33,9 +35,21 @@ function ForgotPassword(props) {
"userSettings", "userSettings",
JSON.stringify(props.appInfo.settings) JSON.stringify(props.appInfo.settings)
); );
if (state.email) { if (state.email) {
props.forgetPassword(state.email); const username = state.email;
let baseUrl = localStorage.getItem("BaseUrl12");
let parseAppId = localStorage.getItem("AppID12");
try {
Parse.serverURL = baseUrl;
Parse.initialize(parseAppId);
await Parse.User.requestPasswordReset(username);
setSentStatus("success");
} catch (err) {
console.log("err ", err.code);
setSentStatus("failed");
} finally {
setTimeout(() => setSentStatus(""), 1000);
}
} }
}; };
@@ -51,6 +65,14 @@ function ForgotPassword(props) {
return ( return (
<div className="bg-white"> <div className="bg-white">
<Title title="Forgot password page" /> <Title title="Forgot password page" />
{sentStatus === "success" && (
<Alert type="success">
Reset password link has been sent to your email id
</Alert>
)}
{sentStatus === "failed" && (
<Alert type={"danger"}>Please setup email adapter </Alert>
)}
<div> <div>
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 "> <div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
<div className="w-[250px] h-[66px] inline-block"> <div className="w-[250px] h-[66px] inline-block">
File diff suppressed because it is too large Load Diff
+184
View File
@@ -0,0 +1,184 @@
import React, { useEffect, useState } from "react";
import Title from "../components/Title";
import axios from "axios";
import Alert from "../primitives/Alert";
import ModalUi from "../primitives/ModalUi";
import { rejectBtn, submitBtn } from "../constant/const";
import { openInNewTab } from "../constant/Utils";
function GenerateToken() {
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [apiToken, SetApiToken] = useState("");
const [isLoader, setIsLoader] = useState(true);
const [copied, setCopied] = useState(false);
const [isGenerate, setIsGenerate] = useState(false);
const [isErr, setIsErr] = useState(false);
const [isModal, setIsModal] = useState(false);
useEffect(() => {
fetchToken();
// eslint-disable-next-line
}, []);
const fetchToken = async () => {
try {
const url = parseBaseUrl + "functions/getapitoken";
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessiontoken: localStorage.getItem("accesstoken")
};
const res = await axios.post(url, {}, { headers: headers });
if (res) {
SetApiToken(res.data.result.result);
}
setIsLoader(false);
} catch (err) {
SetApiToken();
setIsLoader(false);
console.log("Err", err);
}
};
const handleSubmit = async (e) => {
e.preventDefault();
setIsLoader(true);
setIsModal(false);
try {
const url = parseBaseUrl + "functions/generateapitoken";
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessiontoken: localStorage.getItem("accesstoken")
};
await axios.post(url, {}, { headers: headers }).then((res) => {
if (res) {
SetApiToken(res.data.result.token);
// localStorage.setItem("apiToken", res.data.result.token);
setIsGenerate(true);
setTimeout(() => {
setIsGenerate(false);
}, 1500);
setIsLoader(false);
} else {
console.error("Error while generating Token");
setIsLoader(false);
setIsErr(true);
setTimeout(() => {
setIsErr(false);
}, 1500);
}
});
} catch (error) {
setIsLoader(false);
setIsErr(true);
setTimeout(() => {
setIsErr(false);
}, 1500);
console.log("err", error);
}
};
const copytoclipboard = (text) => {
navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => {
setCopied(false);
}, 1500); // Reset copied state after 1.5 seconds
};
const handleModal = () => setIsModal(!isModal);
return (
<React.Fragment>
<Title title={"API Token"} />
{isGenerate && (
<Alert type="success">Token generated successfully!</Alert>
)}
{copied && <Alert type="success">Copied</Alert>}
{isErr && <Alert type="danger">Something went wrong!</Alert>}
{isLoader ? (
<div
style={{
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
</div>
) : (
<div className="bg-white flex flex-col justify-center shadow rounded">
<h1 className="ml-4 mt-3 mb-2 font-semibold">API Token</h1>
<ul className="w-full flex flex-col p-2 text-sm">
<li
className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
>
<span className="w-[40%]">Api Token:</span>{" "}
<span
id="token"
className="w-[60%] md:text-end cursor-pointer"
onClick={() => copytoclipboard(apiToken)}
>
{apiToken && apiToken}
</span>
</li>
</ul>
<div className="flex flex-col md:flex-row items-center justify-center gap-2 pb-4">
<button
type="button"
onClick={apiToken ? handleModal : handleSubmit}
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base focus:outline-none"
>
{apiToken ? "Regenerate Token" : "Generate Token"}
</button>
<button
type="button"
onClick={() =>
openInNewTab(
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
)
}
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
>
View Docs
</button>
</div>
<ModalUi
isOpen={isModal}
title={"Regenerate Token"}
handleClose={handleModal}
>
<div className="m-[20px]">
<div className="text-lg font-normal text-black">
Are you sure you want to regenerate token it will expire old
token?
</div>
<hr className="bg-[#ccc] mt-4 " />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={handleSubmit}
className={submitBtn + "ml-[2px]"}
>
Yes
</button>
<button onClick={handleModal} className={rejectBtn}>
No
</button>
</div>
</div>
</ModalUi>
</div>
)}
</React.Fragment>
);
}
export default GenerateToken;
+2 -2
View File
@@ -30,9 +30,9 @@ function RemoteApp({ app }) {
boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.33)", boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.33)",
backgroundColor: "#ffffff", backgroundColor: "#ffffff",
width: "100%", width: "100%",
overflow: "hidden",
borderRadius: 3, borderRadius: 3,
minHeight: "70vh" height: "100%",
minHeight: "100vh"
}} }}
> >
{RemoteComponent && <RemoteComponent />} {RemoteComponent && <RemoteComponent />}
+90 -115
View File
@@ -8,12 +8,15 @@ import axios from "axios";
import Title from "../components/Title"; import Title from "../components/Title";
import GoogleSignInBtn from "../components/LoginGoogle"; import GoogleSignInBtn from "../components/LoginGoogle";
// import LoginFacebook from "../components/LoginFacebook"; // import LoginFacebook from "../components/LoginFacebook";
import { NavLink, useNavigate } from "react-router-dom"; import { NavLink, useNavigate, useLocation } from "react-router-dom";
import login_img from "../assets/images/login_img.svg"; import login_img from "../assets/images/login_img.svg";
import { useWindowSize } from "../hook/useWindowSize"; import { useWindowSize } from "../hook/useWindowSize";
import ModalUi from "../primitives/ModalUi";
import { modalCancelBtnColor, modalSubmitBtnColor } from "../constant/const";
function Login(props) { function Login(props) {
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation();
const { width } = useWindowSize(); const { width } = useWindowSize();
const [state, setState] = useState({ const [state, setState] = useState({
email: "", email: "",
@@ -132,6 +135,9 @@ function Login(props) {
`${localStorage.getItem("_appName")}_appeditor` `${localStorage.getItem("_appName")}_appeditor`
) { ) {
userSettings.forEach(async (element) => { userSettings.forEach(async (element) => {
const redirectUrl =
location?.state?.from ||
`/${element.pageType}/${element.pageId}`;
if (element.role === _currentRole) { if (element.role === _currentRole) {
let _role = _currentRole.replace( let _role = _currentRole.replace(
`${localStorage.getItem("_appName")}_`, `${localStorage.getItem("_appName")}_`,
@@ -260,9 +266,8 @@ function Login(props) {
localStorage.removeItem( localStorage.removeItem(
"userDetails" "userDetails"
); );
navigate( // Redirect to the appropriate URL after successful login
`/${element.pageType}/${element.pageId}` navigate(redirectUrl);
);
} else { } else {
navigate(`/subscription`, { navigate(`/subscription`, {
replace: true replace: true
@@ -274,9 +279,8 @@ function Login(props) {
}); });
} }
} else { } else {
navigate( // Redirect to the appropriate URL after successful login
`/${element.pageType}/${element.pageId}` navigate(redirectUrl);
);
} }
} }
} else { } else {
@@ -313,9 +317,8 @@ function Login(props) {
}); });
} }
} else { } else {
navigate( // Redirect to the appropriate URL after successful login
`/${element.pageType}/${element.pageId}` navigate(redirectUrl);
);
} }
} }
}, },
@@ -462,6 +465,9 @@ function Login(props) {
`${localStorage.getItem("_appName")}_appeditor` `${localStorage.getItem("_appName")}_appeditor`
) { ) {
userSettings.forEach(async (element) => { userSettings.forEach(async (element) => {
const redirectUrl =
location?.state?.from ||
`/${element.pageType}/${element.pageId}`;
if (element.role === _currentRole) { if (element.role === _currentRole) {
let _role = _currentRole.replace( let _role = _currentRole.replace(
`${localStorage.getItem("_appName")}_`, `${localStorage.getItem("_appName")}_`,
@@ -569,9 +575,7 @@ function Login(props) {
if (billingDate) { if (billingDate) {
if (billingDate > new Date()) { if (billingDate > new Date()) {
localStorage.removeItem("userDetails"); localStorage.removeItem("userDetails");
navigate( navigate(redirectUrl);
`/${element.pageType}/${element.pageId}`
);
} else { } else {
navigate(`/subscription`, { navigate(`/subscription`, {
replace: true replace: true
@@ -581,9 +585,7 @@ function Login(props) {
navigate(`/subscription`, { replace: true }); navigate(`/subscription`, { replace: true });
} }
} else { } else {
navigate( navigate(redirectUrl);
`/${element.pageType}/${element.pageId}`
);
} }
} }
} else { } else {
@@ -599,9 +601,8 @@ function Login(props) {
if (billingDate) { if (billingDate) {
if (billingDate > new Date()) { if (billingDate > new Date()) {
localStorage.removeItem("userDetails"); localStorage.removeItem("userDetails");
navigate( // Redirect to the appropriate URL after successful login
`/${element.pageType}/${element.pageId}` navigate(redirectUrl);
);
} else { } else {
navigate(`/subscription`, { replace: true }); navigate(`/subscription`, { replace: true });
} }
@@ -609,9 +610,7 @@ function Login(props) {
navigate(`/subscription`, { replace: true }); navigate(`/subscription`, { replace: true });
} }
} else { } else {
navigate( navigate(redirectUrl);
`/${element.pageType}/${element.pageId}`
);
} }
} }
}, },
@@ -1134,100 +1133,76 @@ function Login(props) {
{state.toastDescription} {state.toastDescription}
</div> </div>
</div> </div>
{isModal && ( <ModalUi isOpen={isModal} title="Additional Info" showClose={false}>
<div <form className="px-4 py-3">
className="modal fade show" <div className="mb-3">
id="exampleModal" <label
tabIndex="-1" htmlFor="Company"
role="dialog" style={{ display: "flex" }}
style={{ className="block text-xs text-gray-700 font-semibold"
display: "block", >
zIndex: 1, Company <span style={{ fontSize: 13, color: "red" }}>*</span>
backgroundColor: "rgba(0,0,0,0.5)" </label>
}} <input
> type="text"
<div className="modal-dialog" role="document"> className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
<div className="modal-content"> id="Company"
<div className="modal-header"> value={userDetails.Company}
<h5 className="modal-title font-semibold"> onChange={(e) =>
Additional Info setUserDetails({
</h5> ...userDetails,
<span> Company: e.target.value
<span></span> })
</span> }
</div> required
<div className="modal-body"> />
<form className="text-sm">
<div className="form-group">
<label
htmlFor="Company"
style={{ display: "flex" }}
className="col-form-label"
>
Company{" "}
<span style={{ fontSize: 13, color: "red" }}>*</span>
</label>
<input
type="text"
className="form-control"
id="Company"
value={userDetails.Company}
onChange={(e) =>
setUserDetails({
...userDetails,
Company: e.target.value
})
}
required
/>
</div>
<div className="form-group">
<label
htmlFor="JobTitle"
style={{ display: "flex" }}
className="col-form-label"
>
Job Title
<span style={{ fontSize: 13, color: "red" }}>*</span>
</label>
<input
type="text"
className="form-control"
id="JobTitle"
value={userDetails.Destination}
onChange={(e) =>
setUserDetails({
...userDetails,
Destination: e.target.value
})
}
required
/>
</div>
<div className="mt-4">
<button
type="button"
className="bg-[#17a2b8] text-sm p-2 text-white rounded uppercase"
onClick={(e) => handleSubmitbtn(e)}
style={{ marginRight: 10 }}
>
Login
</button>
<button
type="button"
className="bg-[#6c757d] text-sm p-2 text-white rounded uppercase"
onClick={handleCloseModal}
style={{ width: 90 }}
>
Cancel
</button>
</div>
</form>
</div>
</div>
</div> </div>
</div> <div className="mb-3">
)} <label
htmlFor="JobTitle"
style={{ display: "flex" }}
className="block text-xs text-gray-700 font-semibold"
>
Job Title
<span style={{ fontSize: 13, color: "red" }}>*</span>
</label>
<input
type="text"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
id="JobTitle"
value={userDetails.Destination}
onChange={(e) =>
setUserDetails({
...userDetails,
Destination: e.target.value
})
}
required
/>
</div>
<div className="mt-4">
<button
type="button"
className="px-3 py-1.5 text-white rounded shadow-md text-center focus:outline-none "
onClick={(e) => handleSubmitbtn(e)}
style={{
marginRight: 10,
backgroundColor: modalSubmitBtnColor
}}
>
Login
</button>
<button
type="button"
className="py-1.5 text-black border-[1px] border-[#ccc] shadow-md rounded focus:outline-none"
onClick={handleCloseModal}
style={{ width: 75, backgroundColor: modalCancelBtnColor }}
>
Cancel
</button>
</div>
</form>
</ModalUi>
</> </>
) : ( ) : (
<div <div
+4 -2
View File
@@ -2,7 +2,7 @@
import React from "react"; import React from "react";
import Title from "../components/Title"; import Title from "../components/Title";
const PageNotFound = () => { const PageNotFound = ({ prefix }) => {
return ( return (
<div className="flex items-center justify-center h-screen w-full bg-white rounded"> <div className="flex items-center justify-center h-screen w-full bg-white rounded">
<Title title={"Page Not Found"} /> <Title title={"Page Not Found"} />
@@ -10,7 +10,9 @@ const PageNotFound = () => {
<h1 className="text-[60px] lg:text-[120px] font-semibold text-black"> <h1 className="text-[60px] lg:text-[120px] font-semibold text-black">
404 404
</h1> </h1>
<p className="text-[30px] lg:text-[50px] text-black">Page Not Found</p> <p className="text-[30px] lg:text-[50px] text-black">
{prefix ? prefix : "Page"} Not Found
</p>
</div> </div>
</div> </div>
); );
+18 -9
View File
@@ -5,7 +5,7 @@ import axios from "axios";
import { fetchAppInfo, showTenantName } from "../redux/actions/index"; import { fetchAppInfo, showTenantName } from "../redux/actions/index";
import { connect } from "react-redux"; import { connect } from "react-redux";
import Title from "../components/Title"; import Title from "../components/Title";
import { useNavigate } from "react-router-dom"; import { useNavigate, useLocation } from "react-router-dom";
const appId = localStorage.getItem("AppID12"); const appId = localStorage.getItem("AppID12");
const server = localStorage.getItem("BaseUrl12"); const server = localStorage.getItem("BaseUrl12");
@@ -13,6 +13,7 @@ Parse.serverURL = server;
Parse.initialize(appId); Parse.initialize(appId);
const PgSignUp = (props) => { const PgSignUp = (props) => {
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation();
const [parseBaseUrl] = useState(localStorage.getItem("BaseUrl12")); const [parseBaseUrl] = useState(localStorage.getItem("BaseUrl12"));
const [parseAppId] = useState(localStorage.getItem("AppID12")); const [parseAppId] = useState(localStorage.getItem("AppID12"));
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
@@ -74,8 +75,8 @@ const PgSignUp = (props) => {
const res = await Parse.Cloud.run("getUserDetails", params); const res = await Parse.Cloud.run("getUserDetails", params);
// console.log("res", res); // console.log("res", res);
if (res) { if (res) {
const checkUser = new Parse.Query(extClass); const updateQuery = new Parse.Object(extClass);
const updateQuery = await checkUser.get(res.id); updateQuery.id = res.id;
updateQuery.set( updateQuery.set(
"Next_billing_date", "Next_billing_date",
new Date(zohoRes.data.result.nextBillingDate) new Date(zohoRes.data.result.nextBillingDate)
@@ -187,7 +188,7 @@ const PgSignUp = (props) => {
console.log("err ", error); console.log("err ", error);
if (error.message === "Account already exists for this username.") { if (error.message === "Account already exists for this username.") {
alert("Account already exists!"); alert("Account already exists!");
navigate("/"); navigate("/", { replace: true });
} else { } else {
setIsLoader(false); setIsLoader(false);
alert("Something went wrong, please try again later!"); alert("Something went wrong, please try again later!");
@@ -351,7 +352,7 @@ const PgSignUp = (props) => {
element.pageType element.pageType
); );
setIsLoader(false); setIsLoader(false);
navigate("/"); navigate("/", { replace: true });
} else { } else {
extendedInfo.forEach((x) => { extendedInfo.forEach((x) => {
if (x.TenantId) { if (x.TenantId) {
@@ -389,9 +390,12 @@ const PgSignUp = (props) => {
); );
setIsLoader(false); setIsLoader(false);
alert("Registered user successfully"); alert("Registered user successfully");
navigate( const redirectUrl =
`/${element.pageType}/${element.pageId}` location?.state?.from ||
); `/${element.pageType}/${element.pageId}`;
// Redirect to the appropriate URL after successful login
navigate(redirectUrl);
} }
} else { } else {
alert("Registered user successfully"); alert("Registered user successfully");
@@ -402,7 +406,12 @@ const PgSignUp = (props) => {
); );
localStorage.setItem("pageType", element.pageType); localStorage.setItem("pageType", element.pageType);
setIsLoader(false); setIsLoader(false);
navigate(`/${element.pageType}/${element.pageId}`); const redirectUrl =
location?.state?.from ||
`/${element.pageType}/${element.pageId}`;
// Redirect to the appropriate URL after successful login
navigate(redirectUrl);
} }
}, },
(error) => { (error) => {
+19 -28
View File
@@ -39,7 +39,7 @@ const PlanSubscriptions = () => {
setIsLoader(false); setIsLoader(false);
setYearlyVisible(false); setYearlyVisible(false);
} else { } else {
navigate("/"); navigate("/", { replace: true });
} }
// eslint-disable-next-line // eslint-disable-next-line
}, []); }, []);
@@ -78,31 +78,6 @@ const PlanSubscriptions = () => {
id="monthlyPlans" id="monthlyPlans"
className={`${yearlyVisible ? "none" : "block my-2"}`} className={`${yearlyVisible ? "none" : "block my-2"}`}
> >
{/* <div className=" my-2 w-full flex justify-center">
<ul
className="navs"
style={{
listStyle: "none",
display: "flex",
alignItems: "baseline"
}}
>
<li className="nav-item">
<button className="nav-link frequency active" name="1_months">
Monthly
</button>
</li>
<li className="nav-item">
<button
className="nav-link frequency "
onClick={toggleFrequency}
name="1_years"
>
Yearly
</button>
</li>
</ul>
</div> */}
<div className="flex justify-center w-full my-2"> <div className="flex justify-center w-full my-2">
<ul className=" flex flex-col md:flex-row h-full bg-white justify-center border-collapse border-[1px] border-gray-300"> <ul className=" flex flex-col md:flex-row h-full bg-white justify-center border-collapse border-[1px] border-gray-300">
{plansArr.map((item) => ( {plansArr.map((item) => (
@@ -129,11 +104,27 @@ const PlanSubscriptions = () => {
<div <div
className={`${ className={`${
item.subtitle.length <= 32 item.subtitle.length <= 32
? "w-[150px] text-center" ? "w-[150px] text-center"
: "" : ""
} text-sm text-center my-2`} } text-sm text-center my-2`}
> >
<p>{item.subtitle}</p> <p
style={{
backgroundColor: item.subtitlecolor
? item.subtitlecolor
: "white"
}}
>
{item.subtitle.includes("<") ? (
<div
dangerouslySetInnerHTML={{
__html: item.subtitle
}}
/>
) : (
<span>{item.subtitle}</span>
)}
</p>
</div> </div>
</div> </div>
+5 -7
View File
@@ -5,6 +5,7 @@ import axios from "axios";
import reportJson from "../json/ReportJson"; import reportJson from "../json/ReportJson";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import Title from "../components/Title"; import Title from "../components/Title";
import PageNotFound from "./PageNotFound";
const Report = () => { const Report = () => {
const { id } = useParams(); const { id } = useParams();
@@ -15,6 +16,7 @@ const Report = () => {
const [heading, setHeading] = useState([]); const [heading, setHeading] = useState([]);
const [isNextRecord, setIsNextRecord] = useState(false); const [isNextRecord, setIsNextRecord] = useState(false);
const [isMoreDocs, setIsMoreDocs] = useState(true); const [isMoreDocs, setIsMoreDocs] = useState(true);
const [form, setForm] = useState("");
const abortController = new AbortController(); const abortController = new AbortController();
const docPerPage = 10; const docPerPage = 10;
@@ -50,6 +52,7 @@ const Report = () => {
setActions(json.actions); setActions(json.actions);
setHeading(json.heading); setHeading(json.heading);
setReportName(json.reportName); setReportName(json.reportName);
setForm(json.form);
Parse.serverURL = localStorage.getItem("BaseUrl12"); Parse.serverURL = localStorage.getItem("BaseUrl12");
Parse.initialize(localStorage.getItem("AppID12")); Parse.initialize(localStorage.getItem("AppID12"));
const currentUser = Parse.User.current().id; const currentUser = Parse.User.current().id;
@@ -154,15 +157,10 @@ const Report = () => {
setIsNextRecord={setIsNextRecord} setIsNextRecord={setIsNextRecord}
isMoreDocs={isMoreDocs} isMoreDocs={isMoreDocs}
docPerPage={docPerPage} docPerPage={docPerPage}
form={form}
/> />
) : ( ) : (
<div className="flex items-center justify-center h-screen w-full bg-white rounded"> <PageNotFound prefix={"Report"} />
<div className="text-center">
<p className="text-[30px] lg:text-[50px] text-black">
Report Not Found
</p>
</div>
</div>
)} )}
</> </>
)} )}
+171
View File
@@ -0,0 +1,171 @@
import React, { useEffect, useState } from "react";
import Title from "../components/Title";
import axios from "axios";
import Alert from "../primitives/Alert";
import ModalUi from "../primitives/ModalUi";
import { rejectBtn, submitBtn } from "../constant/const";
import { openInNewTab } from "../constant/Utils";
import Parse from "parse";
function Webhook() {
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [webhook, setWebhook] = useState();
const [isLoader, setIsLoader] = useState(true);
const [isGenerate, setIsGenerate] = useState(false);
const [isErr, setIsErr] = useState(false);
const [isModal, setIsModal] = useState(false);
useEffect(() => {
fetchWebhook();
// eslint-disable-next-line
}, []);
const fetchWebhook = async () => {
const email = Parse.User.current().getEmail();
const params = { email: email };
try {
const extRes = await Parse.Cloud.run("getUserDetails", params);
if (extRes) {
setWebhook(extRes.get("Webhook"));
}
setIsLoader(false);
} catch (err) {
setWebhook();
setIsLoader(false);
console.log("Err", err);
}
};
const handleSubmit = async (e) => {
e.preventDefault();
setIsLoader(true);
setIsModal(false);
try {
const params = { url: webhook };
const url = parseBaseUrl + "functions/savewebhook";
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessiontoken: localStorage.getItem("accesstoken")
};
await axios.post(url, params, { headers: headers }).then((res) => {
if (res.data && res.data.result && res.data.result.Webhook) {
setWebhook(res.data.result.Webhook);
setIsGenerate(true);
setTimeout(() => {
setIsGenerate(false);
}, 1500);
setIsLoader(false);
} else {
console.error("Error while generating webhook");
setIsLoader(false);
setIsErr(true);
setTimeout(() => {
setIsErr(false);
}, 1500);
}
});
} catch (error) {
setIsLoader(false);
setIsErr(true);
setTimeout(() => {
setIsErr(false);
}, 1500);
console.log("err", error);
}
};
const handleModal = () => setIsModal(!isModal);
return (
<React.Fragment>
<Title title={"Webhook"} />
{isGenerate && <Alert type="success">Webhook added successfully!</Alert>}
{isErr && <Alert type="danger">Something went wrong!</Alert>}
{isLoader ? (
<div
style={{
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<div
style={{
fontSize: "45px",
color: "#3dd3e0"
}}
className="loader-37"
></div>
</div>
) : (
<div className="bg-white flex flex-col justify-center shadow rounded">
<h1 className="ml-4 mt-3 mb-2 font-semibold">Webhook</h1>
<ul className="w-full flex flex-col p-2 text-sm">
<li
className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
>
<span className="w-[40%]">Webhook:</span>{" "}
<span id="token" className="w-[60%] md:text-end cursor-pointer">
{webhook && webhook}
</span>
</li>
</ul>
<div className="flex flex-col md:flex-row items-center justify-center gap-2 pb-4">
<button
type="button"
onClick={handleModal}
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base focus:outline-none"
>
{webhook ? "Update Webhook" : "Add Webhook"}
</button>
<button
type="button"
onClick={() =>
openInNewTab(
"https://docs.opensignlabs.com/docs/API-docs/save-update-webhook"
)
}
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
>
View Docs
</button>
</div>
<ModalUi
isOpen={isModal}
title={"Regenerate Token"}
handleClose={handleModal}
>
<div className="m-[20px]">
<div className="text-lg font-normal text-black">
<label className="text-sm ml-2">Webhook</label>
<input
value={webhook}
onChange={(e) => setWebhook(e.target.value)}
placeholder="Enter webhook url"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
/>
</div>
<hr className="bg-[#ccc] mt-4 " />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={handleSubmit}
className={submitBtn + "ml-[2px]"}
>
Yes
</button>
<button onClick={handleModal} className={rejectBtn}>
No
</button>
</div>
</div>
</ModalUi>
</div>
)}
</React.Fragment>
);
}
export default Webhook;
File diff suppressed because it is too large Load Diff
+51 -196
View File
@@ -1,209 +1,64 @@
#snackbar { #snackbar {
visibility: hidden; visibility: hidden;
min-width: 250px; min-width: 250px;
margin-left: -125px; margin-left: -125px;
background-color: #333; background-color: #333;
color: #fff; color: #fff;
text-align: center; text-align: center;
border-radius: 2px; border-radius: 2px;
padding: 16px; padding: 16px;
position: fixed; position: fixed;
z-index: 99999; z-index: 99999;
left: 50%; left: 50%;
top: 30px;
font-size: 14px;
}
#snackbar.show {
visibility: visible;
-webkit-animation: fadein 0.5s;
}
@-webkit-keyframes fadein {
from {
top: 0;
opacity: 0;
}
to {
top: 30px; top: 30px;
font-size: 14px; opacity: 1;
} }
}
#_editsnackbar { @keyframes fadein {
visibility: hidden; from {
min-width: 250px; top: 0;
margin-left: -125px; opacity: 0;
background-color: #333; }
color: #fff; to {
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 99999;
left: 50%;
top: 30px; top: 30px;
font-size: 14px; opacity: 1;
} }
}
#_editsnackbar.show { @-webkit-keyframes fadeout {
visibility: visible; from {
-webkit-animation: fadein 0.5s;
}
#UpdateColumnValue.show {
visibility: visible;
-webkit-animation: fadein 0.5s;
}
#DeleteUser.show {
visibility: visible;
-webkit-animation: fadein 0.5s;
}
#DeleteUser {
visibility: hidden;
min-width: 250px;
margin-left: -125px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 99999;
left: 50%;
top: 30px; top: 30px;
font-size: 14px; opacity: 1;
} }
to {
top: 0;
opacity: 0;
}
}
#deleteObj.show { @keyframes fadeout {
visibility: visible; from {
-webkit-animation: fadein 0.5s;
}
#deleteObj {
visibility: hidden;
min-width: 250px;
margin-left: -125px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 99999;
left: 50%;
top: 30px; top: 30px;
font-size: 14px; opacity: 1;
} }
to {
#UpdateColumnValue { top: 0;
visibility: hidden; opacity: 0;
min-width: 250px;
margin-left: -125px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 99999;
left: 50%;
top: 30px;
font-size: 14px;
} }
}
#snackbar.show {
visibility: visible;
-webkit-animation: fadein 0.5s;
}
#snackbar1 {
visibility: hidden;
min-width: 250px;
margin-left: -125px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 99999;
left: 50%;
top: 30px;
font-size: 14px;
}
#snackbar1.show {
visibility: visible;
-webkit-animation: fadein 0.5s;
}
#snackbar10 {
visibility: hidden;
min-width: 250px;
margin-left: -125px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 99999;
left: 50%;
top: 30px;
font-size: 14px;
}
#snackbar10.show {
visibility: visible;
-webkit-animation: fadein 0.5s;
}
#snackbarCol {
visibility: hidden;
min-width: 250px;
margin-left: -125px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 99999;
left: 50%;
top: 30px;
font-size: 14px;
}
#snackbarCol.show {
visibility: visible;
-webkit-animation: fadein 0.5s;
}
@-webkit-keyframes fadein {
from {
top: 0;
opacity: 0;
}
to {
top: 30px;
opacity: 1;
}
}
@keyframes fadein {
from {
top: 0;
opacity: 0;
}
to {
top: 30px;
opacity: 1;
}
}
@-webkit-keyframes fadeout {
from {
top: 30px;
opacity: 1;
}
to {
top: 0;
opacity: 0;
}
}
@keyframes fadeout {
from {
top: 30px;
opacity: 1;
}
to {
top: 0;
opacity: 0;
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
# Use an official Node runtime as the base image # Use an official Node runtime as the base image
FROM node:16 FROM node:18
# Set the working directory inside the container # Set the working directory inside the container
WORKDIR /usr/src/app WORKDIR /usr/src/app
+27
View File
@@ -0,0 +1,27 @@
# Use an official Node runtime as the base image
FROM node:18
# Set the working directory inside the container
WORKDIR /usr/src/app
# Copy package.json and package-lock.json first to leverage Docker cache
COPY apps/OpenSignServer/package*.json ./
# Install application dependencies
RUN npm install
# If you have native dependencies, you'll need extra tools. Uncomment the following line if needed.
# RUN apk add --no-cache make gcc g++ python3
# Copy the current directory contents into the container
COPY apps/OpenSignServer/ .
# Make port 8080 available to the world outside this container
EXPOSE 8080
# Define environment variables if needed
# ENV NODE_ENV production
# ENV DATABASE_URL mongodb://db:27017
# Run the application
CMD ["npm", "start"]
+40
View File
@@ -0,0 +1,40 @@
export function customAPIurl() {
const url = new URL(process.env.SERVER_URL);
return url.pathname === '/api/app' ? url.origin + '/api' : url.origin;
}
export const color = [
'#93a3db',
'#e6c3db',
'#c0e3bc',
'#bce3db',
'#b8ccdb',
'#ceb8db',
'#ffccff',
'#99ffcc',
'#cc99ff',
'#ffcc99',
'#66ccff',
'#ffffcc',
];
export function replaceMailVaribles(subject, body, variables) {
let replacedSubject = subject;
let replacedBody = body;
for (const variable in variables) {
const regex = new RegExp(`{{${variable}}}`, 'g');
if (subject) {
replacedSubject = replacedSubject.replace(regex, variables[variable]);
}
if (body) {
replacedBody = replacedBody.replace(regex, variables[variable]);
}
}
const result = {
subject: replacedSubject,
body: replacedBody,
};
return result;
}
@@ -47,53 +47,78 @@ async function uploadFile(req, res) {
const DO_ACCESS_KEY_ID = process.env.DO_ACCESS_KEY_ID; const DO_ACCESS_KEY_ID = process.env.DO_ACCESS_KEY_ID;
const DO_SECRET_ACCESS_KEY = process.env.DO_SECRET_ACCESS_KEY; const DO_SECRET_ACCESS_KEY = process.env.DO_SECRET_ACCESS_KEY;
const DO_SPACE = process.env.DO_SPACE; const DO_SPACE = process.env.DO_SPACE;
const spacesEndpoint = new aws.Endpoint(DO_ENDPOINT);
const s3 = new aws.S3({
endpoint: spacesEndpoint,
accessKeyId: DO_ACCESS_KEY_ID,
secretAccessKey: DO_SECRET_ACCESS_KEY,
signatureVersion: 'v4',
region: process.env.DO_REGION,
});
const parseBaseUrl = process.env.SERVER_URL; const parseBaseUrl = process.env.SERVER_URL;
const parseAppId = process.env.APP_ID; const parseAppId = process.env.APP_ID;
let fileStorage;
if (process.env.USE_LOCAL == "TRUE") { if (process.env.USE_LOCAL == 'TRUE') {
var fileStorage = multer.diskStorage({ fileStorage = multer.diskStorage({
destination: function(req, file, cb) { destination: function (req, file, cb) {
cb(null, "files/files"); cb(null, 'files/files');
}, },
metadata: function (req, file, cb) { metadata: function (req, file, cb) {
cb(null, { fieldName: 'OPENSIGN_METADATA' }); cb(null, { fieldName: 'OPENSIGN_METADATA' });
}, },
filename: function(req, file, cb) { filename: function (req, file, cb) {
let filename = file.originalname; let filename = file.originalname;
let newFileName = filename.split('.')[0]; let newFileName = filename.split('.')[0];
let extension = filename.split('.')[1]; let extension = filename.split('.')[1];
newFileName = sanitizeFileName(newFileName + '_' + new Date().toISOString() + '.' + extension) newFileName = sanitizeFileName(
newFileName + '_' + new Date().toISOString() + '.' + extension
);
console.log(newFileName); console.log(newFileName);
cb(null, newFileName); cb(null, newFileName);
} },
}); });
} else { } else {
var fileStorage = multerS3({ try {
acl: 'public-read', const spacesEndpoint = new aws.Endpoint(DO_ENDPOINT);
s3, const s3 = new aws.S3({
bucket: DO_SPACE, endpoint: spacesEndpoint,
metadata: function (req, file, cb) { accessKeyId: DO_ACCESS_KEY_ID,
cb(null, { fieldName: 'OPENSIGN_METADATA' }); secretAccessKey: DO_SECRET_ACCESS_KEY,
}, signatureVersion: 'v4',
key: function (req, file, cb) { region: process.env.DO_REGION,
//console.log(file); });
let filename = file.originalname; fileStorage = multerS3({
let newFileName = filename.split('.')[0]; acl: 'public-read',
let extension = filename.split('.')[1]; s3,
newFileName = sanitizeFileName(newFileName + '_' + new Date().toISOString() + '.' + extension) bucket: DO_SPACE,
console.log(newFileName); metadata: function (req, file, cb) {
cb(null, newFileName); cb(null, { fieldName: 'OPENSIGN_METADATA' });
} },
}); key: function (req, file, cb) {
//console.log(file);
let filename = file.originalname;
let newFileName = filename.split('.')[0];
let extension = filename.split('.')[1];
newFileName = sanitizeFileName(
newFileName + '_' + new Date().toISOString() + '.' + extension
);
console.log(newFileName);
cb(null, newFileName);
},
});
} catch (err) {
fileStorage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'files/files');
},
metadata: function (req, file, cb) {
cb(null, { fieldName: 'OPENSIGN_METADATA' });
},
filename: function (req, file, cb) {
let filename = file.originalname;
let newFileName = filename.split('.')[0];
let extension = filename.split('.')[1];
newFileName = sanitizeFileName(
newFileName + '_' + new Date().toISOString() + '.' + extension
);
console.log(newFileName);
cb(null, newFileName);
},
});
}
} }
// const s3 = new aws.S3(); // const s3 = new aws.S3();
@@ -122,7 +147,7 @@ async function uploadFile(req, res) {
const status = 'Success'; const status = 'Success';
//res.header("Access-Control-Allow-Headers", "Content-Type"); //res.header("Access-Control-Allow-Headers", "Content-Type");
//res.setHeader("Access-Control-Allow-Origin", "*"); //res.setHeader("Access-Control-Allow-Origin", "*");
if (process.env.USE_LOCAL == "TRUE") { if (process.env.USE_LOCAL == 'TRUE') {
console.log(req.file); console.log(req.file);
var fileUrl = `${parseBaseUrl}/files/${parseAppId}/${req.file.filename}`; var fileUrl = `${parseBaseUrl}/files/${parseAppId}/${req.file.filename}`;
} else { } else {
@@ -0,0 +1,104 @@
//--npm modules
import express from 'express';
import cors from 'cors';
export const app = express();
import dotenv from 'dotenv';
import getUser from './routes/getUser.js';
import getDocumentList from './routes/getDocumentList.js';
import getDocument from './routes/getDocument.js';
import getContact from './routes/getContact.js';
import deleteContact from './routes/deleteContact.js';
import getContactList from './routes/getContactList.js';
import draftDocument from './routes/draftDocument.js';
import createTemplate from './routes/createTemplate.js';
import getTemplate from './routes/getTemplate.js';
import deletedTemplate from './routes/deleteTemplate.js';
import getTemplatetList from './routes/getTemplateList.js';
import updateTemplate from './routes/updateTemplate.js';
import createContact from './routes/createContact.js';
import multer from 'multer';
// import fs from 'node:fs';
import updateDocument from './routes/updateDocument.js';
import deleteDocument from './routes/deleteDocument.js';
import createDocumentWithTemplate from './routes/CreateDocumentWithTemplate.js';
import saveWebhook from './routes/saveWebhook.js';
import deleteWebhook from './routes/deleteWebhook.js';
import getWebhook from './routes/getWebhook.js';
import createDocumentwithCoordinate from './routes/createDocumentwithCoordinate.js';
import createTemplatewithCoordinate from './routes/createTemplatewithCoordinate.js';
dotenv.config();
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
app.use(cors());
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ limit: '50mb', extended: true }));
// get user details whose api token used
app.get('/getuser', getUser);
// get contact on the basis of id
app.post('/createcontact', createContact);
// get contact on the basis of id
app.get('/contact/:contact_id', getContact);
// soft delete contact
app.delete('/contact/:contact_id', deleteContact);
// get list of contacts
app.get('/contactlist', getContactList);
// create Document
app.post('/createdocumentwithbinary', upload.array('file', 1), createDocumentwithCoordinate);
// create Document with co-ordinate
app.post('/createdocument', createDocumentwithCoordinate);
// create Document with base64 without placeholder
app.post('/draftdocument', draftDocument);
// create Document with templateId
app.post('/createdocument/:template_id', createDocumentWithTemplate);
// get Document on the basis of id
app.get('/document/:document_id', getDocument);
// get document on the basis of id
app.put('/document/:document_id', updateDocument);
// get document on the basis of id
app.delete('/document/:document_id', deleteDocument);
// get all types of documents on the basis of doctype
app.get('/documentlist/:doctype', getDocumentList);
// create Template with co-ordinate
app.post('/createtemplate', createTemplatewithCoordinate);
// create Template
app.post('/drafttemplate', createTemplate);
// create Template with binary
app.post('/createtemplatewithbinary', upload.array('file', 1), createTemplatewithCoordinate);
// get template on the basis of id
app.get('/template/:template_id', getTemplate);
// get template on the basis of id
app.put('/template/:template_id', updateTemplate);
// get template on the basis of id
app.delete('/template/:template_id', deletedTemplate);
// get all types of documents on the basis of doctype
app.get('/templatelist', getTemplatetList);
// set and update webhook
app.get('/webhook', getWebhook);
// set and update webhook
app.post('/webhook', saveWebhook);
// set and update webhook
app.delete('/webhook', deleteWebhook);
@@ -0,0 +1,367 @@
import axios from 'axios';
import { customAPIurl, replaceMailVaribles } from '../../../../Utils.js';
// `sendDoctoWebhook` is used to send res data of document on webhook
async function sendDoctoWebhook(doc, WebhookUrl, userId) {
if (WebhookUrl) {
const params = {
event: 'created',
...doc,
};
await axios
.post(WebhookUrl, params, {
headers: { 'Content-Type': 'application/json' },
})
.then(res => {
try {
// console.log('res ', res);
const webhook = new Parse.Object('contracts_Webhook');
webhook.set('Log', res?.status);
webhook.set('UserId', {
__type: 'Pointer',
className: '_User',
objectId: userId,
});
webhook.save(null, { useMasterKey: true });
} catch (err) {
console.log('err save in contracts_Webhook', err);
}
})
.catch(err => {
console.log('Err send data to webhook', err);
try {
const webhook = new Parse.Object('contracts_Webhook');
webhook.set('Log', err?.status);
webhook.set('UserId', {
__type: 'Pointer',
className: '_User',
objectId: userId,
});
webhook.save(null, { useMasterKey: true });
} catch (err) {
console.log('err save in contracts_Webhook', err);
}
});
// console.log('res ', res.data);
}
}
export default async function createDocumentWithTemplate(request, response) {
const signers = request.body.signers;
const folderId = request.body.folderId;
const templateId = request.params.template_id;
const protocol = customAPIurl();
const baseUrl = new URL(process.env.SERVER_URL);
const send_email = request.body.send_email;
const email_subject = request.body.email_subject;
const email_body = request.body.email_body;
const sendInOrder = request.body.sendInOrder || false;
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 templateQuery = new Parse.Query('contracts_Template');
templateQuery.include('ExtUserPtr');
const templateRes = await templateQuery.get(templateId, { useMasterKey: true });
if (templateRes) {
const template = JSON.parse(JSON.stringify(templateRes));
if (template?.Placeholders?.length > 0) {
const emptyplaceholder = template?.Placeholders.filter(x => !x.signerObjId);
const isValid =
signers.length >= emptyplaceholder.length &&
signers.length <= template?.Placeholders?.length;
const placeholder =
signers.length > emptyplaceholder.length ? template.Placeholders : emptyplaceholder;
const updateSigners = placeholder.every(y => signers?.some(x => x.role === y.Role));
// console.log('isValid ', isValid);
if (isValid && updateSigners) {
const folderPtr = {
__type: 'Pointer',
className: 'contracts_Document',
objectId: folderId,
};
const template = JSON.parse(JSON.stringify(templateRes));
const object = new Parse.Object('contracts_Document');
object.set('Name', template.Name);
if (template?.Note) {
object.set('Note', template.Note);
}
if (template?.Description) {
object.set('Description', template.Description);
}
object.set('IsSendMail', send_email);
if (sendInOrder) {
object.set('SendinOrder', sendInOrder);
} else if (template?.SendinOrder && template?.SendinOrder) {
object.set('SendinOrder', template?.SendinOrder);
}
let templateSigner = template?.Signers ? template?.Signers : [];
let contact = [];
if (signers && signers.length > 0) {
let parseSigners = [...signers];
let createContactUrl = protocol + '/v1/createcontact';
for (const obj of parseSigners) {
const body = {
name: obj?.name || '',
email: obj?.email || '',
phone: obj?.phone || '',
};
try {
const res = await axios.post(createContactUrl, body, {
headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
});
const contactPtr = {
__type: 'Pointer',
className: 'contracts_Contactbook',
objectId: res.data?.objectId,
};
const newObj = { ...obj, contactPtr: contactPtr };
contact.push(newObj);
} catch (err) {
// console.log('err ', err);
if (err?.response?.data?.objectId) {
const contactPtr = {
__type: 'Pointer',
className: 'contracts_Contactbook',
objectId: err.response.data?.objectId,
};
const newObj = { ...obj, contactPtr: contactPtr };
contact.push(newObj);
} else {
console.log('err ', err);
}
}
}
const contactPtrs = contact.map(x => x.contactPtr);
object.set('Signers', [...templateSigner, ...contactPtrs]);
let updatedPlaceholder = template?.Placeholders?.map(x => {
let matchingSigner = contact.find(y => x.Role && x.Role === y.role);
if (matchingSigner) {
return {
...x,
signerObjId: matchingSigner?.contactPtr?.objectId,
signerPtr: matchingSigner?.contactPtr,
};
} else {
return {
...x,
};
}
});
object.set('Placeholders', updatedPlaceholder);
} else {
object.set('Signers', templateSigner);
}
object.set('URL', template.URL);
object.set('CreatedBy', template.CreatedBy);
object.set('ExtUserPtr', {
__type: 'Pointer',
className: 'contracts_Users',
objectId: template.ExtUserPtr.objectId,
});
if (folderId) {
object.set('Folder', folderPtr);
}
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 });
const newDate = new Date();
newDate.setDate(newDate.getDate() + 15);
const localExpireDate = newDate.toLocaleDateString('en-US', {
day: 'numeric',
month: 'long',
year: 'numeric',
});
let sender = template.ExtUserPtr.Email;
let sendMail;
const serverUrl = process.env.SERVER_URL;
const newServer = serverUrl.replaceAll('/', '%2F');
const serverParams = `${newServer}%2F&${process.env.APP_ID}&contracts`;
if (send_email === false) {
console.log("don't send mail");
} else {
let contactMail = contact;
if (sendInOrder) {
contactMail = contact.slice();
contactMail.splice(1);
}
for (let i = 0; i < contactMail.length; i++) {
try {
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
let url = `${process.env.SERVER_URL}/functions/sendmailv3/`;
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Master-Key': process.env.MASTER_KEY,
};
const objectId = contactMail[i].contactPtr.objectId;
const hostUrl = baseUrl.origin + '/loadmf/signmicroapp';
let signPdf = `${hostUrl}/login/${res.id}/${contactMail[i].email}/${objectId}/${serverParams}`;
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
const orgName = template.ExtUserPtr.Company ? template.ExtUserPtr.Company : '';
const themeBGcolor = '#47a3ad';
const email_html =
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src='" +
imgPng +
"' height='50' style='padding:20px; width:170px; height:40px;' /></div><div style='padding: 2px;font-family: system-ui;background-color:" +
themeBGcolor +
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
template.ExtUserPtr.Name +
' has requested you to review and sign <strong> ' +
template.Name +
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
sender +
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
orgName +
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
localExpireDate +
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
signPdf +
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px;'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
sender +
' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' +
openSignUrl +
' target=_blank>here</a>.</p> </div></div></body> </html>';
let replaceVar;
const variables = {
document_title: template.Name,
sender_name: template.ExtUserPtr.Name,
sender_mail: template.ExtUserPtr.Email,
sender_phone: template.ExtUserPtr.Phone,
receiver_name: contactMail[i].name,
receiver_email: contactMail[i].email,
receiver_phone: contactMail[i].phone,
expiry_date: localExpireDate,
company_name: orgName,
signing_url: signPdf,
};
if (email_subject && email_body) {
replaceVar = replaceMailVaribles(email_subject, email_body, variables);
} else if (email_subject) {
replaceVar = replaceMailVaribles(email_subject, '', variables);
replaceVar = { subject: replaceVar.subject, body: email_html };
} else if (email_body) {
replaceVar = replaceMailVaribles(
`${template.ExtUserPtr.Name} has requested you to sign ${template.Name}`,
email_body,
variables
);
} else {
replaceVar = {
subject: `${template.ExtUserPtr.Name} has requested you to sign ${template.Name}`,
body: email_html,
};
}
const subject = replaceVar.subject;
const html = replaceVar.body;
let params = {
recipient: contactMail[i].email,
subject: subject,
from: sender,
html: html,
};
sendMail = await axios.post(url, params, { headers: headers });
} catch (error) {
console.log('error', error);
}
}
}
// if (sendMail.data.result.status === 'success') {
try {
const doc = {
objectId: res.id,
file: template?.URL,
name: template?.Name,
note: template?.Note || '',
description: template?.Description || '',
signers: contact?.map(x => ({ name: x.name, email: x.email, phone: x.phone })),
createdAt: res.createdAt,
};
if (template.ExtUserPtr && template.ExtUserPtr?.Webhook) {
sendDoctoWebhook(doc, template.ExtUserPtr?.Webhook, userPtr?.objectId);
}
} catch (err) {
console.log('Err', err);
}
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_create_document_with_templateid',
properties: { response_code: 200 },
});
}
return response.json({
objectId: res.id,
signurl: contact.map(x => ({
email: x.email,
url: `${baseUrl.origin}/loadmf/signmicroapp/login/${res.id}/${x.email}/${x.contactPtr.objectId}/${serverParams}`,
})),
message: 'Document sent successfully!',
});
// }
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_create_document_with_templateid',
properties: { response_code: 400 },
});
}
return response.status(400).json({ error: 'Please provide signers properly!' });
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_create_document_with_templateid',
properties: { response_code: 400 },
});
}
return response.status(400).json({ error: 'Please setup template properly!' });
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_create_document_with_templateid',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'Invalid template id!' });
}
} else {
return response.status(405).json({ error: 'Invalid API Token!' });
}
} catch (err) {
console.log('err ', err);
if (err.code === 101) {
return response.status(404).json({ error: 'Invalid template id!' });
}
return response.status(400).json({ error: 'Something went wrong, please try again later!' });
}
}
@@ -0,0 +1,216 @@
import axios from 'axios';
export default async function createContact(request, response) {
const serverUrl = process.env.SERVER_URL;
const appId = process.env.APP_ID;
const name = request.body.name;
const phone = request.body.phone;
const email = request.body.email;
const reqToken = request.headers['x-api-token'];
if (!reqToken) {
return response.status(400).json({ error: 'Please Provide API Token' });
}
try {
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,
};
try {
const contactbook = new Parse.Query('contracts_Contactbook');
contactbook.equalTo('Email', email);
contactbook.equalTo('CreatedBy', userPtr);
contactbook.notEqualTo('IsDeleted', true);
const userExists = await contactbook.first({ useMasterKey: true });
if (userExists) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_create_contact',
properties: { response_code: 401 },
});
}
return response
.status(401)
.json({ error: 'Contact already exists!', objectId: userExists.id });
} else {
try {
const Tenant = new Parse.Query('partners_Tenant');
Tenant.equalTo('UserId', userPtr);
const tenantRes = await Tenant.first({ useMasterKey: true });
const contactQuery = new Parse.Object('contracts_Contactbook');
contactQuery.set('Name', name);
contactQuery.set('Phone', phone);
contactQuery.set('Email', email);
contactQuery.set('UserRole', 'contracts_Guest');
if (tenantRes && tenantRes.id) {
contactQuery.set('TenantId', {
__type: 'Pointer',
className: 'partners_Tenant',
objectId: tenantRes.id,
});
}
try {
const _users = Parse.Object.extend('User');
const _user = new _users();
_user.set('name', name);
_user.set('username', email);
_user.set('email', email);
_user.set('phone', phone);
_user.set('password', phone);
const user = await _user.save();
if (user) {
const roleurl = `${serverUrl}/functions/AddUserToRole`;
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': appId,
// sessionToken: localStorage.getItem('accesstoken'),
};
const body = {
appName: 'contracts',
roleName: 'contracts_Guest',
userId: user.id,
};
await axios.post(roleurl, body, { headers: headers });
const currentUser = userPtr;
contactQuery.set('CreatedBy', currentUser);
contactQuery.set('UserId', user);
const acl = new Parse.ACL();
acl.setReadAccess(userPtr.objectId, true);
acl.setWriteAccess(userPtr.objectId, true);
acl.setReadAccess(user.id, true);
acl.setWriteAccess(user.id, true);
contactQuery.setACL(acl);
const contactRes = await contactQuery.save();
const parseRes = JSON.parse(JSON.stringify(contactRes));
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_create_contact',
properties: { response_code: 200 },
});
}
return response.json({
objectId: parseRes.objectId,
name: parseRes.Name,
email: parseRes.Email,
phone: parseRes.Phone,
createdAt: parseRes.createdAt,
updatedAt: parseRes.updatedAt,
});
}
} catch (err) {
console.log('err in', err);
if (err.code === 202) {
const params = { email: email };
const userRes = await Parse.Cloud.run('getUserId', params);
const roleurl = `${serverUrl}/functions/AddUserToRole`;
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': appId,
// sessionToken: localStorage.getItem('accesstoken'),
};
const body = {
appName: 'contracts',
roleName: 'contracts_Guest',
userId: userRes.objectId,
};
await axios.post(roleurl, body, { headers: headers });
contactQuery.set('CreatedBy', userPtr.objectId);
contactQuery.set('UserId', {
__type: 'Pointer',
className: '_User',
objectId: userRes.id,
});
const acl = new Parse.ACL();
acl.setReadAccess(userPtr.objectId, true);
acl.setWriteAccess(userPtr.objectId, true);
acl.setReadAccess(userRes.id, true);
acl.setWriteAccess(userRes.id, true);
contactQuery.setACL(acl);
const contactRes = await contactQuery.save();
if (contactRes) {
const parseRes = JSON.parse(JSON.stringify(contactRes));
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_create_contact',
properties: { response_code: 200 },
});
}
return response.json({
objectId: parseRes.objectId,
name: parseRes.Name,
email: parseRes.Email,
phone: parseRes.Phone,
createdAt: parseRes.createdAt,
updatedAt: parseRes.updatedAt,
});
}
} else {
if (err.code === 137) {
return response.status(401).json({ error: 'Contact already exists!' });
}
return response
.status(400)
.json({ error: 'Something went wrong, please try again later!' });
}
}
} catch (err) {
console.log('err ', err);
if (err.code === 137) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_create_contact',
properties: { response_code: 401 },
});
}
return response.status(401).json({ error: 'Contact already exists!' });
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_create_contact',
properties: { response_code: 400 },
});
}
return response
.status(400)
.json({ error: 'Something went wrong, please try again later!' });
}
}
}
} catch (err) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_create_contact',
properties: { response_code: 400 },
});
}
return response
.status(400)
.json({ error: 'Something went wrong, please try again later!' });
}
} 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!' });
}
}
@@ -0,0 +1,379 @@
import axios from 'axios';
import { color, customAPIurl, replaceMailVaribles } from '../../../../Utils.js';
// `sendDoctoWebhook` is used to send res data of document on webhook
async function sendDoctoWebhook(doc, WebhookUrl, userId) {
if (WebhookUrl) {
const params = {
event: 'created',
...doc,
};
await axios
.post(WebhookUrl, params, {
headers: { 'Content-Type': 'application/json' },
})
.then(res => {
try {
// console.log('res ', res);
const webhook = new Parse.Object('contracts_Webhook');
webhook.set('Log', res?.status);
webhook.set('UserId', {
__type: 'Pointer',
className: '_User',
objectId: userId,
});
webhook.save(null, { useMasterKey: true });
} catch (err) {
console.log('err save in contracts_Webhook', err);
}
})
.catch(err => {
console.log('Err send data to webhook', err);
try {
const webhook = new Parse.Object('contracts_Webhook');
webhook.set('Log', err?.status);
webhook.set('UserId', {
__type: 'Pointer',
className: '_User',
objectId: userId,
});
webhook.save(null, { useMasterKey: true });
} catch (err) {
console.log('err save in contracts_Webhook', err);
}
});
// console.log('res ', res.data);
}
}
const randomId = () => Math.floor(1000 + Math.random() * 9000);
export default async function createDocumentwithCoordinate(request, response) {
const name = request.body.title;
const note = request.body.note;
const description = request.body.description;
const send_email = request.body.send_email;
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 email_subject = request.body.email_subject;
const email_body = request.body.email_body;
const sendInOrder = request.body.sendInOrder || false;
// console.log('fileData ', fileData);
const protocol = customAPIurl();
const baseUrl = new URL(process.env.SERVER_URL);
const reqToken = request.headers['x-api-token'];
if (!reqToken) {
return response.status(400).json({ error: 'Please Provide API Token' });
}
try {
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,
};
if (signers && signers.length > 0) {
let fileUrl;
if (request.files?.[0]) {
const file = new Parse.File(request.files?.[0]?.originalname, {
base64: fileData?.toString('base64'),
});
await file.save({ useMasterKey: true });
fileUrl = file.url();
} else {
const file = new Parse.File(`${name}.pdf`, {
base64: base64File,
});
await file.save({ useMasterKey: true });
fileUrl = file.url();
}
const contractsUser = new Parse.Query('contracts_Users');
contractsUser.equalTo('UserId', userPtr);
const extUser = await contractsUser.first({ useMasterKey: true });
const parseExtUser = JSON.parse(JSON.stringify(extUser));
const extUserPtr = {
__type: 'Pointer',
className: 'contracts_Users',
objectId: extUser.id,
};
const object = new Parse.Object('contracts_Document');
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('IsSendMail', send_email);
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()) {
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);
}
}
}
object.set(
'Signers',
contact?.map(x => x.contactPtr)
);
let updatePlaceholders = contact.map((signer, index) => {
const placeHolder = [];
for (const widget of signer.widgets) {
const pageNumber = widget.page;
const page = placeHolder.find(page => page.pageNumber === pageNumber);
const widgetData = {
xPosition: widget.x,
yPosition: widget.y,
isStamp: widget.type === 'stamp',
key: randomId(),
isDrag: false,
firstXPos: widget.x,
firstYPos: widget.y,
yBottom: 0,
scale: 1,
isMobile: false,
zIndex: 1,
type: widget.type,
widgetValue: '',
Width: widget.w,
Height: widget.h,
};
if (page) {
page.pos.push(widgetData);
} else {
placeHolder.push({
pageNumber,
pos: [widgetData],
});
}
}
return {
signerObjId: signer?.contactPtr?.objectId,
signerPtr: signer?.contactPtr,
Role: signer.role,
Id: randomId(),
blockColor: color[signer?.index],
placeHolder,
};
});
object.set('Placeholders', updatePlaceholders);
}
if (folderId) {
object.set('Folder', {
__type: 'Pointer',
className: 'contracts_Document',
objectId: folderId,
});
}
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 });
const doc = {
objectId: res.id,
file: fileUrl,
name: name,
note: note || '',
description: description || '',
signers: contact?.map(x => ({ name: x.name, email: x.email, phone: x.phone })),
createdAt: res.createdAt,
};
if (parseExtUser && parseExtUser.Webhook) {
sendDoctoWebhook(doc, parseExtUser?.Webhook, userPtr?.objectId);
}
const newDate = new Date();
newDate.setDate(newDate.getDate() + 15);
const localExpireDate = newDate.toLocaleDateString('en-US', {
day: 'numeric',
month: 'long',
year: 'numeric',
});
let sender = parseExtUser.Email;
let sendMail;
const serverUrl = process.env.SERVER_URL;
const newServer = serverUrl.replaceAll('/', '%2F');
const serverParams = `${newServer}%2F&${process.env.APP_ID}&contracts`;
if (send_email === false) {
console.log("don't send mail");
} else {
let contactMail = contact;
if (sendInOrder) {
contactMail = contact.slice();
contactMail.splice(1);
}
for (let i = 0; i < contactMail.length; i++) {
try {
const imgPng = 'https://qikinnovation.ams3.digitaloceanspaces.com/logo.png';
let url = `${process.env.SERVER_URL}/functions/sendmailv3/`;
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Master-Key': process.env.MASTER_KEY,
};
const objectId = contactMail[i].contactPtr.objectId;
const hostUrl = baseUrl.origin + '/loadmf/signmicroapp';
let signPdf = `${hostUrl}/login/${res.id}/${contactMail[i].email}/${objectId}/${serverParams}`;
const openSignUrl = 'https://www.opensignlabs.com/contact-us';
const orgName = parseExtUser.Company ? parseExtUser.Company : '';
const themeBGcolor = '#47a3ad';
const email_html =
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" +
imgPng +
" height='50' style='padding:20px; width:170px; height:40px;' /></div> <div style='padding:2px; font-family: system-ui;background-color:" +
themeBGcolor +
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
parseExtUser.Name +
' has requested you to review and sign <strong> ' +
name +
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
sender +
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
orgName +
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
localExpireDate +
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
signPdf +
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
sender +
' directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=' +
openSignUrl +
' target=_blank>here</a>.</p> </div></div></body> </html>';
let replaceVar;
const variables = {
document_title: name,
sender_name: parseExtUser.Name,
sender_mail: parseExtUser.Email,
sender_phone: parseExtUser.Phone,
receiver_name: contactMail[i].name,
receiver_email: contactMail[i].email,
receiver_phone: contactMail[i].phone,
expiry_date: localExpireDate,
company_name: orgName,
signing_url: signPdf,
};
if (email_subject && email_body) {
replaceVar = replaceMailVaribles(email_subject, email_body, variables);
} else if (email_subject) {
replaceVar = replaceMailVaribles(email_subject, '', variables);
replaceVar = { subject: replaceVar.subject, body: email_html };
} else if (email_body) {
replaceVar = replaceMailVaribles(
`${parseExtUser.Name} has requested you to sign ${name}`,
email_body,
variables
);
} else {
replaceVar = {
subject: `${parseExtUser.Name} has requested you to sign ${parseExtUser.Name}`,
body: email_html,
};
}
const subject = replaceVar.subject;
const html = replaceVar.body;
let params = {
recipient: contactMail[i].email,
subject: subject,
from: sender,
html: html,
};
sendMail = await axios.post(url, params, { headers: headers });
} catch (error) {
console.log('error', error);
}
}
}
// if (sendMail.data.result.status === 'success') {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_create_document',
properties: { response_code: 200 },
});
}
return response.json({
objectId: res.id,
signurl: contact.map(x => ({
email: x.email,
url: `${baseUrl.origin}/loadmf/signmicroapp/login/${res.id}/${x.email}/${x.contactPtr.objectId}/${serverParams}`,
})),
message: 'Document sent successfully!',
});
// }
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_create_document',
properties: { response_code: 400 },
});
}
return response.status(400).json({ error: 'Please provide signers!' });
}
} 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!' });
}
}
@@ -0,0 +1,135 @@
import { customAPIurl } from '../../../../Utils.js';
const randomId = () => Math.floor(1000 + Math.random() * 9000);
export default async function createTemplate(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 SendinOrder = request.body.sendInOrder || false;
const fileData = request.files?.[0] ? request.files[0].buffer : null;
const baseUrl = new URL(process.env.SERVER_URL);
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,
};
let fileUrl;
if (base64File) {
const file = new Parse.File(`${name}.pdf`, {
base64: base64File,
});
await file.save({ useMasterKey: true });
fileUrl = file.url();
} else {
const file = new Parse.File(request.files?.[0]?.originalname, {
base64: fileData?.toString('base64'),
});
await file.save({ useMasterKey: true });
fileUrl = file.url();
}
const contractsUser = new Parse.Query('contracts_Users');
contractsUser.equalTo('UserId', userPtr);
const extUser = await contractsUser.first({ useMasterKey: true });
const extUserPtr = { __type: 'Pointer', className: 'contracts_Users', objectId: extUser.id };
const folderPtr = { __type: 'Pointer', className: 'contracts_Template', objectId: folderId };
const object = new Parse.Object('contracts_Template');
object.set('Name', name);
if (note) {
object.set('Note', note);
}
if (description) {
object.set('Description', description);
}
object.set('URL', fileUrl);
object.set('CreatedBy', userPtr);
object.set('ExtUserPtr', extUserPtr);
if (SendinOrder) {
object.set('SendinOrder', SendinOrder);
}
if (signers && signers.length > 0) {
let parseSigners;
if (base64File) {
parseSigners = signers;
} else {
parseSigners = JSON.parse(signers);
}
let createContactUrl = protocol + '/v1/createcontact';
let contact = [];
for (const obj of parseSigners) {
const body = {
name: obj?.name || '',
email: obj?.email || '',
phone: obj?.phone || '',
};
try {
const res = await axios.post(createContactUrl, body, {
headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
});
// console.log('res ', res.data);
contact.push({
__type: 'Pointer',
className: 'contracts_Contactbook',
objectId: res.data?.objectId,
});
} catch (err) {
// console.log('err ', err.response);
if (err?.response?.data?.objectId) {
contact.push({
__type: 'Pointer',
className: 'contracts_Contactbook',
objectId: err.response.data?.objectId,
});
}
}
}
object.set('Signers', contact);
}
if (folderId) {
object.set('Folder', folderPtr);
}
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 },
});
}
return response.json({
objectId: res.id,
url: baseUrl.origin + '/load/signmicroapp/template/' + res.id,
});
} 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!' });
}
}
@@ -0,0 +1,214 @@
import axios from 'axios';
import { color, customAPIurl } from '../../../../Utils.js';
const randomId = () => Math.floor(1000 + Math.random() * 9000);
export default async function createTemplatewithCoordinate(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 || false;
// console.log('fileData ', fileData);
const protocol = customAPIurl();
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,
};
if (signers && signers.length > 0) {
let fileUrl;
if (request.files?.[0]) {
const file = new Parse.File(request.files?.[0]?.originalname, {
base64: fileData?.toString('base64'),
});
await file.save({ useMasterKey: true });
fileUrl = file.url();
} else {
const file = new Parse.File(`${name}.pdf`, {
base64: base64File,
});
await file.save({ useMasterKey: true });
fileUrl = file.url();
}
const contractsUser = new Parse.Query('contracts_Users');
contractsUser.equalTo('UserId', userPtr);
const extUser = await contractsUser.first({ useMasterKey: true });
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);
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.phone && 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 = contact.map((signer, index) => {
const placeHolder = [];
for (const widget of signer.widgets) {
const pageNumber = widget.page;
const page = placeHolder.find(page => page.pageNumber === pageNumber);
const widgetData = {
xPosition: widget.x,
yPosition: widget.y,
isStamp: widget.type === 'stamp',
key: randomId(),
isDrag: false,
firstXPos: widget.x,
firstYPos: widget.y,
yBottom: 0,
scale: 1,
isMobile: false,
zIndex: 1,
type: widget.type,
widgetValue: '',
Width: widget.w,
Height: widget.h,
};
if (page) {
page.pos.push(widgetData);
} else {
placeHolder.push({
pageNumber,
pos: [widgetData],
});
}
}
return {
signerObjId: signer?.contactPtr?.objectId,
signerPtr: signer?.contactPtr,
Role: signer.role,
Id: randomId(),
blockColor: color[signer?.index],
placeHolder,
};
});
object.set('Placeholders', updatePlaceholders);
}
if (folderId) {
object.set('Folder', {
__type: 'Pointer',
className: 'contracts_Template',
objectId: folderId,
});
}
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_create_template',
properties: { response_code: 200 },
});
}
return response.json({
objectId: res.id,
message: 'Template created successfully!',
});
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_create_template',
properties: { response_code: 400 },
});
}
return response.status(400).json({ error: 'Please provide signers!' });
}
} 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!' });
}
}
@@ -0,0 +1,65 @@
export default async function deleteContact(request, response) {
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 Contactbook = new Parse.Query('contracts_Contactbook');
Contactbook.equalTo('objectId', request.params.contact_id);
Contactbook.equalTo('CreatedBy', userPtr);
const res = await Contactbook.first({ useMasterKey: true });
if (res) {
const isDeleted = res.get('IsDeleted');
if (isDeleted && isDeleted) {
return response.status(404).json({ error: 'Contact not found!' });
} else {
const Contactbook = Parse.Object.extend('contracts_Contactbook');
const deleteQuery = new Contactbook();
deleteQuery.id = request.params.contact_id;
deleteQuery.set('IsDeleted', true);
const deleteRes = await deleteQuery.save(null, { useMasterKey: true });
if (deleteRes) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_delete_contact',
properties: { response_code: 200 },
});
}
return response.json({
objectId: request.params.contact_id,
deletedAt: deleteRes.get('updatedAt'),
});
}
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_delete_contact',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'Contact not found!' });
}
} 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!' });
}
}
@@ -0,0 +1,65 @@
export default async function deleteDocument(request, response) {
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 Document = new Parse.Query('contracts_Document');
Document.equalTo('objectId', request.params.document_id);
Document.equalTo('CreatedBy', userPtr);
const res = await Document.first({ useMasterKey: true });
if (res) {
const isArchive = res.get('IsArchive');
if (isArchive && isArchive) {
return response.status(404).json({ error: 'Document not found!' });
} else {
const Document = Parse.Object.extend('contracts_Document');
const deleteQuery = new Document();
deleteQuery.id = request.params.document_id;
deleteQuery.set('IsArchive', true);
const deleteRes = await deleteQuery.save(null, { useMasterKey: true });
if (deleteRes) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_delete_document',
properties: { response_code: 200 },
});
}
return response.json({
objectId: request.params.document_id,
deletedAt: deleteRes.get('updatedAt'),
});
}
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_delete_document',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'Document not found!' });
}
} 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!' });
}
}
@@ -0,0 +1,71 @@
export default async function deletedTemplate(request, response) {
const reqToken = request.headers['x-api-token'];
if (!reqToken) {
return response.status(400).json({ error: 'Please Provide API Token' });
}
try {
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 template = new Parse.Query('contracts_Template');
template.equalTo('objectId', request.params.template_id);
template.equalTo('CreatedBy', userPtr);
const res = await template.first({ useMasterKey: true });
if (res) {
const isArchive = res.get('IsArchive');
if (isArchive && isArchive) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_delete_template',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'Template not found!' });
} else {
const template = Parse.Object.extend('contracts_Template');
const deleteQuery = new template();
deleteQuery.id = request.params.template_id;
deleteQuery.set('IsArchive', true);
const deleteRes = await deleteQuery.save(null, { useMasterKey: true });
if (deleteRes) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_delete_template',
properties: { response_code: 200 },
});
}
return response.json({
objectId: request.params.template_id,
deletedAt: deleteRes.get('updatedAt'),
});
}
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_delete_template',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'Template not found!' });
}
} 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!' });
}
}
@@ -0,0 +1,57 @@
export default async function deleteWebhook(request, response) {
const reqToken = request.headers['x-api-token'];
if (!reqToken) {
return response.status(400).json({ error: 'Please Provide API Token' });
}
try {
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 query = new Parse.Query('contracts_Users');
query.equalTo('UserId', userPtr);
const user = await query.first({ useMasterKey: true });
if (user) {
const updateQuery = new Parse.Object('contracts_Users');
updateQuery.id = user.id;
updateQuery.unset('Webhook');
const res = await updateQuery.save(null, { useMasterKey: true });
if (res) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_delete_webhook',
properties: { response_code: 200 },
});
}
return response.json({
result: 'Webhook deleted successfully!',
});
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_delete_webhook',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'User not found!' });
}
} 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!' });
}
}
@@ -0,0 +1,157 @@
import axios from 'axios';
import { customAPIurl } from '../../../../Utils.js';
// const randomId = () => Math.floor(1000 + Math.random() * 9000);
export default async function draftDocument(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 send_email = request.body.send_email || true;
const fileData = request.files?.[0] ? request.files[0].buffer : null;
const SendinOrder = request.body.sendInOrder || false;
// console.log('fileData ', fileData);
const protocol = customAPIurl();
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) {
const parseUser = JSON.parse(JSON.stringify(token));
const userPtr = {
__type: 'Pointer',
className: '_User',
objectId: parseUser.userId.objectId,
};
// Valid Token then proceed request
if (signers && signers.length > 0) {
let fileUrl;
if (request.files?.[0]) {
const file = new Parse.File(request.files?.[0]?.originalname, {
base64: fileData?.toString('base64'),
});
await file.save({ useMasterKey: true });
fileUrl = file.url();
} else {
const file = new Parse.File(`${name}.pdf`, {
base64: base64File,
});
await file.save({ useMasterKey: true });
fileUrl = file.url();
}
const contractsUser = new Parse.Query('contracts_Users');
contractsUser.equalTo('UserId', userPtr);
const extUser = await contractsUser.first({ useMasterKey: true });
const extUserPtr = {
__type: 'Pointer',
className: 'contracts_Users',
objectId: extUser.id,
};
const folderPtr = {
__type: 'Pointer',
className: 'contracts_Document',
objectId: folderId,
};
const object = new Parse.Object('contracts_Document');
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('IsSendMail', send_email);
if (signers && signers.length > 0) {
let parseSigners;
if (base64File) {
parseSigners = signers;
} else {
parseSigners = JSON.parse(signers);
}
let createContactUrl = protocol + '/v1/createcontact';
let contact = [];
for (const obj of parseSigners) {
const body = {
name: obj?.name || '',
email: obj?.email || '',
phone: obj?.phone || '',
};
try {
const res = await axios.post(createContactUrl, body, {
headers: { 'Content-Type': 'application/json', 'x-api-token': reqToken },
});
// console.log('res ', res.data);
contact.push({
__type: 'Pointer',
className: 'contracts_Contactbook',
objectId: res.data?.objectId,
});
} catch (err) {
// console.log('err ', err.response);
if (err?.response?.data?.objectId) {
contact.push({
__type: 'Pointer',
className: 'contracts_Contactbook',
objectId: err.response.data?.objectId,
});
}
}
}
object.set('Signers', contact);
}
if (folderId) {
object.set('Folder', folderPtr);
}
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_document',
properties: { response_code: 200 },
});
}
return response.json({
objectId: res.id,
url: protocol + '/load/signmicroapp/placeholdersign/' + res.id,
});
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_draft_document',
properties: { response_code: 400 },
});
}
return response.status(400).json({ error: 'Please provide signers!' });
}
} 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!' });
}
}
@@ -0,0 +1,61 @@
export default async function getContact(request, response) {
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 Contactbook = new Parse.Query('contracts_Contactbook');
Contactbook.equalTo('objectId', request.params.contact_id);
Contactbook.equalTo('CreatedBy', userPtr);
Contactbook.notEqualTo('IsDeleted', true);
Contactbook.select('Name,Email,Phone');
const res = await Contactbook.first({ useMasterKey: true });
if (res) {
const parseRes = JSON.parse(JSON.stringify(res));
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_contact',
properties: { response_code: 200 },
});
}
return response.json({
objectId: parseRes.objectId,
name: parseRes.Name,
email: parseRes.Email,
phone: parseRes.Phone,
createdAt: parseRes.createdAt,
updatedAt: parseRes.updatedAt,
});
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_contact',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'Contact not found!' });
}
} 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!' });
}
}
@@ -0,0 +1,63 @@
export default async function getContactList(request, response) {
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 limit = request?.query?.limit ? parseInt(request.query.limit) : 100;
const skip = request?.query?.skip ? parseInt(request.query.skip) : 0;
const Contactbook = new Parse.Query('contracts_Contactbook');
Contactbook.equalTo('CreatedBy', userPtr);
Contactbook.notEqualTo('IsDeleted', true);
Contactbook.limit(limit);
Contactbook.skip(skip);
Contactbook.descending('createdAt');
const res = await Contactbook.find({ useMasterKey: true });
if (res && res.length > 0) {
const parseRes = JSON.parse(JSON.stringify(res));
const contactlist = parseRes.map(x => ({
objectId: x.objectId,
name: x.Name,
email: x.Email,
phone: x.Phone,
createdAt: x.createdAt,
updatedAt: x.updatedAt,
}));
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_contact_list',
properties: { response_code: 200 },
});
}
return response.json({ result: contactlist });
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_contact_list',
properties: { response_code: 200 },
});
}
return response.json({ result: [] });
}
} 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!' });
}
}
@@ -0,0 +1,84 @@
export default async function getDocument(request, response) {
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 Document = new Parse.Query('contracts_Document');
Document.equalTo('objectId', request.params.document_id);
Document.equalTo('CreatedBy', userPtr);
Document.notEqualTo('IsArchive', true);
Document.include('Signers');
Document.include('Folder');
Document.include('ExtUserPtr');
Document.include('Placeholders.signerPtr');
const res = await Document.first({ useMasterKey: true });
if (res) {
const document = JSON.parse(JSON.stringify(res));
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_document',
properties: { response_code: 200 },
});
}
return response.json({
objectId: document.objectId,
title: document.Name,
note: document.Note || '',
folder: { objectId: document?.Folder?.objectId, name: document?.Folder?.Name } || '',
file: document?.SignedUrl || document.URL,
owner: document?.ExtUserPtr?.Name,
signers:
document?.Placeholders?.map(y => ({
role: y.Role,
name: y?.signerPtr?.Name || '',
email: y?.signerPtr?.Email || '',
phone: y?.signerPtr?.Phone || '',
widgets: y.placeHolder?.flatMap(x =>
x?.pos.map(w => ({
type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature',
x: w.xPosition,
y: w.yPosition,
w: w?.Width || 150,
h: w?.Height || 60,
page: x?.pageNumber,
}))
),
})) ||
document?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) ||
[],
sendInOrder: document?.SendinOrder || false,
createdAt: document.createdAt,
updatedAt: document.updatedAt,
});
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_document',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'Document not found!' });
}
} 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!' });
}
}
@@ -0,0 +1,138 @@
import axios from 'axios';
import reportJson from '../../../parsefunction/reportsJson.js';
import dotenv from 'dotenv';
dotenv.config();
export default async function getDocumentList(request, response) {
const reqToken = request.headers['x-api-token'];
const appId = process.env.APP_ID;
const serverUrl = process.env.SERVER_URL;
if (!reqToken) {
return response.status(400).json({ error: 'Please Provide API Token' });
}
try {
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 docType = request.params.doctype;
const limit = request?.query?.limit ? request.query.limit : 100;
const skip = request?.query?.skip ? request.query.skip : 0;
let reportId;
switch (docType) {
case 'draft':
reportId = 'ByHuevtCFY';
break;
case 'signaturerequest':
reportId = '4Hhwbp482K';
break;
case 'inprogress':
reportId = '1MwEuxLEkF';
break;
case 'completed':
reportId = 'kQUoW4hUXz';
break;
case 'expired':
reportId = 'zNqBHXHsYH';
break;
case 'declined':
reportId = 'UPr2Fm5WY3';
break;
default:
reportId = '';
}
const json = reportId && reportJson(reportId, userPtr.objectId);
const clsName = 'contracts_Document';
if (reportId && json) {
const { params, keys } = json;
const orderBy = '-updatedAt';
const strParams = JSON.stringify(params);
const strKeys = keys.join();
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': appId,
'X-Parse-Master-Key': process.env.MASTER_KEY,
};
const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys},Placeholders&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr,Placeholders.signerPtr`;
try {
const res = await axios.get(url, { headers: headers });
if (res.data && res.data.results.length > 0) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: `api_get_document_list_${docType}`,
properties: { response_code: 200, doc_type: docType },
});
}
const updateRes = res.data.results.map(x => ({
objectId: x.objectId,
title: x.Name,
note: x.Note || '',
folder: { objectId: x?.Folder?.objectId, name: x?.Folder?.Name } || '',
file: x?.SignedUrl || x.URL,
owner: x?.ExtUserPtr?.Name,
signers:
x?.Placeholders?.map(y => ({
role: y.Role,
name: y?.signerPtr?.Name || '',
email: y?.signerPtr?.Email || '',
phone: y?.signerPtr?.Phone || '',
widgets: y.placeHolder?.flatMap(x =>
x?.pos.map(w => ({
type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature',
x: w.xPosition,
y: w.yPosition,
w: w?.Width || 150,
h: w?.Height || 60,
page: x?.pageNumber,
}))
),
})) ||
x?.Signers?.map(y => ({ name: y?.Name, email: y?.Email, phone: y?.Phone })) ||
[],
sendInOrder: x?.SendinOrder || false,
createdAt: x.createdAt,
updatedAt: x.updatedAt,
}));
return response.json({ result: updateRes });
} else {
return response.json({ result: [] });
}
} catch (err) {
console.log('err in getdocument list', err);
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: `api_get_document_list_${docType}`,
properties: { response_code: 400, doc_type: docType },
});
}
return response
.status(400)
.json({ error: 'Something went wrong, please try again later!' });
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: `api_get_document_list_${docType}`,
properties: { response_code: 404, doc_type: docType },
});
}
return response.status(404).json({ error: 'Report not available!' });
}
}
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!' });
}
}
@@ -0,0 +1,84 @@
export default async function getTemplate(request, response) {
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 Template = new Parse.Query('contracts_Template');
Template.equalTo('objectId', request.params.template_id);
Template.equalTo('CreatedBy', userPtr);
Template.notEqualTo('IsArchive', true);
Template.include('Signers');
Template.include('Folder');
Template.include('ExtUserPtr');
Template.include('Placeholders.signerPtr');
const res = await Template.first({ useMasterKey: true });
if (res) {
const template = JSON.parse(JSON.stringify(res));
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_template',
properties: { response_code: 200 },
});
}
return response.json({
objectId: template.objectId,
title: template.Name,
note: template.Note || '',
folder: { objectId: template?.Folder?.objectId, name: template?.Folder?.Name } || '',
file: template?.SignedUrl || template?.URL,
owner: template?.ExtUserPtr?.Name,
signers:
template?.Placeholders?.map(y => ({
role: y.Role,
name: y?.signerPtr?.Name || '',
email: y?.signerPtr?.Email || '',
phone: y?.signerPtr?.Phone || '',
widgets: y.placeHolder?.flatMap(x =>
x?.pos.map(w => ({
type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature',
x: w.xPosition,
y: w.yPosition,
w: w?.Width || 150,
h: w?.Height || 60,
page: x?.pageNumber,
}))
),
})) || [],
sendInOrder: template?.SendinOrder || false,
createdAt: template.createdAt,
updatedAt: template.updatedAt,
});
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_template',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'Template not found!' });
}
} 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!' });
}
}
@@ -0,0 +1,111 @@
import axios from 'axios';
import dotenv from 'dotenv';
dotenv.config();
export default async function getTemplatetList(request, response) {
const reqToken = request.headers['x-api-token'];
const appId = process.env.APP_ID;
const serverUrl = process.env.SERVER_URL;
if (!reqToken) {
return response.status(400).json({ error: 'Please Provide API Token' });
}
try {
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 limit = request?.query?.limit ? request.query.limit : 100;
const skip = request?.query?.skip ? request.query.skip : 0;
const clsName = 'contracts_Template';
const params = {
Type: { $ne: 'Folder' },
CreatedBy: userPtr,
IsArchive: { $ne: true },
};
const keys = [
'Name',
'Note',
'Description',
'Folder.Name',
'URL',
'SignedUrl',
'ExtUserPtr.Name',
'Signers.Name',
'Signers.Email',
'Signers.Phone',
'Placeholders',
];
const orderBy = '-updatedAt';
const strParams = JSON.stringify(params);
const strKeys = keys.join();
const headers = {
'Content-Type': 'application/json',
'X-Parse-Application-Id': appId,
'X-Parse-Master-Key': process.env.MASTER_KEY,
};
const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr,Placeholders.signerPtr`;
const res = await axios.get(url, { headers: headers });
if (res.data && res.data.results.length > 0) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_template_list',
properties: { response_code: 200 },
});
}
const updateRes = res.data.results.map(template => ({
objectId: template.objectId,
title: template.Name,
note: template.Note || '',
folder: { objectId: template?.Folder?.objectId, name: template?.Folder?.Name } || '',
file: template?.SignedUrl || template.URL,
owner: template?.ExtUserPtr?.Name,
signers:
template?.Placeholders?.map(y => ({
role: y.Role,
name: y?.signerPtr?.Name || '',
email: y?.signerPtr?.Email || '',
phone: y?.signerPtr?.Phone || '',
widgets: y.placeHolder?.flatMap(x =>
x?.pos.map(w => ({
type: w?.type ? w.type : w.isStamp ? 'stamp' : 'signature',
x: w.xPosition,
y: w.yPosition,
w: w?.Width || 150,
h: w?.Height || 60,
page: x?.pageNumber,
}))
),
})) || [],
sendInOrder: template?.SendinOrder || false,
createdAt: template.createdAt,
updatedAt: template.updatedAt,
}));
return response.json({ result: updateRes });
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_template_list',
properties: { response_code: 200 },
});
}
return response.json({ result: [] });
}
}
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!' });
}
}
@@ -0,0 +1,62 @@
import dotenv from 'dotenv';
dotenv.config();
export default async function getUser(request, response) {
const reqToken = request.headers['x-api-token'];
if (!reqToken) {
return response.status(400).json({ error: 'Please Provide API Token' });
}
try {
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 query = new Parse.Query('contracts_Users');
query.equalTo('UserId', userPtr);
query.exclude('IsContactEntry,TourStatus,UserRole,TenantId,UserId,CreatedBy,Plan');
const user = await query.first({ useMasterKey: true });
if (user) {
const parseRes = JSON.parse(JSON.stringify(user));
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_your_account_details',
properties: { response_code: 200 },
});
}
return response.json({
objectId: parseRes.objectId,
name: parseRes.Name,
email: parseRes.Email,
phone: parseRes.Phone,
jobTitle: parseRes.JobTitle,
company: parseRes.Company,
createdAt: parseRes.createdAt,
updatedAt: parseRes.updatedAt,
});
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_your_account_details',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'User not found!' });
}
}
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!' });
}
}
@@ -0,0 +1,55 @@
export default async function getWebhook(request, response) {
const reqToken = request.headers['x-api-token'];
if (!reqToken) {
return response.status(400).json({ error: 'Please Provide API Token' });
}
try {
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 query = new Parse.Query('contracts_Users');
query.equalTo('UserId', userPtr);
const user = await query.first({ useMasterKey: true });
if (user) {
const extUser = JSON.parse(JSON.stringify(user));
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_webhook',
properties: { response_code: 200 },
});
}
if (extUser && extUser.Webhook) {
return response.json({
webhook: extUser.Webhook,
});
} else {
return response.json({});
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_get_webhook',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'User not found!' });
}
} 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!' });
}
}
@@ -0,0 +1,85 @@
export default async function saveWebhook(request, response) {
const Url = request.body.url;
const reqToken = request.headers['x-api-token'];
if (!reqToken) {
return response.status(400).json({ error: 'Please Provide API Token' });
}
try {
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 query = new Parse.Query('contracts_Users');
query.equalTo('UserId', userPtr);
const user = await query.first({ useMasterKey: true });
if (user) {
const extUser = JSON.parse(JSON.stringify(user));
const isUrlExist = extUser?.Webhook && extUser?.Webhook === Url;
if (!isUrlExist) {
try {
const updateQuery = new Parse.Object('contracts_Users');
updateQuery.id = user.id;
updateQuery.set('Webhook', Url);
const res = await updateQuery.save(null, { useMasterKey: true });
if (res) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_save_webhook',
properties: { response_code: 200 },
});
}
return response.json({
result: 'Webhook updated successfully!',
});
}
} catch (err) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_save_webhook',
properties: { response_code: 400 },
});
}
console.log('Err ', err);
return response
.status(400)
.json({ error: 'Something went wrong, please try again later!' });
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_save_webhook',
properties: { response_code: 401 },
});
}
return response.status(401).json({ error: 'Webhook url already exists!' });
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_save_webhook',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'User not found!' });
}
} 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!' });
}
}
@@ -0,0 +1,93 @@
export default async function updateDocument(request, response) {
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 allowedKeys = ['name', 'note', 'description', 'folderId'];
const objectKeys = Object.keys(request.body);
const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0;
const parseUser = JSON.parse(JSON.stringify(token));
const userPtr = {
__type: 'Pointer',
className: '_User',
objectId: parseUser.userId.objectId,
};
if (isValid) {
const document = new Parse.Query('contracts_Document');
document.equalTo('objectId', request.params.document_id);
document.equalTo('CreatedBy', userPtr);
const res = await document.first({ useMasterKey: true });
if (res) {
const isArchive = res.get('IsArchive');
if (isArchive && isArchive) {
return response.status(404).json({ message: 'Document not found!' });
} else {
const document = Parse.Object.extend('contracts_Document');
const updateQuery = new document();
updateQuery.id = request.params.document_id;
if (request?.body?.name) {
updateQuery.set('Name', request?.body?.name);
}
if (request?.body?.note) {
updateQuery.set('Note', request?.body?.note);
}
if (request?.body?.description) {
updateQuery.set('Description', request?.body?.description);
}
if (request?.body?.folderId) {
updateQuery.set('Folder', {
__type: 'Pointer',
className: 'contracts_Document',
objectId: request?.body?.folderId,
});
}
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
if (updatedRes) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_update_document',
properties: { response_code: 200 },
});
}
return response.json({
objectId: updatedRes.id,
updatedAt: updatedRes.get('updatedAt'),
});
}
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_update_document',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'Document not found!' });
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_update_document',
properties: { response_code: 400 },
});
}
return response.status(400).json({ error: 'Please provide valid field names!' });
}
} 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!' });
}
}
@@ -0,0 +1,93 @@
export default async function updateTemplate(request, response) {
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 allowedKeys = ['name', 'note', 'description', 'folderId'];
const objectKeys = Object.keys(request.body);
const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0;
const parseUser = JSON.parse(JSON.stringify(token));
const userPtr = {
__type: 'Pointer',
className: '_User',
objectId: parseUser.userId.objectId,
};
if (isValid) {
const template = new Parse.Query('contracts_Template');
template.equalTo('objectId', request.params.template_id);
template.equalTo('CreatedBy', userPtr);
const res = await template.first({ useMasterKey: true });
if (res) {
const isArchive = res.get('IsArchive');
if (isArchive && isArchive) {
return response.status(404).json({ message: 'Template not found!' });
} else {
const template = Parse.Object.extend('contracts_Template');
const updateQuery = new template();
updateQuery.id = request.params.template_id;
if (request?.body?.name) {
updateQuery.set('Name', request?.body?.name);
}
if (request?.body?.note) {
updateQuery.set('Note', request?.body?.note);
}
if (request?.body?.description) {
updateQuery.set('Description', request?.body?.description);
}
if (request?.body?.folderId) {
updateQuery.set('Folder', {
__type: 'Pointer',
className: 'contracts_Template',
objectId: request?.body?.folderId,
});
}
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
if (updatedRes) {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_update_template',
properties: { response_code: 200 },
});
}
return response.json({
objectId: updatedRes.id,
updatedAt: updatedRes.get('updatedAt'),
});
}
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_update_template',
properties: { response_code: 404 },
});
}
return response.status(404).json({ error: 'Template not found!' });
}
} else {
if (request.posthog) {
request.posthog?.capture({
distinctId: parseUser.userId.email,
event: 'api_update_template',
properties: { response_code: 400 },
});
}
return response.status(400).json({ error: 'Please provide valid field names!' });
}
} 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!' });
}
}
+17 -5
View File
@@ -17,6 +17,12 @@ import getUserDetails from './parsefunction/getUserDetails.js';
import getDocument from './parsefunction/getDocument.js'; import getDocument from './parsefunction/getDocument.js';
import getDrive from './parsefunction/getDrive.js'; import getDrive from './parsefunction/getDrive.js';
import getReport from './parsefunction/getReport.js'; import getReport from './parsefunction/getReport.js';
import generateApiToken from './parsefunction/generateApiToken.js';
import getapitoken from './parsefunction/getapitoken.js';
import TemplateAfterSave from './parsefunction/TemplateAfterSave.js';
import GetTemplate from './parsefunction/GetTemplate.js';
import savewebhook from './parsefunction/saveWebhook.js';
import callWebhook from './parsefunction/callWebhook.js';
Parse.Cloud.define('AddUserToRole', addUserToGroups); Parse.Cloud.define('AddUserToRole', addUserToGroups);
Parse.Cloud.define('UserGroups', getUserGroups); Parse.Cloud.define('UserGroups', getUserGroups);
@@ -26,14 +32,20 @@ Parse.Cloud.define('googlesign', GoogleSign);
Parse.Cloud.define('zohodetails', ZohoDetails); Parse.Cloud.define('zohodetails', ZohoDetails);
Parse.Cloud.define('usersignup', usersignup); Parse.Cloud.define('usersignup', usersignup);
Parse.Cloud.define('facebooksign', FacebookSign); Parse.Cloud.define('facebooksign', FacebookSign);
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
Parse.Cloud.define('SendOTPMailV1', sendMailOTPv1); Parse.Cloud.define('SendOTPMailV1', sendMailOTPv1);
Parse.Cloud.define('sendmail', SendMailv1); Parse.Cloud.define('sendmail', SendMailv1);
Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail); Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail);
Parse.Cloud.define('getUserId', getUserId); Parse.Cloud.define('getUserId', getUserId);
Parse.Cloud.define('getUserDetails', getUserDetails); Parse.Cloud.define('getUserDetails', getUserDetails);
Parse.Cloud.define('getDocument', getDocument); Parse.Cloud.define('getDocument', getDocument);
Parse.Cloud.define('getDrive', getDrive) Parse.Cloud.define('getDrive', getDrive);
Parse.Cloud.define('getReport', getReport) Parse.Cloud.define('getReport', getReport);
Parse.Cloud.define('generateapitoken', generateApiToken);
Parse.Cloud.define('getapitoken', getapitoken);
Parse.Cloud.define('getTemplate', GetTemplate);
Parse.Cloud.define('savewebhook', savewebhook);
Parse.Cloud.define('callwebhook', callWebhook);
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave);
Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave);
Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave);
@@ -3,13 +3,13 @@ async function ContactbookAftersave(request) {
you can check as follows */ you can check as follows */
if (!request.original) { if (!request.original) {
const user = request.user; const user = request.user;
const object = request.object;
// Retrieve the current ACL // Retrieve the current ACL
const acl = new Parse.ACL(); const acl = new Parse.ACL();
// Ensure the current user has read access // Ensure the current user has read access
if (acl) { if (acl && request?.user) {
const object = request.object;
acl.setReadAccess(user, true); acl.setReadAccess(user, true);
acl.setWriteAccess(user, true); acl.setWriteAccess(user, true);
acl.setReadAccess(object.get('UserId'), true); acl.setReadAccess(object.get('UserId'), true);
@@ -4,20 +4,11 @@ async function DocumentAftersave(request) {
console.log('new entry is insert in contracts_Document'); console.log('new entry is insert in contracts_Document');
const createdAt = request.object.get('createdAt'); const createdAt = request.object.get('createdAt');
const Folder = request.object.get('Type'); const Folder = request.object.get('Type');
// console.log("createdAt")
// console.log(createdAt)
// console.log("Folder")
// console.log(Folder)
// console.log("before If condition")
if (createdAt && Folder === undefined) { if (createdAt && Folder === undefined) {
// console.log("IN If condition") // console.log("IN If condition")
const TimeToCompleteDays = request.object.get('TimeToCompleteDays'); const TimeToCompleteDays = request.object.get('TimeToCompleteDays');
const ExpiryDate = new Date(createdAt); const ExpiryDate = new Date(createdAt);
// console.log("ExpiryDate")
// console.log(ExpiryDate)
ExpiryDate.setDate(ExpiryDate.getDate() + TimeToCompleteDays); ExpiryDate.setDate(ExpiryDate.getDate() + TimeToCompleteDays);
// console.log("ExpiryDate date after update")
// console.log(ExpiryDate)
const documentQuery = new Parse.Query('contracts_Document'); const documentQuery = new Parse.Query('contracts_Document');
const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true }); const updateQuery = await documentQuery.get(request.object.id, { useMasterKey: true });
updateQuery.set('ExpiryDate', ExpiryDate); updateQuery.set('ExpiryDate', ExpiryDate);
@@ -37,21 +28,23 @@ async function DocumentAftersave(request) {
} }
const signers = request.object.get('Signers'); const signers = request.object.get('Signers');
// console.log("Signers")
// console.log(signers.length)
// update acl of New Document If There are signers present in array // update acl of New Document If There are signers present in array
if (signers && signers.length > 0) { if (signers && signers.length > 0) {
await updateAclDoc(request.object.id); await updateAclDoc(request.object.id);
} else { } else {
await updateSelfDoc(request.object.id); if (request?.object?.id && request.user) {
await updateSelfDoc(request.object.id);
}
} }
} else { } else {
if (request.user) { if (request?.user) {
const signers = request.object.get('Signers'); const signers = request.object.get('Signers');
if (signers && signers.length > 0) { if (signers && signers.length > 0) {
await updateAclDoc(request.object.id); await updateAclDoc(request.object.id);
} else { } else {
await updateSelfDoc(request.object.id); if (request?.object?.id) {
await updateSelfDoc(request.object.id);
}
} }
} }
} }
@@ -65,6 +58,7 @@ async function DocumentAftersave(request) {
// console.log(objId) // console.log(objId)
const Query = new Parse.Query('contracts_Document'); const Query = new Parse.Query('contracts_Document');
Query.include('Signers'); Query.include('Signers');
Query.include('CreatedBy');
const updateACL = await Query.get(objId, { useMasterKey: true }); const updateACL = await Query.get(objId, { useMasterKey: true });
const res = JSON.parse(JSON.stringify(updateACL)); const res = JSON.parse(JSON.stringify(updateACL));
// console.log("res"); // console.log("res");
@@ -87,9 +81,10 @@ async function DocumentAftersave(request) {
const newACL = new Parse.ACL(); const newACL = new Parse.ACL();
newACL.setPublicReadAccess(false); newACL.setPublicReadAccess(false);
newACL.setPublicWriteAccess(false); newACL.setPublicWriteAccess(false);
newACL.setReadAccess(request.user, true); if (res?.CreatedBy) {
newACL.setWriteAccess(request.user, true); newACL.setReadAccess(res?.CreatedBy?.objectId, true);
newACL.setWriteAccess(res?.CreatedBy?.objectId, true);
}
UsersPtr.forEach(x => { UsersPtr.forEach(x => {
newACL.setReadAccess(x.objectId, true); newACL.setReadAccess(x.objectId, true);
newACL.setWriteAccess(x.objectId, true); newACL.setWriteAccess(x.objectId, true);
@@ -100,9 +95,9 @@ async function DocumentAftersave(request) {
} }
async function updateSelfDoc(objId) { async function updateSelfDoc(objId) {
// console.log("In side updateSelfDoc func")
// console.log(objId) // console.log(objId)
const Query = new Parse.Query('contracts_Document'); const Query = new Parse.Query('contracts_Document');
Query.include('CreatedBy');
const updateACL = await Query.get(objId, { useMasterKey: true }); const updateACL = await Query.get(objId, { useMasterKey: true });
const res = JSON.parse(JSON.stringify(updateACL)); const res = JSON.parse(JSON.stringify(updateACL));
// console.log("res"); // console.log("res");
@@ -110,8 +105,10 @@ async function DocumentAftersave(request) {
const newACL = new Parse.ACL(); const newACL = new Parse.ACL();
newACL.setPublicReadAccess(false); newACL.setPublicReadAccess(false);
newACL.setPublicWriteAccess(false); newACL.setPublicWriteAccess(false);
newACL.setReadAccess(request.user, true); if (res?.CreatedBy) {
newACL.setWriteAccess(request.user, true); newACL.setReadAccess(res?.CreatedBy?.objectId, true);
newACL.setWriteAccess(res?.CreatedBy?.objectId, true);
}
updateACL.setACL(newACL); updateACL.setACL(newACL);
updateACL.save(null, { useMasterKey: true }); updateACL.save(null, { useMasterKey: true });
} }
@@ -0,0 +1,53 @@
import axios from 'axios';
export default async function GetTemplate(request) {
const serverUrl = process.env.SERVER_URL;
const templateId = request.params.templateId;
try {
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
const userId = userRes.data && userRes.data.objectId;
// console.log("templateId ", templateId)
// console.log("userId ",userId)
if (templateId && userId) {
try {
const template = new Parse.Query('contracts_Template');
template.equalTo('objectId', templateId);
template.include('ExtUserPtr');
template.include('Signers');
template.include('CreateBy');
const res = await template.first({ useMasterKey: true });
// console.log("res ", res)
if (res) {
// console.log("res ",res)
const acl = res.getACL();
console.log("acl", acl.getReadAccess(userId))
if (acl && acl.getReadAccess(userId)) {
return res;
} else {
return { error: "You don't have access of this document!" };
}
} else {
return { error: "You don't have access of this document!" };
}
} catch (err) {
console.log('err', err);
return err;
}
} else {
return { error: 'Please pass required parameters!' };
}
} catch (err) {
console.log('err', err);
if (err.code == 209) {
return { error: 'Invalid session token' };
} else {
return { error: "You don't have access of this document!" };
}
}
}
@@ -0,0 +1,93 @@
export default async function TemplateAfterSave(request) {
try {
if (!request.original) {
console.log('new entry is insert in contracts_Template');
// update acl of New Document If There are signers present in array
const signers = request.object.get('Signers');
if (signers && signers.length > 0) {
await updateAclDoc(request.object.id);
} else {
if (request?.object?.id && request?.user) {
await updateSelfDoc(request.object.id);
}
}
} else {
if (request?.user) {
const signers = request.object.get('Signers');
if (signers && signers.length > 0) {
await updateAclDoc(request.object.id);
} else {
if (request?.object?.id) {
await updateSelfDoc(request.object.id);
}
}
}
}
} catch (err) {
console.log('err in aftersave of contracts_Template');
console.log(err);
}
async function updateAclDoc(objId) {
// console.log("In side updateAclDoc func")
// console.log(objId)
const Query = new Parse.Query('contracts_Template');
Query.include('Signers');
Query.include('CreatedBy');
const updateACL = await Query.get(objId, { useMasterKey: true });
const res = JSON.parse(JSON.stringify(updateACL));
// console.log("res");
// console.log(JSON.stringify(res));
const UsersPtr = res.Signers.map(item => item.UserId);
if (res.Signers[0].ExtUserPtr) {
const ExtUserSigners = res.Signers.map(item => {
return {
__type: 'Pointer',
className: 'contracts_Users',
objectId: item.ExtUserPtr.objectId,
};
});
updateACL.set('Signers', ExtUserSigners);
}
// console.log("UsersPtr")
// console.log(JSON.stringify(UsersPtr))
const newACL = new Parse.ACL();
newACL.setPublicReadAccess(false);
newACL.setPublicWriteAccess(false);
if (res?.CreatedBy) {
newACL.setReadAccess(res?.CreatedBy?.objectId, true);
newACL.setWriteAccess(res?.CreatedBy?.objectId, true);
}
UsersPtr.forEach(x => {
newACL.setReadAccess(x.objectId, true);
newACL.setWriteAccess(x.objectId, true);
});
updateACL.setACL(newACL);
updateACL.save(null, { useMasterKey: true });
}
async function updateSelfDoc(objId) {
// console.log("Inside updateSelfDoc func")
const Query = new Parse.Query('contracts_Template');
Query.include('CreatedBy');
const updateACL = await Query.get(objId, { useMasterKey: true });
const res = JSON.parse(JSON.stringify(updateACL));
// console.log("res");
// console.log(JSON.stringify(res));
const newACL = new Parse.ACL();
newACL.setPublicReadAccess(false);
newACL.setPublicWriteAccess(false);
if (res?.CreatedBy) {
newACL.setReadAccess(res?.CreatedBy?.objectId, true);
newACL.setWriteAccess(res?.CreatedBy?.objectId, true);
}
updateACL.setACL(newACL);
updateACL.save(null, { useMasterKey: true });
}
}
@@ -0,0 +1,66 @@
import axios from 'axios';
export default async function callWebhook(request) {
const event = request.params.event;
const body = request.params.body;
const serverUrl = process.env.SERVER_URL;
const appId = process.env.APP_ID;
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': appId,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
const userId = userRes.data && userRes.data.objectId;
if (userId) {
const extendcls = new Parse.Query('contracts_Users');
extendcls.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
const res = await extendcls.first({ useMasterKey: true });
if (res) {
const extUser = JSON.parse(JSON.stringify(res));
if (extUser?.Webhook) {
const params = {
event: event,
...body,
};
await axios
.post(extUser?.Webhook, params, {
headers: { 'Content-Type': 'application/json' },
})
.then(res => {
try {
// console.log('res ', res);
const webhook = new Parse.Object('contracts_Webhook');
webhook.set('Log', res?.status);
webhook.set('UserId', {
__type: 'Pointer',
className: '_User',
objectId: userId,
});
webhook.save(null, { useMasterKey: true });
} catch (err) {
console.log('err save in contracts_Webhook', err);
}
})
.catch(err => {
console.log('Err send data to webhook', err);
try {
const webhook = new Parse.Object('contracts_Webhook');
webhook.set('Log', err?.status);
webhook.set('UserId', {
__type: 'Pointer',
className: '_User',
objectId: userId,
});
webhook.save(null, { useMasterKey: true });
} catch (err) {
console.log('err save in contracts_Webhook', err);
}
});
}
return { message: 'webhook called!' };
}
} else {
return { message: 'User not found!' };
}
}
@@ -0,0 +1,44 @@
import { generateApiKey } from 'generate-api-key';
import axios from 'axios';
export default async function generateApiToken(request) {
const serverUrl = process.env.SERVER_URL;
try {
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
const userId = userRes.data && userRes.data.objectId;
if (userId) {
const tokenQuery = new Parse.Query('appToken');
tokenQuery.equalTo('userId', { __type: 'Pointer', className: '_User', objectId: userId });
const token = await tokenQuery.first({ useMasterKey: true });
if (token !== undefined) {
// return exsiting Token
console.log('Regenerate API Token');
const AppToken = Parse.Object.extend('appToken');
const updateToken = new AppToken();
updateToken.id = token.id;
const newToken = generateApiKey({ method: 'base62', prefix: 'opensign' });
updateToken.set('token', newToken);
const updatedRes = await updateToken.save(null, { useMasterKey: true });
return updatedRes;
} else {
// Create New Token
console.log('New API Token Generation');
const appToken = Parse.Object.extend('appToken');
const appTokenQuery = new appToken();
const token = generateApiKey({ method: 'base62', prefix: 'opensign' });
appTokenQuery.set('token', token);
appTokenQuery.set('userId', { __type: 'Pointer', className: '_User', objectId: userId });
const newRes = await appTokenQuery.save(null, { useMasterKey: true });
return newRes;
}
} else {
return 'User not found!';
}
} catch (err) {
console.log('err ', err);
}
}
@@ -21,6 +21,7 @@ export default async function getDocument(request) {
query.include('Signers'); query.include('Signers');
query.include('AuditTrail.UserPtr'); query.include('AuditTrail.UserPtr');
query.include('Placeholders'); query.include('Placeholders');
query.notEqualTo('IsArchive', true)
const res = await query.first({ useMasterKey: true }); const res = await query.first({ useMasterKey: true });
if (res) { if (res) {
const acl = res.getACL(); const acl = res.getACL();
@@ -40,7 +41,7 @@ export default async function getDocument(request) {
return { error: 'Please pass required parameters!' }; return { error: 'Please pass required parameters!' };
} }
} catch (err) { } catch (err) {
console.log('err'); console.log('err', err);
if (err.code == 209) { if (err.code == 209) {
return { error: 'Invalid session token' }; return { error: 'Invalid session token' };
} else { } else {
@@ -16,9 +16,9 @@ export default async function getDrive(request) {
if (userId) { if (userId) {
let url; let url;
if (docId) { if (docId) {
url = `${classUrl}?where={"Folder":{"__type":"Pointer","className":"contracts_Document","objectId":"${docId}"},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"}}&include=ExtUserPtr,Signers,Folder`; url = `${classUrl}?where={"Folder":{"__type":"Pointer","className":"contracts_Document","objectId":"${docId}"},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,Signers,Folder`;
} else { } else {
url = `${classUrl}?where={"Folder":{"$exists":false},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"}}&include=ExtUserPtr,Signers`; url = `${classUrl}?where={"Folder":{"$exists":false},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${userId}"},"IsArchive":{"$ne":true}}&include=ExtUserPtr,Signers`;
} }
try { try {
const res = await axios.get(url, { const res = await axios.get(url, {
@@ -19,7 +19,7 @@ export default async function getReport(request) {
const userId = userRes.data && userRes.data.objectId; const userId = userRes.data && userRes.data.objectId;
if (userId) { if (userId) {
const json = reportId && reportJson(reportId, userId); const json = reportId && reportJson(reportId, userId);
const clsName = reportId === '5KhaPr482K' ? 'contracts_Contactbook' : 'contracts_Document'; const clsName = json?.reportClass ? json.reportClass : 'contracts_Document';
if (json) { if (json) {
const { params, keys } = json; const { params, keys } = json;
const orderBy = '-updatedAt'; const orderBy = '-updatedAt';
@@ -1,9 +1,13 @@
async function getUserDetails(request) { async function getUserDetails(request) {
try { try {
const userId = request.params.userId;
const userQuery = new Parse.Query('contracts_Users'); const userQuery = new Parse.Query('contracts_Users');
userQuery.equalTo('Email', request.params.email); userQuery.equalTo('Email', request.params.email);
userQuery.include('TenantId'); userQuery.include('TenantId');
userQuery.include('UserId') userQuery.include('UserId');
if (userId) {
userQuery.equalTo('CreatedBy', { __type: 'Pointer', className: '_User', objectId: userId });
}
const res = await userQuery.first({ useMasterKey: true }); const res = await userQuery.first({ useMasterKey: true });
return res; return res;
} catch (err) { } catch (err) {
@@ -0,0 +1,29 @@
import axios from 'axios';
export default async function getapitoken(request) {
const serverUrl = process.env.SERVER_URL;
try {
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
const userId = userRes.data && userRes.data.objectId;
if (userId) {
const tokenQuery = new Parse.Query('appToken');
tokenQuery.equalTo('userId', { __type: 'Pointer', className: '_User', objectId: userId });
const res = await tokenQuery.first({ useMasterKey: true });
if (res) {
return { status: 'success', result: res.get('token') };
}
}
} catch (err) {
console.log('Err', err);
console.log('err', err);
if (err.code == 209) {
return { error: 'Invalid session token' };
} else {
return { error: "You don't have access!" };
}
}
}
+189 -105
View File
@@ -1,40 +1,36 @@
import SignPDF from './SignPDF.min.cjs'; import SignPDF from './SignPDF.min.cjs';
import fs from 'node:fs'; import fs from 'node:fs';
import axios from 'axios'; import axios from 'axios';
import FormData from 'form-data';
import plainplaceholder from './customSignPdf/plainplaceholder.min.js';
import { plainAddPlaceholder } from 'node-signpdf/dist/helpers/index.js'; import { plainAddPlaceholder } from 'node-signpdf/dist/helpers/index.js';
const serverUrl = process.env.SERVER_URL, const serverUrl = process.env.SERVER_URL,
APPID = process.env.APP_ID, APPID = process.env.APP_ID,
masterKEY = process.env.MASTER_KEY; masterKEY = process.env.MASTER_KEY;
async function uploadFile(a) { async function uploadFile(e, a) {
try { try {
var e = new FormData(), var t = fs.readFileSync(a),
t = s = new Parse.File(e, [...t]),
(e.append('file', fs.createReadStream(a)), r = (await s.save({ useMasterKey: !0 }), s.url());
{ 'content-type': 'multipart/form-data', 'X-Parse-Application-Id': process.env.APP_ID }), return { imageUrl: r };
s = process.env.SERVER_URL.slice(0, -4) + '/file_upload';
return (await axios.post(s, e, { headers: t })).data;
} catch (e) { } catch (e) {
console.log('err ', e), fs.unlinkSync(a); console.log('Err ', e), fs.unlinkSync(a);
} }
} }
async function updateDoc(t, s, r, i, o, n) { async function updateDoc(t, s, r, i, n, o) {
try { try {
var d = { var d = {
UserPtr: { __type: 'Pointer', className: n, objectId: r }, UserPtr: { __type: 'Pointer', className: o, objectId: r },
SignedUrl: s, SignedUrl: s,
Activity: 'Signed', Activity: 'Signed',
ipAddress: i, ipAddress: i,
}; };
let e; let e;
var l = (e = o.AuditTrail && 0 < o.AuditTrail.length ? [...o.AuditTrail, d] : [d]).filter( var l = (e = n.AuditTrail && 0 < n.AuditTrail.length ? [...n.AuditTrail, d] : [d]).filter(
e => 'Signed' === e.Activity e => 'Signed' === e.Activity
); );
let a = !1; let a = !1;
!((o.Signers && 0 < o.Signers.length && l.length !== o.Signers.length) || !(a = !0)); !((n.Signers && 0 < n.Signers.length && l.length !== n.Signers.length) || !(a = !0));
var p = { SignedUrl: s, AuditTrail: e, IsCompleted: a }; var c = { SignedUrl: s, AuditTrail: e, IsCompleted: a };
await axios.put(serverUrl + '/classes/contracts_Document/' + t, p, { await axios.put(serverUrl + '/classes/contracts_Document/' + t, c, {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-Parse-Application-Id': APPID, 'X-Parse-Application-Id': APPID,
@@ -59,9 +55,9 @@ async function sendMail(e) {
html: html:
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=https://qikinnovation.ams3.digitaloceanspaces.com/logo.png height='50' style='padding:20px'/> </div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document Copy</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document " + "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=https://qikinnovation.ams3.digitaloceanspaces.com/logo.png height='50' style='padding:20px'/> </div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document Copy</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document " +
s + s +
' Standard is attached to this email. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from Open Sign. For any queries regarding this email, please contact the sender ' + ' Standard is attached to this email. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from OpenSign. For any queries regarding this email, please contact the sender ' +
t.Mail + t.Mail +
' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.</p></div></div></body></html>', ' directly. If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>',
}; };
await axios.post(serverUrl + '/functions/sendmailv3', a, { await axios.post(serverUrl + '/functions/sendmailv3', a, {
headers: { headers: {
@@ -84,9 +80,9 @@ async function sendCompletedMail(e) {
html: html:
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=https://qikinnovation.ams3.digitaloceanspaces.com/logo.png height='50' style='padding:20px'/> </div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document sign successfully</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>All parties have successfully signed the document" + "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=https://qikinnovation.ams3.digitaloceanspaces.com/logo.png height='50' style='padding:20px'/> </div><div style='padding:2px;font-family:system-ui; background-color: #47a3ad;'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document sign successfully</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>All parties have successfully signed the document" +
s + s +
'. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from Open Sign. For any queries regarding this email, please contact the sender ' + '. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from OpenSign. For any queries regarding this email, please contact the sender ' +
t.Mail + t.Mail +
' directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.</p></div></div></body></html>', ' directly. If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href=www.opensignlabs.com target=_blank>here</a>.</p></div></div></body></html>',
}; };
await axios.post(serverUrl + '/functions/sendmailv3', a, { await axios.post(serverUrl + '/functions/sendmailv3', a, {
headers: { headers: {
@@ -96,115 +92,203 @@ async function sendCompletedMail(e) {
}, },
}); });
} }
async function PDF(s, r) { async function sendDoctoWebhook(t, e, a, s) {
try { let r = [];
var i = s.params.sign, (r = s
e = s.params.docId, ? { name: s?.Name, email: s?.Email, phone: s?.Phone }
o = s.params.userId, : t?.data?.Signers?.map(e => ({ name: e.Name, email: e.Email, phone: e.Phone })) || [
n = await axios.get(serverUrl + '/classes/contracts_Document/' + e + '?include=ExtUserPtr', { {
headers: { name: t?.data?.ExtUserPtr?.Name,
'Content-Type': 'application/json', email: t?.data?.ExtUserPtr?.Email,
'X-Parse-Application-Id': APPID, phone: t?.data?.ExtUserPtr?.Phone,
'X-Parse-Master-Key': masterKEY,
}, },
]),
t.data.ExtUserPtr?.Webhook &&
((s =
'signed' === a
? { signer: r, signedAt: new Date() }
: { signers: r, completedAt: new Date() }),
(a = {
event: a,
objectId: t?.data?.objectId,
file: e || '',
name: t?.data?.Name,
note: t?.data?.Note || '',
description: t?.data?.Description || '',
...s,
createdAt: t?.data?.createdAt,
}), }),
d = await axios.get(serverUrl + '/users/me', { await axios
.post(t?.data?.ExtUserPtr?.Webhook, a, { headers: { 'Content-Type': 'application/json' } })
.then(e => {
try {
var a = new Parse.Object('contracts_Webhook');
a.set('Log', e?.status),
a.set('UserId', {
__type: 'Pointer',
className: '_User',
objectId: t.data.ExtUserPtr.UserId.objectId,
}),
a.save(null, { useMasterKey: !0 });
} catch (e) {
console.log('err save in contracts_Webhook', e);
}
})
.catch(e => {
console.log('Err send data to webhook', e);
try {
var a = new Parse.Object('contracts_Webhook');
a.set('Log', e?.status),
a.set('UserId', {
__type: 'Pointer',
className: '_User',
objectId: t.data.ExtUserPtr.UserId.objectId,
}),
a.save(null, { useMasterKey: !0 });
} catch (e) {
console.log('err save in contracts_Webhook', e);
}
}));
}
async function PDF(i, n) {
try {
i.params.sign;
var e = i.params.docId,
a = i.params.userId,
o = await axios.get(
serverUrl + '/classes/contracts_Document/' + e + '?include=ExtUserPtr,Signers',
{
headers: {
'Content-Type': 'application/json',
'X-Parse-Application-Id': APPID,
'X-Parse-Master-Key': masterKEY,
},
}
),
t = await axios.get(serverUrl + '/users/me', {
headers: { headers: {
'X-Parse-Application-Id': APPID, 'X-Parse-Application-Id': APPID,
'X-Parse-Session-Token': s.headers.sessiontoken, 'X-Parse-Session-Token': i.headers.sessiontoken,
}, },
}); });
if (!d.data || !d.data.objectId) return { status: 'error', message: 'this user not allowed!' }; if (!t.data || !t.data.objectId) return { status: 'error', message: 'this user not allowed!' };
{ {
var l, var d,
p, l,
c, c,
m = JSON.stringify({ objectId: o }); p = JSON.stringify({ objectId: a });
let a, t; let s, r;
t = o r = a
? (l = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + m, { ? (d = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + p, {
headers: { headers: {
'X-Parse-Application-Id': APPID, 'X-Parse-Application-Id': APPID,
'X-Parse-Session-Token': s.headers.sessiontoken, 'X-Parse-Session-Token': i.headers.sessiontoken,
}, },
})).data && 0 < l.data.results.length })).data && 0 < d.data.results.length
? ((a = l), 'contracts_Contactbook') ? ((s = d), 'contracts_Contactbook')
: ((a = await axios.get(serverUrl + '/classes/contracts_Users?where=' + m, { : ((s = await axios.get(serverUrl + '/classes/contracts_Users?where=' + p, {
headers: { headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
'X-Parse-Application-Id': APPID,
'X-Parse-Master-Key': masterKEY,
},
})), })),
'contracts_Users') 'contracts_Users')
: ((p = JSON.stringify({ : ((l = JSON.stringify({
UserId: { __type: 'Pointer', className: '_User', objectId: d.data.objectId }, UserId: { __type: 'Pointer', className: '_User', objectId: t.data.objectId },
})), })),
(c = await axios.get(serverUrl + '/classes/contracts_Users?where=' + p, { (c = await axios.get(serverUrl + '/classes/contracts_Users?where=' + l, {
headers: { headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
'X-Parse-Application-Id': APPID,
'X-Parse-Master-Key': masterKEY,
},
})).data && 0 < c.data.results.length })).data && 0 < c.data.results.length
? ((a = c), 'contracts_Users') ? ((s = c), 'contracts_Users')
: ((a = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + p, { : ((s = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + l, {
headers: { headers: {
'X-Parse-Application-Id': APPID, 'X-Parse-Application-Id': APPID,
'X-Parse-Session-Token': s.headers.sessiontoken, 'X-Parse-Session-Token': i.headers.sessiontoken,
}, },
})), })),
'contracts_Contactbook')); 'contracts_Contactbook'));
var g = a.data.results[0].Name, var m = s.data.results[0].Name,
h = a.data.results[0].Email; g = s.data.results[0].Email;
if (!s.params.pdfFile) return { status: 'error', message: 'pdf file not present!' }; if (!i.params.pdfFile) return { status: 'error', message: 'pdf file not present!' };
{ {
let e = Buffer.from(s.params.pdfFile, 'base64'); let e = Buffer.from(i.params.pdfFile, 'base64');
var u = process.env.PFX_BASE64, var h = process.env.PFX_BASE64,
f = Buffer.from(u, 'base64'); u = Buffer.from(h, 'base64'),
e = i f = {
? plainplaceholder({ UserPtr: { __type: 'Pointer', className: r, objectId: s.data.results[0].objectId },
pdfBuffer: e, SignedUrl: '',
reason: 'Digitally signed by Open sign for ' + g + ' <' + h + '>', Activity: 'Signed',
location: 'test location', ipAddress: i.headers['x-real-ip'],
signatureLength: 1e4, };
sign: i, let a;
}) var y = (a =
: plainAddPlaceholder({ o.data.AuditTrail && 0 < o.data.AuditTrail.length
pdfBuffer: e, ? [...o.data.AuditTrail, f]
reason: 'Digitally signed by Open sign for ' + g + ' <' + h + '>', : [f]).filter(e => 'Signed' === e.Activity);
location: 'test location', let t = !1;
signatureLength: 1e4, !(
}); (o.data.Signers && 0 < o.data.Signers.length && y.length !== o.data.Signers.length) ||
var y = await new SignPDF(e, f).signPDF(), !(t = !0)
v = `./exports/exported_file_${Math.floor(5e3 * Math.random())}.pdf`, );
P = (fs.writeFileSync(v, y), await uploadFile(v)); var v,
if (P && P.imageUrl) { P,
const r = await updateDoc( b = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`,
s.params.docId, x = './exports/' + b,
P.imageUrl, U =
a.data.results[0].objectId, (t
s.headers['x-real-ip'], ? ((v = o.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')),
n.data, (e =
t v && 0 < v.length
? plainAddPlaceholder({
pdfBuffer: e,
reason: 'Digitally signed by OpenSign for ' + v?.join(', '),
location: 'location',
signatureLength: 1e4,
})
: plainAddPlaceholder({
pdfBuffer: e,
reason: 'Digitally signed by OpenSign for ' + m + ' <' + g + '>',
location: 'location',
signatureLength: 1e4,
})),
(P = await new SignPDF(e, u).signPDF()),
fs.writeFileSync(x, P))
: fs.writeFileSync(x, e),
await uploadFile(b, x));
if (U && U.imageUrl) {
const n = await updateDoc(
i.params.docId,
U.imageUrl,
s.data.results[0].objectId,
i.headers['x-real-ip'],
o.data,
r
); );
var I,
w = {
url: U.imageUrl,
sender: { Mail: o.data.ExtUserPtr.Email, Name: o.data.ExtUserPtr.Name },
pdfName: o.data.Name,
receiver: g,
};
return ( return (
sendMail({ o.data.IsSendMail && !1 === o.data.IsSendMail
url: P.imageUrl, ? console.log("don't send mail")
sender: { Mail: n.data.ExtUserPtr.Email, Name: n.data.ExtUserPtr.Name }, : sendMail(w),
pdfName: n.data.Name, sendDoctoWebhook(o, U.imageUrl, 'signed', s?.data.results?.[0]),
receiver: h, n &&
}), n.isCompleted &&
r && ((I = {
r.isCompleted && url: U.imageUrl,
sendCompletedMail({ sender: { Mail: o.data.ExtUserPtr.Email, Name: 'OpenSign™' },
url: P.imageUrl, pdfName: o.data.Name,
sender: { Mail: n.data.ExtUserPtr.Email, Name: 'Open sign' }, receiver: o.data.ExtUserPtr.Email,
pdfName: n.data.Name,
receiver: n.data.ExtUserPtr.Email,
}), }),
fs.unlinkSync(v), o.data.IsSendMail && !1 === o.data.IsSendMail
console.log('New Signed PDF created called: ' + v), ? console.log("don't send mail")
'success' === r.message : sendCompletedMail(I),
? { status: 'success', data: P.imageUrl } sendDoctoWebhook(o, U.imageUrl, 'completed')),
fs.unlinkSync(x),
console.log('New Signed PDF created called: ' + x),
'success' === n.message
? { status: 'success', data: U.imageUrl }
: { status: 'error', message: 'please provide required parameters!' } : { status: 'error', message: 'please provide required parameters!' }
); );
} }
@@ -7,9 +7,13 @@ export default function reportJson(id, userId) {
return { return {
reportName: 'Draft Documents', reportName: 'Draft Documents',
params: { params: {
Type: null, Type: { $ne: 'Folder' },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
IsArchive: { $ne: true },
$or: [ $or: [
{ Signers: null, SignedUrl: null }, { Signers: { $eq: [] } },
{ Signers: null },
{ Signers: { $exists: true }, Placeholders: null }, { Signers: { $exists: true }, Placeholders: null },
], ],
CreatedBy: { CreatedBy: {
@@ -18,7 +22,16 @@ export default function reportJson(id, userId) {
objectId: currentUserId, objectId: currentUserId,
}, },
}, },
keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], keys: [
'Name',
'Note',
'Folder.Name',
'URL',
'ExtUserPtr.Name',
'Signers.Name',
'Signers.Email',
'Signers.Phone',
],
}; };
// Need your sign report // Need your sign report
case '4Hhwbp482K': case '4Hhwbp482K':
@@ -28,10 +41,23 @@ export default function reportJson(id, userId) {
Type: { $ne: 'Folder' }, Type: { $ne: 'Folder' },
IsCompleted: { $ne: true }, IsCompleted: { $ne: true },
IsDeclined: { $ne: true }, IsDeclined: { $ne: true },
IsArchive: { $ne: true },
ExpiryDate: { ExpiryDate: {
$gt: { __type: 'Date', iso: new Date().toISOString() }, $gt: { __type: 'Date', iso: new Date().toISOString() },
}, },
Placeholders: { $ne: null }, Placeholders: { $ne: null },
Signers: {
$inQuery: {
where: {
UserId: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
},
className: 'contracts_Contactbook',
},
},
}, },
keys: [ keys: [
'Name', 'Name',
@@ -40,6 +66,8 @@ export default function reportJson(id, userId) {
'URL', 'URL',
'ExtUserPtr.Name', 'ExtUserPtr.Name',
'Signers.Name', 'Signers.Name',
'Signers.Email',
'Signers.Phone',
'Signers.UserId', 'Signers.UserId',
'AuditTrail', 'AuditTrail',
], ],
@@ -50,10 +78,11 @@ export default function reportJson(id, userId) {
reportName: 'In-progress documents', reportName: 'In-progress documents',
params: { params: {
Type: { $ne: 'Folder' }, Type: { $ne: 'Folder' },
Signers: { $ne: null }, Signers: { $exists: true, $ne: [] },
Placeholders: { $ne: null }, Placeholders: { $ne: null },
IsCompleted: { $ne: true }, IsCompleted: { $ne: true },
IsDeclined: { $ne: true }, IsDeclined: { $ne: true },
IsArchive: { $ne: true },
CreatedBy: { CreatedBy: {
__type: 'Pointer', __type: 'Pointer',
className: '_User', className: '_User',
@@ -63,22 +92,6 @@ export default function reportJson(id, userId) {
$gt: { __type: 'Date', iso: new Date().toISOString() }, $gt: { __type: 'Date', iso: new Date().toISOString() },
}, },
}, },
keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'],
};
// completed documents report
case 'kQUoW4hUXz':
return {
reportName: 'Completed Documents',
params: {
Type: null,
IsCompleted: true,
CreatedBy: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
IsDeclined: { $ne: true },
},
keys: [ keys: [
'Name', 'Name',
'Note', 'Note',
@@ -86,6 +99,35 @@ export default function reportJson(id, userId) {
'URL', 'URL',
'ExtUserPtr.Name', 'ExtUserPtr.Name',
'Signers.Name', 'Signers.Name',
'Signers.Email',
'Signers.Phone',
],
};
// completed documents report
case 'kQUoW4hUXz':
return {
reportName: 'Completed Documents',
params: {
Type: { $ne: 'Folder' },
IsCompleted: true,
CreatedBy: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
IsDeclined: { $ne: true },
IsArchive: { $ne: true },
},
keys: [
'Name',
'Note',
'Folder.Name',
'URL',
'SignedUrl',
'ExtUserPtr.Name',
'Signers.Name',
'Signers.Email',
'Signers.Phone',
'TimeToCompleteDays', 'TimeToCompleteDays',
], ],
}; };
@@ -96,6 +138,7 @@ export default function reportJson(id, userId) {
reportName: 'Declined Documents', reportName: 'Declined Documents',
params: { params: {
Type: null, Type: null,
IsArchive: { $ne: true },
IsDeclined: true, IsDeclined: true,
CreatedBy: { CreatedBy: {
__type: 'Pointer', __type: 'Pointer',
@@ -104,7 +147,16 @@ export default function reportJson(id, userId) {
}, },
}, },
keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], keys: [
'Name',
'Note',
'Folder.Name',
'URL',
'ExtUserPtr.Name',
'Signers.Name',
'Signers.Email',
'Signers.Phone',
],
}; };
// Expired Documents report // Expired Documents report
case 'zNqBHXHsYH': case 'zNqBHXHsYH':
@@ -113,6 +165,7 @@ export default function reportJson(id, userId) {
params: { params: {
IsCompleted: { $ne: true }, IsCompleted: { $ne: true },
IsDeclined: { $ne: true }, IsDeclined: { $ne: true },
IsArchive: { $ne: true },
Type: { $ne: 'Folder' }, Type: { $ne: 'Folder' },
$and: [ $and: [
{ {
@@ -133,7 +186,16 @@ export default function reportJson(id, userId) {
objectId: currentUserId, objectId: currentUserId,
}, },
}, },
keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], keys: [
'Name',
'Note',
'Folder.Name',
'URL',
'ExtUserPtr.Name',
'Signers.Name',
'Signers.Email',
'Signers.Phone',
],
}; };
// Recently sent for signatures report show on dashboard // Recently sent for signatures report show on dashboard
case 'd9k3UfYHBc': case 'd9k3UfYHBc':
@@ -141,10 +203,11 @@ export default function reportJson(id, userId) {
reportName: 'Recently sent for signatures', reportName: 'Recently sent for signatures',
params: { params: {
Type: { $ne: 'Folder' }, Type: { $ne: 'Folder' },
Signers: { $ne: null }, Signers: { $exists: true, $ne: [] },
Placeholders: { $ne: null }, Placeholders: { $ne: null },
IsCompleted: { $ne: true }, IsCompleted: { $ne: true },
IsDeclined: { $ne: true }, IsDeclined: { $ne: true },
IsArchive: { $ne: true },
CreatedBy: { CreatedBy: {
__type: 'Pointer', __type: 'Pointer',
className: '_User', className: '_User',
@@ -154,7 +217,15 @@ export default function reportJson(id, userId) {
$gt: { __type: 'Date', iso: new Date().toISOString() }, $gt: { __type: 'Date', iso: new Date().toISOString() },
}, },
}, },
keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], keys: [
'Name',
'Folder.Name',
'URL',
'ExtUserPtr.Name',
'Signers.Name',
'Signers.Email',
'Signers.Phone',
],
}; };
// Recent signature requests report show on dashboard // Recent signature requests report show on dashboard
case '5Go51Q7T8r': case '5Go51Q7T8r':
@@ -164,20 +235,33 @@ export default function reportJson(id, userId) {
Type: { $ne: 'Folder' }, Type: { $ne: 'Folder' },
IsCompleted: { $ne: true }, IsCompleted: { $ne: true },
IsDeclined: { $ne: true }, IsDeclined: { $ne: true },
IsArchive: { $ne: true },
ExpiryDate: { ExpiryDate: {
$gt: { __type: 'Date', iso: new Date().toISOString() }, $gt: { __type: 'Date', iso: new Date().toISOString() },
}, },
Placeholders: { $ne: null }, Placeholders: { $ne: null },
Signers: {
$inQuery: {
where: {
UserId: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
},
className: 'contracts_Contactbook',
},
},
}, },
keys: [ keys: [
'Name', 'Name',
'Note',
'Folder.Name',
'URL', 'URL',
'ExtUserPtr.Name', 'ExtUserPtr.Name',
'Signers.Name', 'Signers.Name',
'Signers.UserId', 'Signers.UserId',
'AuditTrail', 'AuditTrail',
'Signers.Email',
'Signers.Phone',
], ],
}; };
// Drafts report show on dashboard // Drafts report show on dashboard
@@ -185,9 +269,13 @@ export default function reportJson(id, userId) {
return { return {
reportName: 'Drafts', reportName: 'Drafts',
params: { params: {
Type: null, Type: { $ne: 'Folder' },
IsCompleted: { $ne: true },
IsDeclined: { $ne: true },
IsArchive: { $ne: true },
$or: [ $or: [
{ Signers: null, SignedUrl: null }, { Signers: { $eq: [] } },
{ Signers: null },
{ Signers: { $exists: true }, Placeholders: null }, { Signers: { $exists: true }, Placeholders: null },
], ],
CreatedBy: { CreatedBy: {
@@ -196,12 +284,22 @@ export default function reportJson(id, userId) {
objectId: currentUserId, objectId: currentUserId,
}, },
}, },
keys: ['Name', 'Note', 'Folder.Name', 'URL', 'ExtUserPtr.Name', 'Signers.Name'], keys: [
'Name',
'Note',
'Folder.Name',
'URL',
'ExtUserPtr.Name',
'Signers.Name',
'Signers.Email',
'Signers.Phone',
],
}; };
// contact book report // contact book report
case '5KhaPr482K': case '5KhaPr482K':
return { return {
reportName: 'Contactbook', reportName: 'Contactbook',
reportClass: 'contracts_Contactbook',
params: { params: {
CreatedBy: { CreatedBy: {
__type: 'Pointer', __type: 'Pointer',
@@ -212,6 +310,31 @@ export default function reportJson(id, userId) {
}, },
keys: ['Name', 'Email', 'Phone'], keys: ['Name', 'Email', 'Phone'],
}; };
// Templates report
case '6TeaPr321t':
return {
reportName: 'Templates',
reportClass: 'contracts_Template',
params: {
Type: { $ne: 'Folder' },
IsArchive: { $ne: true },
CreatedBy: {
__type: 'Pointer',
className: '_User',
objectId: currentUserId,
},
},
keys: [
'Name',
'Note',
'Folder.Name',
'URL',
'ExtUserPtr.Name',
'Signers.Name',
'Signers.Email',
'Signers.Phone',
],
};
default: default:
return null; return null;
} }
@@ -0,0 +1,29 @@
import axios from 'axios';
export default async function savewebhook(request) {
const serverUrl = process.env.SERVER_URL;
try {
const userRes = await axios.get(serverUrl + '/users/me', {
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-Session-Token': request.headers['sessiontoken'],
},
});
const userId = userRes.data && userRes.data.objectId;
const contractuser = new Parse.Query('contracts_Users');
contractuser.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId });
const user = await contractuser.first({ useMasterKey: true });
if (user) {
const updateUser = new Parse.Object('contracts_Users');
updateUser.id = user.id;
updateUser.set('Webhook', request.params.url);
const updatedRes = await updateUser.save(null, { useMasterKey: true });
if (updatedRes) {
return { code: 200, Webhook: updatedRes.get('Webhook') };
}
}
} catch (err) {
console.log('update user', err);
return err;
}
}

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